[systemd-devel] [RFC PATCH] sd-dhcp-client: support non-Ethernet hardware addresses

Dan Williams dcbw at redhat.com
Wed Aug 6 09:22:44 PDT 2014


Like Infiniband.  See RFC 4390 section 2.1 for details on DHCP
and Infiniband; chaddr is zeroed, hlen is set to 0, and htype
is set to ARPHRD_INFINIBAND because IB hardware addresses
are 20 bytes in length.
---
NOTE: because of how dhcp_network_bind_raw_socket() does its packet
filter, it's not easy to change some of the checks it uses without
having callers pass the actual values into the function, which seems
redundant.  Thus I opted for the current approach, but that does
add a warning about mixed declarations and code.  Can anyone think
of a better way to do this?

An possible improvement to sd_dhcp_client_set_mac() would be
keying the MAC address length off 'arp_type' instead of
specifying it explicitly.

 src/libsystemd-network/dhcp-internal.h    | 10 +++--
 src/libsystemd-network/dhcp-network.c     | 39 +++++++++++++++----
 src/libsystemd-network/dhcp-packet.c      |  8 ++--
 src/libsystemd-network/sd-dhcp-client.c   | 63 +++++++++++++++++++++++--------
 src/libsystemd-network/sd-dhcp-server.c   |  6 +--
 src/libsystemd-network/test-dhcp-client.c | 14 +++++--
 src/libsystemd-network/test-dhcp-option.c |  2 +-
 src/network/networkd-link.c               |  9 ++++-
 src/systemd/sd-dhcp-client.h              |  4 +-
 9 files changed, 116 insertions(+), 39 deletions(-)

diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index 1069c8a..d358a49 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -20,22 +20,25 @@
 
   You should have received a copy of the GNU Lesser General Public License
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
 #include <stdint.h>
 #include <linux/if_packet.h>
+#include <net/if_arp.h>
 #include <net/ethernet.h>
 
 #include "socket-util.h"
 
 #include "sd-dhcp-client.h"
 #include "dhcp-protocol.h"
 
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid, struct ether_addr mac_addr);
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
+                                 uint32_t xid, const uint8_t *mac_addr,
+                                 size_t mac_addr_len, uint16_t arp_type);
 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port);
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
                                  const void *packet, size_t len);
 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
                                  const void *packet, size_t len);
 
 int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload,
@@ -43,16 +46,17 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_
 
 typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
                                 const uint8_t *option, void *user_data);
 
 int dhcp_option_parse(DHCPMessage *message, size_t len,
                       dhcp_option_cb_t cb, void *user_data);
 
-int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type,
-                      size_t optlen, size_t *optoffset);
+int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
+                      uint8_t type, uint16_t arp_type, size_t optlen,
+                      size_t *optoffset);
 
 uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
 
 void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
                                    uint16_t source, be32_t destination_addr,
                                    uint16_t destination, uint16_t len);
 
diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c
index 1ced5cf..4d82bcf 100644
--- a/src/libsystemd-network/dhcp-network.c
+++ b/src/libsystemd-network/dhcp-network.c
@@ -18,26 +18,45 @@
 ***/
 
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <string.h>
 #include <linux/if_packet.h>
+#include <linux/if_infiniband.h>
 #include <net/ethernet.h>
 #include <net/if_arp.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <linux/filter.h>
 
 #include "socket-util.h"
 
 #include "dhcp-internal.h"
 
+/* Default broadcast address for IPoIB */
+static const uint8_t ib_bcast_addr[20] = {
+        0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0xff, 0xff, 0xff, 0xff
+};
+
 int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
-                                 uint32_t xid, struct ether_addr mac_addr) {
+                                 uint32_t xid, const uint8_t *mac_addr,
+                                 size_t mac_addr_len, uint16_t arp_type) {
+        struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
+        uint8_t dhcp_hlen = 0;
+
+        assert_return(mac_addr_len > 0, -EINVAL);
+
+        if (arp_type == ARPHRD_ETHER) {
+                assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
+                memcpy(&eth_mac, mac_addr, ETH_ALEN);
+                dhcp_hlen = ETH_ALEN;
+        }
 
         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 ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.protocol)), /* A <- IP protocol */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0),                /* IP protocol == UDP ? */
