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