diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index c609ea6ce0..0a6a54f8f1 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -33,6 +33,15 @@ char *hw_addr_to_string_full( return buffer; } +struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length) { + assert(addr); + assert(length <= HW_ADDR_MAX_SIZE); + + addr->length = length; + memcpy_safe(addr->bytes, bytes, length); + return addr; +} + int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b) { int r; diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 32f45fe813..83ed77d634 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -52,6 +52,8 @@ static inline char *hw_addr_to_string(const struct hw_addr_data *addr, char buff #define HW_ADDR_NULL ((const struct hw_addr_data){}) +struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length); + void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state); int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b); static inline bool hw_addr_equal(const struct hw_addr_data *a, const struct hw_addr_data *b) { diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 326b09ac5e..68f6a7cb3c 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -63,20 +63,26 @@ int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict) { return 0; } -static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, uint16_t arp_type, usec_t t, struct duid *ret_duid, size_t *ret_len) { +static int dhcp_identifier_set_duid_llt( + const struct hw_addr_data *hw_addr, + uint16_t arp_type, + usec_t t, + struct duid *ret_duid, + size_t *ret_len) { + uint16_t time_from_2000y; - assert(addr); + assert(hw_addr); assert(ret_duid); assert(ret_len); - if (addr_len == 0) + if (hw_addr->length == 0) return -EOPNOTSUPP; if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); + assert_return(hw_addr->length == ETH_ALEN, -EINVAL); else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL); else return -EOPNOTSUPP; @@ -88,33 +94,38 @@ static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, ui unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT); unaligned_write_be16(&ret_duid->llt.htype, arp_type); unaligned_write_be32(&ret_duid->llt.time, time_from_2000y); - memcpy(ret_duid->llt.haddr, addr, addr_len); + memcpy(ret_duid->llt.haddr, hw_addr->bytes, hw_addr->length); - *ret_len = offsetof(struct duid, llt.haddr) + addr_len; + *ret_len = offsetof(struct duid, llt.haddr) + hw_addr->length; return 0; } -static int dhcp_identifier_set_duid_ll(const uint8_t *addr, size_t addr_len, uint16_t arp_type, struct duid *ret_duid, size_t *ret_len) { - assert(addr); +static int dhcp_identifier_set_duid_ll( + const struct hw_addr_data *hw_addr, + uint16_t arp_type, + struct duid *ret_duid, + size_t *ret_len) { + + assert(hw_addr); assert(ret_duid); assert(ret_len); - if (addr_len == 0) + if (hw_addr->length == 0) return -EOPNOTSUPP; if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); + assert_return(hw_addr->length == ETH_ALEN, -EINVAL); else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL); else return -EOPNOTSUPP; unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL); unaligned_write_be16(&ret_duid->ll.htype, arp_type); - memcpy(ret_duid->ll.haddr, addr, addr_len); + memcpy(ret_duid->ll.haddr, hw_addr->bytes, hw_addr->length); - *ret_len = offsetof(struct duid, ll.haddr) + addr_len; + *ret_len = offsetof(struct duid, ll.haddr) + hw_addr->length; return 0; } @@ -174,8 +185,7 @@ static int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) int dhcp_identifier_set_duid( DUIDType duid_type, - const uint8_t *addr, - size_t addr_len, + const struct hw_addr_data *hw_addr, uint16_t arp_type, usec_t llt_time, bool test_mode, @@ -184,11 +194,11 @@ int dhcp_identifier_set_duid( switch (duid_type) { case DUID_TYPE_LLT: - return dhcp_identifier_set_duid_llt(addr, addr_len, arp_type, llt_time, ret_duid, ret_len); + return dhcp_identifier_set_duid_llt(hw_addr, arp_type, llt_time, ret_duid, ret_len); case DUID_TYPE_EN: return dhcp_identifier_set_duid_en(test_mode, ret_duid, ret_len); case DUID_TYPE_LL: - return dhcp_identifier_set_duid_ll(addr, addr_len, arp_type, ret_duid, ret_len); + return dhcp_identifier_set_duid_ll(hw_addr, arp_type, ret_duid, ret_len); case DUID_TYPE_UUID: return dhcp_identifier_set_duid_uuid(ret_duid, ret_len); default: @@ -198,8 +208,7 @@ int dhcp_identifier_set_duid( int dhcp_identifier_set_iaid( int ifindex, - const uint8_t *mac, - size_t mac_len, + const struct hw_addr_data *hw_addr, bool legacy_unstable_byteorder, bool use_mac, void *ret) { @@ -212,6 +221,10 @@ int dhcp_identifier_set_iaid( uint64_t id; int r; + assert(ifindex > 0); + assert(hw_addr); + assert(ret); + if (udev_available() && !use_mac) { /* udev should be around */ @@ -240,7 +253,7 @@ int dhcp_identifier_set_iaid( id = siphash24(name, strlen(name), HASH_KEY.bytes); else /* fall back to MAC address if no predictable name available */ - id = siphash24(mac, mac_len, HASH_KEY.bytes); + id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes); id32 = (id & 0xffffffff) ^ (id >> 32); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 697ba3bfbb..8acb8c3210 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -3,6 +3,7 @@ #include "sd-id128.h" +#include "ether-addr-util.h" #include "macro.h" #include "sparse-endian.h" #include "time-util.h" @@ -58,8 +59,7 @@ int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict); int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len); int dhcp_identifier_set_duid( DUIDType duid_type, - const uint8_t *addr, - size_t addr_len, + const struct hw_addr_data *hw_addr, uint16_t arp_type, usec_t llt_time, bool test_mode, @@ -67,8 +67,7 @@ int dhcp_identifier_set_duid( size_t *ret_len); int dhcp_identifier_set_iaid( int ifindex, - const uint8_t *mac, - size_t mac_len, + const struct hw_addr_data *hw_addr, bool legacy_unstable_byteorder, bool use_mac, void *ret); diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index 466d8e4b3f..a311d1d5b9 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -12,6 +12,7 @@ #include "sd-dhcp-client.h" #include "dhcp-protocol.h" +#include "ether-addr-util.h" #include "network-common.h" #include "socket-util.h" @@ -32,10 +33,14 @@ extern const struct hash_ops dhcp_option_hash_ops; typedef struct sd_dhcp_client sd_dhcp_client; -int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, - const uint8_t *mac_addr, size_t mac_addr_len, - const uint8_t *bcast_addr, size_t bcast_addr_len, - uint16_t arp_type, uint16_t port); +int dhcp_network_bind_raw_socket( + int ifindex, + union sockaddr_union *link, + uint32_t xid, + const struct hw_addr_data *hw_addr, + const struct hw_addr_data *bcast_addr, + uint16_t arp_type, + uint16_t port); int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type); int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len); diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index 7abdaa515b..0ee977a8c8 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -18,13 +18,34 @@ #include "socket-util.h" #include "unaligned.h" -static int _bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, - const uint8_t *bcast_addr, - size_t bcast_addr_len, - const struct ether_addr *eth_mac, - uint16_t arp_type, uint8_t dhcp_hlen, - uint16_t port) { +static int _bind_raw_socket( + int ifindex, + union sockaddr_union *link, + uint32_t xid, + const struct hw_addr_data *hw_addr, + const struct hw_addr_data *bcast_addr, + uint16_t arp_type, + uint16_t port) { + + assert(ifindex > 0); + assert(link); + assert(hw_addr); + assert(bcast_addr); + assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND)); + + switch (arp_type) { + case ARPHRD_ETHER: + assert(hw_addr->length == ETH_ALEN); + assert(bcast_addr->length == ETH_ALEN); + break; + case ARPHRD_INFINIBAND: + assert(hw_addr->length == 0); + assert(bcast_addr->length == INFINIBAND_ALEN); + break; + default: + assert_not_reached(); + } + struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */ @@ -53,20 +74,20 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (uint8_t) hw_addr->length, 1, 0), /* address length == hw_addr->length ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally * compare chaddr for ETH_ALEN bytes. */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */ - BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */ + BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(hw_addr->bytes)), /* X <- 4 bytes of client's MAC */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(hw_addr->bytes + 4)), /* X <- remainder of client's MAC */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */ @@ -80,9 +101,6 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, _cleanup_close_ int s = -1; int r; - assert(ifindex > 0); - assert(link); - s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (s < 0) return -errno; @@ -100,9 +118,10 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, .sll_protocol = htobe16(ETH_P_IP), .sll_ifindex = ifindex, .sll_hatype = htobe16(arp_type), - .sll_halen = bcast_addr_len, + .sll_halen = bcast_addr->length, }; - memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */ + /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */ + memcpy(link->ll.sll_addr, bcast_addr->bytes, bcast_addr->length); r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll)); if (r < 0) @@ -115,47 +134,42 @@ int dhcp_network_bind_raw_socket( int ifindex, union sockaddr_union *link, uint32_t xid, - const uint8_t *mac_addr, - size_t mac_addr_len, - const uint8_t *bcast_addr, - size_t bcast_addr_len, + const struct hw_addr_data *hw_addr, + const struct hw_addr_data *bcast_addr, uint16_t arp_type, uint16_t port) { - static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - /* Default broadcast address for IPoIB */ - static const uint8_t ib_bcast[] = { - 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff + static struct hw_addr_data default_eth_bcast = { + .length = ETH_ALEN, + .ether = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}, + }, default_ib_bcast = { + .length = INFINIBAND_ALEN, + .infiniband = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff + }, }; - struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } }; - const uint8_t *default_bcast_addr; - size_t expected_bcast_addr_len; - uint8_t dhcp_hlen = 0; - if (arp_type == ARPHRD_ETHER) { - assert_return(mac_addr_len == ETH_ALEN, -EINVAL); - memcpy(ð_mac, mac_addr, ETH_ALEN); - dhcp_hlen = ETH_ALEN; + assert(ifindex > 0); + assert(link); + assert(hw_addr); - default_bcast_addr = eth_bcast; - expected_bcast_addr_len = ETH_ALEN; - } else if (arp_type == ARPHRD_INFINIBAND) { - default_bcast_addr = ib_bcast; - expected_bcast_addr_len = INFINIBAND_ALEN; - } else + switch (arp_type) { + case ARPHRD_ETHER: + return _bind_raw_socket(ifindex, link, xid, + hw_addr, + (bcast_addr && !hw_addr_is_null(bcast_addr)) ? bcast_addr : &default_eth_bcast, + arp_type, port); + + case ARPHRD_INFINIBAND: + return _bind_raw_socket(ifindex, link, xid, + &HW_ADDR_NULL, + (bcast_addr && !hw_addr_is_null(bcast_addr)) ? bcast_addr : &default_ib_bcast, + arp_type, port); + default: return -EINVAL; - - if (bcast_addr && bcast_addr_len > 0) - assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL); - else { - bcast_addr = default_bcast_addr; - bcast_addr_len = expected_bcast_addr_len; } - - return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len, - ð_mac, arp_type, dhcp_hlen, port); } int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) { diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index dd54bcf6ee..c4972d144c 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -43,9 +43,10 @@ typedef struct DHCPPacket DHCPPacket; #define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr)) #define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE) -#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage)) -#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */ -#define DHCP_MIN_OPTIONS_SIZE (DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE) +#define DHCP_HEADER_SIZE (int32_t)(sizeof(DHCPMessage)) +#define DHCP_MIN_MESSAGE_SIZE 576 /* the minimum internet hosts must be able to receive, see RFC 2132 Section 9.10 */ +#define DHCP_MIN_OPTIONS_SIZE (DHCP_MIN_MESSAGE_SIZE - DHCP_HEADER_SIZE) +#define DHCP_MIN_PACKET_SIZE (DHCP_MIN_MESSAGE_SIZE + DHCP_IP_UDP_SIZE) #define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363) enum { diff --git a/src/libsystemd-network/fuzz-dhcp-client.c b/src/libsystemd-network/fuzz-dhcp-client.c index 1812a61950..a9cfba90e3 100644 --- a/src/libsystemd-network/fuzz-dhcp-client.c +++ b/src/libsystemd-network/fuzz-dhcp-client.c @@ -14,8 +14,8 @@ int dhcp_network_bind_raw_socket( int ifindex, union sockaddr_union *link, uint32_t id, - const uint8_t *addr, size_t addr_len, - const uint8_t *bcaddr, size_t bcaddr_len, + const struct hw_addr_data *hw_addr, + const struct hw_addr_data *bcast_addr, uint16_t arp_type, uint16_t port) { int fd; diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index d2c6361cb8..5b7e3640e8 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -19,6 +19,7 @@ #include "dhcp-lease-internal.h" #include "dhcp-protocol.h" #include "dns-domain.h" +#include "ether-addr-util.h" #include "event-util.h" #include "fd-util.h" #include "hostname-util.h" @@ -86,10 +87,8 @@ struct sd_dhcp_client { Set *req_opts; bool anonymize; be32_t last_addr; - uint8_t mac_addr[MAX_MAC_ADDR_LEN]; - size_t mac_addr_len; - uint8_t bcast_addr[MAX_MAC_ADDR_LEN]; - size_t bcast_addr_len; + struct hw_addr_data hw_addr; + struct hw_addr_data bcast_addr; uint16_t arp_type; sd_dhcp_client_id client_id; size_t client_id_len; @@ -237,6 +236,7 @@ int sd_dhcp_client_set_callback( int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); client->request_broadcast = broadcast; @@ -245,7 +245,7 @@ int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); switch (option) { @@ -268,7 +268,7 @@ int sd_dhcp_client_set_request_address( const struct in_addr *last_addr) { assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); if (last_addr) client->last_addr = last_addr->s_addr; @@ -280,7 +280,7 @@ int sd_dhcp_client_set_request_address( int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) { assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(ifindex > 0, -EINVAL); client->ifindex = ifindex; @@ -314,54 +314,20 @@ int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret) { int sd_dhcp_client_set_mac( sd_dhcp_client *client, - const uint8_t *addr, + const uint8_t *hw_addr, const uint8_t *bcast_addr, size_t addr_len, uint16_t arp_type) { - DHCP_CLIENT_DONT_DESTROY(client); - bool need_restart = false; - int r; - assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); - assert_return(arp_type > 0, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); + 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); - 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 (client->mac_addr_len == addr_len && - memcmp(&client->mac_addr, addr, addr_len) == 0 && - (client->bcast_addr_len > 0) == !!bcast_addr && - (!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0)) - return 0; - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting"); - need_restart = true; - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - } - - memcpy(&client->mac_addr, addr, addr_len); - client->mac_addr_len = addr_len; client->arp_type = arp_type; - client->bcast_addr_len = 0; - - if (bcast_addr) { - memcpy(&client->bcast_addr, bcast_addr, addr_len); - client->bcast_addr_len = addr_len; - } - - if (need_restart && client->state != DHCP_STATE_STOPPED) { - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } + 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; } @@ -396,19 +362,11 @@ int sd_dhcp_client_set_client_id( const uint8_t *data, size_t data_len) { - DHCP_CLIENT_DONT_DESTROY(client); - bool need_restart = false; - int r; - assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(data, -EINVAL); assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL); - 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 @@ -420,23 +378,10 @@ int sd_dhcp_client_set_client_id( "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"); - need_restart = true; - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - } - client->client_id.type = type; memcpy(&client->client_id.raw.data, data, data_len); client->client_id_len = data_len + sizeof (client->client_id.type); - if (need_restart && client->state != DHCP_STATE_STOPPED) { - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } - return 0; } @@ -455,11 +400,11 @@ static int dhcp_client_set_iaid_duid_internal( size_t duid_len, usec_t llt_time) { - DHCP_CLIENT_DONT_DESTROY(client); - int r; size_t len; + int r; assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(duid_len == 0 || duid, -EINVAL); if (duid) { @@ -475,8 +420,7 @@ static int dhcp_client_set_iaid_duid_internal( 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, + r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr, /* legacy_unstable_byteorder = */ true, /* use_mac = */ client->test_mode, &client->client_id.ns.iaid); @@ -491,7 +435,7 @@ static int dhcp_client_set_iaid_duid_internal( len = sizeof(client->client_id.ns.duid.type) + duid_len; } else { - r = dhcp_identifier_set_duid(duid_type, client->mac_addr, client->mac_addr_len, + r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time, client->test_mode, &client->client_id.ns.duid, &len); if (r == -EOPNOTSUPP) @@ -507,14 +451,6 @@ static int dhcp_client_set_iaid_duid_internal( client->client_id_len = sizeof(client->client_id.type) + len + (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 %sDUID, restarting.", iaid_append ? "IAID+" : ""); - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } - return 0; } @@ -561,6 +497,7 @@ int sd_dhcp_client_set_hostname( const char *hostname) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); /* Make sure hostnames qualify as DNS and as Linux hostnames */ if (hostname && @@ -575,6 +512,7 @@ int sd_dhcp_client_set_vendor_class_identifier( const char *vci) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); return free_and_strdup(&client->vendor_class_identifier, vci); } @@ -584,6 +522,7 @@ int sd_dhcp_client_set_mud_url( const char *mudurl) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(mudurl, -EINVAL); assert_return(strlen(mudurl) <= 255, -EINVAL); assert_return(http_url_is_valid(mudurl), -EINVAL); @@ -598,6 +537,7 @@ int sd_dhcp_client_set_user_class( char **s = NULL; assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(!strv_isempty(user_class), -EINVAL); STRV_FOREACH(p, user_class) { @@ -619,6 +559,7 @@ int sd_dhcp_client_set_client_port( uint16_t port) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); client->port = port; @@ -627,7 +568,10 @@ int sd_dhcp_client_set_client_port( int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { assert_return(client, -EINVAL); - assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE); + assert_return(mtu >= DHCP_MIN_PACKET_SIZE, -ERANGE); + + /* MTU may be changed by the acquired lease. Hence, we cannot require that the client is stopped here. + * Please do not add assertion for !sd_dhcp_client_is_running(client) here. */ client->mtu = mtu; @@ -636,6 +580,7 @@ int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); client->max_attempts = max_attempts; @@ -646,6 +591,7 @@ int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) { int r; assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(v, -EINVAL); r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp_option_hash_ops, UINT_TO_PTR(v->option), v); @@ -660,6 +606,7 @@ int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) int r; assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(v, -EINVAL); r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops); @@ -689,6 +636,7 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); client->ip_service_type = type; @@ -697,6 +645,7 @@ int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) { int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); assert_return(fallback_lease_lifetime > 0, -EINVAL); client->fallback_lease_lifetime = fallback_lease_lifetime; @@ -794,7 +743,6 @@ static int client_message_init( _cleanup_free_ DHCPPacket *packet = NULL; size_t optlen, optoffset, size; - be16_t max_size; usec_t time_now; uint16_t secs; int r; @@ -814,7 +762,7 @@ static int client_message_init( return -ENOMEM; r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type, - client->arp_type, client->mac_addr_len, client->mac_addr, + client->arp_type, client->hw_addr.length, client->hw_addr.bytes, optlen, &optoffset); if (r < 0) return r; @@ -851,7 +799,7 @@ static int client_message_init( client->client_id.type = 255; - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, + r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr, /* legacy_unstable_byteorder = */ true, /* use_mac = */ client->test_mode, &client->client_id.ns.iaid); @@ -937,9 +885,9 @@ static int client_message_init( */ /* RFC7844 section 3: SHOULD NOT contain any other option. */ - if (!client->anonymize && type != DHCP_RELEASE) { - max_size = htobe16(size); - r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, + if (!client->anonymize && IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)) { + be16_t max_size = htobe16(MIN(client->mtu - DHCP_IP_UDP_SIZE, (uint32_t) UINT16_MAX)); + r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, 2, &max_size); if (r < 0) @@ -1430,8 +1378,7 @@ static int client_start_delayed(sd_dhcp_client *client) { client->xid = random_u32(); r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, - client->mac_addr, client->mac_addr_len, - client->bcast_addr, client->bcast_addr_len, + &client->hw_addr, &client->bcast_addr, client->arp_type, client->port); if (r < 0) { client_stop(client, r); @@ -1481,8 +1428,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) client->attempt = 0; r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, - client->mac_addr, client->mac_addr_len, - client->bcast_addr, client->bcast_addr_len, + &client->hw_addr, &client->bcast_addr, client->arp_type, client->port); if (r < 0) { client_stop(client, r); @@ -1946,7 +1892,7 @@ static int client_receive_message_udp( if (client->arp_type == ARPHRD_ETHER) { expected_hlen = ETH_ALEN; - expected_chaddr = &client->mac_addr[0]; + expected_chaddr = client->hw_addr.bytes; } if (message->hlen != expected_hlen) { @@ -2042,6 +1988,7 @@ static int client_receive_message_raw( int sd_dhcp_client_send_renew(sd_dhcp_client *client) { assert_return(client, -EINVAL); + assert_return(sd_dhcp_client_is_running(client), -ESTALE); assert_return(client->fd >= 0, -EINVAL); if (!client->lease) @@ -2089,7 +2036,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { int sd_dhcp_client_send_release(sd_dhcp_client *client) { assert_return(client, -EINVAL); - assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE); + assert_return(sd_dhcp_client_is_running(client), -ESTALE); assert_return(client->lease, -EUNATCH); _cleanup_free_ DHCPPacket *release = NULL; @@ -2102,7 +2049,7 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) { /* Fill up release IP and MAC */ release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); + memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length); r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); @@ -2124,7 +2071,7 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) { int sd_dhcp_client_send_decline(sd_dhcp_client *client) { assert_return(client, -EINVAL); - assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE); + assert_return(sd_dhcp_client_is_running(client), -ESTALE); assert_return(client->lease, -EUNATCH); _cleanup_free_ DHCPPacket *release = NULL; @@ -2136,7 +2083,7 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) { return r; release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); + memcpy(&release->dhcp.chaddr, client->hw_addr.bytes, client->hw_addr.length); r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); @@ -2181,6 +2128,7 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t assert_return(client, -EINVAL); assert_return(!client->event, -EBUSY); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); if (event) client->event = sd_event_ref(event); @@ -2197,6 +2145,7 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t int sd_dhcp_client_detach_event(sd_dhcp_client *client) { assert_return(client, -EINVAL); + assert_return(!sd_dhcp_client_is_running(client), -EBUSY); client->event = sd_event_unref(client->event); @@ -2253,7 +2202,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { .state = DHCP_STATE_INIT, .ifindex = -1, .fd = -1, - .mtu = DHCP_DEFAULT_MIN_SIZE, + .mtu = DHCP_MIN_PACKET_SIZE, .port = DHCP_PORT_CLIENT, .anonymize = !!anonymize, .max_attempts = UINT64_MAX, diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 388c5cd2a4..734a4fa27d 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -713,9 +713,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void r = lease_parse_u16(option, len, &lease->mtu, 68); if (r < 0) log_debug_errno(r, "Failed to parse MTU, ignoring: %m"); - if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) { - log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE); - lease->mtu = DHCP_DEFAULT_MIN_SIZE; + if (lease->mtu < DHCP_MIN_PACKET_SIZE) { + log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_MIN_PACKET_SIZE); + lease->mtu = DHCP_MIN_PACKET_SIZE; } break; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 3de10cc199..273dd35e04 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -116,9 +116,8 @@ int sd_dhcp6_client_set_mac( return 0; } - memcpy(client->hw_addr.bytes, addr, addr_len); - client->hw_addr.length = addr_len; client->arp_type = arp_type; + hw_addr_set(&client->hw_addr, addr, addr_len); return 0; } @@ -216,8 +215,8 @@ static int dhcp6_client_set_duid_internal( client->duid_len = sizeof(client->duid.type) + duid_len; } else { - r = dhcp_identifier_set_duid(duid_type, client->hw_addr.bytes, client->hw_addr.length, - client->arp_type, llt_time, client->test_mode, &client->duid, &client->duid_len); + r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time, + client->test_mode, &client->duid, &client->duid_len); if (r == -EOPNOTSUPP) return log_dhcp6_client_errno(client, r, "Failed to set %s. MAC address is not set or " @@ -300,7 +299,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) { if (client->iaid_set) return 0; - r = dhcp_identifier_set_iaid(client->ifindex, client->hw_addr.bytes, client->hw_addr.length, + r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr, /* legacy_unstable_byteorder = */ true, /* use_mac = */ client->test_mode, &iaid); diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index fb86e6c994..8344dc4f4a 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -17,14 +17,19 @@ #include "dhcp-identifier.h" #include "dhcp-internal.h" #include "dhcp-protocol.h" +#include "ether-addr-util.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'}; -static uint8_t bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - +static struct hw_addr_data hw_addr = { + .length = ETH_ALEN, + .ether = {{ 'A', 'B', 'C', '1', '2', '3' }}, +}, bcast_addr = { + .length = ETH_ALEN, + .ether = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }}, +}; typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp); static bool verbose = true; @@ -139,9 +144,9 @@ static void test_dhcp_identifier_set_iaid(void) { uint32_t iaid_legacy; be32_t iaid; - assert_se(dhcp_identifier_set_iaid(42, mac_addr, sizeof(mac_addr), /* legacy = */ true, + assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ true, /* use_mac = */ true, &iaid_legacy) >= 0); - assert_se(dhcp_identifier_set_iaid(42, mac_addr, sizeof(mac_addr), /* legacy = */ false, + assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ false, /* use_mac = */ true, &iaid) >= 0); /* we expect, that the MAC address was hashed. The legacy value is in native @@ -164,7 +169,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(/* test_mode = */ true, &duid, &duid_len) >= 0); - assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, true, /* use_mac = */ true, &iaid) >= 0); + assert_se(dhcp_identifier_set_iaid(42, &hw_addr, /* legacy = */ true, /* use_mac = */ true, &iaid) >= 0); assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len); assert_se(len == 19); @@ -217,7 +222,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const assert_se(ip_check == 0xffff); assert_se(discover->dhcp.xid); - assert_se(memcmp(discover->dhcp.chaddr, &mac_addr, ETH_ALEN) == 0); + assert_se(memcmp(discover->dhcp.chaddr, hw_addr.bytes, hw_addr.length) == 0); size = len - sizeof(struct iphdr) - sizeof(struct udphdr); @@ -231,8 +236,8 @@ int dhcp_network_bind_raw_socket( int ifindex, union sockaddr_union *link, uint32_t id, - const uint8_t *addr, size_t addr_len, - const uint8_t *bcaddr, size_t bcaddr_len, + const struct hw_addr_data *_hw_addr, + const struct hw_addr_data *_bcast_addr, uint16_t arp_type, uint16_t port) { if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0) @@ -282,7 +287,7 @@ static void test_discover_message(sd_event *e) { assert_se(r >= 0); assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0); - assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0); + assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0); dhcp_client_set_test_mode(client, true); assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0); @@ -440,7 +445,7 @@ static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) { memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check)); memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid)); - memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN); + memcpy(&test_addr_acq_ack[56], hw_addr.bytes, hw_addr.length); callback_recv = NULL; @@ -471,7 +476,7 @@ static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) { memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check)); memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid)); - memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN); + memcpy(&test_addr_acq_offer[56], hw_addr.bytes, hw_addr.length); callback_recv = test_addr_acq_recv_request; @@ -500,7 +505,7 @@ static void test_addr_acq(sd_event *e) { assert_se(r >= 0); assert_se(sd_dhcp_client_set_ifindex(client, 42) >= 0); - assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0); + assert_se(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER) >= 0); dhcp_client_set_test_mode(client, true); assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 3795fb32f3..4df2848c54 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -1506,6 +1506,7 @@ static int dhcp4_configure(Link *link) { } int dhcp4_update_mac(Link *link) { + bool restart; int r; assert(link); @@ -1513,13 +1514,30 @@ int dhcp4_update_mac(Link *link) { if (!link->dhcp_client) return 0; - r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.bytes, + restart = sd_dhcp_client_is_running(link->dhcp_client); + + r = sd_dhcp_client_stop(link->dhcp_client); + if (r < 0) + return r; + + r = sd_dhcp_client_set_mac(link->dhcp_client, + link->hw_addr.bytes, link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL, link->hw_addr.length, link->iftype); if (r < 0) return r; - return dhcp4_set_client_identifier(link); + r = dhcp4_set_client_identifier(link); + if (r < 0) + return r; + + if (restart) { + r = sd_dhcp_client_start(link->dhcp_client); + if (r < 0) + return r; + } + + return 0; } int dhcp4_start(Link *link) { diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 855f938b09..6a863794a4 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -247,7 +247,7 @@ int sd_dhcp_client_set_ifname( int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret); int sd_dhcp_client_set_mac( sd_dhcp_client *client, - const uint8_t *addr, + const uint8_t *hw_addr, const uint8_t *bcast_addr, size_t addr_len, uint16_t arp_type);