@@ -53,29 +72,29 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
                 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)),    /* A <- UDP destination port */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_PORT_CLIENT, 1, 0),           /* UDP destination port == DHCP client port ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)),     /* A <- DHCP op */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0),                  /* op == BOOTREPLY ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)),  /* A <- DHCP header type */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),               /* header type == ARPHRD_ETHER ? */
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0),                   /* header type == arp_type ? */
                 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, ETHER_ADDR_LEN, 1, 0),             /* address length == ETHER_ADDR_LEN ? */
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0),                  /* address length == dhcp_hlen ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)),    /* A <- client identifier */
                 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_IMM, htobe32(*((unsigned int *) &mac_addr))),                    /* A <- 4 bytes of client's MAC */
+                BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((unsigned int *) &eth_mac))),                     /* A <- 4 bytes of client's MAC */
                 BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)),                 /* A <- 4 bytes of MAC from dhcp.chaddr */
                 BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                          /* A == 0 ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
-                BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) &mac_addr) + 4)))), /* A <- remainder of client's MAC */
+                BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) &eth_mac) + 4)))),  /* A <- remainder of client's MAC */
                 BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
                 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4),             /* A <- remainder of MAC from dhcp.chaddr */
                 BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                          /* A == 0 ? */
                 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 ? */
@@ -103,16 +122,22 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
         r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
         if (r < 0)
                 return -errno;
 
         link->ll.sll_family = AF_PACKET;
         link->ll.sll_protocol = htons(ETH_P_IP);
         link->ll.sll_ifindex = ifindex;
-        link->ll.sll_halen = ETH_ALEN;
-        memset(link->ll.sll_addr, 0xff, ETH_ALEN);
+        link->ll.sll_hatype = htons(arp_type);
+        link->ll.sll_halen = mac_addr_len;
+        if (mac_addr_len == ETH_ALEN)
+                memset(link->ll.sll_addr, 0xff, ETH_ALEN);
+        else if (mac_addr_len == INFINIBAND_ALEN)
+                memcpy(link->ll.sll_addr, ib_bcast_addr, sizeof (ib_bcast_addr));
+        else
+                assert_not_reached("unhandled hardware address length");
 
         r = bind(s, &link->sa, sizeof(link->ll));
         if (r < 0)
                 return -errno;
 
         r = s;
         s = -1;
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index 9f850fd..7581dae 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -34,23 +34,25 @@
 #include "dhcp-internal.h"
 #include "sd-dhcp-lease.h"
 #include "sd-dhcp-client.h"
 
 #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
 
 int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
