File: | build-scan/../src/libsystemd-network/sd-radv.c |
Warning: | line 112, column 17 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |||||
77 | static 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) | ||||
| |||||
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); | ||||
104 | ra->n_ref--; | ||||
105 | |||||
106 | if (ra->n_ref > 0) | ||||
107 | return NULL((void*)0); | ||||
108 | |||||
109 | while (ra->prefixes) { | ||||
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); | ||||
| |||||
113 | sd_radv_prefix_unref(p); | ||||
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 | |||||
128 | static 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 | |||||
229 | static 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, ×tamp); | ||||
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 | |||||
286 | static 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 | |||||
292 | static 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 | |||||
345 | fail: | ||||
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
| ||||
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); | ||||
764 | p->n_ref--; | ||||
765 | |||||
766 | if (p->n_ref > 0) | ||||
767 | return NULL((void*)0); | ||||
768 | |||||
769 | return mfree(p); | ||||
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 | } |
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 | |
33 | static inline void *mfree(void *memory) { |
34 | free(memory); |
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 | |
46 | void* memdup(const void *p, size_t l) _alloc_(2); |
47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
48 | |
49 | static inline void freep(void *p) { |
50 | free(*(void**) p); |
51 | } |
52 | |
53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
54 | |
55 | static 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 | |
89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
90 | void* 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 | }) |