]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/sd-radv.c
sd-radv: Free DNS domain search list on unref (#6858)
[thirdparty/systemd.git] / src / libsystemd-network / sd-radv.c
1 /***
2 This file is part of systemd.
3
4 Copyright (C) 2017 Intel Corporation. All rights reserved.
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <netinet/icmp6.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <linux/in6.h>
24
25 #include "sd-radv.h"
26
27 #include "macro.h"
28 #include "alloc-util.h"
29 #include "dns-domain.h"
30 #include "fd-util.h"
31 #include "icmp6-util.h"
32 #include "in-addr-util.h"
33 #include "radv-internal.h"
34 #include "socket-util.h"
35 #include "string-util.h"
36 #include "strv.h"
37 #include "util.h"
38 #include "random-util.h"
39
40 _public_ int sd_radv_new(sd_radv **ret) {
41 _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
42
43 assert_return(ret, -EINVAL);
44
45 ra = new0(sd_radv, 1);
46 if (!ra)
47 return -ENOMEM;
48
49 ra->n_ref = 1;
50 ra->fd = -1;
51
52 LIST_HEAD_INIT(ra->prefixes);
53
54 *ret = ra;
55 ra = NULL;
56
57 return 0;
58 }
59
60 _public_ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
61 int r;
62
63 assert_return(ra, -EINVAL);
64 assert_return(!ra->event, -EBUSY);
65
66 if (event)
67 ra->event = sd_event_ref(event);
68 else {
69 r = sd_event_default(&ra->event);
70 if (r < 0)
71 return 0;
72 }
73
74 ra->event_priority = priority;
75
76 return 0;
77 }
78
79 _public_ int sd_radv_detach_event(sd_radv *ra) {
80
81 assert_return(ra, -EINVAL);
82
83 ra->event = sd_event_unref(ra->event);
84 return 0;
85 }
86
87 _public_ sd_event *sd_radv_get_event(sd_radv *ra) {
88 assert_return(ra, NULL);
89
90 return ra->event;
91 }
92
93 static void radv_reset(sd_radv *ra) {
94
95 ra->timeout_event_source =
96 sd_event_source_unref(ra->timeout_event_source);
97
98 ra->recv_event_source =
99 sd_event_source_unref(ra->recv_event_source);
100
101 ra->ra_sent = 0;
102 }
103
104 _public_ sd_radv *sd_radv_ref(sd_radv *ra) {
105 if (!ra)
106 return NULL;
107
108 assert(ra->n_ref > 0);
109 ra->n_ref++;
110
111 return ra;
112 }
113
114 _public_ sd_radv *sd_radv_unref(sd_radv *ra) {
115 if (!ra)
116 return NULL;
117
118 assert(ra->n_ref > 0);
119 ra->n_ref--;
120
121 if (ra->n_ref > 0)
122 return NULL;
123
124 while (ra->prefixes) {
125 sd_radv_prefix *p = ra->prefixes;
126
127 LIST_REMOVE(prefix, ra->prefixes, p);
128 sd_radv_prefix_unref(p);
129 }
130
131 free(ra->rdnss);
132 free(ra->dnssl);
133
134 radv_reset(ra);
135
136 sd_radv_detach_event(ra);
137 return mfree(ra);
138 }
139
140 static int radv_send(sd_radv *ra, const struct in6_addr *dst,
141 const uint32_t router_lifetime) {
142 static const struct ether_addr mac_zero = {};
143 sd_radv_prefix *p;
144 struct sockaddr_in6 dst_addr = {
145 .sin6_family = AF_INET6,
146 .sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
147 };
148 struct nd_router_advert adv = {};
149 struct {
150 struct nd_opt_hdr opthdr;
151 struct ether_addr slladdr;
152 } _packed_ opt_mac = {
153 .opthdr = {
154 .nd_opt_type = ND_OPT_SOURCE_LINKADDR,
155 .nd_opt_len = (sizeof(struct nd_opt_hdr) +
156 sizeof(struct ether_addr) - 1) /8 + 1,
157 },
158 };
159 struct nd_opt_mtu opt_mtu = {
160 .nd_opt_mtu_type = ND_OPT_MTU,
161 .nd_opt_mtu_len = 1,
162 };
163 /* Reserve iov space for RA header, linkaddr, MTU, N prefixes, RDNSS */
164 struct iovec iov[4 + ra->n_prefixes];
165 struct msghdr msg = {
166 .msg_name = &dst_addr,
167 .msg_namelen = sizeof(dst_addr),
168 .msg_iov = iov,
169 };
170
171 if (dst && !in_addr_is_null(AF_INET6, (union in_addr_union*) dst))
172 dst_addr.sin6_addr = *dst;
173
174 adv.nd_ra_type = ND_ROUTER_ADVERT;
175 adv.nd_ra_curhoplimit = ra->hop_limit;
176 adv.nd_ra_flags_reserved = ra->flags;
177 adv.nd_ra_router_lifetime = htobe16(router_lifetime);
178 iov[msg.msg_iovlen].iov_base = &adv;
179 iov[msg.msg_iovlen].iov_len = sizeof(adv);
180 msg.msg_iovlen++;
181
182 /* MAC address is optional, either because the link does not use L2
183 addresses or load sharing is desired. See RFC 4861, Section 4.2 */
184 if (memcmp(&mac_zero, &ra->mac_addr, sizeof(mac_zero))) {
185 opt_mac.slladdr = ra->mac_addr;
186 iov[msg.msg_iovlen].iov_base = &opt_mac;
187 iov[msg.msg_iovlen].iov_len = sizeof(opt_mac);
188 msg.msg_iovlen++;
189 }
190
191 if (ra->mtu) {
192 opt_mtu.nd_opt_mtu_mtu = htobe32(ra->mtu);
193 iov[msg.msg_iovlen].iov_base = &opt_mtu;
194 iov[msg.msg_iovlen].iov_len = sizeof(opt_mtu);
195 msg.msg_iovlen++;
196 }
197
198 LIST_FOREACH(prefix, p, ra->prefixes) {
199 iov[msg.msg_iovlen].iov_base = &p->opt;
200 iov[msg.msg_iovlen].iov_len = sizeof(p->opt);
201 msg.msg_iovlen++;
202 }
203
204 if (ra->rdnss) {
205 iov[msg.msg_iovlen].iov_base = ra->rdnss;
206 iov[msg.msg_iovlen].iov_len = ra->rdnss->length * 8;
207 msg.msg_iovlen++;
208 }
209
210 if (ra->dnssl) {
211 iov[msg.msg_iovlen].iov_base = ra->dnssl;
212 iov[msg.msg_iovlen].iov_len = ra->dnssl->length * 8;
213 msg.msg_iovlen++;
214 }
215
216 if (sendmsg(ra->fd, &msg, 0) < 0)
217 return -errno;
218
219 return 0;
220 }
221
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;
225 struct in6_addr src;
226 triple_timestamp timestamp;
227 int r;
228 ssize_t buflen;
229 _cleanup_free_ char *buf = NULL;
230
231 assert(s);
232 assert(ra);
233 assert(ra->event);
234
235 buflen = next_datagram_size_fd(fd);
236
237 if ((unsigned) buflen < sizeof(struct nd_router_solicit))
238 return log_radv("Too short packet received");
239
240 buf = new0(char, buflen);
241 if (!buf)
242 return 0;
243
244 r = icmp6_receive(fd, buf, buflen, &src, &timestamp);
245 if (r < 0) {
246 switch (r) {
247 case -EADDRNOTAVAIL:
248 (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr);
249 log_radv("Received RS from non-link-local address %s. Ignoring", addr);
250 break;
251
252 case -EMULTIHOP:
253 log_radv("Received RS with invalid hop limit. Ignoring.");
254 break;
255
256 case -EPFNOSUPPORT:
257 log_radv("Received invalid source address from ICMPv6 socket. Ignoring.");
258 break;
259
260 default:
261 log_radv_warning_errno(r, "Error receiving from ICMPv6 socket: %m");
262 break;
263 }
264
265 return 0;
266 }
267
268 (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr);
269
270 r = radv_send(ra, &src, ra->lifetime);
271 if (r < 0)
272 log_radv_warning_errno(r, "Unable to send solicited Router Advertisment to %s: %m", addr);
273 else
274 log_radv("Sent solicited Router Advertisement to %s", addr);
275
276 return 0;
277 }
278
279 static usec_t radv_compute_timeout(usec_t min, usec_t max) {
280 assert_return(min <= max, SD_RADV_DEFAULT_MIN_TIMEOUT_USEC);
281
282 return min + (random_u32() % (max - min));
283 }
284
285 static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
286 int r;
287 sd_radv *ra = userdata;
288 usec_t min_timeout = SD_RADV_DEFAULT_MIN_TIMEOUT_USEC;
289 usec_t max_timeout = SD_RADV_DEFAULT_MAX_TIMEOUT_USEC;
290 usec_t time_now, timeout;
291 char time_string[FORMAT_TIMESPAN_MAX];
292
293 assert(s);
294 assert(ra);
295 assert(ra->event);
296
297 ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source);
298
299 r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
300 if (r < 0)
301 goto fail;
302
303 r = radv_send(ra, NULL, ra->lifetime);
304 if (r < 0)
305 log_radv_warning_errno(r, "Unable to send Router Advertisement: %m");
306
307 /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
308 if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
309 max_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
310 min_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC / 3;
311 }
312
313 timeout = radv_compute_timeout(min_timeout, max_timeout);
314
315 log_radv("Next Router Advertisement in %s",
316 format_timespan(time_string, FORMAT_TIMESPAN_MAX,
317 timeout, USEC_PER_SEC));
318
319 r = sd_event_add_time(ra->event, &ra->timeout_event_source,
320 clock_boottime_or_monotonic(),
321 time_now + timeout, MSEC_PER_SEC,
322 radv_timeout, ra);
323 if (r < 0)
324 goto fail;
325
326 r = sd_event_source_set_priority(ra->timeout_event_source,
327 ra->event_priority);
328 if (r < 0)
329 goto fail;
330
331 r = sd_event_source_set_description(ra->timeout_event_source,
332 "radv-timeout");
333 if (r < 0)
334 goto fail;
335
336 ra->ra_sent++;
337
338 fail:
339 if (r < 0)
340 sd_radv_stop(ra);
341
342 return 0;
343 }
344
345 _public_ int sd_radv_stop(sd_radv *ra) {
346 int r;
347
348 assert_return(ra, -EINVAL);
349
350 log_radv("Stopping IPv6 Router Advertisement daemon");
351
352 /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
353 with zero lifetime */
354 r = radv_send(ra, NULL, 0);
355 if (r < 0)
356 log_radv_warning_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
357
358 radv_reset(ra);
359 ra->fd = safe_close(ra->fd);
360 ra->state = SD_RADV_STATE_IDLE;
361
362 return 0;
363 }
364
365 _public_ int sd_radv_start(sd_radv *ra) {
366 int r = 0;
367
368 assert_return(ra, -EINVAL);
369 assert_return(ra->event, -EINVAL);
370 assert_return(ra->ifindex > 0, -EINVAL);
371
372 if (ra->state != SD_RADV_STATE_IDLE)
373 return 0;
374
375 r = sd_event_add_time(ra->event, &ra->timeout_event_source,
376 clock_boottime_or_monotonic(), 0, 0,
377 radv_timeout, ra);
378 if (r < 0)
379 goto fail;
380
381 r = sd_event_source_set_priority(ra->timeout_event_source,
382 ra->event_priority);
383 if (r < 0)
384 goto fail;
385
386 (void) sd_event_source_set_description(ra->timeout_event_source,
387 "radv-timeout");
388
389 r = icmp6_bind_router_advertisement(ra->ifindex);
390 if (r < 0)
391 goto fail;
392
393 ra->fd = r;
394
395 r = sd_event_add_io(ra->event, &ra->recv_event_source, ra->fd, EPOLLIN, radv_recv, ra);
396 if (r < 0)
397 goto fail;
398
399 r = sd_event_source_set_priority(ra->recv_event_source, ra->event_priority);
400 if (r < 0)
401 goto fail;
402
403 (void) sd_event_source_set_description(ra->recv_event_source, "radv-receive-message");
404
405 ra->state = SD_RADV_STATE_ADVERTISING;
406
407 log_radv("Started IPv6 Router Advertisement daemon");
408
409 return 0;
410
411 fail:
412 radv_reset(ra);
413
414 return r;
415 }
416
417 _public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
418 assert_return(ra, -EINVAL);
419 assert_return(ifindex >= -1, -EINVAL);
420
421 if (ra->state != SD_RADV_STATE_IDLE)
422 return -EBUSY;
423
424 ra->ifindex = ifindex;
425
426 return 0;
427 }
428
429 _public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
430 assert_return(ra, -EINVAL);
431
432 if (ra->state != SD_RADV_STATE_IDLE)
433 return -EBUSY;
434
435 if (mac_addr)
436 ra->mac_addr = *mac_addr;
437 else
438 zero(ra->mac_addr);
439
440 return 0;
441 }
442
443 _public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
444 assert_return(ra, -EINVAL);
445 assert_return(mtu >= 1280, -EINVAL);
446
447 if (ra->state != SD_RADV_STATE_IDLE)
448 return -EBUSY;
449
450 ra->mtu = mtu;
451
452 return 0;
453 }
454
455 _public_ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
456 assert_return(ra, -EINVAL);
457
458 if (ra->state != SD_RADV_STATE_IDLE)
459 return -EBUSY;
460
461 ra->hop_limit = hop_limit;
462
463 return 0;
464 }
465
466 _public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime) {
467 assert_return(ra, -EINVAL);
468
469 if (ra->state != SD_RADV_STATE_IDLE)
470 return -EBUSY;
471
472 /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the
473 preference value MUST be set to (00) by the sender..." */
474 if (router_lifetime == 0 &&
475 (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
476 return -ETIME;
477
478 ra->lifetime = router_lifetime;
479
480 return 0;
481 }
482
483 _public_ int sd_radv_set_managed_information(sd_radv *ra, int managed) {
484 assert_return(ra, -EINVAL);
485
486 if (ra->state != SD_RADV_STATE_IDLE)
487 return -EBUSY;
488
489 SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
490
491 return 0;
492 }
493
494 _public_ int sd_radv_set_other_information(sd_radv *ra, int other) {
495 assert_return(ra, -EINVAL);
496
497 if (ra->state != SD_RADV_STATE_IDLE)
498 return -EBUSY;
499
500 SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
501
502 return 0;
503 }
504
505 _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
506 int r = 0;
507
508 assert_return(ra, -EINVAL);
509 assert_return(IN_SET(preference,
510 SD_NDISC_PREFERENCE_LOW,
511 SD_NDISC_PREFERENCE_MEDIUM,
512 SD_NDISC_PREFERENCE_HIGH), -EINVAL);
513
514 ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
515
516 return r;
517 }
518
519 _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
520 sd_radv_prefix *cur;
521 _cleanup_free_ char *addr_p = NULL;
522
523 assert_return(ra, -EINVAL);
524
525 if (!p)
526 return -EINVAL;
527
528 LIST_FOREACH(prefix, cur, ra->prefixes) {
529 int r;
530
531 r = in_addr_prefix_intersect(AF_INET6,
532 (union in_addr_union*) &cur->opt.in6_addr,
533 cur->opt.prefixlen,
534 (union in_addr_union*) &p->opt.in6_addr,
535 p->opt.prefixlen);
536 if (r > 0) {
537 _cleanup_free_ char *addr_cur = NULL;
538
539 (void) in_addr_to_string(AF_INET6,
540 (union in_addr_union*) &cur->opt.in6_addr,
541 &addr_cur);
542 (void) in_addr_to_string(AF_INET6,
543 (union in_addr_union*) &p->opt.in6_addr,
544 &addr_p);
545
546 log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u",
547 addr_cur, cur->opt.prefixlen,
548 addr_p, p->opt.prefixlen);
549
550 return -EEXIST;
551 }
552 }
553
554 p = sd_radv_prefix_ref(p);
555
556 LIST_APPEND(prefix, ra->prefixes, p);
557
558 ra->n_prefixes++;
559
560 (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
561 log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
562
563 return 0;
564 }
565
566 _public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
567 const struct in6_addr *dns, size_t n_dns) {
568 _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
569 size_t len;
570
571 assert_return(ra, -EINVAL);
572 assert_return(n_dns < 128, -EINVAL);
573
574 if (!dns || n_dns == 0) {
575 ra->rdnss = mfree(ra->rdnss);
576 ra->n_rdnss = 0;
577
578 return 0;
579 }
580
581 len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
582
583 opt_rdnss = malloc0(len);
584 if (!opt_rdnss)
585 return -ENOMEM;
586
587 opt_rdnss->type = SD_RADV_OPT_RDNSS;
588 opt_rdnss->length = len / 8;
589 opt_rdnss->lifetime = htobe32(lifetime);
590
591 memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
592
593 free(ra->rdnss);
594 ra->rdnss = opt_rdnss;
595 opt_rdnss = NULL;
596
597 ra->n_rdnss = n_dns;
598
599 return 0;
600 }
601
602 _public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime,
603 char **search_list) {
604 _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
605 size_t len = 0;
606 char **s;
607 uint8_t *p;
608
609 assert_return(ra, -EINVAL);
610
611 if (!search_list || *search_list == NULL) {
612 ra->dnssl = mfree(ra->dnssl);
613
614 return 0;
615 }
616
617 STRV_FOREACH(s, search_list)
618 len += strlen(*s) + 2;
619
620 len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
621
622 opt_dnssl = malloc0(len);
623 if (!opt_dnssl)
624 return -ENOMEM;
625
626 opt_dnssl->type = SD_RADV_OPT_DNSSL;
627 opt_dnssl->length = len / 8;
628 opt_dnssl->lifetime = htobe32(lifetime);
629
630 p = (uint8_t *)(opt_dnssl + 1);
631 len -= sizeof(struct sd_radv_opt_dns);
632
633 STRV_FOREACH(s, search_list) {
634 int r;
635
636 r = dns_name_to_wire_format(*s, p, len, false);
637 if (r < 0)
638 return r;
639
640 if (len < (size_t)r)
641 return -ENOBUFS;
642
643 p += r;
644 len -= r;
645 }
646
647 free(ra->dnssl);
648 ra->dnssl = opt_dnssl;
649 opt_dnssl = NULL;
650
651 return 0;
652 }
653
654 _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
655 _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
656
657 assert_return(ret, -EINVAL);
658
659 p = new0(sd_radv_prefix, 1);
660 if (!p)
661 return -ENOMEM;
662
663 p->n_ref = 1;
664
665 p->opt.type = ND_OPT_PREFIX_INFORMATION;
666 p->opt.length = (sizeof(p->opt) - 1) /8 + 1;
667
668 p->opt.prefixlen = 64;
669
670 /* RFC 4861, Section 6.2.1 */
671 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, true);
672 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, true);
673 p->opt.preferred_lifetime = htobe32(604800);
674 p->opt.valid_lifetime = htobe32(2592000);
675
676 LIST_INIT(prefix, p);
677
678 *ret = p;
679 p = NULL;
680
681 return 0;
682 }
683
684 _public_ sd_radv_prefix *sd_radv_prefix_ref(sd_radv_prefix *p) {
685 if (!p)
686 return NULL;
687
688 assert(p->n_ref > 0);
689 p->n_ref++;
690
691 return p;
692 }
693
694 _public_ sd_radv_prefix *sd_radv_prefix_unref(sd_radv_prefix *p) {
695 if (!p)
696 return NULL;
697
698 assert(p->n_ref > 0);
699 p->n_ref--;
700
701 if (p->n_ref > 0)
702 return NULL;
703
704 return mfree(p);
705 }
706
707 _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, struct in6_addr *in6_addr,
708 unsigned char prefixlen) {
709 assert_return(p, -EINVAL);
710 assert_return(in6_addr, -EINVAL);
711
712 if (prefixlen < 3 || prefixlen > 128)
713 return -EINVAL;
714
715 if (prefixlen > 64)
716 /* unusual but allowed, log it */
717 log_radv("Unusual prefix length %d greater than 64", prefixlen);
718
719 p->opt.in6_addr = *in6_addr;
720 p->opt.prefixlen = prefixlen;
721
722 return 0;
723 }
724
725 _public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
726 assert_return(p, -EINVAL);
727
728 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
729
730 return 0;
731 }
732
733 _public_ int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
734 int address_autoconfiguration) {
735 assert_return(p, -EINVAL);
736
737 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
738
739 return 0;
740 }
741
742 _public_ int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p,
743 uint32_t valid_lifetime) {
744 assert_return(p, -EINVAL);
745
746 p->opt.valid_lifetime = htobe32(valid_lifetime);
747
748 return 0;
749 }
750
751 _public_ int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p,
752 uint32_t preferred_lifetime) {
753 assert_return(p, -EINVAL);
754
755 p->opt.preferred_lifetime = htobe32(preferred_lifetime);
756
757 return 0;
758 }