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