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/net_if.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/net/ethernet.h>
11 #include <zephyr/net/socket.h>
12 #include <zephyr/net/net_ip.h>
13 #include <zephyr/net/net_pkt.h>
14 #include <route.h>
15 #include "ipv6.h"
16 #include "icmpv6.h"
17 #include <zephyr/net/openthread.h>
18 #include <zephyr/net/mld.h>
19 #include <platform-zephyr.h>
20 #include "openthread_border_router.h"
21 #include <common/code_utils.hpp>
22 
23 static struct otInstance *ot_instance;
24 static struct net_if *ail_iface_ptr;
25 
26 static void handle_ra_from_ot(const uint8_t *buffer, uint16_t buffer_length);
27 
otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,const otIp6Address * aDestAddress,const uint8_t * aBuffer,uint16_t aBufferLength)28 otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex, const otIp6Address *aDestAddress,
29 				 const uint8_t *aBuffer, uint16_t aBufferLength)
30 {
31 	otError error = OT_ERROR_NONE;
32 	struct net_pkt *pkt = NULL;
33 	struct in6_addr dst = {0};
34 	const struct in6_addr *src;
35 
36 	if (aBuffer[0] == NET_ICMPV6_RA) {
37 		handle_ra_from_ot(aBuffer, aBufferLength);
38 		net_ipv6_addr_create_ll_allnodes_mcast(&dst);
39 	} else { /* Router solicitation */
40 		net_ipv6_addr_create_ll_allrouters_mcast(&dst);
41 	}
42 
43 	src = net_if_ipv6_select_src_addr(ail_iface_ptr, &dst);
44 	VerifyOrExit(!net_ipv6_is_addr_unspecified(src), error = OT_ERROR_FAILED);
45 
46 	pkt = net_pkt_alloc_with_buffer(ail_iface_ptr, aBufferLength, AF_INET6, IPPROTO_ICMPV6,
47 					K_MSEC(100));
48 	VerifyOrExit(pkt, error = OT_ERROR_FAILED);
49 
50 	net_pkt_set_ipv6_hop_limit(pkt, NET_IPV6_ND_HOP_LIMIT);
51 
52 	VerifyOrExit(net_ipv6_create(pkt, src, &dst) == 0, error = OT_ERROR_FAILED);
53 	VerifyOrExit(net_pkt_write(pkt, aBuffer, aBufferLength) == 0, error = OT_ERROR_FAILED);
54 	net_pkt_cursor_init(pkt);
55 
56 	VerifyOrExit(net_ipv6_finalize(pkt, IPPROTO_ICMPV6) == 0, error = OT_ERROR_FAILED);
57 	VerifyOrExit(net_send_data(pkt) == 0, error = OT_ERROR_FAILED);
58 
59 exit:
60 	if (error == OT_ERROR_FAILED) {
61 		if (pkt) {
62 			net_pkt_unref(pkt);
63 			pkt = NULL;
64 		}
65 	}
66 
67 	return error;
68 }
69 
otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)70 otError otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)
71 {
72 	OT_UNUSED_VARIABLE(aInfraIfIndex);
73 
74 	return OT_ERROR_NOT_IMPLEMENTED;
75 }
76 
otPlatInfraIfHasAddress(uint32_t aInfraIfIndex,const otIp6Address * aAddress)77 bool otPlatInfraIfHasAddress(uint32_t aInfraIfIndex, const otIp6Address *aAddress)
78 {
79 	struct net_if_addr *ifaddr = NULL;
80 	struct in6_addr addr = {0};
81 
82 	memcpy(addr.s6_addr, aAddress->mFields.m8, sizeof(otIp6Address));
83 
84 	STRUCT_SECTION_FOREACH(net_if, tmp) {
85 		if (net_if_get_by_iface(tmp) != aInfraIfIndex) {
86 			continue;
87 		}
88 		ifaddr = net_if_ipv6_addr_lookup_by_iface(tmp, &addr);
89 		if (ifaddr) {
90 			return true;
91 		} else {
92 			return false;
93 		}
94 	}
95 	return false;
96 }
97 
otPlatGetInfraIfLinkLayerAddress(otInstance * aInstance,uint32_t aIfIndex,otPlatInfraIfLinkLayerAddress * aInfraIfLinkLayerAddress)98 otError otPlatGetInfraIfLinkLayerAddress(otInstance *aInstance, uint32_t aIfIndex,
99 					 otPlatInfraIfLinkLayerAddress *aInfraIfLinkLayerAddress)
100 {
101 	OT_UNUSED_VARIABLE(aInstance);
102 	struct net_if *iface = net_if_get_by_index(aIfIndex);
103 	struct net_linkaddr *link_addr = net_if_get_link_addr(iface);
104 
105 	aInfraIfLinkLayerAddress->mLength = link_addr->len;
106 	memcpy(aInfraIfLinkLayerAddress->mAddress, link_addr->addr, link_addr->len);
107 
108 	return OT_ERROR_NONE;
109 }
110 
infra_if_init(otInstance * instance,struct net_if * ail_iface)111 otError infra_if_init(otInstance *instance, struct net_if *ail_iface)
112 {
113 	otError error = OT_ERROR_NONE;
114 	struct in6_addr addr = {0};
115 	int ret;
116 
117 	ot_instance = instance;
118 	ail_iface_ptr = ail_iface;
119 	net_ipv6_addr_create_ll_allrouters_mcast(&addr);
120 	ret = net_ipv6_mld_join(ail_iface, &addr);
121 	VerifyOrExit(ret == 0, error = OT_ERROR_FAILED);
122 
123 exit:
124 	return error;
125 }
126 
handle_ra_from_ot(const uint8_t * buffer,uint16_t buffer_length)127 static void handle_ra_from_ot(const uint8_t *buffer, uint16_t buffer_length)
128 {
129 	struct net_if *ot_iface = net_if_get_first_by_type(&NET_L2_GET_NAME(OPENTHREAD));
130 	struct net_if_ipv6_prefix *prefix_added = NULL;
131 	struct net_route_entry *route_added = NULL;
132 	struct in6_addr rio_prefix = {0};
133 	struct net_if_addr *ifaddr = NULL;
134 	struct in6_addr addr_to_add_from_pio = {0};
135 	struct in6_addr nexthop = {0};
136 	uint8_t i = sizeof(struct net_icmp_hdr) + sizeof(struct net_icmpv6_ra_hdr);
137 
138 	while (i + sizeof(struct net_icmpv6_nd_opt_hdr) <= buffer_length) {
139 		const struct net_icmpv6_nd_opt_hdr *opt_hdr =
140 			(const struct net_icmpv6_nd_opt_hdr *)&buffer[i];
141 
142 		i += sizeof(struct net_icmpv6_nd_opt_hdr);
143 		switch (opt_hdr->type) {
144 		case NET_ICMPV6_ND_OPT_PREFIX_INFO:
145 			const struct net_icmpv6_nd_opt_prefix_info *pio =
146 				(const struct net_icmpv6_nd_opt_prefix_info *)&buffer[i];
147 			prefix_added = net_if_ipv6_prefix_add(ail_iface_ptr,
148 							      (struct in6_addr *)pio->prefix,
149 							      pio->prefix_len, pio->valid_lifetime);
150 			i += sizeof(struct net_icmpv6_nd_opt_prefix_info);
151 			net_ipv6_addr_generate_iid(
152 				ail_iface_ptr, (struct in6_addr *)pio->prefix,
153 				COND_CODE_1(CONFIG_NET_IPV6_IID_STABLE,
154 				     ((uint8_t *)&ail_iface_ptr->config.ip.ipv6->network_counter),
155 				     (NULL)), COND_CODE_1(CONFIG_NET_IPV6_IID_STABLE,
156 				     (sizeof(ail_iface_ptr->config.ip.ipv6->network_counter)),
157 				     (0U)), 0U, &addr_to_add_from_pio,
158 							       net_if_get_link_addr(ail_iface_ptr));
159 			ifaddr = net_if_ipv6_addr_lookup(&addr_to_add_from_pio, NULL);
160 			if (ifaddr) {
161 				net_if_addr_set_lf(ifaddr, true);
162 			}
163 			net_if_ipv6_addr_add(ail_iface_ptr, &addr_to_add_from_pio,
164 					     NET_ADDR_AUTOCONF, pio->valid_lifetime);
165 			break;
166 		case NET_ICMPV6_ND_OPT_ROUTE:
167 			uint8_t prefix_field_len = (opt_hdr->len - 1) * 8;
168 			const otIp6Address *br_omr_addr = get_ot_slaac_address(ot_instance);
169 
170 			const struct net_icmpv6_nd_opt_route_info *rio =
171 				(const struct net_icmpv6_nd_opt_route_info *)&buffer[i];
172 
173 			i += sizeof(struct net_icmpv6_nd_opt_route_info);
174 			memcpy(&rio_prefix.s6_addr, &buffer[i], prefix_field_len);
175 			if (!otIp6IsAddressUnspecified(br_omr_addr)) {
176 				memcpy(&nexthop.s6_addr, br_omr_addr->mFields.m8,
177 				       sizeof(br_omr_addr->mFields.m8));
178 				net_ipv6_nbr_add(ot_iface, &nexthop, net_if_get_link_addr(ot_iface),
179 						 false, NET_IPV6_NBR_STATE_STALE);
180 				route_added = net_route_add(ot_iface, &rio_prefix, rio->prefix_len,
181 							    &nexthop, rio->route_lifetime,
182 							    rio->flags.prf);
183 			}
184 			break;
185 		default:
186 			break;
187 		}
188 	}
189 }
190