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