diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 7d84b0df50..ee1f0fc21a 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -174,8 +174,9 @@ void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in } } -static bool address_may_have_broadcast(const Address *a) { +static bool address_needs_to_set_broadcast(const Address *a, Link *link) { assert(a); + assert(link); if (a->family != AF_INET) return false; @@ -188,38 +189,26 @@ static bool address_may_have_broadcast(const Address *a) { if (a->prefixlen > 30) return false; + /* If explicitly configured, do not update the address. */ + if (in4_addr_is_set(&a->broadcast)) + return false; + if (a->set_broadcast >= 0) return a->set_broadcast; - return true; /* Defaults to true. */ + /* Defaults to true, except for wireguard, as typical configuration for wireguard does not set + * broadcast. */ + return !streq_ptr(link->kind, "wireguard"); } -void address_set_broadcast(Address *a) { - assert(a); - - if (!address_may_have_broadcast(a)) - return; - - /* If explicitly configured, do not update the address. */ - if (in4_addr_is_set(&a->broadcast)) - return; - - /* If Address= is 0.0.0.0, then the broadcast address will be set later in address_acquire(). */ - if (in4_addr_is_null(&a->in_addr.in)) - return; - - a->broadcast.s_addr = a->in_addr.in.s_addr | htobe32(UINT32_C(0xffffffff) >> a->prefixlen); -} - -static bool address_may_set_broadcast(const Address *a, const Link *link) { +void address_set_broadcast(Address *a, Link *link) { assert(a); assert(link); - if (!address_may_have_broadcast(a)) - return false; + if (!address_needs_to_set_broadcast(a, link)) + return; - /* Typical configuration for wireguard does not set broadcast. */ - return !streq_ptr(link->kind, "wireguard"); + a->broadcast.s_addr = a->in_addr.in.s_addr | htobe32(UINT32_C(0xffffffff) >> a->prefixlen); } static struct ifa_cacheinfo *address_set_cinfo(const Address *a, struct ifa_cacheinfo *cinfo) { @@ -975,7 +964,6 @@ static int address_acquire(Link *link, const Address *original, Address **ret) { return r; na->in_addr = in_addr; - address_set_broadcast(na); *ret = TAKE_PTR(na); return 1; @@ -1037,7 +1025,7 @@ static int address_configure( r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer); if (r < 0) return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m"); - } else if (address_may_set_broadcast(address, link)) { + } else if (in4_addr_is_set(&address->broadcast)) { r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); if (r < 0) return log_link_error_errno(link, r, "Could not append IFA_BROADCAST attribute: %m"); @@ -1132,6 +1120,21 @@ int link_request_address( consume_object = true; } + if (address_needs_to_set_broadcast(address, link)) { + if (!consume_object) { + Address *a; + + r = address_dup(address, &a); + if (r < 0) + return r; + + address = a; + consume_object = true; + } + + address_set_broadcast(address, link); + } + if (address_get(link, address, &existing) < 0) { _cleanup_(address_freep) Address *tmp = NULL; @@ -1922,10 +1925,11 @@ static int address_section_verify(Address *address) { address->section->filename, address->section->line); } - if (address_may_have_broadcast(address)) - address_set_broadcast(address); - else if (address->broadcast.s_addr != 0) { - log_warning("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. " + if (in4_addr_is_set(&address->broadcast) && + (address->family == AF_INET6 || address->prefixlen > 30 || + in_addr_is_set(address->family, &address->in_addr_peer))) { + log_warning("%s: broadcast address is set for an IPv6 address, " + "an IPv4 address with peer address, or with prefix length larger than 30. " "Ignoring Broadcast= setting in the [Address] section from line %u.", address->section->filename, address->section->line); diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index b135c66a09..0b1f3192a2 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -70,7 +70,7 @@ int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, int address_remove(Address *address); int address_dup(const Address *src, Address **ret); bool address_is_ready(const Address *a); -void address_set_broadcast(Address *a); +void address_set_broadcast(Address *a, Link *link); DEFINE_SECTION_CLEANUP_FUNCTIONS(Address, address_free); diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index 48e919ce93..b28d13ba65 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -106,7 +106,7 @@ int link_request_dhcp_server_address(Link *link) { address->family = AF_INET; address->in_addr.in = link->network->dhcp_server_address; address->prefixlen = link->network->dhcp_server_address_prefixlen; - address_set_broadcast(address); + address_set_broadcast(address, link); if (address_get(link, address, &existing) >= 0 && address_exists(existing) && diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index f1d40fb99d..5e3854281c 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -34,7 +34,7 @@ static int address_new_from_ipv4ll(Link *link, Address **ret) { address->prefixlen = 16; address->scope = RT_SCOPE_LINK; address->route_metric = IPV4LL_ROUTE_METRIC; - address_set_broadcast(address); + address_set_broadcast(address, link); *ret = TAKE_PTR(address); return 0;