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