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