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