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