| 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 | }) |