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->m8)) == 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 /* Mark address as deprecated if it is not preferred. */
159 if_addr->addr_state =
160 address->mPreferred ? NET_ADDR_PREFERRED : NET_ADDR_DEPRECATED;
161 }
162 }
163
add_ipv6_addr_to_ot(struct openthread_context * context,const struct in6_addr * addr6)164 void add_ipv6_addr_to_ot(struct openthread_context *context,
165 const struct in6_addr *addr6)
166 {
167 struct otNetifAddress addr = { 0 };
168 struct net_if_ipv6 *ipv6;
169 struct net_if_addr *if_addr = NULL;
170 int i;
171
172 /* IPv6 struct should've already been allocated when we get an
173 * address added event.
174 */
175 ipv6 = context->iface->config.ip.ipv6;
176 if (ipv6 == NULL) {
177 NET_ERR("No IPv6 container allocated");
178 return;
179 }
180
181 /* Find the net_if_addr structure containing the newly added address. */
182 for (i = NET_IF_MAX_IPV6_ADDR - 1; i >= 0; i--) {
183 if (ipv6->unicast[i].is_used &&
184 net_ipv6_addr_cmp(&ipv6->unicast[i].address.in6_addr,
185 addr6)) {
186 if_addr = &ipv6->unicast[i];
187 break;
188 }
189 }
190
191 if (if_addr == NULL) {
192 NET_ERR("No corresponding net_if_addr found");
193 return;
194 }
195
196 memcpy(&addr.mAddress, addr6, sizeof(addr.mAddress));
197
198 if_addr->is_mesh_local = is_mesh_local(
199 context, ipv6->unicast[i].address.in6_addr.s6_addr);
200
201 addr.mValid = true;
202 addr.mPreferred = (if_addr->addr_state == NET_ADDR_PREFERRED);
203 addr.mPrefixLength = 64;
204
205 if (if_addr->addr_type == NET_ADDR_AUTOCONF) {
206 addr.mAddressOrigin = OT_ADDRESS_ORIGIN_SLAAC;
207 } else if (if_addr->addr_type == NET_ADDR_DHCP) {
208 addr.mAddressOrigin = OT_ADDRESS_ORIGIN_DHCPV6;
209 } else if (if_addr->addr_type == NET_ADDR_MANUAL) {
210 addr.mAddressOrigin = OT_ADDRESS_ORIGIN_MANUAL;
211 } else {
212 NET_ERR("Unknown address type");
213 return;
214 }
215
216 openthread_api_mutex_lock(context);
217 otIp6AddUnicastAddress(context->instance, &addr);
218 openthread_api_mutex_unlock(context);
219
220 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
221 char buf[NET_IPV6_ADDR_LEN];
222
223 NET_DBG("Added %s",
224 net_addr_ntop(AF_INET6, &addr.mAddress, buf, sizeof(buf)));
225 }
226 }
227
add_ipv6_maddr_to_ot(struct openthread_context * context,const struct in6_addr * addr6)228 void add_ipv6_maddr_to_ot(struct openthread_context *context,
229 const struct in6_addr *addr6)
230 {
231 struct otIp6Address addr;
232
233 memcpy(&addr, addr6, sizeof(addr));
234
235 openthread_api_mutex_lock(context);
236 otIp6SubscribeMulticastAddress(context->instance, &addr);
237 openthread_api_mutex_unlock(context);
238
239 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
240 char buf[NET_IPV6_ADDR_LEN];
241
242 NET_DBG("Added multicast %s",
243 net_addr_ntop(AF_INET6, &addr, buf, sizeof(buf)));
244 }
245 }
246
add_ipv6_maddr_to_zephyr(struct openthread_context * context)247 void add_ipv6_maddr_to_zephyr(struct openthread_context *context)
248 {
249 const otNetifMulticastAddress *maddress;
250 struct net_if_mcast_addr *zmaddr;
251
252 for (maddress = otIp6GetMulticastAddresses(context->instance);
253 maddress; maddress = maddress->mNext) {
254 if (net_if_ipv6_maddr_lookup(
255 (struct in6_addr *)(&maddress->mAddress),
256 &context->iface) != NULL) {
257 continue;
258 }
259
260 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
261 char buf[NET_IPV6_ADDR_LEN];
262
263 NET_DBG("Adding multicast %s",
264 net_addr_ntop(AF_INET6,
265 (struct in6_addr *)
266 (&maddress->mAddress),
267 buf, sizeof(buf)));
268 }
269
270 zmaddr = net_if_ipv6_maddr_add(context->iface,
271 (struct in6_addr *)(&maddress->mAddress));
272
273 if (zmaddr &&
274 !(net_if_ipv6_maddr_is_joined(zmaddr) ||
275 net_ipv6_is_addr_mcast_iface(
276 (struct in6_addr *)(&maddress->mAddress)) ||
277 net_ipv6_is_addr_mcast_link_all_nodes(
278 (struct in6_addr *)(&maddress->mAddress)))) {
279
280 net_if_ipv6_maddr_join(context->iface, zmaddr);
281 }
282 }
283 }
284
rm_ipv6_addr_from_zephyr(struct openthread_context * context)285 void rm_ipv6_addr_from_zephyr(struct openthread_context *context)
286 {
287 struct in6_addr *ot_addr;
288 struct net_if_addr *zephyr_addr;
289 struct net_if_ipv6 *ipv6;
290 int i;
291
292 if (net_if_config_ipv6_get(context->iface, &ipv6) < 0) {
293 NET_DBG("Cannot find IPv6 address");
294 return;
295 }
296
297 for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) {
298 const otNetifAddress *address;
299 bool used = false;
300
301 zephyr_addr = &ipv6->unicast[i];
302 if (!zephyr_addr->is_used) {
303 continue;
304 }
305
306 for (address = otIp6GetUnicastAddresses(context->instance);
307 address; address = address->mNext) {
308
309 ot_addr = (struct in6_addr *)(&address->mAddress);
310 if (net_ipv6_addr_cmp(ot_addr,
311 &zephyr_addr->address.in6_addr)) {
312
313 used = true;
314 break;
315 }
316 }
317 if (!used) {
318 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
319 char buf[NET_IPV6_ADDR_LEN];
320
321 NET_DBG("Removing %s",
322 net_addr_ntop(AF_INET6,
323 &zephyr_addr->address.in6_addr,
324 buf, sizeof(buf)));
325 }
326
327 net_if_ipv6_addr_rm(context->iface,
328 &zephyr_addr->address.in6_addr);
329 }
330 }
331 }
332
rm_ipv6_maddr_from_zephyr(struct openthread_context * context)333 void rm_ipv6_maddr_from_zephyr(struct openthread_context *context)
334 {
335 struct in6_addr *ot_addr;
336 struct net_if_mcast_addr *zephyr_addr;
337 struct net_if_ipv6 *ipv6;
338 int i;
339
340 if (net_if_config_ipv6_get(context->iface, &ipv6) < 0) {
341 NET_DBG("Cannot find IPv6 address");
342 return;
343 }
344
345 for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
346 const otNetifMulticastAddress *maddress;
347 bool used = false;
348
349 zephyr_addr = &ipv6->mcast[i];
350 if (!zephyr_addr->is_used) {
351 continue;
352 }
353
354 for (maddress = otIp6GetMulticastAddresses(context->instance);
355 maddress; maddress = maddress->mNext) {
356
357 ot_addr = (struct in6_addr *)(&maddress->mAddress);
358 if (net_ipv6_addr_cmp(ot_addr,
359 &zephyr_addr->address.in6_addr)) {
360
361 used = true;
362 break;
363 }
364 }
365 if (!used) {
366 if (CONFIG_OPENTHREAD_L2_LOG_LEVEL == LOG_LEVEL_DBG) {
367 char buf[NET_IPV6_ADDR_LEN];
368
369 NET_DBG("Removing multicast %s",
370 net_addr_ntop(AF_INET6,
371 &zephyr_addr->address.in6_addr,
372 buf, sizeof(buf)));
373 }
374
375 net_if_ipv6_maddr_rm(context->iface,
376 &zephyr_addr->address.in6_addr);
377 }
378 }
379 }
380