-                      uint8_t type, size_t optlen, size_t *optoffset) {
+                      uint8_t type, uint16_t arp_type, size_t optlen,
+                      size_t *optoffset) {
         size_t offset = 0;
         int r;
 
         assert(op == BOOTREQUEST || op == BOOTREPLY);
+        assert(arp_type == ARPHRD_ETHER || arp_type == ARPHRD_INFINIBAND);
 
         message->op = op;
-        message->htype = ARPHRD_ETHER;
-        message->hlen = ETHER_ADDR_LEN;
+        message->htype = arp_type;
+        message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0;
         message->xid = htobe32(xid);
         message->magic = htobe32(DHCP_MAGIC_COOKIE);
 
         r = dhcp_option_append(message, optlen, &offset, 0,
                                DHCP_OPTION_MESSAGE_TYPE, 1, &type);
         if (r < 0)
                 return r;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index f5910d9..b36a18d 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -33,14 +33,16 @@
 #include "async.h"
 
 #include "dhcp-protocol.h"
 #include "dhcp-internal.h"
 #include "dhcp-lease-internal.h"
 #include "sd-dhcp-client.h"
 
+#define MAX_MAC_ADDR_LEN  20  /* INFINIBAND_ALEN */
+
 struct sd_dhcp_client {
         RefCount n_ref;
 
         DHCPState state;
         sd_event *event;
         int event_priority;
         sd_event_source *timeout_resend;
@@ -53,14 +55,17 @@ struct sd_dhcp_client {
         size_t req_opts_allocated;
         size_t req_opts_size;
         be32_t last_addr;
         struct {
                 uint8_t type;
                 struct ether_addr mac_addr;
         } _packed_ client_id;
+        uint8_t mac_addr[MAX_MAC_ADDR_LEN];
+        size_t mac_addr_len;
+        uint16_t arp_type;
         char *hostname;
         char *vendor_class_identifier;
         uint32_t mtu;
         uint32_t xid;
         usec_t start_time;
         uint16_t secs;
         unsigned int attempt;
@@ -159,32 +164,39 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
         assert_return(interface_index > 0, -EINVAL);
 
         client->index = interface_index;
 
         return 0;
 }
 
-int sd_dhcp_client_set_mac(sd_dhcp_client *client,
-                           const struct ether_addr *addr) {
+int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
+                           size_t addr_len, uint16_t arp_type) {
         DHCP_CLIENT_DONT_DESTROY(client);
         bool need_restart = false;
 
         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);
 
-        if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
+        if (client->mac_addr_len == addr_len &&
+            memcmp(&client->mac_addr, 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, DHCP_EVENT_STOP);
         }
 
+        memcpy(&client->mac_addr, addr, addr_len);
+        client->mac_addr_len = addr_len;
+        client->arp_type = arp_type;
+
         memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
         client->client_id.type = 0x01;
 
         if (need_restart && client->state != DHCP_STATE_STOPPED)
                 sd_dhcp_client_start(client);
 
         return 0;
@@ -314,15 +326,15 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
         size = sizeof(DHCPPacket) + optlen;
 
         packet = malloc0(size);
         if (!packet)
                 return -ENOMEM;
 
         r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
-                              optlen, &optoffset);
+                              client->arp_type, optlen, &optoffset);
         if (r < 0)
                 return r;
 
         /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
            refuse to issue an DHCP lease if 'secs' is set to zero */
         packet->dhcp.secs = htobe16(client->secs);
 
@@ -338,17 +350,20 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
            needs this to be disabled as broadcasts are filteretd, so this
            needs to be configurable */
         if (client->request_broadcast)
                 packet->dhcp.flags = htobe16(0x8000);
 
         /* RFC2132 section 4.1.1:
            The client MUST include its hardware address in the ’chaddr’ field, if
-           necessary for delivery of DHCP reply messages.
+           necessary for delivery of DHCP reply messages.  Non-Ethernet
+           interfaces will leave 'chaddr' empty and use the client identifier
+           instead (eg, RFC 4390 section 2.1).
          */
-        memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
+        if (client->mac_addr_len == ETH_ALEN)
+                memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
 
         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
            Identifier option is not set */
         r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
                                DHCP_OPTION_CLIENT_IDENTIFIER,
                                sizeof(client->client_id), &client->client_id);
         if (r < 0)
