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);
#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) {
.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)
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) {
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;
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) {
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)) {
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);
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;
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;
#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);
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)
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);
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);
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,
- link->hw_addr.addr.bytes,
- link->hw_addr.length);
+ 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.");
}
r = sd_dhcp_client_set_mac(link->dhcp_client,
link->hw_addr.addr.bytes,
- link->hw_addr.length, ARPHRD_ETHER);
+ 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");
if (!link->dhcp_client)
return 0;
- r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes, link->hw_addr.length, 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;
assert(link->network);
assert(client);
- r = sd_dhcp6_client_set_mac(client, link->hw_addr.addr.bytes, link->hw_addr.length, 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;
if (r < 0)
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)
log_link_debug_errno(link, r, "Permanent MAC address not found for new device, continuing without: %m");
unsigned short iftype;
char *state_file;
hw_addr_data hw_addr;
+ hw_addr_data bcast_addr;
struct ether_addr permanent_mac;
struct in6_addr ipv6ll_address;
uint32_t mtu;
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(