From: Yu Watanabe Date: Sun, 3 May 2026 06:16:17 +0000 (+0900) Subject: sd-dhcp-client: always set default broadcast hardware address when unspecified X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=304899fa57d0ad5ee57a8c7ee854ad74affe2eda;p=thirdparty%2Fsystemd.git sd-dhcp-client: always set default broadcast hardware address when unspecified The default value for InfiniBand is copied from dhcp-network.c. --- diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index 2919422bd2e..4ea4be594e1 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -301,3 +301,31 @@ void ether_addr_mark_random(struct ether_addr *addr) { addr->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */ addr->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */ } + +int hw_addr_ensure_broadcast(struct hw_addr_data *bcast_addr, uint16_t arp_type) { + assert(bcast_addr); + + if (!hw_addr_is_null(bcast_addr)) + return 0; + + switch (arp_type) { + case ARPHRD_ETHER: + *bcast_addr = (struct hw_addr_data) { + .length = ETH_ALEN, + .ether = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}, + }; + return 0; + case ARPHRD_INFINIBAND: + *bcast_addr = (struct hw_addr_data) { + .length = INFINIBAND_ALEN, + .infiniband = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, + }, + }; + return 0; + default: + return -EAFNOSUPPORT; + } +} diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index d342b5621e0..1d6e4cda7f0 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -106,3 +106,5 @@ extern const struct hash_ops ether_addr_hash_ops; extern const struct hash_ops ether_addr_hash_ops_free; void ether_addr_mark_random(struct ether_addr *addr); + +int hw_addr_ensure_broadcast(struct hw_addr_data *bcast_addr, uint16_t arp_type); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 8b517982b65..463f95ea29b 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -196,44 +196,55 @@ int sd_dhcp_client_set_mac( assert_return(client, -EINVAL); assert_return(!sd_dhcp_client_is_running(client), -EBUSY); - assert_return(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND, ARPHRD_RAWIP, ARPHRD_NONE), -EINVAL); - static const uint8_t default_eth_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, - default_eth_hwaddr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const uint8_t default_eth_hwaddr[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; switch (arp_type) { + case ARPHRD_ETHER: + assert_return(addr_len == ETH_ALEN, -EINVAL); + assert_return(hw_addr, -EINVAL); + break; + + case ARPHRD_INFINIBAND: + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + assert_return(hw_addr, -EINVAL); + break; + case ARPHRD_RAWIP: case ARPHRD_NONE: - /* Linux cellular modem drivers (e.g. qmi_wwan) present a - * network interface of type ARPHRD_RAWIP(519) or - * ARPHRD_NONE(65534) when in point-to-point mode, but these - * are not valid DHCP hardware-type values. + /* Linux cellular modem drivers (e.g. qmi_wwan) present a network interface of type + * ARPHRD_RAWIP(519) or ARPHRD_NONE(65534) when in point-to-point mode, but these are not + * valid DHCP hardware-type values. * - * Apparently, it's best to just pretend that these are ethernet - * devices. Other approaches have been tried, but resulted in - * incompatibilities with some server software. See - * https://lore.kernel.org/netdev/cover.1228948072.git.inaky@linux.intel.com/ - */ + * Apparently, it's best to just pretend that these are ethernet devices. Other approaches + * have been tried, but resulted in incompatibilities with some server software. See + * https://lore.kernel.org/netdev/cover.1228948072.git.inaky@linux.intel.com/ */ arp_type = ARPHRD_ETHER; if (addr_len == 0) { - assert_cc(sizeof(default_eth_hwaddr) == ETH_ALEN); - assert_cc(sizeof(default_eth_bcast) == ETH_ALEN); - hw_addr = default_eth_hwaddr; - bcast_addr = default_eth_bcast; + /* If the specified hardware address length is 0, always use the default ones. */ addr_len = ETH_ALEN; + hw_addr = default_eth_hwaddr; + bcast_addr = NULL; + } else if (addr_len == ETH_ALEN) { + /* If the specified hardware address length is ETH_ALEN, use the default ones when + * unspecified. */ + if (!hw_addr) + hw_addr = default_eth_hwaddr; + } else { + /* Otherwise, user must specify valid addresses. */ + assert_return(hw_addr, -EINVAL); + assert_return(bcast_addr, -EINVAL); } break; - } - assert_return(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND), -EINVAL); - assert_return(hw_addr, -EINVAL); - assert_return(addr_len == (arp_type == ARPHRD_ETHER ? ETH_ALEN : INFINIBAND_ALEN), -EINVAL); + default: + return -EINVAL; + } client->arp_type = arp_type; hw_addr_set(&client->hw_addr, hw_addr, addr_len); hw_addr_set(&client->bcast_addr, bcast_addr, bcast_addr ? addr_len : 0); - - return 0; + return hw_addr_ensure_broadcast(&client->bcast_addr, arp_type); } int sd_dhcp_client_get_client_id(sd_dhcp_client *client, const sd_dhcp_client_id **ret) { @@ -2069,6 +2080,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); assert_return(client->ifindex > 0, -EINVAL); + assert_return(!hw_addr_is_null(&client->bcast_addr), -EINVAL); /* If no client identifier exists, construct an RFC 4361-compliant one */ if (!sd_dhcp_client_id_is_set(&client->client_id)) {