@@ -824,15 +839,17 @@ static int client_start(sd_dhcp_client *client) {
         assert_return(client->fd < 0, -EBUSY);
         assert_return(client->xid == 0, -EINVAL);
         assert_return(client->state == DHCP_STATE_INIT ||
                       client->state == DHCP_STATE_INIT_REBOOT, -EBUSY);
 
         client->xid = random_u32();
 
-        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
+        r = dhcp_network_bind_raw_socket(client->index, &client->link,
+                                         client->xid, client->mac_addr,
+                                         client->mac_addr_len, client->arp_type);
         if (r < 0) {
                 client_stop(client, r);
                 return r;
         }
         client->fd = r;
 
         if (client->state == DHCP_STATE_INIT) {
@@ -868,15 +885,17 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
 
         client->receive_message = sd_event_source_unref(client->receive_message);
         client->fd = asynchronous_close(client->fd);
 
         client->state = DHCP_STATE_REBINDING;
         client->attempt = 1;
 
-        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
+        r = dhcp_network_bind_raw_socket(client->index, &client->link,
+                                         client->xid, client->mac_addr,
+                                         client->mac_addr_len, client->arp_type);
         if (r < 0) {
                 client_stop(client, r);
                 return 0;
         }
         client->fd = r;
 
         return client_initialize_events(client, client_receive_message_raw);
@@ -1292,14 +1311,17 @@ error:
 }
 
 static int client_receive_message_udp(sd_event_source *s, int fd,
                                       uint32_t revents, void *userdata) {
         sd_dhcp_client *client = userdata;
         _cleanup_free_ DHCPMessage *message = NULL;
         int buflen = 0, len, r;
+        const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
+        const struct ether_addr *expected_chaddr = NULL;
+        uint8_t expected_hlen = 0;
 
         assert(s);
         assert(client);
 
         r = ioctl(fd, FIONREAD, &buflen);
         if (r < 0)
                 return r;
@@ -1328,21 +1350,34 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
         }
 
         if (message->op != BOOTREPLY) {
                 log_dhcp_client(client, "not a BOOTREPLY message: ignoring");
                 return 0;
         }
 
-        if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
-                log_dhcp_client(client, "not an ethernet packet");
+        if (message->htype != client->arp_type) {
+                log_dhcp_client(client, "packet type does not match client type");
                 return 0;
         }
 
-        if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
-                   ETH_ALEN)) {
+        if (client->arp_type == ARPHRD_ETHER) {
+                expected_hlen = ETH_ALEN;
+                expected_chaddr = (const struct ether_addr *) &client->mac_addr;
+        } else {
+               /* Non-ethernet links expect zero chaddr */
+               expected_hlen = 0;
+               expected_chaddr = &zero_mac;
+        }
+
+        if (message->hlen != expected_hlen) {
+                log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
+                return 0;
+        }
+
+        if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
                 log_dhcp_client(client, "received chaddr does not match "
                                 "expected: ignoring");
                 return 0;
         }
 
         if (client->state != DHCP_STATE_BOUND &&
             be32toh(message->xid) != client->xid) {
@@ -1429,17 +1464,15 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
                 return r;
 
         if (client->last_addr)
                 client->state = DHCP_STATE_INIT_REBOOT;
 
         r = client_start(client);
         if (r >= 0)
-                log_dhcp_client(client, "STARTED on ifindex %u with address %s",
-                                client->index,
-                                ether_ntoa(&client->client_id.mac_addr));
+                log_dhcp_client(client, "STARTED on ifindex %u", client->index);
 
         return r;
 }
 
 int sd_dhcp_client_stop(sd_dhcp_client *client) {
         DHCP_CLIENT_DONT_DESTROY(client);
 
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index c224aa1..79b104c 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -375,15 +375,15 @@ static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
         assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
 
         packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
         if (!packet)
                 return -ENOMEM;
 
         r = dhcp_message_init(&packet->dhcp, BOOTREPLY, be32toh(req->message->xid),
-                              type, req->max_optlen, &optoffset);
+                              type, ARPHRD_ETHER, req->max_optlen, &optoffset);
         if (r < 0)
                 return r;
 
         packet->dhcp.flags = req->message->flags;
         packet->dhcp.giaddr = req->message->giaddr;
         memcpy(&packet->dhcp.chaddr, &req->message->chaddr, ETH_ALEN);
 
@@ -491,16 +491,16 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, be32_t
         assert(chaddr);
 
         packet = malloc0(sizeof(DHCPPacket) + DHCP_MIN_OPTIONS_SIZE);
         if (!packet)
                 return -ENOMEM;
 
         r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
-                              DHCP_FORCERENEW, DHCP_MIN_OPTIONS_SIZE,
-                              &optoffset);
+                              DHCP_FORCERENEW, ARPHRD_ETHER,
+                              DHCP_MIN_OPTIONS_SIZE, &optoffset);
         if (r < 0)
                 return r;
 
         r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE,
                                &optoffset, 0, DHCP_OPTION_END, 0, NULL);
         if (r < 0)
                 return r;
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index c48aa04..7dab97d 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -192,15 +192,17 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
 
         assert_se(callback_recv);
         callback_recv(size, &discover->dhcp);
 
         return 575;
 }
 
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t id, struct ether_addr mac)
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
+                                 uint32_t id, const uint8_t *addr,
+                                 size_t addr_len, uint16_t arp_type)
 {
         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
                 return -errno;
 
         return test_fd[0];
 }
 
