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