.msg_namelen = sizeof(dst_addr),
.msg_iov = iov,
};
+ usec_t time_now;
+ int r;
+
+ r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0)
+ return r;
if (dst && !in_addr_is_null(AF_INET6, (union in_addr_union*) dst))
dst_addr.sin6_addr = *dst;
}
LIST_FOREACH(prefix, p, ra->prefixes) {
+ if (p->valid_until) {
+
+ if (time_now > p->valid_until)
+ p->opt.valid_lifetime = 0;
+ else
+ p->opt.valid_lifetime = htobe32((p->valid_until - time_now) / USEC_PER_SEC);
+
+ if (time_now > p->preferred_until)
+ p->opt.preferred_lifetime = 0;
+ else
+ p->opt.preferred_lifetime = htobe32((p->preferred_until - time_now) / USEC_PER_SEC);
+ }
iov[msg.msg_iovlen].iov_base = &p->opt;
iov[msg.msg_iovlen].iov_len = sizeof(p->opt);
msg.msg_iovlen++;
return r;
}
-_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
+_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, bool dynamic) {
sd_radv_prefix *cur;
+ int r;
_cleanup_free_ char *addr_p = NULL;
+ char time_string_preferred[FORMAT_TIMESPAN_MAX];
+ char time_string_valid[FORMAT_TIMESPAN_MAX];
+ usec_t time_now, valid, preferred, valid_until, preferred_until;
assert_return(ra, -EINVAL);
return -EINVAL;
LIST_FOREACH(prefix, cur, ra->prefixes) {
- int r;
r = in_addr_prefix_intersect(AF_INET6,
(union in_addr_union*) &cur->opt.in6_addr,
if (r > 0) {
_cleanup_free_ char *addr_cur = NULL;
- (void) in_addr_to_string(AF_INET6,
- (union in_addr_union*) &cur->opt.in6_addr,
- &addr_cur);
(void) in_addr_to_string(AF_INET6,
(union in_addr_union*) &p->opt.in6_addr,
&addr_p);
+ if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
+ goto update;
+
+ (void) in_addr_to_string(AF_INET6,
+ (union in_addr_union*) &cur->opt.in6_addr,
+ &addr_cur);
log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u",
addr_cur, cur->opt.prefixlen,
addr_p, p->opt.prefixlen);
ra->n_prefixes++;
(void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
- log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
+
+ if (!dynamic) {
+ log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
+ return 0;
+ }
+
+ cur = p;
+
+ update:
+ r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0)
+ return r;
+
+ valid = be32toh(p->opt.valid_lifetime) * USEC_PER_SEC;
+ valid_until = usec_add(valid, time_now);
+ if (valid_until == USEC_INFINITY)
+ return -EOVERFLOW;
+
+ preferred = be32toh(p->opt.preferred_lifetime) * USEC_PER_SEC;
+ preferred_until = usec_add(preferred, time_now);
+ if (preferred_until == USEC_INFINITY)
+ return -EOVERFLOW;
+
+ cur->valid_until = valid_until;
+ cur->preferred_until = preferred_until;
+
+ log_radv("%s prefix %s/%u preferred %s valid %s",
+ cur? "Updated": "Added",
+ addr_p, p->opt.prefixlen,
+ format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
+ preferred, USEC_PER_SEC),
+ format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX,
+ valid, USEC_PER_SEC));
return 0;
}
#include <inttypes.h>
#include <net/ethernet.h>
#include <netinet/in.h>
+#include <stdbool.h>
#include <sys/types.h>
#include "sd-ndisc.h"
int sd_radv_set_managed_information(sd_radv *ra, int managed);
int sd_radv_set_other_information(sd_radv *ra, int other);
int sd_radv_set_preference(sd_radv *ra, unsigned preference);
-int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
+int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, bool dynamic);
int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
const struct in6_addr *dns, size_t n_dns);
int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, char **search_list);