static bool address_may_have_broadcast(const Address *a) {
assert(a);
+ if (a->family != AF_INET)
+ return false;
+
+ if (in4_addr_is_set(&a->in_addr_peer.in))
+ return false;
+
/* A /31 or /32 IPv4 address does not have a broadcast address.
* See https://tools.ietf.org/html/rfc3021 */
+ if (a->prefixlen > 30)
+ return false;
+
+ if (a->set_broadcast >= 0)
+ return a->set_broadcast;
- return a->family == AF_INET &&
- in4_addr_is_null(&a->in_addr_peer.in) &&
- a->prefixlen <= 30;
+ return true; /* Defaults to true. */
+}
+
+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) {
if (!address_may_have_broadcast(a))
return false;
- if (a->set_broadcast >= 0)
- return a->set_broadcast;
-
/* Typical configuration for wireguard does not set broadcast. */
return !streq_ptr(link->kind, "wireguard");
}
static int address_acquire(Link *link, const Address *original, Address **ret) {
union in_addr_union in_addr = IN_ADDR_NULL;
- struct in_addr broadcast = {};
_cleanup_(address_freep) Address *na = NULL;
int r;
if (r == 0)
return -EBUSY;
- if (original->family == AF_INET) {
- /* Pick first address in range for ourselves ... */
+ /* Pick first address in range for ourselves. */
+ if (original->family == AF_INET)
in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
-
- /* .. and use last as broadcast address */
- if (original->prefixlen > 30)
- broadcast.s_addr = 0;
- else
- broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
- } else if (original->family == AF_INET6)
+ else if (original->family == AF_INET6)
in_addr.in6.s6_addr[15] |= 1;
r = address_new(&na);
if (r < 0)
return r;
- na->broadcast = broadcast;
na->in_addr = in_addr;
+ address_set_broadcast(na);
r = set_ensure_put(&link->pool_addresses, &address_hash_ops, na);
if (r < 0)
address->section->filename, address->section->line);
}
- if (address_may_have_broadcast(address)) {
- if (address->broadcast.s_addr == 0 && address->set_broadcast != 0)
- address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen);
- } else if (address->broadcast.s_addr != 0) {
+ 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. "
"Ignoring Broadcast= setting in the [Address] section from line %u.",
address->section->filename, address->section->line);