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_DECLARE(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/openthread.h>
13
14 #include <openthread/ip6.h>
15 #include <openthread/thread.h>
16
17 #include "openthread_utils.h"
18
19 #define ALOC16_MASK 0xfc
20
is_anycast_locator(const otNetifAddress * address)21 static bool is_anycast_locator(const otNetifAddress *address)
22 {
23 return address->mAddress.mFields.m16[4] == htons(0x0000) &&
24 address->mAddress.mFields.m16[5] == htons(0x00ff) &&
25 address->mAddress.mFields.m16[6] == htons(0xfe00) &&
26 address->mAddress.mFields.m8[14] == ALOC16_MASK;
27 }
28
is_mesh_local(struct openthread_context * context,const uint8_t * address)29 static bool is_mesh_local(struct openthread_context *context,
30 const uint8_t *address)
31 {
32 const otMeshLocalPrefix *ml_prefix =
33 otThreadGetMeshLocalPrefix(context->instance);
34
35 return (memcmp(address, ml_prefix->m8, sizeof(ml_prefix)) == 0);
36 }
37
pkt_list_add(struct openthread_context * context,struct net_pkt * pkt)38 int pkt_list_add(struct openthread_context *context, struct net_pkt *pkt)
39 {
40 uint16_t i_idx = context->pkt_list_in_idx;
41
42 if (context->pkt_list_full) {
43 return -ENOMEM;
44 }
45
46 i_idx++;
47 if (i_idx == CONFIG_OPENTHREAD_PKT_LIST_SIZE) {
48 i_idx = 0U;
49 }
50
51 if (i_idx == context->pkt_list_out_idx) {
52 context->pkt_list_full = 1U;
53 }
54
55 context->pkt_list[context->pkt_list_in_idx].pkt = pkt;
56 context->pkt_list_in_idx = i_idx;
57
58 return 0;
59 }
60
pkt_list_remove_first(struct openthread_context * context)61 void pkt_list_remove_first(struct openthread_context *context)
62 {
63 uint16_t idx = context->pkt_list_in_idx;
64
65 if (idx == 0U) {
66 idx = CONFIG_OPENTHREAD_PKT_LIST_SIZE - 1;
67 } else {
68 idx--;
69 }
70 context->pkt_list_in_idx = idx;
71
72 if (context->pkt_list_full) {
73 context->pkt_list_full = 0U;
74 }
75 }
76
pkt_list_peek(struct openthread_context * context)77 struct net_pkt *pkt_list_peek(struct openthread_context *context)
78 {
79 if ((context->pkt_list_in_idx == context->pkt_list_out_idx) &&
80 (!context->pkt_list_full)) {
81
82 return NULL;
83 }
84 return context->pkt_list[context->pkt_list_out_idx].pkt;
85 }
86
pkt_list_remove_last(struct openthread_context * context)87 void pkt_list_remove_last(struct openthread_context *context)
88 {
89 if ((context->pkt_list_in_idx == context->pkt_list_out_idx) &&
90 (!context->pkt_list_full)) {
91
92 return;
93 }
94
95 context->pkt_list_out_idx++;
96 if (context->pkt_list_out_idx == CONFIG_OPENTHREAD_PKT_LIST_SIZE) {
97 context->pkt_list_out_idx = 0U;
98 }
99
100 context->pkt_list_full = 0U;
101 }
102
add_ipv6_addr_to_zephyr(struct openthread_context * context)103 void add_ipv6_addr_to_zephyr(struct openthread_context *context)
104 {
105 const otNetifAddress *address;
106 struct net_if_addr *if_addr;
107
108 for (address = otIp6GetUnicastAddresses(context->instance);
109 address; address = address->mNext) {
110
111 if (address->mRloc || is_anycast_locator(address)) {
112 continue;
113 }
114
115 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
116 char buf[NET_IPV6_ADDR_LEN];
117
118 NET_DBG("Adding %s",
119 net_addr_ntop(AF_INET6,
120 (struct in6_addr *)(&address->mAddress),
121 buf, sizeof(buf)));
122 }
123
124 /* Thread and SLAAC are clearly AUTOCONF, handle
125 * manual/NCP addresses in the same way
126 */
127 if ((address->mAddressOrigin == OT_ADDRESS_ORIGIN_THREAD) ||
128 (address->mAddressOrigin == OT_ADDRESS_ORIGIN_SLAAC)) {
129 if_addr = net_if_ipv6_addr_add(
130 context->iface,
131 (struct in6_addr *)(&address->mAddress),
132 NET_ADDR_AUTOCONF, 0);
133 } else if (address->mAddressOrigin ==
134 OT_ADDRESS_ORIGIN_DHCPV6) {
135 if_addr = net_if_ipv6_addr_add(
136 context->iface,
137 (struct in6_addr *)(&address->mAddress),
138 NET_ADDR_DHCP, 0);
139 } else if (address->mAddressOrigin ==
140 OT_ADDRESS_ORIGIN_MANUAL) {
141 if_addr = net_if_ipv6_addr_add(
142 context->iface,
143 (struct in6_addr *)(&address->mAddress),
144 NET_ADDR_MANUAL, 0);
145 } else {
146 NET_ERR("Unknown OpenThread address origin ignored.");
147 continue;
148 }
149
150 if (if_addr == NULL) {
151 NET_ERR("Cannot add OpenThread unicast address");
152 continue;
153 }
154
155 if_addr->is_mesh_local = is_mesh_local(
156 context, address->mAddress.mFields.m8);
157 }
158 }
159
add_ipv6_addr_to_ot(struct openthread_context * context,const struct in6_addr * addr6)160 void add_ipv6_addr_to_ot(struct openthread_context *context,
161 const struct in6_addr *addr6)
162 {
163 struct otNetifAddress addr = { 0 };
164 struct net_if_ipv6 *ipv6;
165 struct net_if_addr *if_addr = NULL;
166 int i;
167
168 /* IPv6 struct should've already been allocated when we get an
169 * address added event.
170 */
171 ipv6 = context->iface->config.ip.ipv6;
172 if (ipv6 == NULL) {
173 NET_ERR("No IPv6 container allocated");
174 return;
175 }
176
177 /* Find the net_if_addr structure containing the newly added address. */
178 for (i = NET_IF_MAX_IPV6_ADDR - 1; i >= 0; i--) {
179 if (ipv6->unicast[i].is_used &&
180 net_ipv6_addr_cmp(&ipv6->unicast[i].address.in6_addr,
181 addr6)) {
182 if_addr = &ipv6->unicast[i];
183 break;
184 }
185 }
186
187 if (if_addr == NULL) {
188 NET_ERR("No corresponding net_if_addr found");
189 return;
190 }
191
192 memcpy(&addr.mAddress, addr6, sizeof(addr.mAddress));
193
194 if_addr->is_mesh_local = is_mesh_local(
195 context, ipv6->unicast[i].address.in6_addr.s6_addr);
196
197 addr.mValid = true;
198 addr.mPreferred = true;
199 addr.mPrefixLength = 64;
200
201 if (if_addr->addr_type == NET_ADDR_AUTOCONF) {
202 addr.mAddressOrigin = OT_ADDRESS_ORIGIN_SLAAC;
203 } else if (if_addr->addr_type == NET_ADDR_DHCP) {
204 addr.mAddressOrigin = OT_ADDRESS_ORIGIN_DHCPV6;
205 } else if (if_addr->addr_type == NET_ADDR_MANUAL) {
206 addr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL;
207 } else {
208 NET_ERR("Unknown address type");
209 return;
210 }
211
212 openthread_api_mutex_lock(context);
213 otIp6AddUnicastAddress(context->instance, &addr);
214 openthread_api_mutex_unlock(context);
215
216 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
217 char buf[NET_IPV6_ADDR_LEN];
218
219 NET_DBG("Added %s",
220 net_addr_ntop(AF_INET6, &addr.mAddress, buf, sizeof(buf)));
221 }
222 }
223
add_ipv6_maddr_to_ot(struct openthread_context * context,const struct in6_addr * addr6)224 void add_ipv6_maddr_to_ot(struct openthread_context *context,
225 const struct in6_addr *addr6)
226 {
227 struct otIp6Address addr;
228
229 memcpy(&addr, addr6, sizeof(addr));
230
231 openthread_api_mutex_lock(context);
232 otIp6SubscribeMulticastAddress(context->instance, &addr);
233 openthread_api_mutex_unlock(context);
234
235 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
236 char buf[NET_IPV6_ADDR_LEN];
237
238 NET_DBG("Added multicast %s",
239 net_addr_ntop(AF_INET6, &addr, buf, sizeof(buf)));
240 }
241 }
242
add_ipv6_maddr_to_zephyr(struct openthread_context * context)243 void add_ipv6_maddr_to_zephyr(struct openthread_context *context)
244 {
245 const otNetifMulticastAddress *maddress;
246 struct net_if_mcast_addr *zmaddr;
247
248 for (maddress = otIp6GetMulticastAddresses(context->instance);
249 maddress; maddress = maddress->mNext) {
250 if (net_if_ipv6_maddr_lookup(
251 (struct in6_addr *)(&maddress->mAddress),
252 &context->iface) != NULL) {
253 continue;
254 }
255
256 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
257 char buf[NET_IPV6_ADDR_LEN];
258
259 NET_DBG("Adding multicast %s",
260 net_addr_ntop(AF_INET6,
261 (struct in6_addr *)
262 (&maddress->mAddress),
263 buf, sizeof(buf)));
264 }
265
266 zmaddr = net_if_ipv6_maddr_add(context->iface,
267 (struct in6_addr *)(&maddress->mAddress));
268
269 if (zmaddr &&
270 !(net_if_ipv6_maddr_is_joined(zmaddr) ||
271 net_ipv6_is_addr_mcast_iface(
272 (struct in6_addr *)(&maddress->mAddress)) ||
273 net_ipv6_is_addr_mcast_link_all_nodes(
274 (struct in6_addr *)(&maddress->mAddress)))) {
275
276 net_if_ipv6_maddr_join(context->iface, zmaddr);
277 }
278 }
279 }
280
rm_ipv6_addr_from_zephyr(struct openthread_context * context)281 void rm_ipv6_addr_from_zephyr(struct openthread_context *context)
282 {
283 struct in6_addr *ot_addr;
284 struct net_if_addr *zephyr_addr;
285 struct net_if_ipv6 *ipv6;
286 int i;
287
288 if (net_if_config_ipv6_get(context->iface, &ipv6) < 0) {
289 NET_DBG("Cannot find IPv6 address");
290 return;
291 }
292
293 for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
294 const otNetifAddress *address;
295 bool used = false;
296
297 zephyr_addr = &ipv6->unicast[i];
298 if (!zephyr_addr->is_used) {
299 continue;
300 }
301
302 for (address = otIp6GetUnicastAddresses(context->instance);
303 address; address = address->mNext) {
304
305 ot_addr = (struct in6_addr *)(&address->mAddress);
306 if (net_ipv6_addr_cmp(ot_addr,
307 &zephyr_addr->address.in6_addr)) {
308
309 used = true;
310 break;
311 }
312 }
313 if (!used) {
314 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
315 char buf[NET_IPV6_ADDR_LEN];
316
317 NET_DBG("Removing %s",
318 net_addr_ntop(AF_INET6,
319 &zephyr_addr->address.in6_addr,
320 buf, sizeof(buf)));
321 }
322
323 net_if_ipv6_addr_rm(context->iface,
324 &zephyr_addr->address.in6_addr);
325 }
326 }
327 }
328
rm_ipv6_maddr_from_zephyr(struct openthread_context * context)329 void rm_ipv6_maddr_from_zephyr(struct openthread_context *context)
330 {
331 struct in6_addr *ot_addr;
332 struct net_if_mcast_addr *zephyr_addr;
333 struct net_if_ipv6 *ipv6;
334 int i;
335
336 if (net_if_config_ipv6_get(context->iface, &ipv6) < 0) {
337 NET_DBG("Cannot find IPv6 address");
338 return;
339 }
340
341 for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
342 const otNetifMulticastAddress *maddress;
343 bool used = false;
344
345 zephyr_addr = &ipv6->mcast[i];
346 if (!zephyr_addr->is_used) {
347 continue;
348 }
349
350 for (maddress = otIp6GetMulticastAddresses(context->instance);
351 maddress; maddress = maddress->mNext) {
352
353 ot_addr = (struct in6_addr *)(&maddress->mAddress);
354 if (net_ipv6_addr_cmp(ot_addr,
355 &zephyr_addr->address.in6_addr)) {
356
357 used = true;
358 break;
359 }
360 }
361 if (!used) {
362 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
363 char buf[NET_IPV6_ADDR_LEN];
364
365 NET_DBG("Removing multicast %s",
366 net_addr_ntop(AF_INET6,
367 &zephyr_addr->address.in6_addr,
368 buf, sizeof(buf)));
369 }
370
371 net_if_ipv6_maddr_rm(context->iface,
372 &zephyr_addr->address.in6_addr);
373 }
374 }
375 }
376