From 6e866b331d7cd4a5e0759dd160dea6edabd3678e Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Fri, 21 Dec 2018 22:06:22 +0100 Subject: New upstream version 240 --- src/libsystemd-network/dhcp-identifier.c | 140 +++++++-- src/libsystemd-network/dhcp-identifier.h | 17 +- src/libsystemd-network/dhcp-network.c | 30 +- src/libsystemd-network/dhcp-packet.c | 82 +++-- src/libsystemd-network/dhcp-server-internal.h | 4 +- src/libsystemd-network/dhcp6-internal.h | 8 +- src/libsystemd-network/dhcp6-lease-internal.h | 2 +- src/libsystemd-network/dhcp6-network.c | 14 +- src/libsystemd-network/dhcp6-option.c | 171 +++++----- src/libsystemd-network/icmp6-util.c | 37 +-- src/libsystemd-network/lldp-internal.h | 4 +- src/libsystemd-network/lldp-neighbor.c | 54 +--- src/libsystemd-network/lldp-neighbor.h | 3 +- src/libsystemd-network/lldp-network.c | 1 + src/libsystemd-network/lldp-network.h | 1 - src/libsystemd-network/ndisc-internal.h | 3 + src/libsystemd-network/ndisc-router.c | 29 +- src/libsystemd-network/network-internal.c | 51 +-- src/libsystemd-network/network-internal.h | 8 +- src/libsystemd-network/radv-internal.h | 1 - src/libsystemd-network/sd-dhcp-client.c | 324 +++++++++---------- src/libsystemd-network/sd-dhcp-lease.c | 46 ++- src/libsystemd-network/sd-dhcp-server.c | 66 ++-- src/libsystemd-network/sd-dhcp6-client.c | 435 +++++++++++++++----------- src/libsystemd-network/sd-dhcp6-lease.c | 56 ++-- src/libsystemd-network/sd-ipv4acd.c | 59 ++-- src/libsystemd-network/sd-ipv4ll.c | 23 +- src/libsystemd-network/sd-lldp.c | 111 +++---- src/libsystemd-network/sd-ndisc.c | 126 ++++---- src/libsystemd-network/sd-radv.c | 208 +++++------- src/libsystemd-network/test-acd.c | 5 +- src/libsystemd-network/test-dhcp-client.c | 43 ++- src/libsystemd-network/test-dhcp-server.c | 10 +- src/libsystemd-network/test-dhcp6-client.c | 83 +++-- src/libsystemd-network/test-ipv4ll-manual.c | 5 +- src/libsystemd-network/test-ipv4ll.c | 7 +- src/libsystemd-network/test-lldp.c | 132 +++++++- src/libsystemd-network/test-ndisc-ra.c | 9 +- src/libsystemd-network/test-ndisc-rs.c | 7 +- 39 files changed, 1211 insertions(+), 1204 deletions(-) (limited to 'src/libsystemd-network') diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 91c485c6c2..07496adaa3 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -1,6 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -#include "libudev.h" +#include +#include + +#include "sd-device.h" #include "sd-id128.h" #include "dhcp-identifier.h" @@ -8,19 +11,26 @@ #include "network-internal.h" #include "siphash24.h" #include "sparse-endian.h" -#include "udev-util.h" #include "virt.h" -#define SYSTEMD_PEN 43793 -#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +#define SYSTEMD_PEN 43793 +#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03) +#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */ -int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { +int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) { struct duid d; assert_cc(sizeof(d.raw) >= MAX_DUID_LEN); if (duid_len > MAX_DUID_LEN) return -EINVAL; + if (!strict) { + /* Strict validation is not requested. We only ensure that the + * DUID is not too long. */ + return 0; + } + switch (duid_type) { case DUID_TYPE_LLT: if (duid_len <= sizeof(d.llt)) @@ -45,6 +55,56 @@ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { return 0; } +int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) { + uint16_t time_from_2000y; + + assert(duid); + assert(len); + assert(addr); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; + + if (t < USEC_2000) + time_from_2000y = 0; + else + time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff); + + unaligned_write_be16(&duid->type, DUID_TYPE_LLT); + unaligned_write_be16(&duid->llt.htype, arp_type); + unaligned_write_be32(&duid->llt.time, time_from_2000y); + memcpy(duid->llt.haddr, addr, addr_len); + + *len = sizeof(duid->type) + sizeof(duid->llt.htype) + sizeof(duid->llt.time) + addr_len; + + return 0; +} + +int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) { + assert(duid); + assert(len); + assert(addr); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; + + unaligned_write_be16(&duid->type, DUID_TYPE_LL); + unaligned_write_be16(&duid->ll.htype, arp_type); + memcpy(duid->ll.haddr, addr, addr_len); + + *len = sizeof(duid->type) + sizeof(duid->ll.htype) + addr_len; + + return 0; +} + int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { sd_id128_t machine_id; uint64_t hash; @@ -54,8 +114,13 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { assert(len); r = sd_id128_get_machine(&machine_id); - if (r < 0) + if (r < 0) { +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10); +#else return r; +#endif + } unaligned_write_be16(&duid->type, DUID_TYPE_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); @@ -63,33 +128,56 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { *len = sizeof(duid->type) + sizeof(duid->en); /* a bit of snake-oil perhaps, but no need to expose the machine-id - directly; duid->en.id might not be aligned, so we need to copy */ + * directly; duid->en.id might not be aligned, so we need to copy */ hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes)); memcpy(duid->en.id, &hash, sizeof(duid->en.id)); return 0; } -int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) { - /* name is a pointer to memory in the udev_device struct, so must - have the same scope */ - _cleanup_(udev_device_unrefp) struct udev_device *device = NULL; +int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len) { + sd_id128_t machine_id; + int r; + + assert(duid); + assert(len); + + r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id); + if (r < 0) + return r; + + unaligned_write_be16(&duid->type, DUID_TYPE_UUID); + memcpy(&duid->raw.data, &machine_id, sizeof(machine_id)); + + *len = sizeof(duid->type) + sizeof(machine_id); + + return 0; +} + +int dhcp_identifier_set_iaid( + int ifindex, + const uint8_t *mac, + size_t mac_len, + bool legacy_unstable_byteorder, + void *_id) { + /* name is a pointer to memory in the sd_device struct, so must + * have the same scope */ + _cleanup_(sd_device_unrefp) sd_device *device = NULL; const char *name = NULL; uint64_t id; + uint32_t id32; if (detect_container() <= 0) { /* not in a container, udev will be around */ - _cleanup_(udev_unrefp) struct udev *udev; char ifindex_str[2 + DECIMAL_STR_MAX(int)]; - - udev = udev_new(); - if (!udev) - return -ENOMEM; + int r; sprintf(ifindex_str, "n%d", ifindex); - device = udev_device_new_from_device_id(udev, ifindex_str); - if (device) { - if (udev_device_get_is_initialized(device) <= 0) + if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) { + r = sd_device_get_is_initialized(device); + if (r < 0) + return r; + if (r == 0) /* not yet ready */ return -EBUSY; @@ -103,10 +191,18 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i /* fall back to MAC address if no predictable name available */ id = siphash24(mac, mac_len, HASH_KEY.bytes); - id = htole64(id); + id32 = (id & 0xffffffff) ^ (id >> 32); - /* fold into 32 bits */ - unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32)); + if (legacy_unstable_byteorder) + /* for historical reasons (a bug), the bits were swapped and thus + * the result was endianness dependant. Preserve that behavior. */ + id32 = __bswap_32(id32); + else + /* the fixed behavior returns a stable byte order. Since LE is expected + * to be more common, swap the bytes on LE to give the same as legacy + * behavior. */ + id32 = be32toh(id32); + unaligned_write_ne32(_id, id32); return 0; } diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index b92c580d40..b3115125d9 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once - #include "sd-id128.h" #include "macro.h" #include "sparse-endian.h" +#include "time-util.h" #include "unaligned.h" typedef enum DUIDType { @@ -28,18 +28,18 @@ struct duid { union { struct { /* DUID_TYPE_LLT */ - uint16_t htype; - uint32_t time; + be16_t htype; + be32_t time; uint8_t haddr[0]; } _packed_ llt; struct { /* DUID_TYPE_EN */ - uint32_t pen; + be32_t pen; uint8_t id[8]; } _packed_ en; struct { /* DUID_TYPE_LL */ - int16_t htype; + be16_t htype; uint8_t haddr[0]; } _packed_ ll; struct { @@ -52,6 +52,9 @@ struct duid { }; } _packed_; -int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len); +int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict); +int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len); +int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len); int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); -int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); +int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len); +int dhcp_identifier_set_iaid(int ifindex, const uint8_t *mac, size_t mac_len, bool legacy_unstable_byteorder, void *_id); diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index 77638338f2..0e5b4147a9 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -78,7 +78,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, .filter = filter }; _cleanup_close_ int s = -1; - int r, on = 1; + int r; assert(ifindex > 0); assert(link); @@ -87,9 +87,9 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, if (s < 0) return -errno; - r = setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on)); + r = setsockopt_int(s, SOL_PACKET, PACKET_AUXDATA, true); if (r < 0) - return -errno; + return r; r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); if (r < 0) @@ -126,8 +126,6 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, const uint8_t *bcast_addr = NULL; uint8_t dhcp_hlen = 0; - assert_return(mac_addr_len > 0, -EINVAL); - if (arp_type == ARPHRD_ETHER) { assert_return(mac_addr_len == ETH_ALEN, -EINVAL); memcpy(ð_mac, mac_addr, ETH_ALEN); @@ -151,19 +149,19 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { }; _cleanup_close_ int s = -1; char ifname[IF_NAMESIZE] = ""; - int r, on = 1, tos = IPTOS_CLASS_CS6; + int r; s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (s < 0) return -errno; - r = setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); + r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6); if (r < 0) - return -errno; + return r; - r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true); if (r < 0) - return -errno; + return r; if (ifindex > 0) { if (if_indextoname(ifindex, ifname) == 0) @@ -175,18 +173,18 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { } if (address == INADDR_ANY) { - r = setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); + r = setsockopt_int(s, IPPROTO_IP, IP_PKTINFO, true); if (r < 0) - return -errno; + return r; - r = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); + r = setsockopt_int(s, SOL_SOCKET, SO_BROADCAST, true); if (r < 0) - return -errno; + return r; } else { - r = setsockopt(s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)); + r = setsockopt_int(s, IPPROTO_IP, IP_FREEBIND, true); if (r < 0) - return -errno; + return r; } r = bind(s, &src.sa, sizeof(src.in)); diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index d29cd06cb1..ad5f8e267a 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -106,70 +106,62 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, ui /* IP */ - if (packet->ip.version != IPVERSION) { - log_debug("ignoring packet: not IPv4"); - return -EINVAL; - } + if (packet->ip.version != IPVERSION) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: not IPv4"); - if (packet->ip.ihl < 5) { - log_debug("ignoring packet: IPv4 IHL (%u words) invalid", - packet->ip.ihl); - return -EINVAL; - } + if (packet->ip.ihl < 5) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: IPv4 IHL (%u words) invalid", + packet->ip.ihl); hdrlen = packet->ip.ihl * 4; - if (hdrlen < 20) { - log_debug("ignoring packet: IPv4 IHL (%zu bytes) " - "smaller than minimum (20 bytes)", hdrlen); - return -EINVAL; - } - - if (len < hdrlen) { - log_debug("ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by IP header", len, - hdrlen); - return -EINVAL; - } + if (hdrlen < 20) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: IPv4 IHL (%zu bytes) " + "smaller than minimum (20 bytes)", + hdrlen); + + if (len < hdrlen) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: packet (%zu bytes) " + "smaller than expected (%zu) by IP header", + len, hdrlen); /* UDP */ - if (packet->ip.protocol != IPPROTO_UDP) { - log_debug("ignoring packet: not UDP"); - return -EINVAL; - } + if (packet->ip.protocol != IPPROTO_UDP) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: not UDP"); - if (len < hdrlen + be16toh(packet->udp.len)) { - log_debug("ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by UDP header", len, - hdrlen + be16toh(packet->udp.len)); - return -EINVAL; - } + if (len < hdrlen + be16toh(packet->udp.len)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: packet (%zu bytes) " + "smaller than expected (%zu) by UDP header", + len, hdrlen + be16toh(packet->udp.len)); - if (be16toh(packet->udp.dest) != port) { - log_debug("ignoring packet: to port %u, which " - "is not the DHCP client port (%u)", - be16toh(packet->udp.dest), port); - return -EINVAL; - } + if (be16toh(packet->udp.dest) != port) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: to port %u, which " + "is not the DHCP client port (%u)", + be16toh(packet->udp.dest), port); /* checksums - computing these is relatively expensive, so only do it if all the other checks have passed */ - if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) { - log_debug("ignoring packet: invalid IP checksum"); - return -EINVAL; - } + if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: invalid IP checksum"); if (checksum && packet->udp.check) { packet->ip.check = packet->udp.len; packet->ip.ttl = 0; if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, - be16toh(packet->udp.len) + 12)) { - log_debug("ignoring packet: invalid UDP checksum"); - return -EINVAL; - } + be16toh(packet->udp.len) + 12)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "ignoring packet: invalid UDP checksum"); } return 0; diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 6355128ddb..8a7c5bc28f 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -78,5 +78,5 @@ int dhcp_server_send_packet(sd_dhcp_server *server, DHCPRequest *req, DHCPPacket *packet, int type, size_t optoffset); -void client_id_hash_func(const void *p, struct siphash *state); -int client_id_compare_func(const void *_a, const void *_b); +void client_id_hash_func(const DHCPClientId *p, struct siphash *state); +int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b); diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index f1cbd6a4f1..157fc0aadd 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -73,8 +73,6 @@ struct DHCP6IA { struct ia_pd ia_pd; struct ia_ta ia_ta; }; - sd_event_source *timeout_t1; - sd_event_source *timeout_t2; LIST_HEAD(DHCP6Address, addresses); }; @@ -86,12 +84,12 @@ typedef struct DHCP6IA DHCP6IA; int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, size_t optlen, const void *optval); -int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia); -int dhcp6_option_append_pd(uint8_t *buf, size_t len, DHCP6IA *pd); +int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia); +int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd); int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen, uint8_t **optvalue); -int dhcp6_option_parse_status(DHCP6Option *option); +int dhcp6_option_parse_status(DHCP6Option *option, size_t len); int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia); int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, struct in6_addr **addrs, size_t count, diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index ff0b0f00ce..e004f48b4e 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -37,7 +37,6 @@ struct sd_dhcp6_lease { size_t ntp_fqdn_count; }; -int dhcp6_lease_clear_timers(DHCP6IA *ia); int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire); DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia); @@ -50,6 +49,7 @@ int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease); int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit); int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid); +int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid); int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen); int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c index 78cd383669..580f43ba40 100644 --- a/src/libsystemd-network/dhcp6-network.c +++ b/src/libsystemd-network/dhcp6-network.c @@ -25,7 +25,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { .in6.sin6_scope_id = index, }; _cleanup_close_ int s = -1; - int r, off = 0, on = 1; + int r; assert(index > 0); assert(local_address); @@ -36,17 +36,17 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { if (s < 0) return -errno; - r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); + r = setsockopt_int(s, IPPROTO_IPV6, IPV6_V6ONLY, true); if (r < 0) - return -errno; + return r; - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); + r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, false); if (r < 0) - return -errno; + return r; - r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true); if (r < 0) - return -errno; + return r; r = bind(s, &src.sa, sizeof(src.in6)); if (r < 0) diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 18196b1257..a2aac9a793 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -37,9 +37,9 @@ typedef struct DHCP6PDPrefixOption { uint8_t options[]; } _packed_ DHCP6PDPrefixOption; -#define DHCP6_OPTION_IA_NA_LEN (sizeof(struct ia_na)) -#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd)) -#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta)) +#define DHCP6_OPTION_IA_NA_LEN (sizeof(struct ia_na)) +#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd)) +#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta)) static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) { @@ -49,14 +49,14 @@ static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, assert_return(*buf, -EINVAL); assert_return(buflen, -EINVAL); - if (optlen > 0xffff || *buflen < optlen + sizeof(DHCP6Option)) + if (optlen > 0xffff || *buflen < optlen + offsetof(DHCP6Option, data)) return -ENOBUFS; option->code = htobe16(optcode); option->len = htobe16(optlen); - *buf += sizeof(DHCP6Option); - *buflen -= sizeof(DHCP6Option); + *buf += offsetof(DHCP6Option, data); + *buflen -= offsetof(DHCP6Option, data); return 0; } @@ -79,14 +79,17 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, return 0; } -int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { +int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) { uint16_t len; uint8_t *ia_hdr; size_t iaid_offset, ia_buflen, ia_addrlen = 0; DHCP6Address *addr; int r; - assert_return(buf && *buf && buflen && ia, -EINVAL); + assert_return(buf, -EINVAL); + assert_return(*buf, -EINVAL); + assert_return(buflen, -EINVAL); + assert_return(ia, -EINVAL); switch (ia->type) { case SD_DHCP6_OPTION_IA_NA: @@ -103,14 +106,14 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { return -EINVAL; } - if (*buflen < len) + if (*buflen < offsetof(DHCP6Option, data) + len) return -ENOBUFS; ia_hdr = *buf; ia_buflen = *buflen; - *buf += sizeof(DHCP6Option); - *buflen -= sizeof(DHCP6Option); + *buf += offsetof(DHCP6Option, data); + *buflen -= offsetof(DHCP6Option, data); memcpy(*buf, (char*) ia + iaid_offset, len); @@ -128,7 +131,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { *buf += sizeof(addr->iaaddr); *buflen -= sizeof(addr->iaaddr); - ia_addrlen += sizeof(DHCP6Option) + sizeof(addr->iaaddr); + ia_addrlen += offsetof(DHCP6Option, data) + sizeof(addr->iaaddr); } r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen); @@ -165,7 +168,7 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { return r; } -int dhcp6_option_append_pd(uint8_t *buf, size_t len, DHCP6IA *pd) { +int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) { DHCP6Option *option = (DHCP6Option *)buf; size_t i = sizeof(*option) + sizeof(pd->ia_pd); DHCP6Address *prefix; @@ -210,7 +213,7 @@ static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, si assert_return(optcode, -EINVAL); assert_return(optlen, -EINVAL); - if (*buflen < sizeof(DHCP6Option)) + if (*buflen < offsetof(DHCP6Option, data)) return -ENOMSG; len = be16toh(option->len); @@ -247,10 +250,11 @@ int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, return 0; } -int dhcp6_option_parse_status(DHCP6Option *option) { +int dhcp6_option_parse_status(DHCP6Option *option, size_t len) { DHCP6StatusOption *statusopt = (DHCP6StatusOption *)option; - if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*statusopt)) + if (len < sizeof(DHCP6StatusOption) || + be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(DHCP6StatusOption)) return -ENOBUFS; return be16toh(statusopt->status); @@ -263,7 +267,7 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, uint32_t lt_valid, lt_pref; int r; - if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*addr_option)) + if (be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(*addr_option)) return -ENOBUFS; lt_valid = be32toh(addr_option->iaaddr.lifetime_valid); @@ -276,8 +280,8 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, return 0; } - if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*addr_option)) { - r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options); + if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*addr_option)) { + r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*addr_option)); if (r != 0) return r < 0 ? r: 0; } @@ -303,7 +307,7 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, uint32_t lt_valid, lt_pref; int r; - if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*pdprefix_option)) + if (be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(*pdprefix_option)) return -ENOBUFS; lt_valid = be32toh(pdprefix_option->iapdprefix.lifetime_valid); @@ -316,8 +320,8 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, return 0; } - if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*pdprefix_option)) { - r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options); + if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*pdprefix_option)) { + r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*pdprefix_option)); if (r != 0) return r < 0 ? r: 0; } @@ -353,10 +357,8 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { switch (iatype) { case SD_DHCP6_OPTION_IA_NA: - if (len < DHCP6_OPTION_IA_NA_LEN) { - r = -ENOBUFS; - goto error; - } + if (len < DHCP6_OPTION_IA_NA_LEN) + return -ENOBUFS; iaaddr_offset = DHCP6_OPTION_IA_NA_LEN; memcpy(&ia->ia_na, iaoption->data, sizeof(ia->ia_na)); @@ -367,18 +369,15 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { log_dhcp6_client(client, "IA NA T1 %ds > T2 %ds", lt_t1, lt_t2); - r = -EINVAL; - goto error; + return -EINVAL; } break; case SD_DHCP6_OPTION_IA_PD: - if (len < sizeof(ia->ia_pd)) { - r = -ENOBUFS; - goto error; - } + if (len < sizeof(ia->ia_pd)) + return -ENOBUFS; iaaddr_offset = sizeof(ia->ia_pd); memcpy(&ia->ia_pd, iaoption->data, sizeof(ia->ia_pd)); @@ -389,17 +388,14 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { log_dhcp6_client(client, "IA PD T1 %ds > T2 %ds", lt_t1, lt_t2); - r = -EINVAL; - goto error; + return -EINVAL; } break; case SD_DHCP6_OPTION_IA_TA: - if (len < DHCP6_OPTION_IA_TA_LEN) { - r = -ENOBUFS; - goto error; - } + if (len < DHCP6_OPTION_IA_TA_LEN) + return -ENOBUFS; iaaddr_offset = DHCP6_OPTION_IA_TA_LEN; memcpy(&ia->ia_ta.id, iaoption->data, sizeof(ia->ia_ta)); @@ -407,8 +403,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { break; default: - r = -ENOMSG; - goto error; + return -ENOMSG; } ia->type = iatype; @@ -417,10 +412,8 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { while (i < len) { DHCP6Option *option = (DHCP6Option *)&iaoption->data[i]; - if (len < i + sizeof(*option) || len < i + sizeof(*option) + be16toh(option->len)) { - r = -ENOBUFS; - goto error; - } + if (len < i + sizeof(*option) || len < i + sizeof(*option) + be16toh(option->len)) + return -ENOBUFS; opt = be16toh(option->code); optlen = be16toh(option->len); @@ -430,13 +423,12 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA)) { log_dhcp6_client(client, "IA Address option not in IA NA or TA option"); - r = -EINVAL; - goto error; + return -EINVAL; } r = dhcp6_option_parse_address(option, ia, <_valid); if (r < 0) - goto error; + return r; if (lt_valid < lt_min) lt_min = lt_valid; @@ -447,13 +439,12 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_PD)) { log_dhcp6_client(client, "IA PD Prefix option not in IA PD option"); - r = -EINVAL; - goto error; + return -EINVAL; } r = dhcp6_option_parse_pdprefix(option, ia, <_valid); if (r < 0) - goto error; + return r; if (lt_valid < lt_min) lt_min = lt_valid; @@ -462,15 +453,14 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { case SD_DHCP6_OPTION_STATUS_CODE: - status = dhcp6_option_parse_status(option); - if (status) { + status = dhcp6_option_parse_status(option, optlen + offsetof(DHCP6Option, data)); + if (status < 0) + return status; + if (status > 0) { log_dhcp6_client(client, "IA status %d", status); - dhcp6_lease_free_ia(ia); - - r = -EINVAL; - goto error; + return -EINVAL; } break; @@ -514,8 +504,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { break; } -error: - return r; + return 0; } int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, @@ -550,6 +539,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * bool first = true; for (;;) { + const char *label; uint8_t c; c = optval[pos++]; @@ -557,47 +547,41 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * if (c == 0) /* End of name */ break; - else if (c <= 63) { - const char *label; - - /* Literal label */ - label = (const char *)&optval[pos]; - pos += c; - if (pos > optlen) - return -EMSGSIZE; - - if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { - r = -ENOMEM; - goto fail; - } - - if (first) - first = false; - else - ret[n++] = '.'; - - r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - goto fail; - - n += r; - continue; - } else { - r = -EBADMSG; - goto fail; - } - } + if (c > 63) + return -EBADMSG; + + /* Literal label */ + label = (const char *)&optval[pos]; + pos += c; + if (pos >= optlen) + return -EMSGSIZE; + + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) + return -ENOMEM; + + if (first) + first = false; + else + ret[n++] = '.'; - if (!GREEDY_REALLOC(ret, allocated, n + 1)) { - r = -ENOMEM; - goto fail; + r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + + n += r; } + if (n == 0) + continue; + + if (!GREEDY_REALLOC(ret, allocated, n + 1)) + return -ENOMEM; + ret[n] = 0; r = strv_extend(&names, ret); if (r < 0) - goto fail; + return r; idx++; } @@ -605,7 +589,4 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * *str_arr = TAKE_PTR(names); return idx; - -fail: - return r; } diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index 736df222f0..e535b12cda 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -17,8 +17,9 @@ #include "fd-util.h" #include "icmp6-util.h" -#include "socket-util.h" #include "in-addr-util.h" +#include "io-util.h" +#include "socket-util.h" #define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ @@ -33,7 +34,6 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter, int index = mreq->ipv6mr_interface; _cleanup_close_ int s = -1; char ifname[IF_NAMESIZE] = ""; - static const int zero = 0, one = 1, hops = 255; int r; s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6); @@ -52,29 +52,29 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter, IPV6_PKTINFO socket option also applies for ICMPv6 multicast. Empirical experiments indicates otherwise and therefore an IPV6_MULTICAST_IF socket option is used here instead */ - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)); + r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, index); if (r < 0) - return -errno; + return r; - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)); + r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, false); if (r < 0) - return -errno; + return r; - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)); + r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255); if (r < 0) - return -errno; + return r; - r = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)); + r = setsockopt_int(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 255); if (r < 0) - return -errno; + return r; - r = setsockopt(s, SOL_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); + r = setsockopt_int(s, SOL_IPV6, IPV6_RECVHOPLIMIT, true); if (r < 0) - return -errno; + return r; - r = setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)); + r = setsockopt_int(s, SOL_SOCKET, SO_TIMESTAMP, true); if (r < 0) - return -errno; + return r; if (if_indextoname(index, ifname) == 0) return -errno; @@ -170,16 +170,11 @@ int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst, struct cmsghdr *cmsg; ssize_t len; - iov.iov_base = buffer; - iov.iov_len = size; + iov = IOVEC_MAKE(buffer, size); len = recvmsg(fd, &msg, MSG_DONTWAIT); - if (len < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; - + if (len < 0) return -errno; - } if ((size_t) len != size) return -EINVAL; diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 7c10a67a35..88b54933c3 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once - #include "sd-event.h" #include "sd-lldp.h" @@ -35,3 +34,6 @@ struct sd_lldp { #define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) #define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__) + +const char* lldp_event_to_string(sd_lldp_event e) _const_; +sd_lldp_event lldp_event_from_string(const char *s) _pure_; diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 5dcb051373..43fc8e03c0 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -7,58 +7,29 @@ #include "in-addr-util.h" #include "lldp-internal.h" #include "lldp-neighbor.h" +#include "missing.h" #include "unaligned.h" +#include "util.h" -static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) { - const LLDPNeighborID *id = p; - +static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) { siphash24_compress(id->chassis_id, id->chassis_id_size, state); siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state); siphash24_compress(id->port_id, id->port_id_size, state); siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state); } -static int lldp_neighbor_id_compare_func(const void *a, const void *b) { - const LLDPNeighborID *x = a, *y = b; - int r; - - r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size)); - if (r != 0) - return r; - - if (x->chassis_id_size < y->chassis_id_size) - return -1; - - if (x->chassis_id_size > y->chassis_id_size) - return 1; - - r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size)); - if (r != 0) - return r; - - if (x->port_id_size < y->port_id_size) - return -1; - if (x->port_id_size > y->port_id_size) - return 1; - - return 0; +int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) { + return memcmp_nn(x->chassis_id, x->chassis_id_size, y->chassis_id, y->chassis_id_size) + ?: memcmp_nn(x->port_id, x->port_id_size, y->port_id, y->port_id_size); } -const struct hash_ops lldp_neighbor_id_hash_ops = { - .hash = lldp_neighbor_id_hash_func, - .compare = lldp_neighbor_id_compare_func -}; +DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(lldp_neighbor_hash_ops, LLDPNeighborID, lldp_neighbor_id_hash_func, lldp_neighbor_id_compare_func, + sd_lldp_neighbor, lldp_neighbor_unlink); int lldp_neighbor_prioq_compare_func(const void *a, const void *b) { const sd_lldp_neighbor *x = a, *y = b; - if (x->until < y->until) - return -1; - - if (x->until > y->until) - return 1; - - return 0; + return CMP(x->until, y->until); } _public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) { @@ -111,7 +82,12 @@ sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) { if (!n->lldp) return NULL; - assert_se(hashmap_remove(n->lldp->neighbor_by_id, &n->id) == n); + /* Only remove the neighbor object from the hash table if it's in there, don't complain if it isn't. This is + * because we are used as destructor call for hashmap_clear() and thus sometimes are called to de-register + * ourselves from the hashtable and sometimes are called after we already are de-registered. */ + + (void) hashmap_remove_value(n->lldp->neighbor_by_id, &n->id, n); + assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0); n->lldp = NULL; diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h index 494bc51760..62dbff42ca 100644 --- a/src/libsystemd-network/lldp-neighbor.h +++ b/src/libsystemd-network/lldp-neighbor.h @@ -80,7 +80,8 @@ static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) { return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2; } -extern const struct hash_ops lldp_neighbor_id_hash_ops; +extern const struct hash_ops lldp_neighbor_hash_ops; +int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y); int lldp_neighbor_prioq_compare_func(const void *a, const void *b); sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n); diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index a4020d1e19..870584c0db 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -5,6 +5,7 @@ #include "fd-util.h" #include "lldp-network.h" +#include "missing.h" #include "socket-util.h" int lldp_network_bind_raw_socket(int ifindex) { diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h index 914139793c..e4ed2898a5 100644 --- a/src/libsystemd-network/lldp-network.h +++ b/src/libsystemd-network/lldp-network.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once - #include "sd-event.h" int lldp_network_bind_raw_socket(int ifindex); diff --git a/src/libsystemd-network/ndisc-internal.h b/src/libsystemd-network/ndisc-internal.h index fdabbc1b0e..0c04fea8e5 100644 --- a/src/libsystemd-network/ndisc-internal.h +++ b/src/libsystemd-network/ndisc-internal.h @@ -38,3 +38,6 @@ struct sd_ndisc { #define log_ndisc_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDISC: " fmt, ##__VA_ARGS__) #define log_ndisc(fmt, ...) log_ndisc_errno(0, fmt, ##__VA_ARGS__) + +const char* ndisc_event_to_string(sd_ndisc_event e) _const_; +sd_ndisc_event ndisc_event_from_string(const char *s) _pure_; diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c index 25b693a458..6935311b9a 100644 --- a/src/libsystemd-network/ndisc-router.c +++ b/src/libsystemd-network/ndisc-router.c @@ -15,28 +15,7 @@ #include "ndisc-router.h" #include "strv.h" -_public_ sd_ndisc_router* sd_ndisc_router_ref(sd_ndisc_router *rt) { - if (!rt) - return NULL; - - assert(rt->n_ref > 0); - rt->n_ref++; - - return rt; -} - -_public_ sd_ndisc_router* sd_ndisc_router_unref(sd_ndisc_router *rt) { - if (!rt) - return NULL; - - assert(rt->n_ref > 0); - rt->n_ref--; - - if (rt->n_ref > 0) - return NULL; - - return mfree(rt); -} +DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree); sd_ndisc_router *ndisc_router_new(size_t raw_size) { sd_ndisc_router *rt; @@ -189,7 +168,7 @@ int ndisc_router_parse(sd_ndisc_router *rt) { if (has_mtu) { log_ndisc("MTU option specified twice, ignoring."); - continue; + break; } if (length != 8) { @@ -230,7 +209,7 @@ int ndisc_router_parse(sd_ndisc_router *rt) { if (has_flag_extension) { log_ndisc("Flags extension option specified twice, ignoring."); - continue; + break; } if (length < 1*8) { @@ -697,7 +676,7 @@ _public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) _cleanup_free_ char *normalized = NULL; e[n] = 0; - r = dns_name_normalize(e, &normalized); + r = dns_name_normalize(e, 0, &normalized); if (r < 0) return r; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 0849b44ee2..b3b134d650 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -23,24 +23,22 @@ #include "utf8.h" #include "util.h" -const char *net_get_name(struct udev_device *device) { +const char *net_get_name(sd_device *device) { const char *name, *field; assert(device); /* fetch some persistent data unique (on this machine) to this device */ - FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") { - name = udev_device_get_property_value(device, field); - if (name) + FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") + if (sd_device_get_property_value(device, field, &name) >= 0) return name; - } return NULL; } #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) -int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) { +int net_get_unique_predictable_data(sd_device *device, uint64_t *result) { size_t l, sz = 0; const char *name = NULL; int r; @@ -124,7 +122,7 @@ bool net_match_config(Set *match_mac, if (match_arch && condition_test(match_arch) <= 0) return false; - if (match_mac && dev_mac && !set_contains(match_mac, dev_mac)) + if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac))) return false; if (!net_condition_test_strv(match_paths, dev_path)) @@ -257,11 +255,10 @@ int config_parse_ifalias(const char *unit, return 0; } - free(*s); - if (*n) - *s = TAKE_PTR(n); + if (isempty(n)) + *s = mfree(*s); else - *s = NULL; + free_and_replace(*s, n); return 0; } @@ -296,7 +293,7 @@ int config_parse_hwaddr(const char *unit, return 0; } - *hwaddr = TAKE_PTR(n); + free_and_replace(*hwaddr, n); return 0; } @@ -374,36 +371,6 @@ int config_parse_hwaddrs(const char *unit, return 0; } -int config_parse_iaid(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - uint32_t iaid; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = safe_atou32(rvalue, &iaid); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Unable to read IAID, ignoring assignment: %s", rvalue); - return 0; - } - - *((uint32_t *)data) = iaid; - - return 0; -} - int config_parse_bridge_port_priority( const char *unit, const char *filename, diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 883f34b95c..0c8da848c1 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -1,15 +1,14 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once - #include +#include "sd-device.h" #include "sd-dhcp-lease.h" #include "condition.h" #include "conf-parser.h" #include "set.h" -#include "udev.h" #define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 #define LINK_BRIDGE_PORT_PRIORITY_MAX 63 @@ -36,11 +35,10 @@ CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); CONFIG_PARSER_PROTOTYPE(config_parse_ifnames); CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); -CONFIG_PARSER_PROTOTYPE(config_parse_iaid); CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); -int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); -const char *net_get_name(struct udev_device *device); +int net_get_unique_predictable_data(sd_device *device, uint64_t *result); +const char *net_get_name(sd_device *device); void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); int deserialize_in_addrs(struct in_addr **addresses, const char *string); diff --git a/src/libsystemd-network/radv-internal.h b/src/libsystemd-network/radv-internal.h index b221c6f6c5..cd44352307 100644 --- a/src/libsystemd-network/radv-internal.h +++ b/src/libsystemd-network/radv-internal.h @@ -85,5 +85,4 @@ struct sd_radv_prefix { #define log_radv_full(level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "RADV: " fmt, ##__VA_ARGS__) #define log_radv_errno(error, fmt, ...) log_radv_full(LOG_DEBUG, error, fmt, ##__VA_ARGS__) -#define log_radv_warning_errno(error, fmt, ...) log_radv_full(LOG_WARNING, error, fmt, ##__VA_ARGS__) #define log_radv(fmt, ...) log_radv_errno(0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index ff434f8ce7..2d7ffd22ca 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -21,11 +21,13 @@ #include "dhcp-lease-internal.h" #include "dhcp-protocol.h" #include "dns-domain.h" +#include "event-util.h" #include "hostname-util.h" +#include "io-util.h" #include "random-util.h" #include "string-util.h" -#include "util.h" #include "strv.h" +#include "util.h" #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) @@ -86,7 +88,7 @@ struct sd_dhcp_client { uint32_t mtu; uint32_t xid; usec_t start_time; - unsigned int attempt; + unsigned attempt; usec_t request_sent; sd_event_source *timeout_t1; sd_event_source *timeout_t2; @@ -298,27 +300,22 @@ int sd_dhcp_client_set_client_id( assert_return(data, -EINVAL); assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL); - switch (type) { - - case ARPHRD_ETHER: - if (data_len != ETH_ALEN) - return -EINVAL; - break; - - case ARPHRD_INFINIBAND: - if (data_len != INFINIBAND_ALEN) - return -EINVAL; - break; - - default: - break; - } - if (client->client_id_len == data_len + sizeof(client->client_id.type) && client->client_id.type == type && memcmp(&client->client_id.raw.data, data, data_len) == 0) return 0; + /* For hardware types, log debug message about unexpected data length. + * + * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only + * last last 8 bytes of the address are stable and suitable to put into + * the client-id. The caller is advised to account for that. */ + if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) || + (type == ARPHRD_INFINIBAND && data_len != 8)) + log_dhcp_client(client, "Changing client ID to hardware type %u with " + "unexpected address length %zu", + type, data_len); + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { log_dhcp_client(client, "Changing client ID on running DHCP " "client, restarting"); @@ -341,13 +338,15 @@ int sd_dhcp_client_set_client_id( * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -static int dhcp_client_set_iaid_duid( +static int dhcp_client_set_iaid_duid_internal( sd_dhcp_client *client, + bool iaid_append, + bool iaid_set, uint32_t iaid, - bool append_iaid, uint16_t duid_type, const void *duid, - size_t duid_len) { + size_t duid_len, + usec_t llt_time) { DHCP_CLIENT_DONT_DESTROY(client); int r; @@ -357,7 +356,7 @@ static int dhcp_client_set_iaid_duid( assert_return(duid_len == 0 || duid != NULL, -EINVAL); if (duid != NULL) { - r = dhcp_validate_duid_len(duid_type, duid_len); + r = dhcp_validate_duid_len(duid_type, duid_len, true); if (r < 0) return r; } @@ -365,34 +364,60 @@ static int dhcp_client_set_iaid_duid( zero(client->client_id); client->client_id.type = 255; - if (append_iaid) { - /* If IAID is not configured, generate it. */ - if (iaid == 0) { + if (iaid_append) { + if (iaid_set) + client->client_id.ns.iaid = htobe32(iaid); + else { r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, + true, &client->client_id.ns.iaid); if (r < 0) return r; - } else - client->client_id.ns.iaid = htobe32(iaid); + } } if (duid != NULL) { client->client_id.ns.duid.type = htobe16(duid_type); memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); len = sizeof(client->client_id.ns.duid.type) + duid_len; - } else if (duid_type == DUID_TYPE_EN) { - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); - if (r < 0) - return r; } else - return -EOPNOTSUPP; + switch (duid_type) { + case DUID_TYPE_LLT: + if (client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len); + if (r < 0) + return r; + break; + case DUID_TYPE_EN: + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); + if (r < 0) + return r; + break; + case DUID_TYPE_LL: + if (client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len); + if (r < 0) + return r; + break; + case DUID_TYPE_UUID: + r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len); + if (r < 0) + return r; + break; + default: + return -EINVAL; + } client->client_id_len = sizeof(client->client_id.type) + len + - (append_iaid ? sizeof(client->client_id.ns.iaid) : 0); + (iaid_append ? sizeof(client->client_id.ns.iaid) : 0); if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Configured IAID+DUID, restarting."); + log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : ""); client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); sd_dhcp_client_start(client); } @@ -402,11 +427,20 @@ static int dhcp_client_set_iaid_duid( int sd_dhcp_client_set_iaid_duid( sd_dhcp_client *client, + bool iaid_set, uint32_t iaid, uint16_t duid_type, const void *duid, size_t duid_len) { - return dhcp_client_set_iaid_duid(client, iaid, true, duid_type, duid, duid_len); + return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0); +} + +int sd_dhcp_client_set_iaid_duid_llt( + sd_dhcp_client *client, + bool iaid_set, + uint32_t iaid, + usec_t llt_time) { + return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time); } int sd_dhcp_client_set_duid( @@ -414,7 +448,13 @@ int sd_dhcp_client_set_duid( uint16_t duid_type, const void *duid, size_t duid_len) { - return dhcp_client_set_iaid_duid(client, 0, false, duid_type, duid, duid_len); + return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0); +} + +int sd_dhcp_client_set_duid_llt( + sd_dhcp_client *client, + usec_t llt_time) { + return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time); } int sd_dhcp_client_set_hostname( @@ -506,11 +546,10 @@ static int client_initialize(sd_dhcp_client *client) { client->fd = asynchronous_close(client->fd); - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - - client->timeout_t1 = sd_event_source_unref(client->timeout_t1); - client->timeout_t2 = sd_event_source_unref(client->timeout_t2); - client->timeout_expire = sd_event_source_unref(client->timeout_expire); + (void) event_source_disable(client->timeout_resend); + (void) event_source_disable(client->timeout_t1); + (void) event_source_disable(client->timeout_t2); + (void) event_source_disable(client->timeout_expire); client->attempt = 1; @@ -611,7 +650,8 @@ static int client_message_init( client->client_id.type = 255; - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid); + r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, + true, &client->client_id.ns.iaid); if (r < 0) return r; @@ -659,7 +699,7 @@ static int client_message_init( let the server know how large the server may make its DHCP messages. Note (from ConnMan): Some DHCP servers will send bigger DHCP packets - than the defined default size unless the Maximum Messge Size option + than the defined default size unless the Maximum Message Size option is explicitly set RFC3442 "Requirements to Avoid Sizing Constraints": @@ -1024,22 +1064,11 @@ static int client_timeout_resend( next_timeout += (random_u32() & 0x1fffff); - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - - r = sd_event_add_time(client->event, - &client->timeout_resend, - clock_boottime_or_monotonic(), - next_timeout, 10 * USEC_PER_MSEC, - client_timeout_resend, client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); + r = event_reset_time(client->event, &client->timeout_resend, + clock_boottime_or_monotonic(), + next_timeout, 10 * USEC_PER_MSEC, + client_timeout_resend, client, + client->event_priority, "dhcp4-resend-timer", true); if (r < 0) goto error; @@ -1136,31 +1165,16 @@ static int client_initialize_time_events(sd_dhcp_client *client) { assert(client); assert(client->event); - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - if (client->start_delay) { assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0); usec += client->start_delay; } - r = sd_event_add_time(client->event, - &client->timeout_resend, - clock_boottime_or_monotonic(), - usec, 0, - client_timeout_resend, client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); - if (r < 0) - goto error; - -error: + r = event_reset_time(client->event, &client->timeout_resend, + clock_boottime_or_monotonic(), + usec, 0, + client_timeout_resend, client, + client->event_priority, "dhcp4-resend-timer", true); if (r < 0) client_stop(client, r); @@ -1418,13 +1432,14 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { assert(client->lease); assert(client->lease->lifetime); - client->timeout_t1 = sd_event_source_unref(client->timeout_t1); - client->timeout_t2 = sd_event_source_unref(client->timeout_t2); - client->timeout_expire = sd_event_source_unref(client->timeout_expire); - /* don't set timers for infinite leases */ - if (client->lease->lifetime == 0xffffffff) + if (client->lease->lifetime == 0xffffffff) { + (void) event_source_disable(client->timeout_t1); + (void) event_source_disable(client->timeout_t2); + (void) event_source_disable(client->timeout_expire); + return 0; + } r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) @@ -1476,19 +1491,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { } /* arm lifetime timeout */ - r = sd_event_add_time(client->event, &client->timeout_expire, - clock_boottime_or_monotonic(), - lifetime_timeout, 10 * USEC_PER_MSEC, - client_timeout_expire, client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->timeout_expire, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime"); + r = event_reset_time(client->event, &client->timeout_expire, + clock_boottime_or_monotonic(), + lifetime_timeout, 10 * USEC_PER_MSEC, + client_timeout_expire, client, + client->event_priority, "dhcp4-lifetime", true); if (r < 0) return r; @@ -1500,21 +1507,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return 0; /* arm T2 timeout */ - r = sd_event_add_time(client->event, - &client->timeout_t2, - clock_boottime_or_monotonic(), - t2_timeout, - 10 * USEC_PER_MSEC, - client_timeout_t2, client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->timeout_t2, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout"); + r = event_reset_time(client->event, &client->timeout_t2, + clock_boottime_or_monotonic(), + t2_timeout, 10 * USEC_PER_MSEC, + client_timeout_t2, client, + client->event_priority, "dhcp4-t2-timeout", true); if (r < 0) return r; @@ -1526,20 +1523,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return 0; /* arm T1 timeout */ - r = sd_event_add_time(client->event, - &client->timeout_t1, - clock_boottime_or_monotonic(), - t1_timeout, 10 * USEC_PER_MSEC, - client_timeout_t1, client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->timeout_t1, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer"); + r = event_reset_time(client->event, &client->timeout_t1, + clock_boottime_or_monotonic(), + t1_timeout, 10 * USEC_PER_MSEC, + client_timeout_t1, client, + client->event_priority, "dhcp4-t1-timer", true); if (r < 0) return r; @@ -1564,26 +1552,14 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i r = client_handle_offer(client, message, len); if (r >= 0) { - client->timeout_resend = - sd_event_source_unref(client->timeout_resend); - client->state = DHCP_STATE_REQUESTING; client->attempt = 1; - r = sd_event_add_time(client->event, - &client->timeout_resend, - clock_boottime_or_monotonic(), - 0, 0, - client_timeout_resend, client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); + r = event_reset_time(client->event, &client->timeout_resend, + clock_boottime_or_monotonic(), + 0, 0, + client_timeout_resend, client, + client->event_priority, "dhcp4-resend-timer", true); if (r < 0) goto error; } else if (r == -ENOMSG) @@ -1600,8 +1576,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i r = client_handle_ack(client, message, len); if (r >= 0) { client->start_delay = 0; - client->timeout_resend = - sd_event_source_unref(client->timeout_resend); + (void) event_source_disable(client->timeout_resend); client->receive_message = sd_event_source_unref(client->receive_message); client->fd = asynchronous_close(client->fd); @@ -1641,8 +1616,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i } else if (r == -EADDRNOTAVAIL) { /* got a NAK, let's restart the client */ - client->timeout_resend = - sd_event_source_unref(client->timeout_resend); + client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED); r = client_initialize(client); if (r < 0) @@ -1809,8 +1783,7 @@ static int client_receive_message_raw( if (!packet) return -ENOMEM; - iov.iov_base = packet; - iov.iov_len = buflen; + iov = IOVEC_MAKE(packet, buflen); len = recvmsg(fd, &msg, 0); if (len < 0) { @@ -1912,33 +1885,17 @@ sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { return client->event; } -sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) { - - if (!client) - return NULL; - - assert(client->n_ref >= 1); - client->n_ref++; - - return client; -} - -sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { - - if (!client) - return NULL; - - assert(client->n_ref >= 1); - client->n_ref--; - - if (client->n_ref > 0) - return NULL; +static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { + assert(client); log_dhcp_client(client, "FREE"); - client_initialize(client); + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + client->timeout_t1 = sd_event_source_unref(client->timeout_t1); + client->timeout_t2 = sd_event_source_unref(client->timeout_t2); + client->timeout_expire = sd_event_source_unref(client->timeout_expire); - client->receive_message = sd_event_source_unref(client->receive_message); + client_initialize(client); sd_dhcp_client_detach_event(client); @@ -1951,24 +1908,27 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { return mfree(client); } +DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free); + int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL; assert_return(ret, -EINVAL); - client = new0(sd_dhcp_client, 1); + client = new(sd_dhcp_client, 1); if (!client) return -ENOMEM; - client->n_ref = 1; - client->state = DHCP_STATE_INIT; - client->ifindex = -1; - client->fd = -1; - client->attempt = 1; - client->mtu = DHCP_DEFAULT_MIN_SIZE; - client->port = DHCP_PORT_CLIENT; - - client->anonymize = !!anonymize; + *client = (sd_dhcp_client) { + .n_ref = 1, + .state = DHCP_STATE_INIT, + .ifindex = -1, + .fd = -1, + .attempt = 1, + .mtu = DHCP_DEFAULT_MIN_SIZE, + .port = DHCP_PORT_CLIENT, + .anonymize = !!anonymize, + }; /* NOTE: this could be moved to a function. */ if (anonymize) { client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize); diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index dbd80442e6..13badbf0bf 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -16,6 +16,7 @@ #include "dhcp-lease-internal.h" #include "dhcp-protocol.h" #include "dns-domain.h" +#include "env-file.h" #include "fd-util.h" #include "fileio.h" #include "hexdecoct.h" @@ -25,6 +26,8 @@ #include "parse-util.h" #include "stdio-util.h" #include "string-util.h" +#include "strv.h" +#include "tmpfile-util.h" #include "unaligned.h" int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { @@ -245,27 +248,8 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, s return 0; } -sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { - - if (!lease) - return NULL; - - assert(lease->n_ref >= 1); - lease->n_ref++; - - return lease; -} - -sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { - - if (!lease) - return NULL; - - assert(lease->n_ref >= 1); - lease->n_ref--; - - if (lease->n_ref > 0) - return NULL; +static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { + assert(lease); while (lease->private_options) { struct sd_dhcp_raw_option *option = lease->private_options; @@ -276,6 +260,8 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { free(option); } + free(lease->root_path); + free(lease->timezone); free(lease->hostname); free(lease->domainname); free(lease->dns); @@ -287,6 +273,8 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { return mfree(lease); } +DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free); + static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { assert(option); assert(ret); @@ -346,8 +334,7 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { if (!string) return -ENOMEM; - free(*ret); - *ret = string; + free_and_replace(*ret, string); } return 0; @@ -368,7 +355,7 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { return 0; } - r = dns_name_normalize(name, &normalized); + r = dns_name_normalize(name, 0, &normalized); if (r < 0) return r; @@ -1031,7 +1018,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (r < 0) return r; - r = parse_env_file(NULL, lease_file, NEWLINE, + r = parse_env_file(NULL, lease_file, "ADDRESS", &address, "ROUTER", &router, "NETMASK", &netmask, @@ -1082,8 +1069,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "OPTION_251", &options[27], "OPTION_252", &options[28], "OPTION_253", &options[29], - "OPTION_254", &options[30], - NULL); + "OPTION_254", &options[30]); if (r < 0) return r; @@ -1315,3 +1301,9 @@ int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) { *gateway = route->gw_addr; return 0; } + +int sd_dhcp_route_get_option(sd_dhcp_route *route) { + assert_return(route, -EINVAL); + + return route->option; +} diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 5ca46b3502..7cb44d1fdf 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -12,6 +12,7 @@ #include "dhcp-server-internal.h" #include "fd-util.h" #include "in-addr-util.h" +#include "io-util.h" #include "sd-id128.h" #include "siphash24.h" #include "string-util.h" @@ -20,12 +21,12 @@ #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12) -static void dhcp_lease_free(DHCPLease *lease) { +static DHCPLease *dhcp_lease_free(DHCPLease *lease) { if (!lease) - return; + return NULL; free(lease->client_id.data); - free(lease); + return mfree(lease); } /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet @@ -89,7 +90,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres server->bound_leases[server_off - offset] = &server->invalid_lease; /* Drop any leases associated with the old address range */ - hashmap_clear_with_destructor(server->leases_by_client_id, dhcp_lease_free); + hashmap_clear(server->leases_by_client_id); } return 0; @@ -101,20 +102,7 @@ int sd_dhcp_server_is_running(sd_dhcp_server *server) { return !!server->receive_message; } -sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) { - - if (!server) - return NULL; - - assert(server->n_ref >= 1); - server->n_ref++; - - return server; -} - -void client_id_hash_func(const void *p, struct siphash *state) { - const DHCPClientId *id = p; - +void client_id_hash_func(const DHCPClientId *id, struct siphash *state) { assert(id); assert(id->length); assert(id->data); @@ -123,37 +111,24 @@ void client_id_hash_func(const void *p, struct siphash *state) { siphash24_compress(id->data, id->length, state); } -int client_id_compare_func(const void *_a, const void *_b) { - const DHCPClientId *a, *b; - - a = _a; - b = _b; +int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) { + int r; assert(!a->length || a->data); assert(!b->length || b->data); - if (a->length != b->length) - return a->length < b->length ? -1 : 1; + r = CMP(a->length, b->length); + if (r != 0) + return r; return memcmp(a->data, b->data, a->length); } -static const struct hash_ops client_id_hash_ops = { - .hash = client_id_hash_func, - .compare = client_id_compare_func -}; - -sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { - DHCPLease *lease; - - if (!server) - return NULL; - - assert(server->n_ref >= 1); - server->n_ref--; +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(dhcp_lease_hash_ops, DHCPClientId, client_id_hash_func, client_id_compare_func, + DHCPLease, dhcp_lease_free); - if (server->n_ref > 0) - return NULL; +static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) { + assert(server); log_dhcp_server(server, "UNREF"); @@ -165,14 +140,14 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { free(server->dns); free(server->ntp); - while ((lease = hashmap_steal_first(server->leases_by_client_id))) - dhcp_lease_free(lease); hashmap_free(server->leases_by_client_id); free(server->bound_leases); return mfree(server); } +DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server, sd_dhcp_server, dhcp_server_free); + int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) { _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL; @@ -190,7 +165,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) { server->netmask = htobe32(INADDR_ANY); server->ifindex = ifindex; - server->leases_by_client_id = hashmap_new(&client_id_hash_ops); + server->leases_by_client_id = hashmap_new(&dhcp_lease_hash_ops); if (!server->leases_by_client_id) return -ENOMEM; @@ -957,8 +932,7 @@ static int server_receive_message(sd_event_source *s, int fd, if (!message) return -ENOMEM; - iov.iov_base = message; - iov.iov_len = buflen; + iov = IOVEC_MAKE(message, buflen); len = recvmsg(fd, &msg, 0); if (len < 0) { @@ -1002,7 +976,7 @@ int sd_dhcp_server_start(sd_dhcp_server *server) { assert_return(server->fd < 0, -EBUSY); assert_return(server->address != htobe32(INADDR_ANY), -EUNATCH); - r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0); + r = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (r < 0) { r = -errno; sd_dhcp_server_stop(server); diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index b3bc259280..593ffd1b64 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -16,6 +16,7 @@ #include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" #include "dns-domain.h" +#include "event-util.h" #include "fd-util.h" #include "hostname-util.h" #include "in-addr-util.h" @@ -27,6 +28,13 @@ #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN +/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */ +enum { + DHCP6_REQUEST_IA_NA = 1, + DHCP6_REQUEST_IA_TA = 2, /* currently not used */ + DHCP6_REQUEST_IA_PD = 4, +}; + struct sd_dhcp6_client { unsigned n_ref; @@ -40,12 +48,15 @@ struct sd_dhcp6_client { uint16_t arp_type; DHCP6IA ia_na; DHCP6IA ia_pd; - bool prefix_delegation; + sd_event_source *timeout_t1; + sd_event_source *timeout_t2; + unsigned request; be32_t transaction_id; usec_t transaction_start; struct sd_dhcp6_lease *lease; int fd; bool information_request; + bool iaid_set; be16_t *req_opts; size_t req_opts_allocated; size_t req_opts_len; @@ -182,43 +193,86 @@ static int client_ensure_duid(sd_dhcp6_client *client) { * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -int sd_dhcp6_client_set_duid( +static int dhcp6_client_set_duid_internal( sd_dhcp6_client *client, uint16_t duid_type, const void *duid, - size_t duid_len) { - + size_t duid_len, + usec_t llt_time) { int r; + assert_return(client, -EINVAL); assert_return(duid_len == 0 || duid != NULL, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); if (duid != NULL) { - r = dhcp_validate_duid_len(duid_type, duid_len); - if (r < 0) - return r; - } + r = dhcp_validate_duid_len(duid_type, duid_len, true); + if (r < 0) { + r = dhcp_validate_duid_len(duid_type, duid_len, false); + if (r < 0) + return r; + log_dhcp6_client(client, "Setting DUID of type %u with unexpected content", duid_type); + } - if (duid != NULL) { client->duid.type = htobe16(duid_type); memcpy(&client->duid.raw.data, duid, duid_len); client->duid_len = sizeof(client->duid.type) + duid_len; - } else if (duid_type == DUID_TYPE_EN) { - r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); - if (r < 0) - return r; } else - return -EOPNOTSUPP; + switch (duid_type) { + case DUID_TYPE_LLT: + if (client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_llt(&client->duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); + if (r < 0) + return r; + break; + case DUID_TYPE_EN: + r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); + if (r < 0) + return r; + break; + case DUID_TYPE_LL: + if (client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_ll(&client->duid, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); + if (r < 0) + return r; + break; + case DUID_TYPE_UUID: + r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len); + if (r < 0) + return r; + break; + default: + return -EINVAL; + } return 0; } +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t duid_type, + const void *duid, + size_t duid_len) { + return dhcp6_client_set_duid_internal(client, duid_type, duid, duid_len, 0); +} + +int sd_dhcp6_client_set_duid_llt( + sd_dhcp6_client *client, + usec_t llt_time) { + return dhcp6_client_set_duid_internal(client, DUID_TYPE_LLT, NULL, 0, llt_time); +} + int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) { assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); client->ia_na.ia_na.id = htobe32(iaid); client->ia_pd.ia_pd.id = htobe32(iaid); + client->iaid_set = true; return 0; } @@ -287,10 +341,44 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) return 0; } -int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, bool delegation) { +int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) { assert_return(client, -EINVAL); + assert_return(delegation, -EINVAL); - client->prefix_delegation = delegation; + *delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD); + + return 0; +} + +int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) { + assert_return(client, -EINVAL); + + SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation); + + return 0; +} + +int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) { + assert_return(client, -EINVAL); + assert_return(request, -EINVAL); + + *request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA); + + return 0; +} + +int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) { + assert_return(client, -EINVAL); + + SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request); + + return 0; +} + +int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id) { + assert_return(client, -EINVAL); + + client->transaction_id = transaction_id; return 0; } @@ -314,21 +402,10 @@ static void client_notify(sd_dhcp6_client *client, int event) { client->callback(client, event, client->userdata); } -static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) { - assert(client); - - if (client->lease) { - dhcp6_lease_clear_timers(&client->lease->ia); - sd_dhcp6_lease_unref(client->lease); - } - - client->lease = lease; -} - static int client_reset(sd_dhcp6_client *client) { assert(client); - client_set_lease(client, NULL); + client->lease = sd_dhcp6_lease_unref(client->lease); client->receive_message = sd_event_source_unref(client->receive_message); @@ -336,16 +413,13 @@ static int client_reset(sd_dhcp6_client *client) { client->transaction_id = 0; client->transaction_start = 0; - client->ia_na.timeout_t1 = - sd_event_source_unref(client->ia_na.timeout_t1); - client->ia_na.timeout_t2 = - sd_event_source_unref(client->ia_na.timeout_t2); - client->retransmit_time = 0; client->retransmit_count = 0; - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - client->timeout_resend_expire = - sd_event_source_unref(client->timeout_resend_expire); + + (void) event_source_disable(client->timeout_resend); + (void) event_source_disable(client->timeout_resend_expire); + (void) event_source_disable(client->timeout_t1); + (void) event_source_disable(client->timeout_t2); client->state = DHCP6_STATE_STOPPED; @@ -398,9 +472,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { if (r < 0) return r; - r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na); - if (r < 0) - return r; + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) { + r = dhcp6_option_append_ia(&opt, &optlen, + &client->ia_na); + if (r < 0) + return r; + } if (client->fqdn) { r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); @@ -408,7 +485,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } - if (client->prefix_delegation) { + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd); if (r < 0) return r; @@ -433,9 +510,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { if (r < 0) return r; - r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); - if (r < 0) - return r; + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) { + r = dhcp6_option_append_ia(&opt, &optlen, + &client->lease->ia); + if (r < 0) + return r; + } if (client->fqdn) { r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); @@ -443,7 +523,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } - if (client->prefix_delegation) { + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd); if (r < 0) return r; @@ -457,9 +537,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { case DHCP6_STATE_REBIND: message->type = DHCP6_REBIND; - r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); - if (r < 0) - return r; + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) { + r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); + if (r < 0) + return r; + } if (client->fqdn) { r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); @@ -467,7 +549,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } - if (client->prefix_delegation) { + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd); if (r < 0) return r; @@ -524,8 +606,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) assert(client); assert(client->lease); - client->lease->ia.timeout_t2 = - sd_event_source_unref(client->lease->ia.timeout_t2); + (void) event_source_disable(client->timeout_t2); log_dhcp6_client(client, "Timeout T2"); @@ -541,8 +622,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) assert(client); assert(client->lease); - client->lease->ia.timeout_t1 = - sd_event_source_unref(client->lease->ia.timeout_t1); + (void) event_source_disable(client->timeout_t1); log_dhcp6_client(client, "Timeout T1"); @@ -590,7 +670,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda assert(client); assert(client->event); - client->timeout_resend = sd_event_source_unref(client->timeout_resend); + (void) event_source_disable(client->timeout_resend); switch (client->state) { case DHCP6_STATE_INFORMATION_REQUEST: @@ -632,7 +712,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda init_retransmit_time = DHCP6_REB_TIMEOUT; max_retransmit_time = DHCP6_REB_MAX_RT; - if (!client->timeout_resend_expire) { + if (event_source_is_enabled(client->timeout_resend_expire) <= 0) { r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, &expire); if (r < 0) { @@ -681,43 +761,24 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda log_dhcp6_client(client, "Next retransmission in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC)); - r = sd_event_add_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), - time_now + client->retransmit_time, - 10 * USEC_PER_MSEC, client_timeout_resend, - client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer"); + r = event_reset_time(client->event, &client->timeout_resend, + clock_boottime_or_monotonic(), + time_now + client->retransmit_time, 10 * USEC_PER_MSEC, + client_timeout_resend, client, + client->event_priority, "dhcp6-resend-timer", true); if (r < 0) goto error; - if (max_retransmit_duration && !client->timeout_resend_expire) { + if (max_retransmit_duration && event_source_is_enabled(client->timeout_resend_expire) <= 0) { log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs", max_retransmit_duration / USEC_PER_SEC); - r = sd_event_add_time(client->event, - &client->timeout_resend_expire, - clock_boottime_or_monotonic(), - time_now + max_retransmit_duration, - USEC_PER_SEC, - client_timeout_resend_expire, client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend_expire, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer"); + r = event_reset_time(client->event, &client->timeout_resend_expire, + clock_boottime_or_monotonic(), + time_now + max_retransmit_duration, USEC_PER_SEC, + client_timeout_resend_expire, client, + client->event_priority, "dhcp6-resend-expire-timer", true); if (r < 0) goto error; } @@ -731,19 +792,20 @@ error: static int client_ensure_iaid(sd_dhcp6_client *client) { int r; - be32_t iaid; + uint32_t iaid; assert(client); - if (client->ia_na.ia_na.id) + if (client->iaid_set) return 0; - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &iaid); + r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid); if (r < 0) return r; client->ia_na.ia_na.id = iaid; client->ia_pd.ia_pd.id = iaid; + client->iaid_set = true; return 0; } @@ -753,10 +815,11 @@ static int client_parse_message( DHCP6Message *message, size_t len, sd_dhcp6_lease *lease) { + + uint32_t lt_t1 = ~0, lt_t2 = ~0; + bool clientid = false; size_t pos = 0; int r; - bool clientid = false; - uint32_t lt_t1 = ~0, lt_t2 = ~0; assert(client); assert(message); @@ -766,20 +829,22 @@ static int client_parse_message( len -= sizeof(DHCP6Message); while (pos < len) { - DHCP6Option *option = (DHCP6Option *)&message->options[pos]; + DHCP6Option *option = (DHCP6Option *) &message->options[pos]; uint16_t optcode, optlen; - int status; - uint8_t *optval; be32_t iaid_lease; + uint8_t *optval; + int status; - if (len < offsetof(DHCP6Option, data) || - len < offsetof(DHCP6Option, data) + be16toh(option->len)) + if (len < pos + offsetof(DHCP6Option, data)) return -ENOBUFS; optcode = be16toh(option->code); optlen = be16toh(option->len); optval = option->data; + if (len < pos + offsetof(DHCP6Option, data) + optlen) + return -ENOBUFS; + switch (optcode) { case SD_DHCP6_OPTION_CLIENTID: if (clientid) { @@ -824,13 +889,14 @@ static int client_parse_message( break; case SD_DHCP6_OPTION_STATUS_CODE: - status = dhcp6_option_parse_status(option); - if (status) { + status = dhcp6_option_parse_status(option, optlen + sizeof(DHCP6Option)); + if (status < 0) + return status; + + if (status > 0) { log_dhcp6_client(client, "%s Status %s", dhcp6_message_type_to_string(message->type), dhcp6_message_status_to_string(status)); - dhcp6_lease_free_ia(&lease->ia); - dhcp6_lease_free_ia(&lease->pd); return -EINVAL; } @@ -876,7 +942,7 @@ static int client_parse_message( if (r < 0 && r != -ENOMSG) return r; - r = dhcp6_lease_get_iaid(lease, &iaid_lease); + r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease); if (r < 0) return r; @@ -929,7 +995,7 @@ static int client_parse_message( break; } - pos += sizeof(*option) + optlen; + pos += offsetof(DHCP6Option, data) + optlen; } if (!clientid) { @@ -989,8 +1055,8 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si return 0; } - client_set_lease(client, lease); - lease = NULL; + sd_dhcp6_lease_unref(client->lease); + client->lease = TAKE_PTR(lease); return DHCP6_STATE_BOUND; } @@ -1018,8 +1084,8 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver r = dhcp6_lease_get_preference(client->lease, &pref_lease); if (r < 0 || pref_advertise > pref_lease) { - client_set_lease(client, lease); - lease = NULL; + sd_dhcp6_lease_unref(client->lease); + client->lease = TAKE_PTR(lease); r = 0; } @@ -1144,26 +1210,47 @@ static int client_receive_message( return 0; } - if (r >= 0) - log_dhcp6_client(client, "Recv %s", - dhcp6_message_type_to_string(message->type)); + log_dhcp6_client(client, "Recv %s", + dhcp6_message_type_to_string(message->type)); return 0; } +static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1, + uint32_t *lifetime_t2) { + assert_return(client, -EINVAL); + assert_return(client->lease, -EINVAL); + + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) { + *lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1); + *lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2); + + return 0; + } + + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) { + *lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1); + *lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2); + + return 0; + } + + return -ENOMSG; +} + static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { int r; usec_t timeout, time_now; char time_string[FORMAT_TIMESPAN_MAX]; + uint32_t lifetime_t1, lifetime_t2; assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); assert_return(client->ifindex > 0, -EINVAL); assert_return(client->state != state, -EINVAL); - client->timeout_resend_expire = - sd_event_source_unref(client->timeout_resend_expire); - client->timeout_resend = sd_event_source_unref(client->timeout_resend); + (void) event_source_disable(client->timeout_resend_expire); + (void) event_source_disable(client->timeout_resend); client->retransmit_time = 0; client->retransmit_count = 0; @@ -1214,57 +1301,40 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { case DHCP6_STATE_BOUND: - if (client->lease->ia.ia_na.lifetime_t1 == 0xffffffff || - client->lease->ia.ia_na.lifetime_t2 == 0xffffffff) { + r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2); + if (r < 0) + goto error; + if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) { log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x", - be32toh(client->lease->ia.ia_na.lifetime_t1), - be32toh(client->lease->ia.ia_na.lifetime_t2)); + lifetime_t1, lifetime_t2); return 0; } - timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t1) * USEC_PER_SEC); + timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC); log_dhcp6_client(client, "T1 expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); - r = sd_event_add_time(client->event, - &client->lease->ia.timeout_t1, - clock_boottime_or_monotonic(), time_now + timeout, - 10 * USEC_PER_SEC, client_timeout_t1, - client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->lease->ia.timeout_t1, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout"); + r = event_reset_time(client->event, &client->timeout_t1, + clock_boottime_or_monotonic(), + time_now + timeout, 10 * USEC_PER_SEC, + client_timeout_t1, client, + client->event_priority, "dhcp6-t1-timeout", true); if (r < 0) goto error; - timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t2) * USEC_PER_SEC); + timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC); log_dhcp6_client(client, "T2 expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); - r = sd_event_add_time(client->event, - &client->lease->ia.timeout_t2, - clock_boottime_or_monotonic(), time_now + timeout, - 10 * USEC_PER_SEC, client_timeout_t2, - client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->lease->ia.timeout_t2, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout"); + r = event_reset_time(client->event, &client->timeout_t2, + clock_boottime_or_monotonic(), + time_now + timeout, 10 * USEC_PER_SEC, + client_timeout_t2, client, + client->event_priority, "dhcp6-t2-timeout", true); if (r < 0) goto error; @@ -1276,18 +1346,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { client->transaction_id = random_u32() & htobe32(0x00ffffff); client->transaction_start = time_now; - r = sd_event_add_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), 0, 0, client_timeout_resend, - client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout"); + r = event_reset_time(client->event, &client->timeout_resend, + clock_boottime_or_monotonic(), + 0, 0, + client_timeout_resend, client, + client->event_priority, "dhcp6-resend-timeout", true); if (r < 0) goto error; @@ -1326,6 +1389,9 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { if (!IN_SET(client->state, DHCP6_STATE_STOPPED)) return -EBUSY; + if (!client->information_request && !client->request) + return -EINVAL; + r = client_reset(client); if (r < 0) return r; @@ -1394,27 +1460,13 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) { return client->event; } -sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) { - - if (!client) - return NULL; - - assert(client->n_ref >= 1); - client->n_ref++; - - return client; -} - -sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { - - if (!client) - return NULL; - - assert(client->n_ref >= 1); - client->n_ref--; +static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) { + assert(client); - if (client->n_ref > 0) - return NULL; + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + client->timeout_resend_expire = sd_event_source_unref(client->timeout_resend_expire); + client->timeout_t1 = sd_event_source_unref(client->timeout_t1); + client->timeout_t2 = sd_event_source_unref(client->timeout_t2); client_reset(client); @@ -1427,29 +1479,36 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { return mfree(client); } +DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_free); + int sd_dhcp6_client_new(sd_dhcp6_client **ret) { _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; + _cleanup_free_ be16_t *req_opts = NULL; size_t t; assert_return(ret, -EINVAL); - client = new0(sd_dhcp6_client, 1); - if (!client) + req_opts = new(be16_t, ELEMENTSOF(default_req_opts)); + if (!req_opts) return -ENOMEM; - client->n_ref = 1; - client->ia_na.type = SD_DHCP6_OPTION_IA_NA; - client->ia_pd.type = SD_DHCP6_OPTION_IA_PD; - client->ifindex = -1; - client->fd = -1; + for (t = 0; t < ELEMENTSOF(default_req_opts); t++) + req_opts[t] = htobe16(default_req_opts[t]); - client->req_opts_len = ELEMENTSOF(default_req_opts); - client->req_opts = new0(be16_t, client->req_opts_len); - if (!client->req_opts) + client = new(sd_dhcp6_client, 1); + if (!client) return -ENOMEM; - for (t = 0; t < client->req_opts_len; t++) - client->req_opts[t] = htobe16(default_req_opts[t]); + *client = (sd_dhcp6_client) { + .n_ref = 1, + .ia_na.type = SD_DHCP6_OPTION_IA_NA, + .ia_pd.type = SD_DHCP6_OPTION_IA_PD, + .ifindex = -1, + .request = DHCP6_REQUEST_IA_NA, + .fd = -1, + .req_opts_len = ELEMENTSOF(default_req_opts), + .req_opts = TAKE_PTR(req_opts), + }; *ret = TAKE_PTR(client); diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index 779ad54b4a..8b424811ad 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -11,15 +11,6 @@ #include "strv.h" #include "util.h" -int dhcp6_lease_clear_timers(DHCP6IA *ia) { - assert_return(ia, -EINVAL); - - ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1); - ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2); - - return 0; -} - int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) { DHCP6Address *addr; uint32_t valid = 0, t; @@ -48,8 +39,6 @@ DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) { if (!ia) return NULL; - dhcp6_lease_clear_timers(ia); - while (ia->addresses) { address = ia->addresses; @@ -63,15 +52,16 @@ DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) { int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) { + uint8_t *serverid; + assert_return(lease, -EINVAL); assert_return(id, -EINVAL); - free(lease->serverid); - - lease->serverid = memdup(id, len); - if (!lease->serverid) - return -EINVAL; + serverid = memdup(id, len); + if (!serverid) + return -ENOMEM; + free_and_replace(lease->serverid, serverid); lease->serverid_len = len; return 0; @@ -136,6 +126,15 @@ int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) { return 0; } +int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) { + assert_return(lease, -EINVAL); + assert_return(iaid, -EINVAL); + + *iaid = lease->pd.ia_pd.id; + + return 0; +} + int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr, uint32_t *lifetime_preferred, uint32_t *lifetime_valid) { @@ -374,27 +373,8 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) { return -ENOENT; } -sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) { - - if (!lease) - return NULL; - - assert(lease->n_ref >= 1); - lease->n_ref++; - - return lease; -} - -sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { - - if (!lease) - return NULL; - - assert(lease->n_ref >= 1); - lease->n_ref--; - - if (lease->n_ref > 0) - return NULL; +static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) { + assert(lease); free(lease->serverid); dhcp6_lease_free_ia(&lease->ia); @@ -410,6 +390,8 @@ sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { return mfree(lease); } +DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free); + int dhcp6_lease_new(sd_dhcp6_lease **ret) { sd_dhcp6_lease *lease; diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index a40d40db90..59359aec79 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -14,6 +14,7 @@ #include "alloc-util.h" #include "arp-util.h" #include "ether-addr-util.h" +#include "event-util.h" #include "fd-util.h" #include "in-addr-util.h" #include "list.h" @@ -89,7 +90,7 @@ static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_count static void ipv4acd_reset(sd_ipv4acd *acd) { assert(acd); - acd->timer_event_source = sd_event_source_unref(acd->timer_event_source); + (void) event_source_disable(acd->timer_event_source); acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source); acd->fd = safe_close(acd->fd); @@ -97,25 +98,10 @@ static void ipv4acd_reset(sd_ipv4acd *acd) { ipv4acd_set_state(acd, IPV4ACD_STATE_INIT, true); } -sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd) { - if (!acd) - return NULL; - - assert_se(acd->n_ref >= 1); - acd->n_ref++; - - return acd; -} - -sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) { - if (!acd) - return NULL; - - assert_se(acd->n_ref >= 1); - acd->n_ref--; +static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) { + assert(acd); - if (acd->n_ref > 0) - return NULL; + acd->timer_event_source = sd_event_source_unref(acd->timer_event_source); ipv4acd_reset(acd); sd_ipv4acd_detach_event(acd); @@ -123,19 +109,23 @@ sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) { return mfree(acd); } +DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4acd, sd_ipv4acd, ipv4acd_free); + int sd_ipv4acd_new(sd_ipv4acd **ret) { _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL; assert_return(ret, -EINVAL); - acd = new0(sd_ipv4acd, 1); + acd = new(sd_ipv4acd, 1); if (!acd) return -ENOMEM; - acd->n_ref = 1; - acd->state = IPV4ACD_STATE_INIT; - acd->ifindex = -1; - acd->fd = -1; + *acd = (sd_ipv4acd) { + .n_ref = 1, + .state = IPV4ACD_STATE_INIT, + .ifindex = -1, + .fd = -1, + }; *ret = TAKE_PTR(acd); @@ -166,9 +156,7 @@ int sd_ipv4acd_stop(sd_ipv4acd *acd) { static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata); static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) { - _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL; usec_t next_timeout, time_now; - int r; assert(acd); @@ -179,20 +167,11 @@ static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_u assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0); - r = sd_event_add_time(acd->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, acd); - if (r < 0) - return r; - - r = sd_event_source_set_priority(timer, acd->event_priority); - if (r < 0) - return r; - - (void) sd_event_source_set_description(timer, "ipv4acd-timer"); - - sd_event_source_unref(acd->timer_event_source); - acd->timer_event_source = TAKE_PTR(timer); - - return 0; + return event_reset_time(acd->event, &acd->timer_event_source, + clock_boottime_or_monotonic(), + time_now + next_timeout, 0, + ipv4acd_on_timeout, acd, + acd->event_priority, "ipv4acd-timer", true); } static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) { diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 7307e1668f..e451dff744 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -55,30 +55,15 @@ struct sd_ipv4ll { static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); -sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) { - if (!ll) - return NULL; - - assert(ll->n_ref >= 1); - ll->n_ref++; - - return ll; -} - -sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) { - if (!ll) - return NULL; - - assert(ll->n_ref >= 1); - ll->n_ref--; - - if (ll->n_ref > 0) - return NULL; +static sd_ipv4ll *ipv4ll_free(sd_ipv4ll *ll) { + assert(ll); sd_ipv4acd_unref(ll->acd); return mfree(ll); } +DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4ll, sd_ipv4ll, ipv4ll_free); + int sd_ipv4ll_new(sd_ipv4ll **ret) { _cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL; int r; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index c75d6079e1..969fc71051 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -2,36 +2,47 @@ #include #include +#include #include "sd-lldp.h" #include "alloc-util.h" +#include "ether-addr-util.h" +#include "event-util.h" #include "fd-util.h" #include "lldp-internal.h" #include "lldp-neighbor.h" #include "lldp-network.h" #include "socket-util.h" -#include "ether-addr-util.h" +#include "string-table.h" #define LLDP_DEFAULT_NEIGHBORS_MAX 128U -static void lldp_flush_neighbors(sd_lldp *lldp) { - sd_lldp_neighbor *n; +static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = { + [SD_LLDP_EVENT_ADDED] = "added", + [SD_LLDP_EVENT_REMOVED] = "removed", + [SD_LLDP_EVENT_UPDATED] = "updated", + [SD_LLDP_EVENT_REFRESHED] = "refreshed", +}; + +DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event); +static void lldp_flush_neighbors(sd_lldp *lldp) { assert(lldp); - while ((n = hashmap_first(lldp->neighbor_by_id))) - lldp_neighbor_unlink(n); + hashmap_clear(lldp->neighbor_by_id); } static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { assert(lldp); + assert(event >= 0 && event < _SD_LLDP_EVENT_MAX); - log_lldp("Invoking callback for '%c'.", event); - - if (!lldp->callback) + if (!lldp->callback) { + log_lldp("Received '%s' event.", lldp_event_to_string(event)); return; + } + log_lldp("Invoking callback for '%s' event.", lldp_event_to_string(event)); lldp->callback(lldp, event, n, lldp->userdata); } @@ -119,7 +130,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { } if (lldp_neighbor_equal(n, old)) { - /* Is this equal, then restart the TTL counter, but don't do anyting else. */ + /* Is this equal, then restart the TTL counter, but don't do anything else. */ old->timestamp = n->timestamp; lldp_start_timer(lldp, old); lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); @@ -223,7 +234,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v static void lldp_reset(sd_lldp *lldp) { assert(lldp); - lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); + (void) event_source_disable(lldp->timer_event_source); lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); lldp->fd = safe_close(lldp->fd); } @@ -329,27 +340,10 @@ _public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) { return 0; } -_public_ sd_lldp* sd_lldp_ref(sd_lldp *lldp) { - - if (!lldp) - return NULL; - - assert(lldp->n_ref > 0); - lldp->n_ref++; - - return lldp; -} - -_public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { - - if (!lldp) - return NULL; - - assert(lldp->n_ref > 0); - lldp->n_ref --; +static sd_lldp* lldp_free(sd_lldp *lldp) { + assert(lldp); - if (lldp->n_ref > 0) - return NULL; + lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); lldp_reset(lldp); sd_lldp_detach_event(lldp); @@ -360,22 +354,26 @@ _public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { return mfree(lldp); } +DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp, sd_lldp, lldp_free); + _public_ int sd_lldp_new(sd_lldp **ret) { _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; int r; assert_return(ret, -EINVAL); - lldp = new0(sd_lldp, 1); + lldp = new(sd_lldp, 1); if (!lldp) return -ENOMEM; - lldp->n_ref = 1; - lldp->fd = -1; - lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX; - lldp->capability_mask = (uint16_t) -1; + *lldp = (sd_lldp) { + .n_ref = 1, + .fd = -1, + .neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX, + .capability_mask = (uint16_t) -1, + }; - lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops); + lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_hash_ops); if (!lldp->neighbor_by_id) return -ENOMEM; @@ -388,10 +386,8 @@ _public_ int sd_lldp_new(sd_lldp **ret) { return 0; } -static int neighbor_compare_func(const void *a, const void *b) { - const sd_lldp_neighbor * const*x = a, * const *y = b; - - return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id); +static int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) { + return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id); } static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { @@ -411,7 +407,6 @@ static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) { sd_lldp_neighbor *n; - int r; assert(lldp); @@ -419,35 +414,17 @@ static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) { lldp_neighbor_start_ttl(neighbor); n = prioq_peek(lldp->neighbor_by_expiry); - if (!n) { - - if (lldp->timer_event_source) - return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF); - - return 0; - } - - if (lldp->timer_event_source) { - r = sd_event_source_set_time(lldp->timer_event_source, n->until); - if (r < 0) - return r; - - return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT); - } + if (!n) + return event_source_disable(lldp->timer_event_source); if (!lldp->event) return 0; - r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp); - if (r < 0) - return r; - - r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority); - if (r < 0) - return r; - - (void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer"); - return 0; + return event_reset_time(lldp->event, &lldp->timer_event_source, + clock_boottime_or_monotonic(), + n->until, 0, + on_timer_event, lldp, + lldp->event_priority, "lldp-timer", true); } _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { @@ -479,7 +456,7 @@ _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { assert((size_t) k == hashmap_size(lldp->neighbor_by_id)); /* Return things in a stable order */ - qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func); + typesafe_qsort(l, k, neighbor_compare_func); *ret = l; return k; diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 2d81160b02..79b2ea8bf2 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -9,6 +9,7 @@ #include "sd-ndisc.h" #include "alloc-util.h" +#include "event-util.h" #include "fd-util.h" #include "icmp6-util.h" #include "in-addr-util.h" @@ -16,19 +17,30 @@ #include "ndisc-router.h" #include "random-util.h" #include "socket-util.h" +#include "string-table.h" #include "string-util.h" #include "util.h" #define NDISC_TIMEOUT_NO_RA_USEC (NDISC_ROUTER_SOLICITATION_INTERVAL * NDISC_MAX_ROUTER_SOLICITATIONS) +static const char * const ndisc_event_table[_SD_NDISC_EVENT_MAX] = { + [SD_NDISC_EVENT_TIMEOUT] = "timeout", + [SD_NDISC_EVENT_ROUTER] = "router", +}; + +DEFINE_STRING_TABLE_LOOKUP(ndisc_event, sd_ndisc_event); + static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event event, sd_ndisc_router *rt) { assert(ndisc); + assert(event >= 0 && event < _SD_NDISC_EVENT_MAX); - log_ndisc("Invoking callback for '%c'.", event); - if (!ndisc->callback) + if (!ndisc->callback) { + log_ndisc("Received '%s' event.", ndisc_event_to_string(event)); return; + } + log_ndisc("Invoking callback for '%s' event.", ndisc_event_to_string(event)); ndisc->callback(ndisc, event, rt, ndisc->userdata); } @@ -100,56 +112,42 @@ _public_ sd_event *sd_ndisc_get_event(sd_ndisc *nd) { return nd->event; } -_public_ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { - - if (!nd) - return NULL; - - assert(nd->n_ref > 0); - nd->n_ref++; - - return nd; -} - -static int ndisc_reset(sd_ndisc *nd) { +static void ndisc_reset(sd_ndisc *nd) { assert(nd); - nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); - nd->timeout_no_ra = sd_event_source_unref(nd->timeout_no_ra); + (void) event_source_disable(nd->timeout_event_source); + (void) event_source_disable(nd->timeout_no_ra); nd->retransmit_time = 0; nd->recv_event_source = sd_event_source_unref(nd->recv_event_source); nd->fd = safe_close(nd->fd); - - return 0; } -_public_ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { - - if (!nd) - return NULL; - - assert(nd->n_ref > 0); - nd->n_ref--; +static sd_ndisc *ndisc_free(sd_ndisc *nd) { + assert(nd); - if (nd->n_ref > 0) - return NULL; + nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); + nd->timeout_no_ra = sd_event_source_unref(nd->timeout_no_ra); ndisc_reset(nd); sd_ndisc_detach_event(nd); return mfree(nd); } +DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc, sd_ndisc, ndisc_free); + _public_ int sd_ndisc_new(sd_ndisc **ret) { _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL; assert_return(ret, -EINVAL); - nd = new0(sd_ndisc, 1); + nd = new(sd_ndisc, 1); if (!nd) return -ENOMEM; - nd->n_ref = 1; - nd->fd = -1; + *nd = (sd_ndisc) { + .n_ref = 1, + .fd = -1, + }; *ret = TAKE_PTR(nd); @@ -238,14 +236,21 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda break; case -EPFNOSUPPORT: - log_ndisc("Received invalid source address from ICMPv6 socket."); + log_ndisc("Received invalid source address from ICMPv6 socket. Ignoring."); + break; + + case -EAGAIN: /* ignore spurious wakeups */ + break; + + default: + log_ndisc_errno(r, "Unexpected error while reading from ICMPv6, ignoring: %m"); break; } return 0; } - nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); + (void) event_source_disable(nd->timeout_event_source); return ndisc_handle_datagram(nd, rt); } @@ -257,10 +262,10 @@ static usec_t ndisc_timeout_compute_random(usec_t val) { } static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) { + char time_string[FORMAT_TIMESPAN_MAX]; sd_ndisc *nd = userdata; usec_t time_now; int r; - char time_string[FORMAT_TIMESPAN_MAX]; assert(s); assert(nd); @@ -268,8 +273,6 @@ static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) { assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0); - nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); - if (!nd->retransmit_time) nd->retransmit_time = ndisc_timeout_compute_random(NDISC_ROUTER_SOLICITATION_INTERVAL); else { @@ -279,25 +282,14 @@ static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) { nd->retransmit_time += ndisc_timeout_compute_random(nd->retransmit_time); } - r = sd_event_add_time(nd->event, &nd->timeout_event_source, - clock_boottime_or_monotonic(), - time_now + nd->retransmit_time, - 10 * USEC_PER_MSEC, ndisc_timeout, nd); + r = event_reset_time(nd->event, &nd->timeout_event_source, + clock_boottime_or_monotonic(), + time_now + nd->retransmit_time, 10 * USEC_PER_MSEC, + ndisc_timeout, nd, + nd->event_priority, "ndisc-timeout-no-ra", true); if (r < 0) goto fail; - r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority); - if (r < 0) - goto fail; - - (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout-no-ra"); - - r = sd_event_source_set_enabled(nd->timeout_event_source, SD_EVENT_ONESHOT); - if (r < 0) { - log_ndisc_errno(r, "Error reenabling timer: %m"); - goto fail; - } - r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); if (r < 0) { log_ndisc_errno(r, "Error sending Router Solicitation: %m"); @@ -311,7 +303,7 @@ static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) { return 0; fail: - sd_ndisc_stop(nd); + (void) sd_ndisc_stop(nd); return 0; } @@ -323,7 +315,7 @@ static int ndisc_timeout_no_ra(sd_event_source *s, uint64_t usec, void *userdata log_ndisc("No RA received before link confirmation timeout"); - nd->timeout_no_ra = sd_event_source_unref(nd->timeout_no_ra); + (void) event_source_disable(nd->timeout_no_ra); ndisc_callback(nd, SD_NDISC_EVENT_TIMEOUT, NULL); return 0; @@ -353,7 +345,6 @@ _public_ int sd_ndisc_start(sd_ndisc *nd) { return 0; assert(!nd->recv_event_source); - assert(!nd->timeout_event_source); r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) @@ -373,29 +364,22 @@ _public_ int sd_ndisc_start(sd_ndisc *nd) { (void) sd_event_source_set_description(nd->recv_event_source, "ndisc-receive-message"); - r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_timeout, nd); + r = event_reset_time(nd->event, &nd->timeout_event_source, + clock_boottime_or_monotonic(), + 0, 0, + ndisc_timeout, nd, + nd->event_priority, "ndisc-timeout", true); if (r < 0) goto fail; - r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority); + r = event_reset_time(nd->event, &nd->timeout_no_ra, + clock_boottime_or_monotonic(), + time_now + NDISC_TIMEOUT_NO_RA_USEC, 10 * USEC_PER_MSEC, + ndisc_timeout_no_ra, nd, + nd->event_priority, "ndisc-timeout-no-ra", true); if (r < 0) goto fail; - (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout"); - - r = sd_event_add_time(nd->event, &nd->timeout_no_ra, - clock_boottime_or_monotonic(), - time_now + NDISC_TIMEOUT_NO_RA_USEC, - 10 * USEC_PER_MSEC, ndisc_timeout_no_ra, nd); - if (r < 0) - goto fail; - - r = sd_event_source_set_priority(nd->timeout_no_ra, nd->event_priority); - if (r < 0) - goto fail; - - (void) sd_event_source_set_description(nd->timeout_no_ra, "ndisc-timeout-no-ra"); - log_ndisc("Started IPv6 Router Solicitation client"); return 1; diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c index 86750b876c..098e01fb82 100644 --- a/src/libsystemd-network/sd-radv.c +++ b/src/libsystemd-network/sd-radv.c @@ -9,32 +9,35 @@ #include "sd-radv.h" -#include "macro.h" #include "alloc-util.h" #include "dns-domain.h" +#include "ether-addr-util.h" +#include "event-util.h" #include "fd-util.h" #include "icmp6-util.h" #include "in-addr-util.h" +#include "io-util.h" +#include "macro.h" #include "radv-internal.h" +#include "random-util.h" #include "socket-util.h" #include "string-util.h" #include "strv.h" #include "util.h" -#include "random-util.h" _public_ int sd_radv_new(sd_radv **ret) { _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL; assert_return(ret, -EINVAL); - ra = new0(sd_radv, 1); + ra = new(sd_radv, 1); if (!ra) return -ENOMEM; - ra->n_ref = 1; - ra->fd = -1; - - LIST_HEAD_INIT(ra->prefixes); + *ra = (sd_radv) { + .n_ref = 1, + .fd = -1, + }; *ret = TAKE_PTR(ra); @@ -77,8 +80,7 @@ _public_ sd_event *sd_radv_get_event(sd_radv *ra) { static void radv_reset(sd_radv *ra) { assert(ra); - ra->timeout_event_source = - sd_event_source_unref(ra->timeout_event_source); + (void) event_source_disable(ra->timeout_event_source); ra->recv_event_source = sd_event_source_unref(ra->recv_event_source); @@ -86,26 +88,10 @@ static void radv_reset(sd_radv *ra) { ra->ra_sent = 0; } -_public_ sd_radv *sd_radv_ref(sd_radv *ra) { +static sd_radv *radv_free(sd_radv *ra) { if (!ra) return NULL; - assert(ra->n_ref > 0); - ra->n_ref++; - - return ra; -} - -_public_ sd_radv *sd_radv_unref(sd_radv *ra) { - if (!ra) - return NULL; - - assert(ra->n_ref > 0); - ra->n_ref--; - - if (ra->n_ref > 0) - return NULL; - while (ra->prefixes) { sd_radv_prefix *p = ra->prefixes; @@ -116,6 +102,8 @@ _public_ sd_radv *sd_radv_unref(sd_radv *ra) { free(ra->rdnss); free(ra->dnssl); + ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source); + radv_reset(ra); sd_radv_detach_event(ra); @@ -125,9 +113,9 @@ _public_ sd_radv *sd_radv_unref(sd_radv *ra) { return mfree(ra); } -static int radv_send(sd_radv *ra, const struct in6_addr *dst, - const uint32_t router_lifetime) { - static const struct ether_addr mac_zero = {}; +DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free); + +static int radv_send(sd_radv *ra, const struct in6_addr *dst, uint32_t router_lifetime) { sd_radv_prefix *p; struct sockaddr_in6 dst_addr = { .sin6_family = AF_INET6, @@ -159,35 +147,31 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t time_now; int r; + assert(ra); + r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) return r; - if (dst && !in_addr_is_null(AF_INET6, (union in_addr_union*) dst)) + if (dst && !IN6_IS_ADDR_UNSPECIFIED(dst)) dst_addr.sin6_addr = *dst; adv.nd_ra_type = ND_ROUTER_ADVERT; adv.nd_ra_curhoplimit = ra->hop_limit; adv.nd_ra_flags_reserved = ra->flags; adv.nd_ra_router_lifetime = htobe16(router_lifetime); - iov[msg.msg_iovlen].iov_base = &adv; - iov[msg.msg_iovlen].iov_len = sizeof(adv); - msg.msg_iovlen++; + iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv)); /* MAC address is optional, either because the link does not use L2 addresses or load sharing is desired. See RFC 4861, Section 4.2 */ - if (memcmp(&mac_zero, &ra->mac_addr, sizeof(mac_zero))) { + if (!ether_addr_is_null(&ra->mac_addr)) { opt_mac.slladdr = ra->mac_addr; - iov[msg.msg_iovlen].iov_base = &opt_mac; - iov[msg.msg_iovlen].iov_len = sizeof(opt_mac); - msg.msg_iovlen++; + iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac)); } if (ra->mtu) { opt_mtu.nd_opt_mtu_mtu = htobe32(ra->mtu); - iov[msg.msg_iovlen].iov_base = &opt_mtu; - iov[msg.msg_iovlen].iov_len = sizeof(opt_mtu); - msg.msg_iovlen++; + iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mtu, sizeof(opt_mtu)); } LIST_FOREACH(prefix, p, ra->prefixes) { @@ -203,22 +187,14 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, else p->opt.preferred_lifetime = htobe32((p->preferred_until - time_now) / USEC_PER_SEC); } - iov[msg.msg_iovlen].iov_base = &p->opt; - iov[msg.msg_iovlen].iov_len = sizeof(p->opt); - msg.msg_iovlen++; + iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt)); } - if (ra->rdnss) { - iov[msg.msg_iovlen].iov_base = ra->rdnss; - iov[msg.msg_iovlen].iov_len = ra->rdnss->length * 8; - msg.msg_iovlen++; - } + if (ra->rdnss) + iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8); - if (ra->dnssl) { - iov[msg.msg_iovlen].iov_base = ra->dnssl; - iov[msg.msg_iovlen].iov_len = ra->dnssl->length * 8; - msg.msg_iovlen++; - } + if (ra->dnssl) + iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8); if (sendmsg(ra->fd, &msg, 0) < 0) return -errno; @@ -240,13 +216,12 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat assert(ra->event); buflen = next_datagram_size_fd(fd); - - if ((unsigned) buflen < sizeof(struct nd_router_solicit)) - return log_radv("Too short packet received"); + if (buflen < 0) + return (int) buflen; buf = new0(char, buflen); if (!buf) - return 0; + return -ENOMEM; r = icmp6_receive(fd, buf, buflen, &src, ×tamp); if (r < 0) { @@ -264,21 +239,29 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat log_radv("Received invalid source address from ICMPv6 socket. Ignoring."); break; + case -EAGAIN: /* ignore spurious wakeups */ + break; + default: - log_radv_warning_errno(r, "Error receiving from ICMPv6 socket: %m"); + log_radv_errno(r, "Unexpected error receiving from ICMPv6 socket: %m"); break; } return 0; } + if ((size_t) buflen < sizeof(struct nd_router_solicit)) { + log_radv("Too short packet received"); + return 0; + } + (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr); r = radv_send(ra, &src, ra->lifetime); if (r < 0) - log_radv_warning_errno(r, "Unable to send solicited Router Advertisement to %s: %m", addr); + log_radv_errno(r, "Unable to send solicited Router Advertisement to %s: %m", strnull(addr)); else - log_radv("Sent solicited Router Advertisement to %s", addr); + log_radv("Sent solicited Router Advertisement to %s", strnull(addr)); return 0; } @@ -301,15 +284,13 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) { assert(ra); assert(ra->event); - ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source); - r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) goto fail; r = radv_send(ra, NULL, ra->lifetime); if (r < 0) - log_radv_warning_errno(r, "Unable to send Router Advertisement: %m"); + log_radv_errno(r, "Unable to send Router Advertisement: %m"); /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */ if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) { @@ -323,28 +304,20 @@ static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) { format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); - r = sd_event_add_time(ra->event, &ra->timeout_event_source, - clock_boottime_or_monotonic(), - time_now + timeout, MSEC_PER_SEC, - radv_timeout, ra); - if (r < 0) - goto fail; - - r = sd_event_source_set_priority(ra->timeout_event_source, - ra->event_priority); - if (r < 0) - goto fail; - - r = sd_event_source_set_description(ra->timeout_event_source, - "radv-timeout"); + r = event_reset_time(ra->event, &ra->timeout_event_source, + clock_boottime_or_monotonic(), + time_now + timeout, MSEC_PER_SEC, + radv_timeout, ra, + ra->event_priority, "radv-timeout", true); if (r < 0) goto fail; ra->ra_sent++; + return 0; + fail: - if (r < 0) - sd_radv_stop(ra); + sd_radv_stop(ra); return 0; } @@ -363,7 +336,7 @@ _public_ int sd_radv_stop(sd_radv *ra) { with zero lifetime */ r = radv_send(ra, NULL, 0); if (r < 0) - log_radv_warning_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m"); + log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m"); radv_reset(ra); ra->fd = safe_close(ra->fd); @@ -373,7 +346,7 @@ _public_ int sd_radv_stop(sd_radv *ra) { } _public_ int sd_radv_start(sd_radv *ra) { - int r = 0; + int r; assert_return(ra, -EINVAL); assert_return(ra->event, -EINVAL); @@ -382,20 +355,14 @@ _public_ int sd_radv_start(sd_radv *ra) { if (ra->state != SD_RADV_STATE_IDLE) return 0; - r = sd_event_add_time(ra->event, &ra->timeout_event_source, - clock_boottime_or_monotonic(), 0, 0, - radv_timeout, ra); - if (r < 0) - goto fail; - - r = sd_event_source_set_priority(ra->timeout_event_source, - ra->event_priority); + r = event_reset_time(ra->event, &ra->timeout_event_source, + clock_boottime_or_monotonic(), + 0, 0, + radv_timeout, ra, + ra->event_priority, "radv-timeout", true); if (r < 0) goto fail; - (void) sd_event_source_set_description(ra->timeout_event_source, - "radv-timeout"); - r = icmp6_bind_router_advertisement(ra->ifindex); if (r < 0) goto fail; @@ -523,7 +490,7 @@ _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) { return r; } -_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, bool dynamic) { +_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) { sd_radv_prefix *cur; int r; _cleanup_free_ char *addr_p = NULL; @@ -536,6 +503,10 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, bool dynamic) { if (!p) return -EINVAL; + /* Refuse prefixes that don't have a prefix set */ + if (IN6_IS_ADDR_UNSPECIFIED(&p->opt.in6_addr)) + return -ENOEXEC; + LIST_FOREACH(prefix, cur, ra->prefixes) { r = in_addr_prefix_intersect(AF_INET6, @@ -718,56 +689,33 @@ _public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, } _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) { - _cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL; + sd_radv_prefix *p; assert_return(ret, -EINVAL); - p = new0(sd_radv_prefix, 1); + p = new(sd_radv_prefix, 1); if (!p) return -ENOMEM; - p->n_ref = 1; + *p = (sd_radv_prefix) { + .n_ref = 1, - p->opt.type = ND_OPT_PREFIX_INFORMATION; - p->opt.length = (sizeof(p->opt) - 1) /8 + 1; + .opt.type = ND_OPT_PREFIX_INFORMATION, + .opt.length = (sizeof(p->opt) - 1)/8 + 1, + .opt.prefixlen = 64, - p->opt.prefixlen = 64; + /* RFC 4861, Section 6.2.1 */ + .opt.flags = ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO, - /* RFC 4861, Section 6.2.1 */ - SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, true); - SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, true); - p->opt.preferred_lifetime = htobe32(604800); - p->opt.valid_lifetime = htobe32(2592000); - - LIST_INIT(prefix, p); - - *ret = TAKE_PTR(p); + .opt.preferred_lifetime = htobe32(604800), + .opt.valid_lifetime = htobe32(2592000), + }; + *ret = p; return 0; } -_public_ sd_radv_prefix *sd_radv_prefix_ref(sd_radv_prefix *p) { - if (!p) - return NULL; - - assert(p->n_ref > 0); - p->n_ref++; - - return p; -} - -_public_ sd_radv_prefix *sd_radv_prefix_unref(sd_radv_prefix *p) { - if (!p) - return NULL; - - assert(p->n_ref > 0); - p->n_ref--; - - if (p->n_ref > 0) - return NULL; - - return mfree(p); -} +DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree); _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr, unsigned char prefixlen) { diff --git a/src/libsystemd-network/test-acd.c b/src/libsystemd-network/test-acd.c index 079e760996..302eea2c30 100644 --- a/src/libsystemd-network/test-acd.c +++ b/src/libsystemd-network/test-acd.c @@ -13,6 +13,7 @@ #include "in-addr-util.h" #include "netlink-util.h" +#include "tests.h" #include "util.h" static void acd_handler(sd_ipv4acd *acd, int event, void *userdata) { @@ -83,9 +84,7 @@ static int test_acd(const char *ifname, const char *address) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); if (argc == 3) return test_acd(argv[1], argv[2]); diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 0e257633b8..fe6788d91b 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "sd-dhcp-client.h" #include "sd-event.h" @@ -16,6 +17,8 @@ #include "dhcp-internal.h" #include "dhcp-protocol.h" #include "fd-util.h" +#include "random-util.h" +#include "tests.h" #include "util.h" static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'}; @@ -152,6 +155,35 @@ static void test_checksum(void) { assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae)); } +static void test_dhcp_identifier_set_iaid(void) { + uint32_t iaid_legacy; + be32_t iaid; + int ifindex; + + for (;;) { + char ifname[IFNAMSIZ]; + + /* try to find an ifindex which does not exist. I causes dhcp_identifier_set_iaid() + * to hash the MAC address. */ + pseudo_random_bytes(&ifindex, sizeof(ifindex)); + if (ifindex > 0 && !if_indextoname(ifindex, ifname)) + break; + } + + assert_se(dhcp_identifier_set_iaid(ifindex, mac_addr, sizeof(mac_addr), true, &iaid_legacy) >= 0); + assert_se(dhcp_identifier_set_iaid(ifindex, mac_addr, sizeof(mac_addr), false, &iaid) >= 0); + + /* we expect, that the MAC address was hashed. The legacy value is in native + * endianness. */ + assert_se(iaid_legacy == 0x8dde4ba8u); + assert_se(iaid == htole32(0x8dde4ba8u)); +#if __BYTE_ORDER == __LITTLE_ENDIAN + assert_se(iaid == iaid_legacy); +#else + assert_se(iaid == __bswap_32(iaid_legacy)); +#endif +} + static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) { switch(code) { case SD_DHCP_OPTION_CLIENT_IDENTIFIER: @@ -161,7 +193,7 @@ static int check_options(uint8_t code, uint8_t len, const void *option, void *us size_t duid_len; assert_se(dhcp_identifier_set_duid_en(&duid, &duid_len) >= 0); - assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, &iaid) >= 0); + assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, true, &iaid) >= 0); assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len); assert_se(len == 19); @@ -231,7 +263,7 @@ int dhcp_network_bind_raw_socket( const uint8_t *addr, size_t addr_len, uint16_t arp_type, uint16_t port) { - if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0) + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0) return -errno; return test_fd[0]; @@ -240,7 +272,7 @@ int dhcp_network_bind_raw_socket( int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { int fd; - fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); + fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (fd < 0) return -errno; @@ -524,15 +556,14 @@ static void test_addr_acq(sd_event *e) { int main(int argc, char *argv[]) { _cleanup_(sd_event_unrefp) sd_event *e; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); assert_se(sd_event_new(&e) >= 0); test_request_basic(e); test_request_anonymize(e); test_checksum(); + test_dhcp_identifier_set_iaid(); test_discover_message(e); test_addr_acq(e); diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 815b11e997..ea998939bc 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -9,6 +9,7 @@ #include "sd-event.h" #include "dhcp-server-internal.h" +#include "tests.h" static void test_pool(struct in_addr *address, unsigned size, int ret) { _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL; @@ -54,9 +55,8 @@ static int test_basic(sd_event *event) { test_pool(&address_lo, 1, 0); r = sd_dhcp_server_start(server); - if (r == -EPERM) - return EXIT_TEST_SKIP; + return log_info_errno(r, "sd_dhcp_server_start failed: %m"); assert_se(r >= 0); assert_se(sd_dhcp_server_start(server) == -EBUSY); @@ -229,15 +229,13 @@ int main(int argc, char *argv[]) { _cleanup_(sd_event_unrefp) sd_event *e; int r; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); assert_se(sd_event_new(&e) >= 0); r = test_basic(e); if (r != 0) - return r; + return log_tests_skipped("cannot start dhcp server"); test_message_handler(); test_client_id_hash(); diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 27c0002fe2..fa94b3cb75 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -19,14 +19,14 @@ #include "fd-util.h" #include "macro.h" #include "socket-util.h" +#include "tests.h" +#include "util.h" #include "virt.h" static struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} }; -static bool verbose = true; - static sd_event_source *hangcheck; static int test_dhcp_fd[2]; static int test_index = 42; @@ -36,9 +36,9 @@ static uint8_t test_duid[14] = { }; static int test_client_basic(sd_event *e) { sd_dhcp6_client *client; + int v; - if (verbose) - printf("* %s\n", __FUNCTION__); + log_debug("/* %s */", __func__); assert_se(sd_dhcp6_client_new(&client) >= 0); assert_se(client); @@ -67,6 +67,36 @@ static int test_client_basic(sd_event *e) { assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST); assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL); + assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0); + v = 0; + assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0); + assert_se(v); + assert_se(sd_dhcp6_client_set_information_request(client, 0) >= 0); + v = 42; + assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0); + assert_se(v == 0); + + v = 0; + assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0); + assert_se(v); + v = 0; + assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0); + assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0); + assert_se(v); + v = 42; + assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0); + assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0); + assert_se(v); + + assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0); + assert_se(sd_dhcp6_client_set_prefix_delegation(client, 1) >= 0); + v = 0; + assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0); + assert_se(v); + v = 0; + assert_se(sd_dhcp6_client_get_prefix_delegation(client, &v) >= 0); + assert_se(v); + assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0); assert_se(sd_dhcp6_client_detach_event(client) >= 0); @@ -97,8 +127,7 @@ static int test_option(sd_event *e) { size_t zero = 0, pos = 3; size_t buflen = sizeof(packet), outlen = sizeof(result); - if (verbose) - printf("* %s\n", __FUNCTION__); + log_debug("/* %s */", __func__); assert_se(buflen == outlen); @@ -211,8 +240,7 @@ static int test_option_status(sd_event *e) { DHCP6IA ia, pd; int r = 0; - if (verbose) - printf("* %s\n", __FUNCTION__); + log_debug("/* %s */", __func__); zero(ia); option = (DHCP6Option *)option1; @@ -345,8 +373,7 @@ static int test_advertise_option(sd_event *e) { struct in6_addr *addrs; char **domains; - if (verbose) - printf("* %s\n", __FUNCTION__); + log_debug("/* %s */", __func__); assert_se(len >= sizeof(DHCP6Message)); @@ -493,6 +520,8 @@ static void test_client_solicit_cb(sd_dhcp6_client *client, int event, struct in6_addr *addrs; char **domains; + log_debug("/* %s */", __func__); + assert_se(e); assert_se(event == SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE); @@ -510,9 +539,6 @@ static void test_client_solicit_cb(sd_dhcp6_client *client, int event, assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EBUSY); - if (verbose) - printf(" got DHCPv6 event %d\n", event); - sd_event_exit(e, 0); } @@ -543,8 +569,9 @@ static int test_client_verify_request(DHCP6Message *request, size_t len) { be32_t val; uint32_t lt_pref, lt_valid; - assert_se(request->type == DHCP6_REQUEST); + log_debug("/* %s */", __func__); + assert_se(request->type == DHCP6_REQUEST); assert_se(dhcp6_lease_new(&lease) >= 0); len -= sizeof(DHCP6Message); @@ -651,6 +678,8 @@ static int test_client_verify_solicit(DHCP6Message *solicit, size_t len) { found_elapsed_time = false, found_fqdn = false; size_t pos = 0; + log_debug("/* %s */", __func__); + assert_se(solicit->type == DHCP6_SOLICIT); len -= sizeof(DHCP6Message); @@ -718,6 +747,8 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event, struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; char **domains; + log_debug("/* %s */", __func__); + assert_se(e); assert_se(event == SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST); @@ -733,9 +764,6 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event, assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1); assert_se(!memcmp(addrs, &msg_advertise[159], 16)); - if (verbose) - printf(" got DHCPv6 event %d\n", event); - assert_se(sd_dhcp6_client_set_information_request(client, false) == -EBUSY); assert_se(sd_dhcp6_client_set_callback(client, NULL, e) >= 0); assert_se(sd_dhcp6_client_stop(client) >= 0); @@ -759,8 +787,9 @@ static int test_client_verify_information_request(DHCP6Message *information_requ struct in6_addr addr; uint32_t lt_pref, lt_valid; - assert_se(information_request->type == DHCP6_INFORMATION_REQUEST); + log_debug("/* %s */", __func__); + assert_se(information_request->type == DHCP6_INFORMATION_REQUEST); assert_se(dhcp6_lease_new(&lease) >= 0); len -= sizeof(DHCP6Message); @@ -824,7 +853,6 @@ int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, assert_se(server_address); assert_se(packet); assert_se(len > sizeof(DHCP6Message) + 4); - assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast)); message = (DHCP6Message *)packet; @@ -851,7 +879,7 @@ int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { assert_se(index == test_index); - if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0) + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_dhcp_fd) < 0) return -errno; return test_dhcp_fd[0]; @@ -861,10 +889,9 @@ static int test_client_solicit(sd_event *e) { sd_dhcp6_client *client; usec_t time_now = now(clock_boottime_or_monotonic()); struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; - int val = true; + int val; - if (verbose) - printf("* %s\n", __FUNCTION__); + log_debug("/* %s */", __func__); assert_se(sd_dhcp6_client_new(&client) >= 0); assert_se(client); @@ -878,10 +905,10 @@ static int test_client_solicit(sd_event *e) { assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1); assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0); - assert_se(val == false); - assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0); + assert_se(val == 0); + assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0); assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0); - assert_se(val == true); + assert_se(val); assert_se(sd_dhcp6_client_set_callback(client, test_client_information_cb, e) >= 0); @@ -910,9 +937,7 @@ int main(int argc, char *argv[]) { assert_se(sd_event_new(&e) >= 0); - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_client_basic(e); test_option(e); diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c index 125133f039..fd827ff401 100644 --- a/src/libsystemd-network/test-ipv4ll-manual.c +++ b/src/libsystemd-network/test-ipv4ll-manual.c @@ -15,6 +15,7 @@ #include "netlink-util.h" #include "parse-util.h" #include "string-util.h" +#include "tests.h" #include "util.h" static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) { @@ -95,9 +96,7 @@ static int test_ll(const char *ifname, const char *seed) { } int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); if (argc == 2) return test_ll(argv[1], NULL); diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index ee9cce02a8..2e1488cb0a 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -15,6 +15,7 @@ #include "arp-util.h" #include "fd-util.h" #include "socket-util.h" +#include "tests.h" #include "util.h" static bool verbose = false; @@ -78,7 +79,7 @@ int arp_send_announcement(int fd, int ifindex, } int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac) { - if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0) + if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0) return -errno; return test_fd[0]; @@ -193,9 +194,7 @@ static void test_basic_request(sd_event *e) { int main(int argc, char *argv[]) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); assert_se(sd_event_new(&e) >= 0); diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index ac8ba2b707..cb4545d901 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -24,7 +24,7 @@ static int test_fd[2] = { -1, -1 }; static int lldp_handler_calls; int lldp_network_bind_raw_socket(int ifindex) { - if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0) + if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0) return -errno; return test_fd[0]; @@ -229,6 +229,135 @@ static void test_receive_oui_packet(sd_event *e) { assert_se(stop_lldp(lldp) == 0); } +static void test_multiple_neighbors_sorted(sd_event *e) { + + static const uint8_t frame1[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x04, 0x01, '1', '/', '2', /* Chassis component: "1/2" */ + 0x04, 0x04, 0x02, '2', '/', '3', /* Port component: "2/3" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + static const uint8_t frame2[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x04, 0x01, '2', '/', '1', /* Chassis component: "2/1" */ + 0x04, 0x04, 0x02, '1', '/', '3', /* Port component: "1/3" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + static const uint8_t frame3[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x05, 0x01, '2', '/', '1', '0', /* Chassis component: "2/10" */ + 0x04, 0x04, 0x02, '1', '/', '0', /* Port component: "1/0" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + static const uint8_t frame4[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x05, 0x01, '2', '/', '1', '9', /* Chassis component: "2/19" */ + 0x04, 0x04, 0x02, '1', '/', '0', /* Port component: "1/0" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + static const uint8_t frame5[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x04, 0x01, '1', '/', '2', /* Chassis component: "1/2" */ + 0x04, 0x05, 0x02, '2', '/', '1', '0', /* Port component: "2/10" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + static const uint8_t frame6[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x04, 0x01, '1', '/', '2', /* Chassis component: "1/2" */ + 0x04, 0x05, 0x02, '2', '/', '3', '9', /* Port component: "2/10" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + static const char* expected[] = { + /* ordered pairs of Chassis+Port */ + "1/2", "2/10", + "1/2", "2/3", + "1/2", "2/39", + "2/1", "1/3", + "2/10", "1/0", + "2/19", "1/0", + }; + + sd_lldp *lldp; + sd_lldp_neighbor **neighbors; + int i; + uint8_t type; + const void *data; + size_t length, expected_length; + uint16_t ttl; + + lldp_handler_calls = 0; + assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0); + + assert_se(write(test_fd[1], frame1, sizeof(frame1)) == sizeof(frame1)); + sd_event_run(e, 0); + assert_se(write(test_fd[1], frame2, sizeof(frame2)) == sizeof(frame2)); + sd_event_run(e, 0); + assert_se(write(test_fd[1], frame3, sizeof(frame3)) == sizeof(frame3)); + sd_event_run(e, 0); + assert_se(write(test_fd[1], frame4, sizeof(frame4)) == sizeof(frame4)); + sd_event_run(e, 0); + assert_se(write(test_fd[1], frame5, sizeof(frame5)) == sizeof(frame5)); + sd_event_run(e, 0); + assert_se(write(test_fd[1], frame6, sizeof(frame6)) == sizeof(frame6)); + sd_event_run(e, 0); + assert_se(lldp_handler_calls == 6); + + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 6); + + for (i = 0; i < 6; i++) { + assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[i], &type, &data, &length) == 0); + assert_se(type == SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT); + expected_length = strlen(expected[2 * i]); + assert_se(length == expected_length); + assert_se(memcmp(data, expected[2 * i], expected_length) == 0); + + assert_se(sd_lldp_neighbor_get_port_id(neighbors[i], &type, &data, &length) == 0); + assert_se(type == SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT); + expected_length = strlen(expected[2 * i + 1]); + assert_se(length == expected_length); + assert_se(memcmp(data, expected[2 * i + 1], expected_length) == 0); + + assert_se(sd_lldp_neighbor_get_ttl(neighbors[i], &ttl) == 0); + assert_se(ttl == 120); + } + + for (i = 0; i < 6; i++) + sd_lldp_neighbor_unref(neighbors[i]); + free(neighbors); + + assert_se(stop_lldp(lldp) == 0); +} + int main(int argc, char *argv[]) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; @@ -239,6 +368,7 @@ int main(int argc, char *argv[]) { test_receive_basic_packet(e); test_receive_incomplete_packet(e); test_receive_oui_packet(e); + test_multiple_neighbors_sorted(e); return 0; } diff --git a/src/libsystemd-network/test-ndisc-ra.c b/src/libsystemd-network/test-ndisc-ra.c index d5a0237663..c4c1c81140 100644 --- a/src/libsystemd-network/test-ndisc-ra.c +++ b/src/libsystemd-network/test-ndisc-ra.c @@ -13,6 +13,7 @@ #include "icmp6-util.h" #include "socket-util.h" #include "strv.h" +#include "tests.h" static struct ether_addr mac_addr = { .ether_addr_octet = { 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53 } @@ -292,11 +293,11 @@ static void test_ra(void) { sd_event *e; sd_radv *ra; usec_t time_now = now(clock_boottime_or_monotonic()); - unsigned int i; + unsigned i; printf("* %s\n", __FUNCTION__); - assert_se(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, test_fd) >= 0); + assert_se(socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) >= 0); assert_se(sd_event_new(&e) >= 0); @@ -357,9 +358,7 @@ static void test_ra(void) { int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_radv_prefix(); test_radv(); diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index b9d0e7dc90..caf94d10f8 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -14,6 +14,7 @@ #include "socket-util.h" #include "strv.h" #include "ndisc-internal.h" +#include "tests.h" static struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} @@ -175,7 +176,7 @@ static int test_rs_hangcheck(sd_event_source *s, uint64_t usec, int icmp6_bind_router_solicitation(int index) { assert_se(index == 42); - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0) + if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0) return -errno; return test_fd[0]; @@ -407,9 +408,7 @@ static void test_timeout(void) { int main(int argc, char *argv[]) { - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_rs(); test_timeout(); -- cgit v1.2.1