@@ -240,15 +242,18 @@ static void test_discover_message(sd_event *e)
         assert_se(r >= 0);
         assert_se(client);
 
         r = sd_dhcp_client_attach_event(client, e, 0);
         assert_se(r >= 0);
 
         assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
-        assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
+        assert_se(sd_dhcp_client_set_mac(client,
+                                         (const uint8_t *) &mac_addr,
+                                         sizeof (mac_addr),
+                                         ARPHRD_ETHER) >= 0);
 
         assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
 
         callback_recv = test_discover_message_verify;
 
         res = sd_dhcp_client_start(client);
 
@@ -458,15 +463,18 @@ static void test_addr_acq(sd_event *e) {
         assert_se(r >= 0);
         assert_se(client);
 
         r = sd_dhcp_client_attach_event(client, e, 0);
         assert_se(r >= 0);
 
         assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
-        assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
+        assert_se(sd_dhcp_client_set_mac(client,
+                                         (const uint8_t *) &mac_addr,
+                                         sizeof (mac_addr),
+                                         ARPHRD_ETHER) >= 0);
 
         assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
                 >= 0);
 
         callback_recv = test_addr_acq_recv_discover;
 
         assert_se(sd_event_add_time(e, &test_hangcheck,
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
index 92c58e0..ed81fe7 100644
--- a/src/libsystemd-network/test-dhcp-option.c
+++ b/src/libsystemd-network/test-dhcp-option.c
@@ -88,15 +88,15 @@ static void test_message_init(void)
         size_t optlen = 4, optoffset;
         size_t len = sizeof(DHCPMessage) + optlen;
         uint8_t *magic;
 
         message = malloc0(len);
 
         assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
-                  DHCP_DISCOVER, optlen, &optoffset) >= 0);
+                  DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0);
 
         assert_se(message->xid == htobe32(0x12345678));
         assert_se(message->op == BOOTREQUEST);
 
         magic = (uint8_t*)&message->magic;
 
         assert_se(magic[0] == 99);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index eff14ca..6516f38 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1815,15 +1815,17 @@ static int link_configure(Link *link) {
                 if (r < 0)
                         return r;
 
                 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
                 if (r < 0)
                         return r;
 
-                r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
+                r = sd_dhcp_client_set_mac(link->dhcp_client,
+                                           (const uint8_t *) &link->mac,
+                                           sizeof (link->mac), ARPHRD_ETHER);
                 if (r < 0)
                         return r;
 
                 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
                 if (r < 0)
                         return r;
 
@@ -2246,15 +2248,18 @@ int link_update(Link *link, sd_rtnl_message *m) {
                                                          "address in IPv4LL client: %s",
                                                          strerror(-r));
                                         return r;
                                 }
                         }
 
                         if (link->dhcp_client) {
-                                r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
+                                r = sd_dhcp_client_set_mac(link->dhcp_client,
+                                                           (const uint8_t *) &link->mac,
+                                                           sizeof (link->mac),
+                                                           ARPHRD_ETHER);
                                 if (r < 0) {
                                         log_warning_link(link, "Could not update MAC "
                                                          "address in DHCP client: %s",
                                                          strerror(-r));
                                         return r;
                                 }
                         }
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index 98c6782..7416f82 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -45,16 +45,16 @@ int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
 
 
 int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option);
 int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
                                        const struct in_addr *last_address);
 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast);
 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index);
-int sd_dhcp_client_set_mac(sd_dhcp_client *client,
-                           const struct ether_addr *addr);
+int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
+                           size_t addr_len, uint16_t arp_type);
 int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu);
 int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname);
 int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci);
 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret);
 
 int sd_dhcp_client_stop(sd_dhcp_client *client);
 int sd_dhcp_client_start(sd_dhcp_client *client);
-- 
1.9.3




More information about the systemd-devel mailing list