1 /** @file
2  * @brief IPv6 privacy extension (RFC 8981)
3  */
4 
5 /*
6  * Copyright (c) 2018 Intel Corporation
7  * Copyright (c) 2024 Nordic Semiconductor
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(net_ipv6_pe, CONFIG_NET_IPV6_PE_LOG_LEVEL);
14 
15 #include <errno.h>
16 #include <stdlib.h>
17 
18 #include <zephyr/kernel.h>
19 #include <zephyr/random/random.h>
20 
21 #include <mbedtls/md.h>
22 
23 #include <zephyr/net/net_core.h>
24 #include <zephyr/net/net_pkt.h>
25 #include <zephyr/net/net_if.h>
26 
27 #include "net_private.h"
28 #include "ipv6.h"
29 
30 /* From RFC 5453 */
31 static const struct in6_addr reserved_anycast_subnet = { { {
32 			0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
33 			0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
34 		} } };
35 
36 /* RFC 8981 ch 3.8 preferred lifetime must be smaller than valid lifetime */
37 BUILD_ASSERT(CONFIG_NET_IPV6_PE_TEMP_PREFERRED_LIFETIME <
38 	     CONFIG_NET_IPV6_PE_TEMP_VALID_LIFETIME);
39 
40 /* IPv6 privacy extension (RFC 8981) constants. Note that the code uses
41  * seconds value internally for applicable options. These are also values
42  * that can be changed at runtime if needed as recommended in RFC 8981
43  * chapter 3.6.
44  */
45 static uint32_t temp_valid_lifetime =
46 	CONFIG_NET_IPV6_PE_TEMP_VALID_LIFETIME * SEC_PER_MIN;
47 #define TEMP_VALID_LIFETIME temp_valid_lifetime
48 
49 static uint32_t temp_preferred_lifetime =
50 	CONFIG_NET_IPV6_PE_TEMP_PREFERRED_LIFETIME * SEC_PER_MIN;
51 #define TEMP_PREFERRED_LIFETIME temp_preferred_lifetime
52 
53 /* This is the upper bound on DESYNC_FACTOR. The value is in seconds.
54  * See RFC 8981 ch 3.8 for details.
55  *
56  * RFC says the DESYNC_FACTOR should be 0.4 times the preferred lifetime.
57  * This is too short for Zephyr as it means that the address is very long
58  * time in deprecated state and not being used. Make this 7% of the preferred
59  * time to deprecate the addresses later.
60  */
61 #define MAX_DESYNC_FACTOR   ((uint32_t)((uint64_t)TEMP_PREFERRED_LIFETIME * \
62 				       (uint64_t)7U) / (uint64_t)100U)
63 #define DESYNC_FACTOR(ipv6) ((ipv6)->desync_factor)
64 
65 #define TEMP_IDGEN_RETRIES      CONFIG_NET_IPV6_PE_TEMP_IDGEN_RETRIES
66 
67 /* The REGEN_ADVANCE is in seconds
68  * retrans_timer (in ms) is specified in RFC 4861
69  * dup_addr_detect_transmits (in ms) is specified in RFC 4862
70  */
REGEN_ADVANCE(uint32_t retrans_timer,uint32_t dup_addr_detect_transmits)71 static inline uint32_t REGEN_ADVANCE(uint32_t retrans_timer,
72 				     uint32_t dup_addr_detect_transmits)
73 {
74 	return (2U + (uint32_t)((uint64_t)TEMP_IDGEN_RETRIES *
75 				(uint64_t)retrans_timer *
76 				(uint64_t)dup_addr_detect_transmits /
77 				(uint64_t)1000U));
78 }
79 
80 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
81 /* Is this denylisting filter or not */
82 static bool ipv6_pe_denylist;
83 static struct in6_addr ipv6_pe_filter[CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT];
84 
85 static K_MUTEX_DEFINE(lock);
86 #endif
87 
88 /* We need to periodically update the private address. */
89 static struct k_work_delayable temp_lifetime;
90 
ipv6_pe_use_this_prefix(const struct in6_addr * prefix)91 static bool ipv6_pe_use_this_prefix(const struct in6_addr *prefix)
92 {
93 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
94 	int filter_found = false;
95 	bool ret = true;
96 
97 	k_mutex_lock(&lock, K_FOREVER);
98 
99 	ARRAY_FOR_EACH(ipv6_pe_filter, i) {
100 		if (net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) {
101 			continue;
102 		}
103 
104 		filter_found = true;
105 
106 		if (net_ipv6_addr_cmp(prefix, &ipv6_pe_filter[i])) {
107 			if (ipv6_pe_denylist) {
108 				ret = false;
109 			}
110 
111 			goto out;
112 		}
113 	}
114 
115 	if (filter_found) {
116 		/* There was no match so if we are deny listing, then this
117 		 * address must be acceptable.
118 		 */
119 		if (!ipv6_pe_denylist) {
120 			ret = false;
121 			goto out;
122 		}
123 	}
124 
125 out:
126 	k_mutex_unlock(&lock);
127 
128 	return ret;
129 #else
130 	ARG_UNUSED(prefix);
131 
132 	return true;
133 #endif
134 }
135 
ipv6_pe_prefix_already_exists(struct net_if_ipv6 * ipv6,const struct in6_addr * prefix)136 static bool ipv6_pe_prefix_already_exists(struct net_if_ipv6 *ipv6,
137 					  const struct in6_addr *prefix)
138 {
139 	ARRAY_FOR_EACH(ipv6->unicast, i) {
140 		if (!ipv6->unicast[i].is_used ||
141 		    ipv6->unicast[i].address.family != AF_INET6 ||
142 		    !ipv6->unicast[i].is_temporary ||
143 		    ipv6->unicast[i].addr_state == NET_ADDR_DEPRECATED) {
144 			continue;
145 		}
146 
147 		if (net_ipv6_is_prefix(
148 			    (uint8_t *)&ipv6->unicast[i].address.in6_addr,
149 			    (uint8_t *)prefix, 64)) {
150 			return true;
151 		}
152 	}
153 
154 	return false;
155 }
156 
ipv6_pe_prefix_remove(struct net_if * iface,struct net_if_ipv6 * ipv6,const struct in6_addr * prefix)157 static int ipv6_pe_prefix_remove(struct net_if *iface,
158 				 struct net_if_ipv6 *ipv6,
159 				 const struct in6_addr *prefix)
160 {
161 	int count = 0;
162 
163 	ARRAY_FOR_EACH(ipv6->unicast, i) {
164 		if (ipv6->unicast[i].is_used &&
165 		    ipv6->unicast[i].address.family == AF_INET6 &&
166 		    ipv6->unicast[i].is_temporary &&
167 		    net_ipv6_is_prefix(
168 			    (uint8_t *)&ipv6->unicast[i].address.in6_addr,
169 			    (uint8_t *)prefix, 64)) {
170 			net_if_ipv6_addr_rm(iface,
171 					    &ipv6->unicast[i].address.in6_addr);
172 			count++;
173 		}
174 	}
175 
176 	return count;
177 }
178 
ipv6_pe_prefix_update_lifetimes(struct net_if_ipv6 * ipv6,const struct in6_addr * prefix,uint32_t vlifetime)179 static bool ipv6_pe_prefix_update_lifetimes(struct net_if_ipv6 *ipv6,
180 					    const struct in6_addr *prefix,
181 					    uint32_t vlifetime)
182 {
183 	int32_t addr_age, new_age;
184 
185 	ARRAY_FOR_EACH(ipv6->unicast, i) {
186 		if (!(ipv6->unicast[i].is_used &&
187 		      ipv6->unicast[i].address.family == AF_INET6 &&
188 		      ipv6->unicast[i].is_temporary &&
189 		      ipv6->unicast[i].addr_state == NET_ADDR_PREFERRED &&
190 		      net_ipv6_is_prefix(
191 			      (uint8_t *)&ipv6->unicast[i].address.in6_addr,
192 			      (uint8_t *)prefix, 64))) {
193 			continue;
194 		}
195 
196 		addr_age = k_uptime_seconds() - ipv6->unicast[i].addr_create_time;
197 		new_age = abs(addr_age) + vlifetime;
198 
199 		if ((new_age >= TEMP_VALID_LIFETIME) ||
200 		    (new_age >= (TEMP_PREFERRED_LIFETIME -
201 				 DESYNC_FACTOR(ipv6)))) {
202 			break;
203 		}
204 
205 		net_if_ipv6_addr_update_lifetime(&ipv6->unicast[i], vlifetime);
206 
207 		/* RFC 8981 ch 3.5, "... at most one temporary address per
208 		 * prefix should be in a non-deprecated state at any given
209 		 * time on a given interface."
210 		 * Because of this there is no need to continue the loop.
211 		 */
212 		return true;
213 	}
214 
215 	return false;
216 }
217 
218 /* RFC 8981 ch 3.3.2 */
gen_temporary_iid(struct net_if * iface,const struct in6_addr * prefix,uint8_t * network_id,size_t network_id_len,uint8_t dad_counter,uint8_t * temporary_iid,size_t temporary_iid_len)219 static int gen_temporary_iid(struct net_if *iface,
220 			     const struct in6_addr *prefix,
221 			     uint8_t *network_id, size_t network_id_len,
222 			     uint8_t dad_counter,
223 			     uint8_t *temporary_iid,
224 			     size_t temporary_iid_len)
225 {
226 	const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
227 	mbedtls_md_context_t ctx;
228 	uint8_t digest[32];
229 	int ret;
230 	static bool once;
231 	static uint8_t secret_key[16]; /* Min 128 bits, RFC 8981 ch 3.3.2 */
232 	struct {
233 		struct in6_addr prefix;
234 		uint32_t current_time;
235 		uint8_t network_id[16];
236 		uint8_t mac[6];
237 		uint8_t dad_counter;
238 	} buf = {
239 		.current_time = k_uptime_get_32(),
240 		.dad_counter = dad_counter,
241 	};
242 
243 	memcpy(&buf.prefix, prefix, sizeof(struct in6_addr));
244 
245 	if (network_id != NULL && network_id_len > 0) {
246 		memcpy(buf.network_id, network_id,
247 		       MIN(network_id_len, sizeof(buf.network_id)));
248 	}
249 
250 	memcpy(buf.mac, net_if_get_link_addr(iface)->addr,
251 	       MIN(sizeof(buf.mac), net_if_get_link_addr(iface)->len));
252 
253 	if (!once) {
254 		sys_rand_get(&secret_key, sizeof(secret_key));
255 		once = true;
256 	}
257 
258 	mbedtls_md_init(&ctx);
259 	ret = mbedtls_md_setup(&ctx, md_info, true);
260 	if (ret != 0) {
261 		NET_DBG("Cannot %s hmac (%d)", "setup", ret);
262 		goto err;
263 	}
264 
265 	ret = mbedtls_md_hmac_starts(&ctx, secret_key, sizeof(secret_key));
266 	if (ret != 0) {
267 		NET_DBG("Cannot %s hmac (%d)", "start", ret);
268 		goto err;
269 	}
270 
271 	ret = mbedtls_md_hmac_update(&ctx, (uint8_t *)&buf, sizeof(buf));
272 	if (ret != 0) {
273 		NET_DBG("Cannot %s hmac (%d)", "update", ret);
274 		goto err;
275 	}
276 
277 	ret = mbedtls_md_hmac_finish(&ctx, digest);
278 	if (ret != 0) {
279 		NET_DBG("Cannot %s hmac (%d)", "finish", ret);
280 		goto err;
281 	}
282 
283 	memcpy(temporary_iid, digest, MIN(sizeof(digest), temporary_iid_len));
284 
285 err:
286 	mbedtls_md_free(&ctx);
287 
288 	return ret;
289 }
290 
net_ipv6_pe_start(struct net_if * iface,const struct in6_addr * prefix,uint32_t vlifetime,uint32_t preferred_lifetime)291 void net_ipv6_pe_start(struct net_if *iface, const struct in6_addr *prefix,
292 		       uint32_t vlifetime, uint32_t preferred_lifetime)
293 {
294 	struct net_if_addr *ifaddr;
295 	struct net_if_ipv6 *ipv6;
296 	struct in6_addr addr;
297 	k_ticks_t remaining;
298 	k_timeout_t vlifetimeout;
299 	int i, ret, dad_count = 1;
300 	int32_t lifetime;
301 	bool valid = false;
302 
303 	net_if_lock(iface);
304 
305 	if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
306 		NET_WARN("Cannot do DAD IPv6 config is not valid.");
307 		goto out;
308 	}
309 
310 	if (!ipv6) {
311 		goto out;
312 	}
313 
314 	/* Check if user agrees to use this prefix */
315 	if (!ipv6_pe_use_this_prefix(prefix)) {
316 		NET_DBG("Prefix %s/64 is not to be used",
317 			net_sprint_ipv6_addr(prefix));
318 		goto out;
319 	}
320 
321 	/* If the prefix is already added and it is still valid and is not
322 	 * deprecated, then we do not try to add it again.
323 	 */
324 	if (ipv6_pe_prefix_already_exists(ipv6, prefix)) {
325 		if (vlifetime == 0) {
326 			i = ipv6_pe_prefix_remove(iface, ipv6, prefix);
327 
328 			NET_DBG("Removed %d addresses using prefix %s/64",
329 				i, net_sprint_ipv6_addr(prefix));
330 		} else {
331 			ipv6_pe_prefix_update_lifetimes(ipv6, prefix, vlifetime);
332 		}
333 
334 		goto out;
335 	}
336 
337 	preferred_lifetime = MIN(preferred_lifetime,
338 				 TEMP_PREFERRED_LIFETIME -
339 				 DESYNC_FACTOR(ipv6));
340 	if (preferred_lifetime == 0 ||
341 	    preferred_lifetime <= REGEN_ADVANCE(ipv6->retrans_timer, 1U)) {
342 		NET_DBG("Too short preferred lifetime (%u <= %u), temp address not "
343 			"created for prefix %s/64", preferred_lifetime,
344 			REGEN_ADVANCE(ipv6->retrans_timer, 1U),
345 			net_sprint_ipv6_addr(prefix));
346 		goto out;
347 	}
348 
349 	NET_DBG("Starting PE process for prefix %s/64",
350 		net_sprint_ipv6_addr(prefix));
351 
352 	net_ipaddr_copy(&addr, prefix);
353 
354 	do {
355 		ret = gen_temporary_iid(iface, prefix,
356 					COND_CODE_1(CONFIG_NET_INTERFACE_NAME,
357 						    (iface->config.name,
358 						     sizeof(iface->config.name)),
359 						    (net_if_get_device(iface)->name,
360 						     strlen(net_if_get_device(iface)->name))),
361 					dad_count,
362 					&addr.s6_addr[8], 8U);
363 		if (ret == 0) {
364 			ifaddr = net_if_ipv6_addr_lookup(&addr, NULL);
365 			if (ifaddr == NULL && !net_ipv6_is_addr_unspecified(&addr) &&
366 			    memcmp(&addr, &reserved_anycast_subnet,
367 				   sizeof(struct in6_addr)) != 0) {
368 				valid = true;
369 				break;
370 			}
371 		}
372 
373 	} while (dad_count++ < TEMP_IDGEN_RETRIES);
374 
375 	if (valid == false) {
376 		NET_WARN("Could not create a valid iid for prefix %s/64 for interface %d",
377 			 net_sprint_ipv6_addr(prefix),
378 			 net_if_get_by_iface(iface));
379 		NET_WARN("Disabling IPv6 PE for interface %d",
380 			 net_if_get_by_iface(iface));
381 		net_mgmt_event_notify(NET_EVENT_IPV6_PE_DISABLED, iface);
382 		iface->pe_enabled = false;
383 		goto out;
384 	}
385 
386 	vlifetime = MIN(TEMP_VALID_LIFETIME, vlifetime);
387 
388 	ifaddr = net_if_ipv6_addr_add(iface, &addr, NET_ADDR_AUTOCONF, vlifetime);
389 	if (!ifaddr) {
390 		NET_ERR("Cannot add %s address to interface %d",
391 			net_sprint_ipv6_addr(&addr),
392 			net_if_get_by_iface(iface));
393 		goto out;
394 	}
395 
396 	lifetime = TEMP_VALID_LIFETIME -
397 		REGEN_ADVANCE(net_if_ipv6_get_retrans_timer(iface), 1U);
398 
399 	DESYNC_FACTOR(ipv6) = sys_rand32_get() % MAX_DESYNC_FACTOR;
400 
401 	/* Make sure that the address timeout happens at least two seconds
402 	 * after the deprecation.
403 	 */
404 	DESYNC_FACTOR(ipv6) = MIN(DESYNC_FACTOR(ipv6) + 2U, lifetime);
405 
406 	ifaddr->is_temporary = true;
407 	ifaddr->addr_preferred_lifetime = preferred_lifetime;
408 	ifaddr->addr_timeout = ifaddr->addr_preferred_lifetime - DESYNC_FACTOR(ipv6);
409 	ifaddr->addr_create_time = k_uptime_seconds();
410 
411 	NET_DBG("Lifetime %d desync %d timeout %d preferred %d valid %d",
412 		lifetime, DESYNC_FACTOR(ipv6), ifaddr->addr_timeout,
413 		ifaddr->addr_preferred_lifetime, vlifetime);
414 
415 	NET_DBG("Starting DAD for %s iface %d", net_sprint_ipv6_addr(&addr),
416 		net_if_get_by_iface(iface));
417 
418 	net_if_ipv6_start_dad(iface, ifaddr);
419 
420 	vlifetimeout = K_SECONDS(ifaddr->addr_timeout);
421 
422 	remaining = k_work_delayable_remaining_get(&temp_lifetime);
423 	if (remaining == 0 || remaining > vlifetimeout.ticks) {
424 		NET_DBG("Next check for temp addresses in %d seconds",
425 			ifaddr->addr_timeout);
426 		k_work_schedule(&temp_lifetime, vlifetimeout);
427 	}
428 
429 out:
430 	net_if_unlock(iface);
431 }
432 
433 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
434 
iface_cb(struct net_if * iface,void * user_data)435 static void iface_cb(struct net_if *iface, void *user_data)
436 {
437 	bool is_new_filter_denylist = !ipv6_pe_denylist;
438 	struct in6_addr *prefix = user_data;
439 	struct net_if_ipv6 *ipv6;
440 	int ret;
441 
442 	net_if_lock(iface);
443 
444 	if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
445 		goto out;
446 	}
447 
448 	if (!ipv6) {
449 		goto out;
450 	}
451 
452 	ARRAY_FOR_EACH(ipv6->unicast, i) {
453 		if (!ipv6->unicast[i].is_used ||
454 		    ipv6->unicast[i].address.family != AF_INET6 ||
455 		    !ipv6->unicast[i].is_temporary) {
456 			continue;
457 		}
458 
459 		ret = net_ipv6_is_prefix(
460 				(uint8_t *)&ipv6->unicast[i].address.in6_addr,
461 				(uint8_t *)prefix, 64);
462 
463 		/* TODO: Do this removal gracefully so that applications
464 		 * have time to cope with this change.
465 		 */
466 		if (is_new_filter_denylist) {
467 			if (ret) {
468 				net_if_ipv6_addr_rm(iface,
469 					    &ipv6->unicast[i].address.in6_addr);
470 			}
471 		} else {
472 			if (!ret) {
473 				net_if_ipv6_addr_rm(iface,
474 					    &ipv6->unicast[i].address.in6_addr);
475 			}
476 		}
477 	}
478 
479 out:
480 	net_if_unlock(iface);
481 }
482 
483 /* If we change filter value, then check if existing IPv6 prefixes will
484  * conflict with the new filter.
485  */
ipv6_pe_recheck_filters(bool is_denylist)486 static void ipv6_pe_recheck_filters(bool is_denylist)
487 {
488 	k_mutex_lock(&lock, K_FOREVER);
489 
490 	ARRAY_FOR_EACH(ipv6_pe_filter, i) {
491 		if (net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) {
492 			continue;
493 		}
494 
495 		net_if_foreach(iface_cb, &ipv6_pe_filter[i]);
496 	}
497 
498 	k_mutex_unlock(&lock);
499 }
500 #endif /* CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 */
501 
502 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
send_filter_event(struct in6_addr * addr,bool is_denylist,int event_type)503 static void send_filter_event(struct in6_addr *addr, bool is_denylist,
504 			      int event_type)
505 {
506 	if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) {
507 		struct net_event_ipv6_pe_filter info;
508 
509 		net_ipaddr_copy(&info.prefix, addr);
510 		info.is_deny_list = is_denylist;
511 
512 		net_mgmt_event_notify_with_info(event_type,
513 						NULL,
514 						(const void *)&info,
515 						sizeof(info));
516 	} else {
517 		net_mgmt_event_notify(event_type, NULL);
518 	}
519 }
520 #endif
521 
net_ipv6_pe_add_filter(struct in6_addr * addr,bool is_denylist)522 int net_ipv6_pe_add_filter(struct in6_addr *addr, bool is_denylist)
523 {
524 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
525 	bool found = false;
526 	int free_slot = -1;
527 	int ret = 0;
528 
529 	k_mutex_lock(&lock, K_FOREVER);
530 
531 	ARRAY_FOR_EACH(ipv6_pe_filter, i) {
532 		if (free_slot < 0 &&
533 		    net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) {
534 			free_slot = i;
535 			continue;
536 		}
537 
538 		if (net_ipv6_is_prefix((uint8_t *)addr,
539 				       (uint8_t *)&ipv6_pe_filter[i],
540 				       64)) {
541 			found = true;
542 			break;
543 		}
544 	}
545 
546 	if (found) {
547 		NET_DBG("Filter %s already in the list",
548 			net_sprint_ipv6_addr(addr));
549 		ret = -EALREADY;
550 		goto out;
551 	}
552 
553 	if (free_slot < 0) {
554 		NET_DBG("All filters in use");
555 		ret = -ENOMEM;
556 		goto out;
557 	}
558 
559 	net_ipaddr_copy(&ipv6_pe_filter[free_slot], addr);
560 
561 	if (ipv6_pe_denylist != is_denylist) {
562 		ipv6_pe_recheck_filters(is_denylist);
563 	}
564 
565 	ipv6_pe_denylist = is_denylist ? true : false;
566 
567 	NET_DBG("Adding %s list filter %s",
568 		ipv6_pe_denylist ? "deny" : "allow",
569 		net_sprint_ipv6_addr(&ipv6_pe_filter[free_slot]));
570 
571 	send_filter_event(&ipv6_pe_filter[free_slot],
572 			  is_denylist,
573 			  NET_EVENT_IPV6_PE_FILTER_ADD);
574 out:
575 	k_mutex_unlock(&lock);
576 
577 	return ret;
578 #else
579 	ARG_UNUSED(addr);
580 	ARG_UNUSED(is_denylist);
581 
582 	return -ENOTSUP;
583 #endif
584 }
585 
net_ipv6_pe_del_filter(struct in6_addr * addr)586 int net_ipv6_pe_del_filter(struct in6_addr *addr)
587 {
588 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
589 	int ret = -ENOENT;
590 
591 	k_mutex_lock(&lock, K_FOREVER);
592 
593 	ARRAY_FOR_EACH(ipv6_pe_filter, i) {
594 		if (net_ipv6_addr_cmp(&ipv6_pe_filter[i], addr)) {
595 			NET_DBG("Removing %s list filter %s",
596 				ipv6_pe_denylist ? "deny" : "allow",
597 				net_sprint_ipv6_addr(&ipv6_pe_filter[i]));
598 
599 			send_filter_event(&ipv6_pe_filter[i],
600 					  ipv6_pe_denylist,
601 					  NET_EVENT_IPV6_PE_FILTER_DEL);
602 
603 			net_ipaddr_copy(&ipv6_pe_filter[i],
604 					net_ipv6_unspecified_address());
605 
606 			ret = 0;
607 			goto out;
608 		}
609 	}
610 
611 out:
612 	k_mutex_unlock(&lock);
613 
614 	return ret;
615 #else
616 	ARG_UNUSED(addr);
617 
618 	return -ENOTSUP;
619 #endif
620 }
621 
net_ipv6_pe_check_dad(int count)622 bool net_ipv6_pe_check_dad(int count)
623 {
624 	return count <= TEMP_IDGEN_RETRIES;
625 }
626 
net_ipv6_pe_filter_foreach(net_ipv6_pe_filter_cb_t cb,void * user_data)627 int net_ipv6_pe_filter_foreach(net_ipv6_pe_filter_cb_t cb, void *user_data)
628 {
629 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
630 	int i, count = 0;
631 
632 	k_mutex_lock(&lock, K_FOREVER);
633 
634 	for (i = 0; i < CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT; i++) {
635 		if (net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) {
636 			continue;
637 		}
638 
639 		cb(&ipv6_pe_filter[i], ipv6_pe_denylist, user_data);
640 
641 		count++;
642 	}
643 
644 	k_mutex_unlock(&lock);
645 
646 	return count;
647 #else
648 	ARG_UNUSED(cb);
649 	ARG_UNUSED(user_data);
650 
651 	return 0;
652 #endif
653 }
654 
655 struct deprecated_work {
656 	struct k_work_delayable work;
657 	struct net_if *iface;
658 	struct in6_addr addr;
659 };
660 
661 static struct deprecated_work trigger_deprecated_event;
662 
send_deprecated_event(struct k_work * work)663 static void send_deprecated_event(struct k_work *work)
664 {
665 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
666 	struct deprecated_work *dw = CONTAINER_OF(dwork,
667 						  struct deprecated_work,
668 						  work);
669 
670 	net_mgmt_event_notify_with_info(NET_EVENT_IPV6_ADDR_DEPRECATED,
671 					dw->iface, &dw->addr,
672 					sizeof(struct in6_addr));
673 }
674 
renewal_cb(struct net_if * iface,void * user_data)675 static void renewal_cb(struct net_if *iface, void *user_data)
676 {
677 	struct net_if_ipv6 *ipv6;
678 	struct in6_addr prefix;
679 
680 	if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
681 		return;
682 	}
683 
684 	if (!ipv6) {
685 		return;
686 	}
687 
688 	ARRAY_FOR_EACH(ipv6->unicast, i) {
689 		int32_t diff;
690 
691 		if (!ipv6->unicast[i].is_used ||
692 		    ipv6->unicast[i].address.family != AF_INET6 ||
693 		    !ipv6->unicast[i].is_temporary ||
694 		    ipv6->unicast[i].addr_state == NET_ADDR_DEPRECATED) {
695 			continue;
696 		}
697 
698 		/* If the address is too old, then generate a new one
699 		 * and remove the old address.
700 		 */
701 		diff = (int32_t)(ipv6->unicast[i].addr_create_time - k_uptime_seconds());
702 		diff = abs(diff);
703 
704 		if (diff < (ipv6->unicast[i].addr_preferred_lifetime -
705 			    REGEN_ADVANCE(ipv6->retrans_timer, 1U) -
706 			    DESYNC_FACTOR(ipv6))) {
707 			continue;
708 		}
709 
710 		net_ipaddr_copy(&prefix, &ipv6->unicast[i].address.in6_addr);
711 		memset(prefix.s6_addr + 8, 0, sizeof(prefix) - 8);
712 
713 		NET_DBG("IPv6 address %s is deprecated",
714 			net_sprint_ipv6_addr(&ipv6->unicast[i].address.in6_addr));
715 
716 		ipv6->unicast[i].addr_state = NET_ADDR_DEPRECATED;
717 
718 		/* Create a new temporary address and then notify users
719 		 * that the old address is deprecated so that they can
720 		 * re-connect to use the new address. We cannot send deprecated
721 		 * event immediately because the new IPv6 will need to do DAD
722 		 * and that takes a bit time.
723 		 */
724 		net_ipv6_pe_start(iface, &prefix,
725 				  TEMP_VALID_LIFETIME,
726 				  TEMP_PREFERRED_LIFETIME);
727 
728 		/* It is very unlikely but still a small possibility that there
729 		 * could be another work already pending.
730 		 * Fixing this would require allocating space for the work
731 		 * somewhere. Currently this does not look like worth fixing.
732 		 * Print a warning if there is a work already pending.
733 		 */
734 		if (k_work_delayable_is_pending(&trigger_deprecated_event.work)) {
735 			NET_WARN("Work already pending for deprecated event sending.");
736 		}
737 
738 		trigger_deprecated_event.iface = iface;
739 		memcpy(&trigger_deprecated_event.addr,
740 		       &ipv6->unicast[i].address.in6_addr,
741 		       sizeof(struct in6_addr));
742 
743 		/* 500ms should be enough for DAD to pass */
744 		k_work_schedule(&trigger_deprecated_event.work, K_MSEC(500));
745 	}
746 }
747 
ipv6_pe_renew(struct k_work * work)748 static void ipv6_pe_renew(struct k_work *work)
749 {
750 	ARG_UNUSED(work);
751 
752 	net_if_foreach(renewal_cb, NULL);
753 }
754 
net_ipv6_pe_init(struct net_if * iface)755 int net_ipv6_pe_init(struct net_if *iface)
756 {
757 	int32_t lifetime;
758 	int ret = 0;
759 
760 	net_mgmt_event_notify(NET_EVENT_IPV6_PE_ENABLED, iface);
761 
762 	lifetime = TEMP_VALID_LIFETIME -
763 		REGEN_ADVANCE(net_if_ipv6_get_retrans_timer(iface), 1U);
764 
765 	if (lifetime <= 0) {
766 		iface->pe_enabled = false;
767 		net_mgmt_event_notify(NET_EVENT_IPV6_PE_DISABLED, iface);
768 		ret = -EINVAL;
769 		goto out;
770 	}
771 
772 	iface->pe_enabled = true;
773 	iface->pe_prefer_public =
774 		IS_ENABLED(CONFIG_NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES) ?
775 		true : false;
776 
777 	k_work_init_delayable(&temp_lifetime, ipv6_pe_renew);
778 	k_work_init_delayable(&trigger_deprecated_event.work,
779 			      send_deprecated_event);
780 
781 out:
782 	NET_DBG("pe %s prefer %s lifetime %d sec",
783 		iface->pe_enabled ? "enabled" : "disabled",
784 		iface->pe_prefer_public ? "public" : "temporary",
785 		lifetime);
786 
787 	return ret;
788 }
789