1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2017 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
7 #include <netinet/in.h>
12 #include "alloc-util.h"
13 #include "dns-domain.h"
14 #include "ether-addr-util.h"
15 #include "event-util.h"
17 #include "icmp6-util.h"
18 #include "in-addr-util.h"
21 #include "memory-util.h"
22 #include "network-common.h"
23 #include "radv-internal.h"
24 #include "random-util.h"
25 #include "socket-util.h"
26 #include "string-util.h"
29 _public_
int sd_radv_new(sd_radv
**ret
) {
30 _cleanup_(sd_radv_unrefp
) sd_radv
*ra
= NULL
;
32 assert_return(ret
, -EINVAL
);
48 _public_
int sd_radv_attach_event(sd_radv
*ra
, sd_event
*event
, int64_t priority
) {
51 assert_return(ra
, -EINVAL
);
52 assert_return(!ra
->event
, -EBUSY
);
55 ra
->event
= sd_event_ref(event
);
57 r
= sd_event_default(&ra
->event
);
62 ra
->event_priority
= priority
;
67 _public_
int sd_radv_detach_event(sd_radv
*ra
) {
69 assert_return(ra
, -EINVAL
);
71 ra
->event
= sd_event_unref(ra
->event
);
75 _public_ sd_event
*sd_radv_get_event(sd_radv
*ra
) {
76 assert_return(ra
, NULL
);
81 _public_
int sd_radv_is_running(sd_radv
*ra
) {
82 assert_return(ra
, false);
84 return ra
->state
!= SD_RADV_STATE_IDLE
;
87 static void radv_reset(sd_radv
*ra
) {
90 (void) event_source_disable(ra
->timeout_event_source
);
92 ra
->recv_event_source
= sd_event_source_disable_unref(ra
->recv_event_source
);
97 static sd_radv
*radv_free(sd_radv
*ra
) {
101 while (ra
->prefixes
) {
102 sd_radv_prefix
*p
= ra
->prefixes
;
104 LIST_REMOVE(prefix
, ra
->prefixes
, p
);
105 sd_radv_prefix_unref(p
);
108 while (ra
->route_prefixes
) {
109 sd_radv_route_prefix
*p
= ra
->route_prefixes
;
111 LIST_REMOVE(prefix
, ra
->route_prefixes
, p
);
112 sd_radv_route_prefix_unref(p
);
120 sd_event_source_unref(ra
->timeout_event_source
);
121 sd_radv_detach_event(ra
);
123 ra
->fd
= safe_close(ra
->fd
);
129 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv
, sd_radv
, radv_free
);
131 static int radv_send(sd_radv
*ra
, const struct in6_addr
*dst
, uint32_t router_lifetime
) {
132 sd_radv_route_prefix
*rt
;
134 struct sockaddr_in6 dst_addr
= {
135 .sin6_family
= AF_INET6
,
136 .sin6_addr
= IN6ADDR_ALL_NODES_MULTICAST_INIT
,
138 struct nd_router_advert adv
= {};
140 struct nd_opt_hdr opthdr
;
141 struct ether_addr slladdr
;
142 } _packed_ opt_mac
= {
144 .nd_opt_type
= ND_OPT_SOURCE_LINKADDR
,
145 .nd_opt_len
= (sizeof(struct nd_opt_hdr
) +
146 sizeof(struct ether_addr
) - 1) /8 + 1,
149 struct nd_opt_mtu opt_mtu
= {
150 .nd_opt_mtu_type
= ND_OPT_MTU
,
153 /* Reserve iov space for RA header, linkaddr, MTU, N prefixes, N routes, RDNSS
155 struct iovec iov
[5 + ra
->n_prefixes
+ ra
->n_route_prefixes
];
156 struct msghdr msg
= {
157 .msg_name
= &dst_addr
,
158 .msg_namelen
= sizeof(dst_addr
),
166 r
= sd_event_now(ra
->event
, clock_boottime_or_monotonic(), &time_now
);
170 if (dst
&& in6_addr_is_set(dst
))
171 dst_addr
.sin6_addr
= *dst
;
173 adv
.nd_ra_type
= ND_ROUTER_ADVERT
;
174 adv
.nd_ra_curhoplimit
= ra
->hop_limit
;
175 adv
.nd_ra_flags_reserved
= ra
->flags
;
176 adv
.nd_ra_router_lifetime
= htobe16(router_lifetime
);
177 iov
[msg
.msg_iovlen
++] = IOVEC_MAKE(&adv
, sizeof(adv
));
179 /* MAC address is optional, either because the link does not use L2
180 addresses or load sharing is desired. See RFC 4861, Section 4.2 */
181 if (!ether_addr_is_null(&ra
->mac_addr
)) {
182 opt_mac
.slladdr
= ra
->mac_addr
;
183 iov
[msg
.msg_iovlen
++] = IOVEC_MAKE(&opt_mac
, sizeof(opt_mac
));
187 opt_mtu
.nd_opt_mtu_mtu
= htobe32(ra
->mtu
);
188 iov
[msg
.msg_iovlen
++] = IOVEC_MAKE(&opt_mtu
, sizeof(opt_mtu
));
191 LIST_FOREACH(prefix
, p
, ra
->prefixes
) {
192 if (p
->valid_until
) {
194 if (time_now
> p
->valid_until
)
195 p
->opt
.valid_lifetime
= 0;
197 p
->opt
.valid_lifetime
= htobe32((p
->valid_until
- time_now
) / USEC_PER_SEC
);
199 if (time_now
> p
->preferred_until
)
200 p
->opt
.preferred_lifetime
= 0;
202 p
->opt
.preferred_lifetime
= htobe32((p
->preferred_until
- time_now
) / USEC_PER_SEC
);
204 iov
[msg
.msg_iovlen
++] = IOVEC_MAKE(&p
->opt
, sizeof(p
->opt
));
207 LIST_FOREACH(prefix
, rt
, ra
->route_prefixes
)
208 iov
[msg
.msg_iovlen
++] = IOVEC_MAKE(&rt
->opt
, sizeof(rt
->opt
));
211 iov
[msg
.msg_iovlen
++] = IOVEC_MAKE(ra
->rdnss
, ra
->rdnss
->length
* 8);
214 iov
[msg
.msg_iovlen
++] = IOVEC_MAKE(ra
->dnssl
, ra
->dnssl
->length
* 8);
216 if (sendmsg(ra
->fd
, &msg
, 0) < 0)
222 static int radv_recv(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
223 sd_radv
*ra
= userdata
;
224 _cleanup_free_
char *addr
= NULL
;
226 triple_timestamp timestamp
;
229 _cleanup_free_
char *buf
= NULL
;
235 buflen
= next_datagram_size_fd(fd
);
239 buf
= new0(char, buflen
);
243 r
= icmp6_receive(fd
, buf
, buflen
, &src
, ×tamp
);
247 (void) in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &src
, &addr
);
248 log_radv(ra
, "Received RS from non-link-local address %s. Ignoring", addr
);
252 log_radv(ra
, "Received RS with invalid hop limit. Ignoring.");
256 log_radv(ra
, "Received invalid source address from ICMPv6 socket. Ignoring.");
259 case -EAGAIN
: /* ignore spurious wakeups */
263 log_radv_errno(ra
, r
, "Unexpected error receiving from ICMPv6 socket, Ignoring: %m");
270 if ((size_t) buflen
< sizeof(struct nd_router_solicit
)) {
271 log_radv(ra
, "Too short packet received, ignoring");
275 (void) in_addr_to_string(AF_INET6
, (const union in_addr_union
*) &src
, &addr
);
277 r
= radv_send(ra
, &src
, ra
->lifetime
);
279 log_radv_errno(ra
, r
, "Unable to send solicited Router Advertisement to %s, ignoring: %m", strnull(addr
));
281 log_radv(ra
, "Sent solicited Router Advertisement to %s", strnull(addr
));
286 static usec_t
radv_compute_timeout(usec_t min
, usec_t max
) {
287 assert_return(min
<= max
, SD_RADV_DEFAULT_MIN_TIMEOUT_USEC
);
289 /* RFC 4861: min must be no less than 3s, max must be no less than 4s */
290 min
= MAX(min
, 3*USEC_PER_SEC
);
291 max
= MAX(max
, 4*USEC_PER_SEC
);
293 return min
+ (random_u32() % (max
- min
));
296 static int radv_timeout(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
298 sd_radv
*ra
= userdata
;
299 usec_t min_timeout
= SD_RADV_DEFAULT_MIN_TIMEOUT_USEC
;
300 usec_t max_timeout
= SD_RADV_DEFAULT_MAX_TIMEOUT_USEC
;
301 usec_t time_now
, timeout
;
307 r
= sd_event_now(ra
->event
, clock_boottime_or_monotonic(), &time_now
);
311 r
= radv_send(ra
, NULL
, ra
->lifetime
);
313 log_radv_errno(ra
, r
, "Unable to send Router Advertisement: %m");
315 /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
316 if (ra
->ra_sent
< SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS
) {
317 max_timeout
= SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC
;
318 min_timeout
= SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC
/ 3;
321 /* RFC 4861, Section 6.2.1, lifetime must be at least MaxRtrAdvInterval,
322 so lower the interval here */
323 if (ra
->lifetime
> 0 && (ra
->lifetime
* USEC_PER_SEC
) < max_timeout
) {
324 max_timeout
= ra
->lifetime
* USEC_PER_SEC
;
325 min_timeout
= max_timeout
/ 3;
328 timeout
= radv_compute_timeout(min_timeout
, max_timeout
);
329 log_radv(ra
, "Next Router Advertisement in %s", FORMAT_TIMESPAN(timeout
, USEC_PER_SEC
));
331 r
= event_reset_time(ra
->event
, &ra
->timeout_event_source
,
332 clock_boottime_or_monotonic(),
333 time_now
+ timeout
, MSEC_PER_SEC
,
335 ra
->event_priority
, "radv-timeout", true);
349 _public_
int sd_radv_stop(sd_radv
*ra
) {
355 if (ra
->state
== SD_RADV_STATE_IDLE
)
358 log_radv(ra
, "Stopping IPv6 Router Advertisement daemon");
360 /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
361 with zero lifetime */
362 r
= radv_send(ra
, NULL
, 0);
364 log_radv_errno(ra
, r
, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
367 ra
->fd
= safe_close(ra
->fd
);
368 ra
->state
= SD_RADV_STATE_IDLE
;
373 _public_
int sd_radv_start(sd_radv
*ra
) {
376 assert_return(ra
, -EINVAL
);
377 assert_return(ra
->event
, -EINVAL
);
378 assert_return(ra
->ifindex
> 0, -EINVAL
);
380 if (ra
->state
!= SD_RADV_STATE_IDLE
)
383 r
= event_reset_time(ra
->event
, &ra
->timeout_event_source
,
384 clock_boottime_or_monotonic(),
387 ra
->event_priority
, "radv-timeout", true);
391 r
= icmp6_bind_router_advertisement(ra
->ifindex
);
397 r
= sd_event_add_io(ra
->event
, &ra
->recv_event_source
, ra
->fd
, EPOLLIN
, radv_recv
, ra
);
401 r
= sd_event_source_set_priority(ra
->recv_event_source
, ra
->event_priority
);
405 (void) sd_event_source_set_description(ra
->recv_event_source
, "radv-receive-message");
407 ra
->state
= SD_RADV_STATE_ADVERTISING
;
409 log_radv(ra
, "Started IPv6 Router Advertisement daemon");
419 _public_
int sd_radv_set_ifindex(sd_radv
*ra
, int ifindex
) {
420 assert_return(ra
, -EINVAL
);
421 assert_return(ifindex
> 0, -EINVAL
);
423 if (ra
->state
!= SD_RADV_STATE_IDLE
)
426 ra
->ifindex
= ifindex
;
431 int sd_radv_set_ifname(sd_radv
*ra
, const char *ifname
) {
432 assert_return(ra
, -EINVAL
);
433 assert_return(ifname
, -EINVAL
);
435 if (!ifname_valid_full(ifname
, IFNAME_VALID_ALTERNATIVE
))
438 return free_and_strdup(&ra
->ifname
, ifname
);
441 int sd_radv_get_ifname(sd_radv
*ra
, const char **ret
) {
444 assert_return(ra
, -EINVAL
);
446 r
= get_ifname(ra
->ifindex
, &ra
->ifname
);
456 _public_
int sd_radv_set_mac(sd_radv
*ra
, const struct ether_addr
*mac_addr
) {
457 assert_return(ra
, -EINVAL
);
459 if (ra
->state
!= SD_RADV_STATE_IDLE
)
463 ra
->mac_addr
= *mac_addr
;
470 _public_
int sd_radv_set_mtu(sd_radv
*ra
, uint32_t mtu
) {
471 assert_return(ra
, -EINVAL
);
472 assert_return(mtu
>= 1280, -EINVAL
);
479 _public_
int sd_radv_set_hop_limit(sd_radv
*ra
, uint8_t hop_limit
) {
480 assert_return(ra
, -EINVAL
);
482 if (ra
->state
!= SD_RADV_STATE_IDLE
)
485 ra
->hop_limit
= hop_limit
;
490 _public_
int sd_radv_set_router_lifetime(sd_radv
*ra
, uint16_t router_lifetime
) {
491 assert_return(ra
, -EINVAL
);
493 if (ra
->state
!= SD_RADV_STATE_IDLE
)
496 /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
497 * to (00) by the sender..." */
498 if (router_lifetime
== 0 &&
499 (ra
->flags
& (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM
<< 3))
502 ra
->lifetime
= router_lifetime
;
507 _public_
int sd_radv_set_managed_information(sd_radv
*ra
, int managed
) {
508 assert_return(ra
, -EINVAL
);
510 if (ra
->state
!= SD_RADV_STATE_IDLE
)
513 SET_FLAG(ra
->flags
, ND_RA_FLAG_MANAGED
, managed
);
518 _public_
int sd_radv_set_other_information(sd_radv
*ra
, int other
) {
519 assert_return(ra
, -EINVAL
);
521 if (ra
->state
!= SD_RADV_STATE_IDLE
)
524 SET_FLAG(ra
->flags
, ND_RA_FLAG_OTHER
, other
);
529 _public_
int sd_radv_set_preference(sd_radv
*ra
, unsigned preference
) {
530 assert_return(ra
, -EINVAL
);
531 assert_return(IN_SET(preference
,
532 SD_NDISC_PREFERENCE_LOW
,
533 SD_NDISC_PREFERENCE_MEDIUM
,
534 SD_NDISC_PREFERENCE_HIGH
), -EINVAL
);
536 /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
537 * to (00) by the sender..." */
538 if (ra
->lifetime
== 0 && preference
!= SD_NDISC_PREFERENCE_MEDIUM
)
541 ra
->flags
= (ra
->flags
& ~(0x3 << 3)) | (preference
<< 3);
546 _public_
int sd_radv_add_prefix(sd_radv
*ra
, sd_radv_prefix
*p
, int dynamic
) {
549 _cleanup_free_
char *addr_p
= NULL
;
550 usec_t time_now
, valid
, preferred
, valid_until
, preferred_until
;
552 assert_return(ra
, -EINVAL
);
557 /* Refuse prefixes that don't have a prefix set */
558 if (in6_addr_is_null(&p
->opt
.in6_addr
))
561 (void) in_addr_prefix_to_string(AF_INET6
,
562 (const union in_addr_union
*) &p
->opt
.in6_addr
,
563 p
->opt
.prefixlen
, &addr_p
);
565 LIST_FOREACH(prefix
, cur
, ra
->prefixes
) {
567 r
= in_addr_prefix_intersect(AF_INET6
,
568 (const union in_addr_union
*) &cur
->opt
.in6_addr
,
570 (const union in_addr_union
*) &p
->opt
.in6_addr
,
577 if (dynamic
&& cur
->opt
.prefixlen
== p
->opt
.prefixlen
)
580 _cleanup_free_
char *addr_cur
= NULL
;
581 (void) in_addr_prefix_to_string(AF_INET6
,
582 (const union in_addr_union
*) &cur
->opt
.in6_addr
,
583 cur
->opt
.prefixlen
, &addr_cur
);
584 return log_radv_errno(ra
, SYNTHETIC_ERRNO(EEXIST
),
585 "IPv6 prefix %s already configured, ignoring %s",
586 strna(addr_cur
), strna(addr_p
));
589 p
= sd_radv_prefix_ref(p
);
591 LIST_APPEND(prefix
, ra
->prefixes
, p
);
596 log_radv(ra
, "Added prefix %s", strna(addr_p
));
602 /* If RAs have already been sent, send an RA immediately to announce the newly-added prefix */
603 if (ra
->ra_sent
> 0) {
604 r
= radv_send(ra
, NULL
, ra
->lifetime
);
606 log_radv_errno(ra
, r
, "Unable to send Router Advertisement for added prefix: %m");
608 log_radv(ra
, "Sent Router Advertisement for added prefix");
612 r
= sd_event_now(ra
->event
, clock_boottime_or_monotonic(), &time_now
);
616 valid
= be32toh(p
->opt
.valid_lifetime
) * USEC_PER_SEC
;
617 valid_until
= usec_add(valid
, time_now
);
618 if (valid_until
== USEC_INFINITY
)
621 preferred
= be32toh(p
->opt
.preferred_lifetime
) * USEC_PER_SEC
;
622 preferred_until
= usec_add(preferred
, time_now
);
623 if (preferred_until
== USEC_INFINITY
)
626 cur
->valid_until
= valid_until
;
627 cur
->preferred_until
= preferred_until
;
629 log_radv(ra
, "Updated prefix %s preferred %s valid %s",
631 FORMAT_TIMESPAN(preferred
, USEC_PER_SEC
),
632 FORMAT_TIMESPAN(valid
, USEC_PER_SEC
));
637 _public_ sd_radv_prefix
*sd_radv_remove_prefix(sd_radv
*ra
,
638 const struct in6_addr
*prefix
,
639 unsigned char prefixlen
) {
640 sd_radv_prefix
*cur
, *next
;
642 assert_return(ra
, NULL
);
643 assert_return(prefix
, NULL
);
645 LIST_FOREACH_SAFE(prefix
, cur
, next
, ra
->prefixes
) {
646 if (prefixlen
!= cur
->opt
.prefixlen
)
649 if (!in6_addr_equal(prefix
, &cur
->opt
.in6_addr
))
652 LIST_REMOVE(prefix
, ra
->prefixes
, cur
);
654 sd_radv_prefix_unref(cur
);
662 _public_
int sd_radv_add_route_prefix(sd_radv
*ra
, sd_radv_route_prefix
*p
, int dynamic
) {
663 usec_t time_now
, valid
, valid_until
;
664 _cleanup_free_
char *pretty
= NULL
;
665 sd_radv_route_prefix
*cur
;
668 assert_return(ra
, -EINVAL
);
673 (void) in_addr_prefix_to_string(AF_INET6
,
674 (const union in_addr_union
*) &p
->opt
.in6_addr
,
675 p
->opt
.prefixlen
, &pretty
);
677 LIST_FOREACH(prefix
, cur
, ra
->route_prefixes
) {
679 r
= in_addr_prefix_intersect(AF_INET6
,
680 (const union in_addr_union
*) &cur
->opt
.in6_addr
,
682 (const union in_addr_union
*) &p
->opt
.in6_addr
,
689 if (dynamic
&& cur
->opt
.prefixlen
== p
->opt
.prefixlen
)
692 _cleanup_free_
char *addr
= NULL
;
693 (void) in_addr_prefix_to_string(AF_INET6
,
694 (const union in_addr_union
*) &cur
->opt
.in6_addr
,
695 cur
->opt
.prefixlen
, &addr
);
696 return log_radv_errno(ra
, SYNTHETIC_ERRNO(EEXIST
),
697 "IPv6 route prefix %s already configured, ignoring %s",
698 strna(addr
), strna(pretty
));
701 p
= sd_radv_route_prefix_ref(p
);
703 LIST_APPEND(prefix
, ra
->route_prefixes
, p
);
704 ra
->n_route_prefixes
++;
707 log_radv(ra
, "Added prefix %s", strna(pretty
));
711 /* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
712 if (ra
->ra_sent
> 0) {
713 r
= radv_send(ra
, NULL
, ra
->lifetime
);
715 log_radv_errno(ra
, r
, "Unable to send Router Advertisement for added route prefix: %m");
717 log_radv(ra
, "Sent Router Advertisement for added route prefix");
721 r
= sd_event_now(ra
->event
, clock_boottime_or_monotonic(), &time_now
);
725 valid
= be32toh(p
->opt
.lifetime
) * USEC_PER_SEC
;
726 valid_until
= usec_add(valid
, time_now
);
727 if (valid_until
== USEC_INFINITY
)
730 log_radv(ra
, "Updated route prefix %s valid %s",
732 FORMAT_TIMESPAN(valid
, USEC_PER_SEC
));
737 _public_
int sd_radv_set_rdnss(sd_radv
*ra
, uint32_t lifetime
,
738 const struct in6_addr
*dns
, size_t n_dns
) {
739 _cleanup_free_
struct sd_radv_opt_dns
*opt_rdnss
= NULL
;
742 assert_return(ra
, -EINVAL
);
743 assert_return(n_dns
< 128, -EINVAL
);
745 if (!dns
|| n_dns
== 0) {
746 ra
->rdnss
= mfree(ra
->rdnss
);
752 len
= sizeof(struct sd_radv_opt_dns
) + sizeof(struct in6_addr
) * n_dns
;
754 opt_rdnss
= malloc0(len
);
758 opt_rdnss
->type
= SD_RADV_OPT_RDNSS
;
759 opt_rdnss
->length
= len
/ 8;
760 opt_rdnss
->lifetime
= htobe32(lifetime
);
762 memcpy(opt_rdnss
+ 1, dns
, n_dns
* sizeof(struct in6_addr
));
764 free_and_replace(ra
->rdnss
, opt_rdnss
);
771 _public_
int sd_radv_set_dnssl(sd_radv
*ra
, uint32_t lifetime
,
772 char **search_list
) {
773 _cleanup_free_
struct sd_radv_opt_dns
*opt_dnssl
= NULL
;
778 assert_return(ra
, -EINVAL
);
780 if (strv_isempty(search_list
)) {
781 ra
->dnssl
= mfree(ra
->dnssl
);
785 STRV_FOREACH(s
, search_list
)
786 len
+= strlen(*s
) + 2;
788 len
= (sizeof(struct sd_radv_opt_dns
) + len
+ 7) & ~0x7;
790 opt_dnssl
= malloc0(len
);
794 opt_dnssl
->type
= SD_RADV_OPT_DNSSL
;
795 opt_dnssl
->length
= len
/ 8;
796 opt_dnssl
->lifetime
= htobe32(lifetime
);
798 p
= (uint8_t *)(opt_dnssl
+ 1);
799 len
-= sizeof(struct sd_radv_opt_dns
);
801 STRV_FOREACH(s
, search_list
) {
804 r
= dns_name_to_wire_format(*s
, p
, len
, false);
815 free_and_replace(ra
->dnssl
, opt_dnssl
);
820 _public_
int sd_radv_prefix_new(sd_radv_prefix
**ret
) {
823 assert_return(ret
, -EINVAL
);
825 p
= new(sd_radv_prefix
, 1);
829 *p
= (sd_radv_prefix
) {
832 .opt
.type
= ND_OPT_PREFIX_INFORMATION
,
833 .opt
.length
= (sizeof(p
->opt
) - 1)/8 + 1,
836 /* RFC 4861, Section 6.2.1 */
837 .opt
.flags
= ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
,
839 .opt
.preferred_lifetime
= htobe32(604800),
840 .opt
.valid_lifetime
= htobe32(2592000),
847 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix
, sd_radv_prefix
, mfree
);
849 _public_
int sd_radv_prefix_set_prefix(sd_radv_prefix
*p
, const struct in6_addr
*in6_addr
,
850 unsigned char prefixlen
) {
851 assert_return(p
, -EINVAL
);
852 assert_return(in6_addr
, -EINVAL
);
854 if (prefixlen
< 3 || prefixlen
> 128)
858 /* unusual but allowed, log it */
859 log_radv(NULL
, "Unusual prefix length %d greater than 64", prefixlen
);
861 p
->opt
.in6_addr
= *in6_addr
;
862 p
->opt
.prefixlen
= prefixlen
;
867 _public_
int sd_radv_prefix_get_prefix(sd_radv_prefix
*p
, struct in6_addr
*ret_in6_addr
,
868 unsigned char *ret_prefixlen
) {
869 assert_return(p
, -EINVAL
);
870 assert_return(ret_in6_addr
, -EINVAL
);
871 assert_return(ret_prefixlen
, -EINVAL
);
873 *ret_in6_addr
= p
->opt
.in6_addr
;
874 *ret_prefixlen
= p
->opt
.prefixlen
;
879 _public_
int sd_radv_prefix_set_onlink(sd_radv_prefix
*p
, int onlink
) {
880 assert_return(p
, -EINVAL
);
882 SET_FLAG(p
->opt
.flags
, ND_OPT_PI_FLAG_ONLINK
, onlink
);
887 _public_
int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix
*p
,
888 int address_autoconfiguration
) {
889 assert_return(p
, -EINVAL
);
891 SET_FLAG(p
->opt
.flags
, ND_OPT_PI_FLAG_AUTO
, address_autoconfiguration
);
896 _public_
int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix
*p
,
897 uint32_t valid_lifetime
) {
898 assert_return(p
, -EINVAL
);
900 p
->opt
.valid_lifetime
= htobe32(valid_lifetime
);
905 _public_
int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix
*p
,
906 uint32_t preferred_lifetime
) {
907 assert_return(p
, -EINVAL
);
909 p
->opt
.preferred_lifetime
= htobe32(preferred_lifetime
);
914 _public_
int sd_radv_route_prefix_new(sd_radv_route_prefix
**ret
) {
915 sd_radv_route_prefix
*p
;
917 assert_return(ret
, -EINVAL
);
919 p
= new(sd_radv_route_prefix
, 1);
923 *p
= (sd_radv_route_prefix
) {
926 .opt
.type
= SD_RADV_OPT_ROUTE_INFORMATION
,
927 .opt
.length
= DIV_ROUND_UP(sizeof(p
->opt
), 8),
930 .opt
.lifetime
= htobe32(604800),
937 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_route_prefix
, sd_radv_route_prefix
, mfree
);
939 _public_
int sd_radv_route_prefix_set_prefix(sd_radv_route_prefix
*p
, const struct in6_addr
*in6_addr
,
940 unsigned char prefixlen
) {
941 assert_return(p
, -EINVAL
);
942 assert_return(in6_addr
, -EINVAL
);
948 /* unusual but allowed, log it */
949 log_radv(NULL
, "Unusual prefix length %u greater than 64", prefixlen
);
951 p
->opt
.in6_addr
= *in6_addr
;
952 p
->opt
.prefixlen
= prefixlen
;
957 _public_
int sd_radv_route_prefix_set_lifetime(sd_radv_route_prefix
*p
, uint32_t valid_lifetime
) {
958 assert_return(p
, -EINVAL
);
960 p
->opt
.lifetime
= htobe32(valid_lifetime
);