diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index e875696a1a..2af2ce02e5 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include +#include #include #include #include @@ -9,6 +10,20 @@ #include "macro.h" #include "string-util.h" +char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) { + assert(addr); + assert(buffer); + assert(addr->length <= HW_ADDR_MAX_SIZE); + + for (size_t i = 0; i < addr->length; i++) { + sprintf(&buffer[3*i], "%02"PRIx8, addr->addr.bytes[i]); + if (i < addr->length - 1) + buffer[3*i + 2] = ':'; + } + + return buffer; +} + char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { assert(addr); assert(buffer); diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 4e44b30be9..462caded03 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -1,11 +1,35 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once +#include #include #include #include "hash-funcs.h" +/* This is MAX_ADDR_LEN as defined in linux/netdevice.h, but net/if_arp.h + * defines a macro of the same name with a much lower size. */ +#define HW_ADDR_MAX_SIZE 32 + +union hw_addr_union { + struct ether_addr ether; + uint8_t infiniband[INFINIBAND_ALEN]; + uint8_t bytes[HW_ADDR_MAX_SIZE]; +}; + +typedef struct hw_addr_data { + union hw_addr_union addr; + size_t length; +} hw_addr_data; + +#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE) +char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]); + +/* Use only as function argument, never stand-alone! */ +#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){}) + +#define HW_ADDR_NULL ((const hw_addr_data){}) + #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X" #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index 7e8149487a..d0c99f985b 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -29,10 +29,10 @@ typedef struct DHCPServerData { extern const struct hash_ops dhcp_option_hash_ops; -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, uint16_t arp_type, - uint16_t port); +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_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 f48e7c3490..c5ee7e7ef2 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -19,9 +19,9 @@ #include "unaligned.h" static int _bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, + 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) { @@ -104,9 +104,9 @@ 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 = mac_addr_len, + .sll_halen = bcast_addr_len, }; - memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len); + memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll)); if (r < 0) @@ -115,34 +115,44 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, return TAKE_FD(s); } -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, uint16_t arp_type, - uint16_t port) { +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) { 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 - }; + }; struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } }; - const uint8_t *bcast_addr = NULL; + 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); - bcast_addr = eth_bcast; dhcp_hlen = ETH_ALEN; + + default_bcast_addr = eth_bcast; + expected_bcast_addr_len = ETH_ALEN; } else if (arp_type == ARPHRD_INFINIBAND) { - assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL); - bcast_addr = ib_bcast; + default_bcast_addr = ib_bcast; + expected_bcast_addr_len = INFINIBAND_ALEN; } else return -EINVAL; - return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len, - bcast_addr, ð_mac, arp_type, dhcp_hlen, port); + 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/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 2bfe64a81c..d95bbd3167 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,6 +82,8 @@ struct sd_dhcp_client { 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; uint16_t arp_type; sd_dhcp_client_id client_id; size_t client_id_len; @@ -277,6 +279,7 @@ int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) { int sd_dhcp_client_set_mac( sd_dhcp_client *client, const uint8_t *addr, + const uint8_t *bcast_addr, size_t addr_len, uint16_t arp_type) { @@ -297,7 +300,9 @@ int sd_dhcp_client_set_mac( return -EINVAL; if (client->mac_addr_len == addr_len && - memcmp(&client->mac_addr, addr, addr_len) == 0) + 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)) { @@ -309,6 +314,12 @@ int sd_dhcp_client_set_mac( 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); @@ -1381,9 +1392,10 @@ 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->arp_type, client->port); + 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->arp_type, client->port); if (r < 0) { client_stop(client, r); return r; @@ -1431,10 +1443,10 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) client->state = DHCP_STATE_REBINDING; client->attempt = 0; - r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, - client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type, - client->port); + 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->arp_type, client->port); if (r < 0) { client_stop(client, r); return 0; diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 4d748ea66d..b916212d6f 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -23,6 +23,7 @@ #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 }; typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp); @@ -247,6 +248,7 @@ int dhcp_network_bind_raw_socket( union sockaddr_union *link, uint32_t id, const uint8_t *addr, size_t addr_len, + const uint8_t *bcaddr, size_t bcaddr_len, uint16_t arp_type, uint16_t port) { if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0) @@ -296,7 +298,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, ETH_ALEN, ARPHRD_ETHER) >= 0); + assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0); assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0); @@ -513,7 +515,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, ETH_ALEN, ARPHRD_ETHER) >= 0); + assert_se(sd_dhcp_client_set_mac(client, mac_addr, bcast_addr, ETH_ALEN, ARPHRD_ETHER) >= 0); assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e) >= 0); diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index da4f5ba688..2ffff861b2 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -495,6 +495,25 @@ int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short t return 0; } +int netlink_message_append_hw_addr(sd_netlink_message *m, unsigned short type, const hw_addr_data *data) { + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + assert_return(data, -EINVAL); + assert_return(data->length > 0, -EINVAL); + + r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR); + if (r < 0) + return r; + + r = add_rtattr(m, type, data->addr.bytes, data->length); + if (r < 0) + return r; + + return 0; +} + int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) { int r; @@ -864,6 +883,30 @@ int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short typ return 0; } +int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, hw_addr_data *data) { + int r; + void *attr_data; + + assert_return(m, -EINVAL); + + r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR); + if (r < 0) + return r; + + r = netlink_message_read_internal(m, type, &attr_data, NULL); + if (r < 0) + return r; + else if ((size_t) r > sizeof(union hw_addr_union)) + return -EIO; + + if (data) { + memcpy(data->addr.bytes, attr_data, r); + data->length = r; + } + + return 0; +} + int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) { int r; void *attr_data; diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index 2768d5fdc4..8f6c06af6e 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -5,6 +5,7 @@ #include "sd-netlink.h" +#include "ether-addr-util.h" #include "in-addr-util.h" #include "ordered-set.h" #include "socket-util.h" @@ -100,9 +101,11 @@ int rtnl_log_create_error(int r); userdata, description); \ }) +int netlink_message_append_hw_addr(sd_netlink_message *m, unsigned short type, const hw_addr_data *data); int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data); int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data); +int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, hw_addr_data *data); int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short type, int family, union in_addr_union *data); void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 86e53e6da4..142ffc33e1 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -135,7 +135,7 @@ typedef struct LinkInfo { sd_device *sd_device; int ifindex; unsigned short iftype; - struct ether_addr mac_address; + hw_addr_data hw_address; struct ether_addr permanent_mac_address; uint32_t master; uint32_t mtu; @@ -416,13 +416,14 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns, b info->alternative_names = TAKE_PTR(altnames); info->has_mac_address = - sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 && - memcmp(&info->mac_address, ÐER_ADDR_NULL, sizeof(struct ether_addr)) != 0; + netlink_message_read_hw_addr(m, IFLA_ADDRESS, &info->hw_address) >= 0 && + memcmp(&info->hw_address, &HW_ADDR_NULL, sizeof(hw_addr_data)) != 0; info->has_permanent_mac_address = ethtool_get_permanent_macaddr(NULL, info->name, &info->permanent_mac_address) >= 0 && memcmp(&info->permanent_mac_address, ÐER_ADDR_NULL, sizeof(struct ether_addr)) != 0 && - memcmp(&info->permanent_mac_address, &info->mac_address, sizeof(struct ether_addr)) != 0; + (info->hw_address.length != sizeof(struct ether_addr) || + memcmp(&info->permanent_mac_address, info->hw_address.addr.bytes, sizeof(struct ether_addr)) != 0); (void) sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu); (void) sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu); @@ -1526,9 +1527,9 @@ static int link_status_one( if (info->has_mac_address) { _cleanup_free_ char *description = NULL; - char ea[ETHER_ADDR_TO_STRING_MAX]; - (void) ieee_oui(hwdb, &info->mac_address, &description); + if (info->hw_address.length == ETH_ALEN) + (void) ieee_oui(hwdb, &info->hw_address.addr.ether, &description); r = table_add_many(table, TABLE_EMPTY, @@ -1536,7 +1537,7 @@ static int link_status_one( if (r < 0) return table_log_add_error(r); r = table_add_cell_stringf(table, NULL, "%s%s%s%s", - ether_addr_to_string(&info->mac_address, ea), + HW_ADDR_TO_STR(&info->hw_address), description ? " (" : "", strempty(description), description ? ")" : ""); diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 9130fae778..d24104d55a 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include +#include #include "alloc-util.h" #include "firewall-util.h" @@ -21,16 +22,24 @@ int generate_ipv6_eui_64_address(const Link *link, struct in6_addr *ret) { assert(link); assert(ret); + if (link->iftype == ARPHRD_INFINIBAND) { + /* see RFC4391 section 8 */ + memcpy(&ret->s6_addr[8], &link->hw_addr.addr.infiniband[12], 8); + ret->s6_addr[8] ^= 1 << 1; + + return 0; + } + /* see RFC4291 section 2.5.1 */ - ret->s6_addr[8] = link->mac.ether_addr_octet[0]; + ret->s6_addr[8] = link->hw_addr.addr.ether.ether_addr_octet[0]; ret->s6_addr[8] ^= 1 << 1; - ret->s6_addr[9] = link->mac.ether_addr_octet[1]; - ret->s6_addr[10] = link->mac.ether_addr_octet[2]; + ret->s6_addr[9] = link->hw_addr.addr.ether.ether_addr_octet[1]; + ret->s6_addr[10] = link->hw_addr.addr.ether.ether_addr_octet[2]; ret->s6_addr[11] = 0xff; ret->s6_addr[12] = 0xfe; - ret->s6_addr[13] = link->mac.ether_addr_octet[3]; - ret->s6_addr[14] = link->mac.ether_addr_octet[4]; - ret->s6_addr[15] = link->mac.ether_addr_octet[5]; + ret->s6_addr[13] = link->hw_addr.addr.ether.ether_addr_octet[3]; + ret->s6_addr[14] = link->hw_addr.addr.ether.ether_addr_octet[4]; + ret->s6_addr[15] = link->hw_addr.addr.ether.ether_addr_octet[5]; return 0; } @@ -1373,7 +1382,7 @@ static int ipv4_dad_configure(Address *address) { if (r < 0) return r; - r = sd_ipv4acd_set_mac(address->acd, &address->link->mac); + r = sd_ipv4acd_set_mac(address->acd, &address->link->hw_addr.addr.ether); if (r < 0) return r; @@ -1403,7 +1412,7 @@ static int ipv4_dad_update_mac_one(Address *address) { if (r < 0) return r; - r = sd_ipv4acd_set_mac(address->acd, &address->link->mac); + r = sd_ipv4acd_set_mac(address->acd, &address->link->hw_addr.addr.ether); if (r < 0) return r; diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index bb8c34f7cc..319ef61593 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -650,7 +650,7 @@ static int dhcp4_configure_dad(Link *link) { if (r < 0) return r; - r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->mac); + r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.addr.ether); if (r < 0) return r; @@ -672,7 +672,7 @@ static int dhcp4_dad_update_mac(Link *link) { if (r < 0) return r; - r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->mac); + r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.addr.ether); if (r < 0) return r; @@ -1271,14 +1271,24 @@ static int dhcp4_set_client_identifier(Link *link) { return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); break; } - case DHCP_CLIENT_ID_MAC: + case DHCP_CLIENT_ID_MAC: { + const uint8_t *hw_addr = link->hw_addr.addr.bytes; + size_t hw_addr_len = link->hw_addr.length; + + if (link->iftype == ARPHRD_INFINIBAND && hw_addr_len == INFINIBAND_ALEN) { + /* set_client_id expects only last 8 bytes of an IB address */ + hw_addr += INFINIBAND_ALEN - 8; + hw_addr_len -= INFINIBAND_ALEN - 8; + } + r = sd_dhcp_client_set_client_id(link->dhcp_client, - ARPHRD_ETHER, - (const uint8_t *) &link->mac, - sizeof(link->mac)); + link->iftype, + hw_addr, + hw_addr_len); if (r < 0) return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m"); break; + } default: assert_not_reached("Unknown client identifier type."); } @@ -1325,8 +1335,9 @@ int dhcp4_configure(Link *link) { return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to initialize DHCP4 client: %m"); r = sd_dhcp_client_set_mac(link->dhcp_client, - (const uint8_t *) &link->mac, - sizeof (link->mac), ARPHRD_ETHER); + link->hw_addr.addr.bytes, + link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL, + link->hw_addr.length, link->iftype); if (r < 0) return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m"); @@ -1484,7 +1495,9 @@ int dhcp4_update_mac(Link *link) { if (!link->dhcp_client) return 0; - r = sd_dhcp_client_set_mac(link->dhcp_client, (const uint8_t *) &link->mac, sizeof (link->mac), ARPHRD_ETHER); + r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes, + link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL, + link->hw_addr.length, link->iftype); if (r < 0) return r; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index d9cc4ccf41..e7dc10c2be 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -1357,7 +1357,7 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) { assert(link->network); assert(client); - r = sd_dhcp6_client_set_mac(client, (const uint8_t *) &link->mac, sizeof (link->mac), ARPHRD_ETHER); + r = sd_dhcp6_client_set_mac(client, link->hw_addr.addr.bytes, link->hw_addr.length, link->iftype); if (r < 0) return r; diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 3be395e1ad..2f4107580b 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -181,7 +181,7 @@ int ipv4ll_configure(Link *link) { return r; } - r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac); + r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.addr.ether); if (r < 0) return r; @@ -211,7 +211,7 @@ int ipv4ll_update_mac(Link *link) { if (r < 0) return r; - r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac); + r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.addr.ether); if (r < 0) return r; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9dd29bb203..1eca07771a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -421,9 +421,13 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { if (r < 0) log_link_debug_errno(link, r, "New device has no master, continuing without"); - r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac); + r = netlink_message_read_hw_addr(message, IFLA_ADDRESS, &link->hw_addr); if (r < 0) - log_link_debug_errno(link, r, "MAC address not found for new device, continuing without"); + log_link_debug_errno(link, r, "Hardware address not found for new device, continuing without"); + + r = netlink_message_read_hw_addr(message, IFLA_BROADCAST, &link->bcast_addr); + if (r < 0) + log_link_debug_errno(link, r, "Broadcast address not found for new device, continuing without"); r = ethtool_get_permanent_macaddr(&manager->ethtool_fd, link->ifname, &link->permanent_mac); if (r < 0) @@ -2167,7 +2171,7 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for r = network_get(link->manager, link->iftype, link->sd_device, link->ifname, link->alternative_names, link->driver, - &link->mac, &link->permanent_mac, + &link->hw_addr.addr.ether, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network); if (r == -ENOENT) { link_enter_unmanaged(link); @@ -2302,7 +2306,7 @@ static int link_initialized_and_synced(Link *link) { r = network_get(link->manager, link->iftype, link->sd_device, link->ifname, link->alternative_names, link->driver, - &link->mac, &link->permanent_mac, + &link->hw_addr.addr.ether, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network); if (r == -ENOENT) { link_enter_unmanaged(link); @@ -2697,7 +2701,7 @@ static int link_admin_state_up(Link *link) { int link_update(Link *link, sd_netlink_message *m) { _cleanup_strv_free_ char **s = NULL; - struct ether_addr mac; + hw_addr_data hw_addr; const char *ifname; uint32_t mtu; bool had_carrier, carrier_gained, carrier_lost, link_was_admin_up; @@ -2756,19 +2760,13 @@ int link_update(Link *link, sd_netlink_message *m) { /* The kernel may broadcast NEWLINK messages without the MAC address set, simply ignore them. */ - r = sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &mac); - if (r >= 0 && memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN) != 0) { + r = netlink_message_read_hw_addr(m, IFLA_ADDRESS, &hw_addr); + if (r >= 0 && (link->hw_addr.length != hw_addr.length || + memcmp(link->hw_addr.addr.bytes, hw_addr.addr.bytes, hw_addr.length) != 0)) { - memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN); + memcpy(link->hw_addr.addr.bytes, hw_addr.addr.bytes, hw_addr.length); - log_link_debug(link, "Gained new MAC address: " - "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - mac.ether_addr_octet[0], - mac.ether_addr_octet[1], - mac.ether_addr_octet[2], - mac.ether_addr_octet[3], - mac.ether_addr_octet[4], - mac.ether_addr_octet[5]); + log_link_debug(link, "Gained new hardware address: %s", HW_ADDR_TO_STR(&hw_addr)); r = ipv4ll_update_mac(link); if (r < 0) @@ -2787,7 +2785,7 @@ int link_update(Link *link, sd_netlink_message *m) { return log_link_warning_errno(link, r, "Could not update MAC address for Router Advertisement: %m"); if (link->ndisc) { - r = sd_ndisc_set_mac(link->ndisc, &link->mac); + r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.addr.ether); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC for NDisc: %m"); } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index a7ae2645f9..159e7e705b 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -16,6 +16,7 @@ #include "sd-radv.h" #include "sd-netlink.h" +#include "ether-addr-util.h" #include "log-link.h" #include "network-util.h" #include "networkd-util.h" @@ -52,7 +53,8 @@ typedef struct Link { char *kind; unsigned short iftype; char *state_file; - struct ether_addr mac; + hw_addr_data hw_addr; + hw_addr_data bcast_addr; struct ether_addr permanent_mac; struct in6_addr ipv6ll_address; uint32_t mtu; diff --git a/src/network/networkd-lldp-rx.c b/src/network/networkd-lldp-rx.c index 65a8a314d6..4d431ac840 100644 --- a/src/network/networkd-lldp-rx.c +++ b/src/network/networkd-lldp-rx.c @@ -93,7 +93,7 @@ int link_lldp_rx_configure(Link *link) { if (r < 0) return r; - r = sd_lldp_set_filter_address(link->lldp, &link->mac); + r = sd_lldp_set_filter_address(link->lldp, &link->hw_addr.addr.ether); if (r < 0) return r; diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index c8e56a5fec..4a1b5fb5f8 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -313,7 +313,7 @@ static int link_send_lldp(Link *link) { SD_LLDP_SYSTEM_CAPABILITIES_STATION; r = lldp_make_packet(link->network->lldp_emit, - &link->mac, + &link->hw_addr.addr.ether, sd_id128_to_string(machine_id, machine_id_string), link->ifname, (uint16_t) ttl, diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 6fde8fe239..a61eaa9fc8 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "sd-ndisc.h" @@ -593,7 +594,11 @@ static int make_stableprivate_address(Link *link, const struct in6_addr *prefix, l = MAX(DIV_ROUND_UP(prefix_len, 8), 8); siphash24_compress(prefix, l, &state); siphash24_compress_string(link->ifname, &state); - siphash24_compress(&link->mac, sizeof(struct ether_addr), &state); + /* Only last 8 bytes of IB MAC are stable */ + if (link->iftype == ARPHRD_INFINIBAND) + siphash24_compress(&link->hw_addr.addr.infiniband[12], 8, &state); + else + siphash24_compress(link->hw_addr.addr.bytes, link->hw_addr.length, &state); siphash24_compress(&dad_counter, sizeof(uint8_t), &state); rid = htole64(siphash24_finalize(&state)); @@ -1257,7 +1262,7 @@ int ndisc_configure(Link *link) { return r; } - r = sd_ndisc_set_mac(link->ndisc, &link->mac); + r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.addr.ether); if (r < 0) return r; diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index eb10f21cbd..a4162cf874 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -659,7 +659,7 @@ int radv_configure(Link *link) { if (r < 0) return r; - r = sd_radv_set_mac(link->radv, &link->mac); + r = sd_radv_set_mac(link->radv, &link->hw_addr.addr.ether); if (r < 0) return r; @@ -727,7 +727,7 @@ int radv_update_mac(Link *link) { if (r < 0) return r; - r = sd_radv_set_mac(link->radv, &link->mac); + r = sd_radv_set_mac(link->radv, &link->hw_addr.addr.ether); if (r < 0) return r; diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index ac3b5b369c..e0aa93a55b 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -126,6 +126,7 @@ int sd_dhcp_client_set_ifindex( int sd_dhcp_client_set_mac( sd_dhcp_client *client, const uint8_t *addr, + const uint8_t *bcast_addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(