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 mbedtls_md_setup(&ctx, md_info, true);
260 ret = mbedtls_md_hmac_starts(&ctx, secret_key, sizeof(secret_key));
261 if (ret != 0) {
262 NET_DBG("Cannot %s hmac (%d)", "start", ret);
263 goto err;
264 }
265
266 ret = mbedtls_md_hmac_update(&ctx, (uint8_t *)&buf, sizeof(buf));
267 if (ret != 0) {
268 NET_DBG("Cannot %s hmac (%d)", "update", ret);
269 goto err;
270 }
271
272 ret = mbedtls_md_hmac_finish(&ctx, digest);
273 if (ret != 0) {
274 NET_DBG("Cannot %s hmac (%d)", "finish", ret);
275 goto err;
276 }
277
278 memcpy(temporary_iid, digest, MIN(sizeof(digest), temporary_iid_len));
279
280 err:
281 mbedtls_md_free(&ctx);
282
283 return ret;
284 }
285
net_ipv6_pe_start(struct net_if * iface,const struct in6_addr * prefix,uint32_t vlifetime,uint32_t preferred_lifetime)286 void net_ipv6_pe_start(struct net_if *iface, const struct in6_addr *prefix,
287 uint32_t vlifetime, uint32_t preferred_lifetime)
288 {
289 struct net_if_addr *ifaddr;
290 struct net_if_ipv6 *ipv6;
291 struct in6_addr addr;
292 k_ticks_t remaining;
293 k_timeout_t vlifetimeout;
294 int i, ret, dad_count = 1;
295 int32_t lifetime;
296 bool valid = false;
297
298 net_if_lock(iface);
299
300 if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
301 NET_WARN("Cannot do DAD IPv6 config is not valid.");
302 goto out;
303 }
304
305 if (!ipv6) {
306 goto out;
307 }
308
309 /* Check if user agrees to use this prefix */
310 if (!ipv6_pe_use_this_prefix(prefix)) {
311 NET_DBG("Prefix %s/64 is not to be used",
312 net_sprint_ipv6_addr(prefix));
313 goto out;
314 }
315
316 /* If the prefix is already added and it is still valid and is not
317 * deprecated, then we do not try to add it again.
318 */
319 if (ipv6_pe_prefix_already_exists(ipv6, prefix)) {
320 if (vlifetime == 0) {
321 i = ipv6_pe_prefix_remove(iface, ipv6, prefix);
322
323 NET_DBG("Removed %d addresses using prefix %s/64",
324 i, net_sprint_ipv6_addr(prefix));
325 } else {
326 ipv6_pe_prefix_update_lifetimes(ipv6, prefix, vlifetime);
327 }
328
329 goto out;
330 }
331
332 preferred_lifetime = MIN(preferred_lifetime,
333 TEMP_PREFERRED_LIFETIME -
334 DESYNC_FACTOR(ipv6));
335 if (preferred_lifetime == 0 ||
336 preferred_lifetime <= REGEN_ADVANCE(ipv6->retrans_timer, 1U)) {
337 NET_DBG("Too short preferred lifetime (%u <= %u), temp address not "
338 "created for prefix %s/64", preferred_lifetime,
339 REGEN_ADVANCE(ipv6->retrans_timer, 1U),
340 net_sprint_ipv6_addr(prefix));
341 goto out;
342 }
343
344 NET_DBG("Starting PE process for prefix %s/64",
345 net_sprint_ipv6_addr(prefix));
346
347 net_ipaddr_copy(&addr, prefix);
348
349 do {
350 ret = gen_temporary_iid(iface, prefix,
351 COND_CODE_1(CONFIG_NET_INTERFACE_NAME,
352 (iface->config.name,
353 sizeof(iface->config.name)),
354 (net_if_get_device(iface)->name,
355 strlen(net_if_get_device(iface)->name))),
356 dad_count,
357 &addr.s6_addr[8], 8U);
358 if (ret == 0) {
359 ifaddr = net_if_ipv6_addr_lookup(&addr, NULL);
360 if (ifaddr == NULL && !net_ipv6_is_addr_unspecified(&addr) &&
361 memcmp(&addr, &reserved_anycast_subnet,
362 sizeof(struct in6_addr)) != 0) {
363 valid = true;
364 break;
365 }
366 }
367
368 } while (dad_count++ < TEMP_IDGEN_RETRIES);
369
370 if (valid == false) {
371 NET_WARN("Could not create a valid iid for prefix %s/64 for interface %d",
372 net_sprint_ipv6_addr(prefix),
373 net_if_get_by_iface(iface));
374 NET_WARN("Disabling IPv6 PE for interface %d",
375 net_if_get_by_iface(iface));
376 net_mgmt_event_notify(NET_EVENT_IPV6_PE_DISABLED, iface);
377 iface->pe_enabled = false;
378 goto out;
379 }
380
381 vlifetime = MIN(TEMP_VALID_LIFETIME, vlifetime);
382
383 ifaddr = net_if_ipv6_addr_add(iface, &addr, NET_ADDR_AUTOCONF, vlifetime);
384 if (!ifaddr) {
385 NET_ERR("Cannot add %s address to interface %d",
386 net_sprint_ipv6_addr(&addr),
387 net_if_get_by_iface(iface));
388 goto out;
389 }
390
391 lifetime = TEMP_VALID_LIFETIME -
392 REGEN_ADVANCE(net_if_ipv6_get_retrans_timer(iface), 1U);
393
394 DESYNC_FACTOR(ipv6) = sys_rand32_get() % MAX_DESYNC_FACTOR;
395
396 /* Make sure that the address timeout happens at least two seconds
397 * after the deprecation.
398 */
399 DESYNC_FACTOR(ipv6) = MIN(DESYNC_FACTOR(ipv6) + 2U, lifetime);
400
401 ifaddr->is_temporary = true;
402 ifaddr->addr_preferred_lifetime = preferred_lifetime;
403 ifaddr->addr_timeout = ifaddr->addr_preferred_lifetime - DESYNC_FACTOR(ipv6);
404 ifaddr->addr_create_time = k_uptime_seconds();
405
406 NET_DBG("Lifetime %d desync %d timeout %d preferred %d valid %d",
407 lifetime, DESYNC_FACTOR(ipv6), ifaddr->addr_timeout,
408 ifaddr->addr_preferred_lifetime, vlifetime);
409
410 NET_DBG("Starting DAD for %s iface %d", net_sprint_ipv6_addr(&addr),
411 net_if_get_by_iface(iface));
412
413 net_if_ipv6_start_dad(iface, ifaddr);
414
415 vlifetimeout = K_SECONDS(ifaddr->addr_timeout);
416
417 remaining = k_work_delayable_remaining_get(&temp_lifetime);
418 if (remaining == 0 || remaining > vlifetimeout.ticks) {
419 NET_DBG("Next check for temp addresses in %d seconds",
420 ifaddr->addr_timeout);
421 k_work_schedule(&temp_lifetime, vlifetimeout);
422 }
423
424 out:
425 net_if_unlock(iface);
426 }
427
428 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
429
iface_cb(struct net_if * iface,void * user_data)430 static void iface_cb(struct net_if *iface, void *user_data)
431 {
432 bool is_new_filter_denylist = !ipv6_pe_denylist;
433 struct in6_addr *prefix = user_data;
434 struct net_if_ipv6 *ipv6;
435 int ret;
436
437 net_if_lock(iface);
438
439 if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
440 goto out;
441 }
442
443 if (!ipv6) {
444 goto out;
445 }
446
447 ARRAY_FOR_EACH(ipv6->unicast, i) {
448 if (!ipv6->unicast[i].is_used ||
449 ipv6->unicast[i].address.family != AF_INET6 ||
450 !ipv6->unicast[i].is_temporary) {
451 continue;
452 }
453
454 ret = net_ipv6_is_prefix(
455 (uint8_t *)&ipv6->unicast[i].address.in6_addr,
456 (uint8_t *)prefix, 64);
457
458 /* TODO: Do this removal gracefully so that applications
459 * have time to cope with this change.
460 */
461 if (is_new_filter_denylist) {
462 if (ret) {
463 net_if_ipv6_addr_rm(iface,
464 &ipv6->unicast[i].address.in6_addr);
465 }
466 } else {
467 if (!ret) {
468 net_if_ipv6_addr_rm(iface,
469 &ipv6->unicast[i].address.in6_addr);
470 }
471 }
472 }
473
474 out:
475 net_if_unlock(iface);
476 }
477
478 /* If we change filter value, then check if existing IPv6 prefixes will
479 * conflict with the new filter.
480 */
ipv6_pe_recheck_filters(bool is_denylist)481 static void ipv6_pe_recheck_filters(bool is_denylist)
482 {
483 k_mutex_lock(&lock, K_FOREVER);
484
485 ARRAY_FOR_EACH(ipv6_pe_filter, i) {
486 if (net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) {
487 continue;
488 }
489
490 net_if_foreach(iface_cb, &ipv6_pe_filter[i]);
491 }
492
493 k_mutex_unlock(&lock);
494 }
495 #endif /* CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0 */
496
497 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
send_filter_event(struct in6_addr * addr,bool is_denylist,int event_type)498 static void send_filter_event(struct in6_addr *addr, bool is_denylist,
499 int event_type)
500 {
501 if (IS_ENABLED(CONFIG_NET_MGMT_EVENT_INFO)) {
502 struct net_event_ipv6_pe_filter info;
503
504 net_ipaddr_copy(&info.prefix, addr);
505 info.is_deny_list = is_denylist;
506
507 net_mgmt_event_notify_with_info(event_type,
508 NULL,
509 (const void *)&info,
510 sizeof(info));
511 } else {
512 net_mgmt_event_notify(event_type, NULL);
513 }
514 }
515 #endif
516
net_ipv6_pe_add_filter(struct in6_addr * addr,bool is_denylist)517 int net_ipv6_pe_add_filter(struct in6_addr *addr, bool is_denylist)
518 {
519 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
520 bool found = false;
521 int free_slot = -1;
522 int ret = 0;
523
524 k_mutex_lock(&lock, K_FOREVER);
525
526 ARRAY_FOR_EACH(ipv6_pe_filter, i) {
527 if (free_slot < 0 &&
528 net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) {
529 free_slot = i;
530 continue;
531 }
532
533 if (net_ipv6_is_prefix((uint8_t *)addr,
534 (uint8_t *)&ipv6_pe_filter[i],
535 64)) {
536 found = true;
537 break;
538 }
539 }
540
541 if (found) {
542 NET_DBG("Filter %s already in the list",
543 net_sprint_ipv6_addr(addr));
544 ret = -EALREADY;
545 goto out;
546 }
547
548 if (free_slot < 0) {
549 NET_DBG("All filters in use");
550 ret = -ENOMEM;
551 goto out;
552 }
553
554 net_ipaddr_copy(&ipv6_pe_filter[free_slot], addr);
555
556 if (ipv6_pe_denylist != is_denylist) {
557 ipv6_pe_recheck_filters(is_denylist);
558 }
559
560 ipv6_pe_denylist = is_denylist ? true : false;
561
562 NET_DBG("Adding %s list filter %s",
563 ipv6_pe_denylist ? "deny" : "allow",
564 net_sprint_ipv6_addr(&ipv6_pe_filter[free_slot]));
565
566 send_filter_event(&ipv6_pe_filter[free_slot],
567 is_denylist,
568 NET_EVENT_IPV6_PE_FILTER_ADD);
569 out:
570 k_mutex_unlock(&lock);
571
572 return ret;
573 #else
574 ARG_UNUSED(addr);
575 ARG_UNUSED(is_denylist);
576
577 return -ENOTSUP;
578 #endif
579 }
580
net_ipv6_pe_del_filter(struct in6_addr * addr)581 int net_ipv6_pe_del_filter(struct in6_addr *addr)
582 {
583 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
584 int ret = -ENOENT;
585
586 k_mutex_lock(&lock, K_FOREVER);
587
588 ARRAY_FOR_EACH(ipv6_pe_filter, i) {
589 if (net_ipv6_addr_cmp(&ipv6_pe_filter[i], addr)) {
590 NET_DBG("Removing %s list filter %s",
591 ipv6_pe_denylist ? "deny" : "allow",
592 net_sprint_ipv6_addr(&ipv6_pe_filter[i]));
593
594 send_filter_event(&ipv6_pe_filter[i],
595 ipv6_pe_denylist,
596 NET_EVENT_IPV6_PE_FILTER_DEL);
597
598 net_ipaddr_copy(&ipv6_pe_filter[i],
599 net_ipv6_unspecified_address());
600
601 ret = 0;
602 goto out;
603 }
604 }
605
606 out:
607 k_mutex_unlock(&lock);
608
609 return ret;
610 #else
611 ARG_UNUSED(addr);
612
613 return -ENOTSUP;
614 #endif
615 }
616
net_ipv6_pe_check_dad(int count)617 bool net_ipv6_pe_check_dad(int count)
618 {
619 return count <= TEMP_IDGEN_RETRIES;
620 }
621
net_ipv6_pe_filter_foreach(net_ipv6_pe_filter_cb_t cb,void * user_data)622 int net_ipv6_pe_filter_foreach(net_ipv6_pe_filter_cb_t cb, void *user_data)
623 {
624 #if CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT > 0
625 int i, count = 0;
626
627 k_mutex_lock(&lock, K_FOREVER);
628
629 for (i = 0; i < CONFIG_NET_IPV6_PE_FILTER_PREFIX_COUNT; i++) {
630 if (net_ipv6_is_addr_unspecified(&ipv6_pe_filter[i])) {
631 continue;
632 }
633
634 cb(&ipv6_pe_filter[i], ipv6_pe_denylist, user_data);
635
636 count++;
637 }
638
639 k_mutex_unlock(&lock);
640
641 return count;
642 #else
643 ARG_UNUSED(cb);
644 ARG_UNUSED(user_data);
645
646 return 0;
647 #endif
648 }
649
650 struct deprecated_work {
651 struct k_work_delayable work;
652 struct net_if *iface;
653 struct in6_addr addr;
654 };
655
656 static struct deprecated_work trigger_deprecated_event;
657
send_deprecated_event(struct k_work * work)658 static void send_deprecated_event(struct k_work *work)
659 {
660 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
661 struct deprecated_work *dw = CONTAINER_OF(dwork,
662 struct deprecated_work,
663 work);
664
665 net_mgmt_event_notify_with_info(NET_EVENT_IPV6_ADDR_DEPRECATED,
666 dw->iface, &dw->addr,
667 sizeof(struct in6_addr));
668 }
669
renewal_cb(struct net_if * iface,void * user_data)670 static void renewal_cb(struct net_if *iface, void *user_data)
671 {
672 struct net_if_ipv6 *ipv6;
673 struct in6_addr prefix;
674
675 if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
676 return;
677 }
678
679 if (!ipv6) {
680 return;
681 }
682
683 ARRAY_FOR_EACH(ipv6->unicast, i) {
684 int32_t diff;
685
686 if (!ipv6->unicast[i].is_used ||
687 ipv6->unicast[i].address.family != AF_INET6 ||
688 !ipv6->unicast[i].is_temporary ||
689 ipv6->unicast[i].addr_state == NET_ADDR_DEPRECATED) {
690 continue;
691 }
692
693 /* If the address is too old, then generate a new one
694 * and remove the old address.
695 */
696 diff = (int32_t)(ipv6->unicast[i].addr_create_time - k_uptime_seconds());
697 diff = abs(diff);
698
699 if (diff < (ipv6->unicast[i].addr_preferred_lifetime -
700 REGEN_ADVANCE(ipv6->retrans_timer, 1U) -
701 DESYNC_FACTOR(ipv6))) {
702 continue;
703 }
704
705 net_ipaddr_copy(&prefix, &ipv6->unicast[i].address.in6_addr);
706 memset(prefix.s6_addr + 8, 0, sizeof(prefix) - 8);
707
708 NET_DBG("IPv6 address %s is deprecated",
709 net_sprint_ipv6_addr(&ipv6->unicast[i].address.in6_addr));
710
711 ipv6->unicast[i].addr_state = NET_ADDR_DEPRECATED;
712
713 /* Create a new temporary address and then notify users
714 * that the old address is deprecated so that they can
715 * re-connect to use the new address. We cannot send deprecated
716 * event immediately because the new IPv6 will need to do DAD
717 * and that takes a bit time.
718 */
719 net_ipv6_pe_start(iface, &prefix,
720 TEMP_VALID_LIFETIME,
721 TEMP_PREFERRED_LIFETIME);
722
723 /* It is very unlikely but still a small possibility that there
724 * could be another work already pending.
725 * Fixing this would require allocating space for the work
726 * somewhere. Currently this does not look like worth fixing.
727 * Print a warning if there is a work already pending.
728 */
729 if (k_work_delayable_is_pending(&trigger_deprecated_event.work)) {
730 NET_WARN("Work already pending for deprecated event sending.");
731 }
732
733 trigger_deprecated_event.iface = iface;
734 memcpy(&trigger_deprecated_event.addr,
735 &ipv6->unicast[i].address.in6_addr,
736 sizeof(struct in6_addr));
737
738 /* 500ms should be enough for DAD to pass */
739 k_work_schedule(&trigger_deprecated_event.work, K_MSEC(500));
740 }
741 }
742
ipv6_pe_renew(struct k_work * work)743 static void ipv6_pe_renew(struct k_work *work)
744 {
745 ARG_UNUSED(work);
746
747 net_if_foreach(renewal_cb, NULL);
748 }
749
net_ipv6_pe_init(struct net_if * iface)750 int net_ipv6_pe_init(struct net_if *iface)
751 {
752 int32_t lifetime;
753 int ret = 0;
754
755 net_mgmt_event_notify(NET_EVENT_IPV6_PE_ENABLED, iface);
756
757 lifetime = TEMP_VALID_LIFETIME -
758 REGEN_ADVANCE(net_if_ipv6_get_retrans_timer(iface), 1U);
759
760 if (lifetime <= 0) {
761 iface->pe_enabled = false;
762 net_mgmt_event_notify(NET_EVENT_IPV6_PE_DISABLED, iface);
763 ret = -EINVAL;
764 goto out;
765 }
766
767 iface->pe_enabled = true;
768 iface->pe_prefer_public =
769 IS_ENABLED(CONFIG_NET_IPV6_PE_PREFER_PUBLIC_ADDRESSES) ?
770 true : false;
771
772 k_work_init_delayable(&temp_lifetime, ipv6_pe_renew);
773 k_work_init_delayable(&trigger_deprecated_event.work,
774 send_deprecated_event);
775
776 out:
777 NET_DBG("pe %s prefer %s lifetime %d sec",
778 iface->pe_enabled ? "enabled" : "disabled",
779 iface->pe_prefer_public ? "public" : "temporary",
780 lifetime);
781
782 return ret;
783 }
784