Bug Summary

File:build-scan/../src/libsystemd-network/sd-radv.c
Warning:line 112, column 17
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sd-radv.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/libsystemd-network/libsystemd-network.a.p -I src/libsystemd-network -I ../src/libsystemd-network -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I . -I .. -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/libsystemd-network/sd-radv.c

../src/libsystemd-network/sd-radv.c

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

../src/basic/alloc-util.h

1/* SPDX-License-Identifier: LGPL-2.1+ */
2#pragma once
3
4#include <alloca.h>
5#include <stddef.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include "macro.h"
10
11#define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n)))
12
13#define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t)))
14
15#define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while
(0); (t*) __builtin_alloca (sizeof(t)*(n)); })
\
16 ({ \
17 assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while
(0)
; \
18 (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \
19 })
20
21#define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while
(0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_
= __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_)
; }); })
\
22 ({ \
23 assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)"
), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while
(0)
; \
24 (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca
(_len_); (void *) memset(_new_, 0, _len_); })
; \
25 })
26
27#define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n)))
28
29#define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
30
31#define malloc0(n)(calloc(1, (n))) (calloc(1, (n)))
32
33static inline void *mfree(void *memory) {
34 free(memory);
24
Memory is released
35 return NULL((void*)0);
36}
37
38#define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \
39 ({ \
40 free(a); \
41 (a) = (b); \
42 (b) = NULL((void*)0); \
43 0; \
44 })
45
46void* memdup(const void *p, size_t l) _alloc_(2);
47void* memdup_suffix0(const void *p, size_t l) _alloc_(2);
48
49static inline void freep(void *p) {
50 free(*(void**) p);
51}
52
53#define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep)))
54
55static inline bool_Bool size_multiply_overflow(size_t size, size_t need) {
56 return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL
) / need)),0))
;
57}
58
59_malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
60 if (size_multiply_overflow(size, need))
61 return NULL((void*)0);
62
63 return malloc(size * need);
64}
65
66#if !HAVE_REALLOCARRAY1
67_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) {
68 if (size_multiply_overflow(size, need))
69 return NULL((void*)0);
70
71 return realloc(p, size * need);
72}
73#endif
74
75_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
76 if (size_multiply_overflow(size, need))
77 return NULL((void*)0);
78
79 return memdup(p, size * need);
80}
81
82_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
83 if (size_multiply_overflow(size, need))
84 return NULL((void*)0);
85
86 return memdup_suffix0(p, size * need);
87}
88
89void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
90void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
91
92#define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need
), sizeof((array)[0]))
\
93 greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
94
95#define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need
), sizeof((array)[0]))
\
96 greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
97
98#define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_
); (void *) memset(_new_, 0, _len_); })
\
99 ({ \
100 char *_new_; \
101 size_t _len_ = n; \
102 _new_ = alloca(_len_)__builtin_alloca (_len_); \
103 (void *) memset(_new_, 0, _len_); \
104 })
105
106/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
107#define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca
((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) &
~_mask_); })
\
108 ({ \
109 void *_ptr_; \
110 size_t _mask_ = (align) - 1; \
111 _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \
112 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
113 })
114
115#define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_
; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_
) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_
); }); (void*)memset(_new_, 0, _size_); })
\
116 ({ \
117 void *_new_; \
118 size_t _size_ = (size); \
119 _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca
((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) &
~_mask_); })
; \
120 (void*)memset(_new_, 0, _size_); \
121 })
122
123/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
124 * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
125#define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \
126 ({ \
127 typeof(ptr) _ptr_ = (ptr); \
128 (ptr) = NULL((void*)0); \
129 _ptr_; \
130 })