Zbigniew Jędrzejewski-Szmek db38be
From 76253e73f9c9c24fec755e485516f3b55d0707b4 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek db38be
From: Dan Williams <dcbw@redhat.com>
Zbigniew Jędrzejewski-Szmek db38be
Date: Wed, 8 Oct 2014 14:15:45 -0500
Zbigniew Jędrzejewski-Szmek db38be
Subject: [PATCH] sd-dhcp-client: support non-Ethernet hardware addresses
Zbigniew Jędrzejewski-Szmek db38be
Zbigniew Jędrzejewski-Szmek db38be
Like Infiniband.  See RFC 4390 section 2.1 for details on DHCP
Zbigniew Jędrzejewski-Szmek db38be
and Infiniband; chaddr is zeroed, hlen is set to 0, and htype
Zbigniew Jędrzejewski-Szmek db38be
is set to ARPHRD_INFINIBAND because IB hardware addresses
Zbigniew Jędrzejewski-Szmek db38be
are 20 bytes in length.
Zbigniew Jędrzejewski-Szmek db38be
---
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/dhcp-internal.h     | 10 ++--
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/dhcp-network.c      | 54 ++++++++++++++++++----
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/dhcp-packet.c       |  8 ++--
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/sd-dhcp-client.c    | 74 +++++++++++++++++++++++-------
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/sd-dhcp-server.c    |  8 ++--
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/sd-dhcp6-client.c   | 36 +++++++++++----
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/test-dhcp-client.c  | 14 ++++--
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/test-dhcp-option.c  |  2 +-
Zbigniew Jędrzejewski-Szmek db38be
 src/libsystemd-network/test-dhcp6-client.c |  8 +++-
Zbigniew Jędrzejewski-Szmek db38be
 src/network/networkd-dhcp4.c               |  4 +-
Zbigniew Jędrzejewski-Szmek db38be
 src/network/networkd-link.c                | 12 +++--
Zbigniew Jędrzejewski-Szmek db38be
 src/systemd/sd-dhcp-client.h               |  4 +-
Zbigniew Jędrzejewski-Szmek db38be
 src/systemd/sd-dhcp6-client.h              |  4 +-
Zbigniew Jędrzejewski-Szmek db38be
 13 files changed, 179 insertions(+), 59 deletions(-)
Zbigniew Jędrzejewski-Szmek db38be
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
Zbigniew Jędrzejewski-Szmek db38be
index 1069c8a03b..d358a49307 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/dhcp-internal.h
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/dhcp-internal.h
Zbigniew Jędrzejewski-Szmek db38be
@@ -24,6 +24,7 @@
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
 #include <stdint.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <linux/if_packet.h>
Zbigniew Jędrzejewski-Szmek db38be
+#include <net/if_arp.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <net/ethernet.h>
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
 #include "socket-util.h"
Zbigniew Jędrzejewski-Szmek db38be
@@ -31,7 +32,9 @@
Zbigniew Jędrzejewski-Szmek db38be
 #include "sd-dhcp-client.h"
Zbigniew Jędrzejewski-Szmek db38be
 #include "dhcp-protocol.h"
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid, struct ether_addr mac_addr);
Zbigniew Jędrzejewski-Szmek db38be
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
+                                 uint32_t xid, const uint8_t *mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                 size_t mac_addr_len, uint16_t arp_type);
Zbigniew Jędrzejewski-Szmek db38be
 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port);
Zbigniew Jędrzejewski-Szmek db38be
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
                                  const void *packet, size_t len);
Zbigniew Jędrzejewski-Szmek db38be
@@ -47,8 +50,9 @@ typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
Zbigniew Jędrzejewski-Szmek db38be
 int dhcp_option_parse(DHCPMessage *message, size_t len,
Zbigniew Jędrzejewski-Szmek db38be
                       dhcp_option_cb_t cb, void *user_data);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type,
Zbigniew Jędrzejewski-Szmek db38be
-                      size_t optlen, size_t *optoffset);
Zbigniew Jędrzejewski-Szmek db38be
+int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
Zbigniew Jędrzejewski-Szmek db38be
+                      uint8_t type, uint16_t arp_type, size_t optlen,
Zbigniew Jędrzejewski-Szmek db38be
+                      size_t *optoffset);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
 uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c
Zbigniew Jędrzejewski-Szmek db38be
index 1ced5cf292..29e9993f66 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/dhcp-network.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/dhcp-network.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -22,6 +22,7 @@
Zbigniew Jędrzejewski-Szmek db38be
 #include <sys/socket.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <string.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <linux/if_packet.h>
Zbigniew Jędrzejewski-Szmek db38be
+#include <linux/if_infiniband.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <net/ethernet.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <net/if_arp.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <stdio.h>
Zbigniew Jędrzejewski-Szmek db38be
@@ -32,9 +33,12 @@
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
 #include "dhcp-internal.h"
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
-                                 uint32_t xid, struct ether_addr mac_addr) {
Zbigniew Jędrzejewski-Szmek db38be
-
Zbigniew Jędrzejewski-Szmek db38be
+static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
+                            uint32_t xid, const uint8_t *mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                            size_t mac_addr_len,
Zbigniew Jędrzejewski-Szmek db38be
+                            const uint8_t *bcast_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                            const struct ether_addr *eth_mac,
Zbigniew Jędrzejewski-Szmek db38be
+                            uint16_t arp_type, uint8_t dhcp_hlen) {
Zbigniew Jędrzejewski-Szmek db38be
         struct sock_filter filter[] = {
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                 /* A <- packet length */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0),         /* packet >= DHCPPacket ? */
Zbigniew Jędrzejewski-Szmek db38be
@@ -57,21 +61,21 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0),                  /* op == BOOTREPLY ? */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)),  /* A <- DHCP header type */
Zbigniew Jędrzejewski-Szmek db38be
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),               /* header type == ARPHRD_ETHER ? */
Zbigniew Jędrzejewski-Szmek db38be
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0),                   /* header type == arp_type ? */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)),   /* A <- mac address length */
Zbigniew Jędrzejewski-Szmek db38be
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHER_ADDR_LEN, 1, 0),             /* address length == ETHER_ADDR_LEN ? */
Zbigniew Jędrzejewski-Szmek db38be
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0),                  /* address length == dhcp_hlen ? */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)),    /* A <- client identifier */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0),                        /* client identifier == xid ? */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
Zbigniew Jędrzejewski-Szmek db38be
-                BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((unsigned int *) &mac_addr))),                    /* A <- 4 bytes of client's MAC */
Zbigniew Jędrzejewski-Szmek db38be
+                BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((unsigned int *) eth_mac))),                     /* A <- 4 bytes of client's MAC */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)),                 /* A <- 4 bytes of MAC from dhcp.chaddr */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                          /* A == 0 ? */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
Zbigniew Jędrzejewski-Szmek db38be
-                BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) &mac_addr) + 4)))), /* A <- remainder of client's MAC */
Zbigniew Jędrzejewski-Szmek db38be
+                BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) eth_mac) + 4)))),   /* A <- remainder of client's MAC */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4),             /* A <- remainder of MAC from dhcp.chaddr */
Zbigniew Jędrzejewski-Szmek db38be
                 BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
Zbigniew Jędrzejewski-Szmek db38be
@@ -107,8 +111,9 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
         link->ll.sll_family = AF_PACKET;
Zbigniew Jędrzejewski-Szmek db38be
         link->ll.sll_protocol = htons(ETH_P_IP);
Zbigniew Jędrzejewski-Szmek db38be
         link->ll.sll_ifindex = ifindex;
Zbigniew Jędrzejewski-Szmek db38be
-        link->ll.sll_halen = ETH_ALEN;
Zbigniew Jędrzejewski-Szmek db38be
-        memset(link->ll.sll_addr, 0xff, ETH_ALEN);
Zbigniew Jędrzejewski-Szmek db38be
+        link->ll.sll_hatype = htons(arp_type);
Zbigniew Jędrzejewski-Szmek db38be
+        link->ll.sll_halen = mac_addr_len;
Zbigniew Jędrzejewski-Szmek db38be
+        memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         r = bind(s, &link->sa, sizeof(link->ll));
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0)
Zbigniew Jędrzejewski-Szmek db38be
@@ -120,6 +125,37 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
         return r;
Zbigniew Jędrzejewski-Szmek db38be
 }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
+int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
+                                 uint32_t xid, const uint8_t *mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                 size_t mac_addr_len, uint16_t arp_type) {
Zbigniew Jędrzejewski-Szmek db38be
+        static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
Zbigniew Jędrzejewski-Szmek db38be
+        /* Default broadcast address for IPoIB */
Zbigniew Jędrzejewski-Szmek db38be
+        static const uint8_t ib_bcast[] = {
Zbigniew Jędrzejewski-Szmek db38be
+                0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
Zbigniew Jędrzejewski-Szmek db38be
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Zbigniew Jędrzejewski-Szmek db38be
+                0xff, 0xff, 0xff, 0xff
Zbigniew Jędrzejewski-Szmek db38be
+          };
Zbigniew Jędrzejewski-Szmek db38be
+        struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
Zbigniew Jędrzejewski-Szmek db38be
+        const uint8_t *bcast_addr = NULL;
Zbigniew Jędrzejewski-Szmek db38be
+        uint8_t dhcp_hlen = 0;
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        assert_return(mac_addr_len > 0, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        if (arp_type == ARPHRD_ETHER) {
Zbigniew Jędrzejewski-Szmek db38be
+                assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+                memcpy(&eth_mac, mac_addr, ETH_ALEN);
Zbigniew Jędrzejewski-Szmek db38be
+                bcast_addr = eth_bcast;
Zbigniew Jędrzejewski-Szmek db38be
+                dhcp_hlen = ETH_ALEN;
Zbigniew Jędrzejewski-Szmek db38be
+        } else if (arp_type == ARPHRD_INFINIBAND) {
Zbigniew Jędrzejewski-Szmek db38be
+                assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+                bcast_addr = ib_bcast;
Zbigniew Jędrzejewski-Szmek db38be
+        } else
Zbigniew Jędrzejewski-Szmek db38be
+                return -EINVAL;
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len,
Zbigniew Jędrzejewski-Szmek db38be
+                                bcast_addr, &eth_mac, arp_type, dhcp_hlen);
Zbigniew Jędrzejewski-Szmek db38be
+}
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
 int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) {
Zbigniew Jędrzejewski-Szmek db38be
         union sockaddr_union src = {
Zbigniew Jędrzejewski-Szmek db38be
                 .in.sin_family = AF_INET,
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
Zbigniew Jędrzejewski-Szmek db38be
index 9f850fdebb..7581daeeeb 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/dhcp-packet.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/dhcp-packet.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -38,15 +38,17 @@
Zbigniew Jędrzejewski-Szmek db38be
 #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
 int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
Zbigniew Jędrzejewski-Szmek db38be
-                      uint8_t type, size_t optlen, size_t *optoffset) {
Zbigniew Jędrzejewski-Szmek db38be
+                      uint8_t type, uint16_t arp_type, size_t optlen,
Zbigniew Jędrzejewski-Szmek db38be
+                      size_t *optoffset) {
Zbigniew Jędrzejewski-Szmek db38be
         size_t offset = 0;
Zbigniew Jędrzejewski-Szmek db38be
         int r;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert(op == BOOTREQUEST || op == BOOTREPLY);
Zbigniew Jędrzejewski-Szmek db38be
+        assert(arp_type == ARPHRD_ETHER || arp_type == ARPHRD_INFINIBAND);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         message->op = op;
Zbigniew Jędrzejewski-Szmek db38be
-        message->htype = ARPHRD_ETHER;
Zbigniew Jędrzejewski-Szmek db38be
-        message->hlen = ETHER_ADDR_LEN;
Zbigniew Jędrzejewski-Szmek db38be
+        message->htype = arp_type;
Zbigniew Jędrzejewski-Szmek db38be
+        message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0;
Zbigniew Jędrzejewski-Szmek db38be
         message->xid = htobe32(xid);
Zbigniew Jędrzejewski-Szmek db38be
         message->magic = htobe32(DHCP_MAGIC_COOKIE);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
Zbigniew Jędrzejewski-Szmek db38be
index 2f94c16078..0eba4c379d 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/sd-dhcp-client.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/sd-dhcp-client.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -23,6 +23,7 @@
Zbigniew Jędrzejewski-Szmek db38be
 #include <stdio.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <net/ethernet.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <net/if_arp.h>
Zbigniew Jędrzejewski-Szmek db38be
+#include <linux/if_infiniband.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <netinet/ether.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <sys/param.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <sys/ioctl.h>
Zbigniew Jędrzejewski-Szmek db38be
@@ -37,6 +38,8 @@
Zbigniew Jędrzejewski-Szmek db38be
 #include "dhcp-lease-internal.h"
Zbigniew Jędrzejewski-Szmek db38be
 #include "sd-dhcp-client.h"
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
+#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
 struct sd_dhcp_client {
Zbigniew Jędrzejewski-Szmek db38be
         RefCount n_ref;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
@@ -57,6 +60,9 @@ struct sd_dhcp_client {
Zbigniew Jędrzejewski-Szmek db38be
                 uint8_t type;
Zbigniew Jędrzejewski-Szmek db38be
                 struct ether_addr mac_addr;
Zbigniew Jędrzejewski-Szmek db38be
         } _packed_ client_id;
Zbigniew Jędrzejewski-Szmek db38be
+        uint8_t mac_addr[MAX_MAC_ADDR_LEN];
Zbigniew Jędrzejewski-Szmek db38be
+        size_t mac_addr_len;
Zbigniew Jędrzejewski-Szmek db38be
+        uint16_t arp_type;
Zbigniew Jędrzejewski-Szmek db38be
         char *hostname;
Zbigniew Jędrzejewski-Szmek db38be
         char *vendor_class_identifier;
Zbigniew Jędrzejewski-Szmek db38be
         uint32_t mtu;
Zbigniew Jędrzejewski-Szmek db38be
@@ -163,15 +169,25 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
Zbigniew Jędrzejewski-Szmek db38be
         return 0;
Zbigniew Jędrzejewski-Szmek db38be
 }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-int sd_dhcp_client_set_mac(sd_dhcp_client *client,
Zbigniew Jędrzejewski-Szmek db38be
-                           const struct ether_addr *addr) {
Zbigniew Jędrzejewski-Szmek db38be
+int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
Zbigniew Jędrzejewski-Szmek db38be
+                           size_t addr_len, uint16_t arp_type) {
Zbigniew Jędrzejewski-Szmek db38be
         DHCP_CLIENT_DONT_DESTROY(client);
Zbigniew Jędrzejewski-Szmek db38be
         bool need_restart = false;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_return(client, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
         assert_return(addr, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+        assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+        assert_return(arp_type > 0, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        if (arp_type == ARPHRD_ETHER)
Zbigniew Jędrzejewski-Szmek db38be
+                assert_return(addr_len == ETH_ALEN, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+        else if (arp_type == ARPHRD_INFINIBAND)
Zbigniew Jędrzejewski-Szmek db38be
+                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+        else
Zbigniew Jędrzejewski-Szmek db38be
+                return -EINVAL;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-        if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0)
Zbigniew Jędrzejewski-Szmek db38be
+        if (client->mac_addr_len == addr_len &&
Zbigniew Jędrzejewski-Szmek db38be
+            memcmp(&client->mac_addr, addr, addr_len) == 0)
Zbigniew Jędrzejewski-Szmek db38be
                 return 0;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
Zbigniew Jędrzejewski-Szmek db38be
@@ -181,6 +197,10 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client,
Zbigniew Jędrzejewski-Szmek db38be
                 client_stop(client, DHCP_EVENT_STOP);
Zbigniew Jędrzejewski-Szmek db38be
         }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
+        memcpy(&client->mac_addr, addr, addr_len);
Zbigniew Jędrzejewski-Szmek db38be
+        client->mac_addr_len = addr_len;
Zbigniew Jędrzejewski-Szmek db38be
+        client->arp_type = arp_type;
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
         memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
Zbigniew Jędrzejewski-Szmek db38be
         client->client_id.type = 0x01;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
@@ -318,7 +338,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
Zbigniew Jędrzejewski-Szmek db38be
                 return -ENOMEM;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
Zbigniew Jędrzejewski-Szmek db38be
-                              optlen, &optoffset);
Zbigniew Jędrzejewski-Szmek db38be
+                              client->arp_type, optlen, &optoffset);
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0)
Zbigniew Jędrzejewski-Szmek db38be
                 return r;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
@@ -337,14 +357,17 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
Zbigniew Jędrzejewski-Szmek db38be
            Note: some interfaces needs this to be enabled, but some networks
Zbigniew Jędrzejewski-Szmek db38be
            needs this to be disabled as broadcasts are filteretd, so this
Zbigniew Jędrzejewski-Szmek db38be
            needs to be configurable */
Zbigniew Jędrzejewski-Szmek db38be
-        if (client->request_broadcast)
Zbigniew Jędrzejewski-Szmek db38be
+        if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
Zbigniew Jędrzejewski-Szmek db38be
                 packet->dhcp.flags = htobe16(0x8000);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         /* RFC2132 section 4.1.1:
Zbigniew Jędrzejewski-Szmek db38be
            The client MUST include its hardware address in the ’chaddr’ field, if
Zbigniew Jędrzejewski-Szmek db38be
-           necessary for delivery of DHCP reply messages.
Zbigniew Jędrzejewski-Szmek db38be
+           necessary for delivery of DHCP reply messages.  Non-Ethernet
Zbigniew Jędrzejewski-Szmek db38be
+           interfaces will leave 'chaddr' empty and use the client identifier
Zbigniew Jędrzejewski-Szmek db38be
+           instead (eg, RFC 4390 section 2.1).
Zbigniew Jędrzejewski-Szmek db38be
          */
Zbigniew Jędrzejewski-Szmek db38be
-        memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN);
Zbigniew Jędrzejewski-Szmek db38be
+        if (client->arp_type == ARPHRD_ETHER)
Zbigniew Jędrzejewski-Szmek db38be
+                memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         /* Some DHCP servers will refuse to issue an DHCP lease if the Client
Zbigniew Jędrzejewski-Szmek db38be
            Identifier option is not set */
Zbigniew Jędrzejewski-Szmek db38be
@@ -843,7 +866,9 @@ static int client_start(sd_dhcp_client *client) {
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         client->xid = random_u32();
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
Zbigniew Jędrzejewski-Szmek db38be
+        r = dhcp_network_bind_raw_socket(client->index, &client->link,
Zbigniew Jędrzejewski-Szmek db38be
+                                         client->xid, client->mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                         client->mac_addr_len, client->arp_type);
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0) {
Zbigniew Jędrzejewski-Szmek db38be
                 client_stop(client, r);
Zbigniew Jędrzejewski-Szmek db38be
                 return r;
Zbigniew Jędrzejewski-Szmek db38be
@@ -887,7 +912,9 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
Zbigniew Jędrzejewski-Szmek db38be
         client->state = DHCP_STATE_REBINDING;
Zbigniew Jędrzejewski-Szmek db38be
         client->attempt = 1;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-        r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr);
Zbigniew Jędrzejewski-Szmek db38be
+        r = dhcp_network_bind_raw_socket(client->index, &client->link,
Zbigniew Jędrzejewski-Szmek db38be
+                                         client->xid, client->mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                         client->mac_addr_len, client->arp_type);
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0) {
Zbigniew Jędrzejewski-Szmek db38be
                 client_stop(client, r);
Zbigniew Jędrzejewski-Szmek db38be
                 return 0;
Zbigniew Jędrzejewski-Szmek db38be
@@ -1331,6 +1358,9 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
Zbigniew Jędrzejewski-Szmek db38be
         sd_dhcp_client *client = userdata;
Zbigniew Jędrzejewski-Szmek db38be
         _cleanup_free_ DHCPMessage *message = NULL;
Zbigniew Jędrzejewski-Szmek db38be
         int buflen = 0, len, r;
Zbigniew Jędrzejewski-Szmek db38be
+        const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
Zbigniew Jędrzejewski-Szmek db38be
+        const struct ether_addr *expected_chaddr = NULL;
Zbigniew Jędrzejewski-Szmek db38be
+        uint8_t expected_hlen = 0;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert(s);
Zbigniew Jędrzejewski-Szmek db38be
         assert(client);
Zbigniew Jędrzejewski-Szmek db38be
@@ -1367,13 +1397,26 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
Zbigniew Jędrzejewski-Szmek db38be
                 return 0;
Zbigniew Jędrzejewski-Szmek db38be
         }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-        if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) {
Zbigniew Jędrzejewski-Szmek db38be
-                log_dhcp_client(client, "not an ethernet packet");
Zbigniew Jędrzejewski-Szmek db38be
+        if (message->htype != client->arp_type) {
Zbigniew Jędrzejewski-Szmek db38be
+                log_dhcp_client(client, "packet type does not match client type");
Zbigniew Jędrzejewski-Szmek db38be
+                return 0;
Zbigniew Jędrzejewski-Szmek db38be
+        }
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        if (client->arp_type == ARPHRD_ETHER) {
Zbigniew Jędrzejewski-Szmek db38be
+                expected_hlen = ETH_ALEN;
Zbigniew Jędrzejewski-Szmek db38be
+                expected_chaddr = (const struct ether_addr *) &client->mac_addr;
Zbigniew Jędrzejewski-Szmek db38be
+        } else {
Zbigniew Jędrzejewski-Szmek db38be
+               /* Non-ethernet links expect zero chaddr */
Zbigniew Jędrzejewski-Szmek db38be
+               expected_hlen = 0;
Zbigniew Jędrzejewski-Szmek db38be
+               expected_chaddr = &zero_mac;
Zbigniew Jędrzejewski-Szmek db38be
+        }
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        if (message->hlen != expected_hlen) {
Zbigniew Jędrzejewski-Szmek db38be
+                log_dhcp_client(client, "unexpected packet hlen %d", message->hlen);
Zbigniew Jędrzejewski-Szmek db38be
                 return 0;
Zbigniew Jędrzejewski-Szmek db38be
         }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-        if (memcmp(&message->chaddr[0], &client->client_id.mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
-                   ETH_ALEN)) {
Zbigniew Jędrzejewski-Szmek db38be
+        if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
Zbigniew Jędrzejewski-Szmek db38be
                 log_dhcp_client(client, "received chaddr does not match "
Zbigniew Jędrzejewski-Szmek db38be
                                 "expected: ignoring");
Zbigniew Jędrzejewski-Szmek db38be
                 return 0;
Zbigniew Jędrzejewski-Szmek db38be
@@ -1455,7 +1498,6 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
Zbigniew Jędrzejewski-Szmek db38be
 }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp_client_start(sd_dhcp_client *client) {
Zbigniew Jędrzejewski-Szmek db38be
-        char buffer[ETHER_ADDR_TO_STRING_MAX];
Zbigniew Jędrzejewski-Szmek db38be
         int r;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_return(client, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
@@ -1469,9 +1511,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         r = client_start(client);
Zbigniew Jędrzejewski-Szmek db38be
         if (r >= 0)
Zbigniew Jędrzejewski-Szmek db38be
-                log_dhcp_client(client, "STARTED on ifindex %u with address %s",
Zbigniew Jędrzejewski-Szmek db38be
-                                client->index,
Zbigniew Jędrzejewski-Szmek db38be
-                                ether_addr_to_string(&client->client_id.mac_addr, buffer));
Zbigniew Jędrzejewski-Szmek db38be
+                log_dhcp_client(client, "STARTED on ifindex %u", client->index);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         return r;
Zbigniew Jędrzejewski-Szmek db38be
 }
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
Zbigniew Jędrzejewski-Szmek db38be
index a6d6178e72..24fedd2375 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/sd-dhcp-server.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/sd-dhcp-server.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -392,8 +392,8 @@ static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
Zbigniew Jędrzejewski-Szmek db38be
                 return -ENOMEM;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
Zbigniew Jędrzejewski-Szmek db38be
-                              be32toh(req->message->xid), type, req->max_optlen,
Zbigniew Jędrzejewski-Szmek db38be
-                              &optoffset);
Zbigniew Jędrzejewski-Szmek db38be
+                              be32toh(req->message->xid), type, ARPHRD_ETHER,
Zbigniew Jędrzejewski-Szmek db38be
+                              req->max_optlen, &optoffset);
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0)
Zbigniew Jędrzejewski-Szmek db38be
                 return r;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
@@ -513,8 +513,8 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
Zbigniew Jędrzejewski-Szmek db38be
                 return -ENOMEM;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
Zbigniew Jędrzejewski-Szmek db38be
-                              DHCP_FORCERENEW, DHCP_MIN_OPTIONS_SIZE,
Zbigniew Jędrzejewski-Szmek db38be
-                              &optoffset);
Zbigniew Jędrzejewski-Szmek db38be
+                              DHCP_FORCERENEW, ARPHRD_ETHER,
Zbigniew Jędrzejewski-Szmek db38be
+                              DHCP_MIN_OPTIONS_SIZE, &optoffset);
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0)
Zbigniew Jędrzejewski-Szmek db38be
                 return r;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
Zbigniew Jędrzejewski-Szmek db38be
index 6ea68c915f..fa4f9b5dc2 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/sd-dhcp6-client.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/sd-dhcp6-client.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -22,6 +22,7 @@
Zbigniew Jędrzejewski-Szmek db38be
 #include <errno.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <string.h>
Zbigniew Jędrzejewski-Szmek db38be
 #include <sys/ioctl.h>
Zbigniew Jędrzejewski-Szmek db38be
+#include <linux/if_infiniband.h>
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
 #include "udev.h"
Zbigniew Jędrzejewski-Szmek db38be
 #include "udev-util.h"
Zbigniew Jędrzejewski-Szmek db38be
@@ -44,6 +45,8 @@
Zbigniew Jędrzejewski-Szmek db38be
  */
Zbigniew Jędrzejewski-Szmek db38be
 #define MAX_DUID_LEN 128
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
+#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
 struct sd_dhcp6_client {
Zbigniew Jędrzejewski-Szmek db38be
         RefCount n_ref;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
@@ -51,7 +54,9 @@ struct sd_dhcp6_client {
Zbigniew Jędrzejewski-Szmek db38be
         sd_event *event;
Zbigniew Jędrzejewski-Szmek db38be
         int event_priority;
Zbigniew Jędrzejewski-Szmek db38be
         int index;
Zbigniew Jędrzejewski-Szmek db38be
-        struct ether_addr mac_addr;
Zbigniew Jędrzejewski-Szmek db38be
+        uint8_t mac_addr[MAX_MAC_ADDR_LEN];
Zbigniew Jędrzejewski-Szmek db38be
+        size_t mac_addr_len;
Zbigniew Jędrzejewski-Szmek db38be
+        uint16_t arp_type;
Zbigniew Jędrzejewski-Szmek db38be
         DHCP6IA ia_na;
Zbigniew Jędrzejewski-Szmek db38be
         be32_t transaction_id;
Zbigniew Jędrzejewski-Szmek db38be
         usec_t transaction_start;
Zbigniew Jędrzejewski-Szmek db38be
@@ -160,15 +165,28 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
Zbigniew Jędrzejewski-Szmek db38be
         return 0;
Zbigniew Jędrzejewski-Szmek db38be
 }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
Zbigniew Jędrzejewski-Szmek db38be
-                            const struct ether_addr *mac_addr)
Zbigniew Jędrzejewski-Szmek db38be
+int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
Zbigniew Jędrzejewski-Szmek db38be
+                            size_t addr_len, uint16_t arp_type)
Zbigniew Jędrzejewski-Szmek db38be
 {
Zbigniew Jędrzejewski-Szmek db38be
         assert_return(client, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
-
Zbigniew Jędrzejewski-Szmek db38be
-        if (mac_addr)
Zbigniew Jędrzejewski-Szmek db38be
-                memcpy(&client->mac_addr, mac_addr, sizeof(client->mac_addr));
Zbigniew Jędrzejewski-Szmek db38be
+        assert_return(addr, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+        assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+        assert_return(arp_type > 0, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        if (arp_type == ARPHRD_ETHER)
Zbigniew Jędrzejewski-Szmek db38be
+                assert_return(addr_len == ETH_ALEN, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
+        else if (arp_type == ARPHRD_INFINIBAND)
Zbigniew Jędrzejewski-Szmek db38be
+                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
         else
Zbigniew Jędrzejewski-Szmek db38be
-                memset(&client->mac_addr, 0x00, sizeof(client->mac_addr));
Zbigniew Jędrzejewski-Szmek db38be
+                return -EINVAL;
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        if (client->mac_addr_len == addr_len &&
Zbigniew Jędrzejewski-Szmek db38be
+            memcmp(&client->mac_addr, addr, addr_len) == 0)
Zbigniew Jędrzejewski-Szmek db38be
+                return 0;
Zbigniew Jędrzejewski-Szmek db38be
+
Zbigniew Jędrzejewski-Szmek db38be
+        memcpy(&client->mac_addr, addr, addr_len);
Zbigniew Jędrzejewski-Szmek db38be
+        client->mac_addr_len = addr_len;
Zbigniew Jędrzejewski-Szmek db38be
+        client->arp_type = arp_type;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         return 0;
Zbigniew Jędrzejewski-Szmek db38be
 }
Zbigniew Jędrzejewski-Szmek db38be
@@ -646,8 +664,8 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
Zbigniew Jędrzejewski-Szmek db38be
                 siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
Zbigniew Jędrzejewski-Szmek db38be
         else
Zbigniew Jędrzejewski-Szmek db38be
                 /* fall back to mac address if no predictable name available */
Zbigniew Jędrzejewski-Szmek db38be
-                siphash24((uint8_t*)&id, &client->mac_addr, ETH_ALEN,
Zbigniew Jędrzejewski-Szmek db38be
-                          HASH_KEY.bytes);
Zbigniew Jędrzejewski-Szmek db38be
+                siphash24((uint8_t*)&id, &client->mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                          client->mac_addr_len, HASH_KEY.bytes);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         /* fold into 32 bits */
Zbigniew Jędrzejewski-Szmek db38be
         client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
Zbigniew Jędrzejewski-Szmek db38be
index c48aa04b8d..7dab97de2f 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/test-dhcp-client.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/test-dhcp-client.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -196,7 +196,9 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
         return 575;
Zbigniew Jędrzejewski-Szmek db38be
 }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t id, struct ether_addr mac)
Zbigniew Jędrzejewski-Szmek db38be
+int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
Zbigniew Jędrzejewski-Szmek db38be
+                                 uint32_t id, const uint8_t *addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                 size_t addr_len, uint16_t arp_type)
Zbigniew Jędrzejewski-Szmek db38be
 {
Zbigniew Jędrzejewski-Szmek db38be
         if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
Zbigniew Jędrzejewski-Szmek db38be
                 return -errno;
Zbigniew Jędrzejewski-Szmek db38be
@@ -244,7 +246,10 @@ static void test_discover_message(sd_event *e)
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(r >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
-        assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
+        assert_se(sd_dhcp_client_set_mac(client,
Zbigniew Jędrzejewski-Szmek db38be
+                                         (const uint8_t *) &mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                         sizeof (mac_addr),
Zbigniew Jędrzejewski-Szmek db38be
+                                         ARPHRD_ETHER) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
@@ -462,7 +467,10 @@ static void test_addr_acq(sd_event *e) {
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(r >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
-        assert_se(sd_dhcp_client_set_mac(client, &mac_addr) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
+        assert_se(sd_dhcp_client_set_mac(client,
Zbigniew Jędrzejewski-Szmek db38be
+                                         (const uint8_t *) &mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                         sizeof (mac_addr),
Zbigniew Jędrzejewski-Szmek db38be
+                                         ARPHRD_ETHER) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
Zbigniew Jędrzejewski-Szmek db38be
                 >= 0);
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
Zbigniew Jędrzejewski-Szmek db38be
index 63cdc7aa06..eac3844f96 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/test-dhcp-option.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/test-dhcp-option.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -92,7 +92,7 @@ static void test_message_init(void)
Zbigniew Jędrzejewski-Szmek db38be
         message = malloc0(len);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
Zbigniew Jędrzejewski-Szmek db38be
-                  DHCP_DISCOVER, optlen, &optoffset) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
+                  DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(message->xid == htobe32(0x12345678));
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(message->op == BOOTREQUEST);
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
Zbigniew Jędrzejewski-Szmek db38be
index 37ddfc2cfa..26b28a20e8 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/libsystemd-network/test-dhcp6-client.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/libsystemd-network/test-dhcp6-client.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -66,7 +66,9 @@ static int test_client_basic(sd_event *e) {
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp6_client_set_index(client, -1) == 0);
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp6_client_set_index(client, 42) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-        assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
+        assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                          sizeof (mac_addr),
Zbigniew Jędrzejewski-Szmek db38be
+                                          ARPHRD_ETHER) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_CLIENTID) == -EINVAL);
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
Zbigniew Jędrzejewski-Szmek db38be
@@ -572,7 +574,9 @@ static int test_client_solicit(sd_event *e) {
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
Zbigniew Jędrzejewski-Szmek db38be
-        assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
+        assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
Zbigniew Jędrzejewski-Szmek db38be
+                                          sizeof (mac_addr),
Zbigniew Jędrzejewski-Szmek db38be
+                                          ARPHRD_ETHER) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
         assert_se(sd_dhcp6_client_set_callback(client,
Zbigniew Jędrzejewski-Szmek db38be
                                                test_client_solicit_cb, e) >= 0);
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
Zbigniew Jędrzejewski-Szmek db38be
index e451af8643..63bfa86f99 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/network/networkd-dhcp4.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/network/networkd-dhcp4.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -599,7 +599,9 @@ int dhcp4_configure(Link *link) {
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0)
Zbigniew Jędrzejewski-Szmek db38be
                 return r;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-        r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
Zbigniew Jędrzejewski-Szmek db38be
+        r = sd_dhcp_client_set_mac(link->dhcp_client,
Zbigniew Jędrzejewski-Szmek db38be
+                                   (const uint8_t *) &link->mac,
Zbigniew Jędrzejewski-Szmek db38be
+                                   sizeof (link->mac), ARPHRD_ETHER);
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0)
Zbigniew Jędrzejewski-Szmek db38be
                 return r;
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
Zbigniew Jędrzejewski-Szmek db38be
index dcbe38a90a..c6e173fbc6 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/network/networkd-link.c
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/network/networkd-link.c
Zbigniew Jędrzejewski-Szmek db38be
@@ -909,7 +909,9 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
Zbigniew Jędrzejewski-Szmek db38be
                 return;
Zbigniew Jędrzejewski-Szmek db38be
         }
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
-        r = sd_dhcp6_client_set_mac(link->dhcp6_client, &link->mac);
Zbigniew Jędrzejewski-Szmek db38be
+        r = sd_dhcp6_client_set_mac(link->dhcp6_client,
Zbigniew Jędrzejewski-Szmek db38be
+                                    (const uint8_t *) &link->mac,
Zbigniew Jędrzejewski-Szmek db38be
+                                    sizeof (link->mac), ARPHRD_ETHER);
Zbigniew Jędrzejewski-Szmek db38be
         if (r < 0) {
Zbigniew Jędrzejewski-Szmek db38be
                 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
Zbigniew Jędrzejewski-Szmek db38be
                 return;
Zbigniew Jędrzejewski-Szmek db38be
@@ -1647,7 +1649,9 @@ int link_update(Link *link, sd_rtnl_message *m) {
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
                         if (link->dhcp_client) {
Zbigniew Jędrzejewski-Szmek db38be
                                 r = sd_dhcp_client_set_mac(link->dhcp_client,
Zbigniew Jędrzejewski-Szmek db38be
-                                                           &link->mac);
Zbigniew Jędrzejewski-Szmek db38be
+                                                           (const uint8_t *) &link->mac,
Zbigniew Jędrzejewski-Szmek db38be
+                                                           sizeof (link->mac),
Zbigniew Jędrzejewski-Szmek db38be
+                                                           ARPHRD_ETHER);
Zbigniew Jędrzejewski-Szmek db38be
                                 if (r < 0) {
Zbigniew Jędrzejewski-Szmek db38be
                                         log_warning_link(link,
Zbigniew Jędrzejewski-Szmek db38be
                                                          "Could not update MAC address in DHCP client: %s",
Zbigniew Jędrzejewski-Szmek db38be
@@ -1658,7 +1662,9 @@ int link_update(Link *link, sd_rtnl_message *m) {
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
                         if (link->dhcp6_client) {
Zbigniew Jędrzejewski-Szmek db38be
                                 r = sd_dhcp6_client_set_mac(link->dhcp6_client,
Zbigniew Jędrzejewski-Szmek db38be
-                                                            &link->mac);
Zbigniew Jędrzejewski-Szmek db38be
+                                                            (const uint8_t *) &link->mac,
Zbigniew Jędrzejewski-Szmek db38be
+                                                            sizeof (link->mac),
Zbigniew Jędrzejewski-Szmek db38be
+                                                            ARPHRD_ETHER);
Zbigniew Jędrzejewski-Szmek db38be
                                 if (r < 0) {
Zbigniew Jędrzejewski-Szmek db38be
                                         log_warning_link(link,
Zbigniew Jędrzejewski-Szmek db38be
                                                          "Could not update MAC address in DHCPv6 client: %s",
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
Zbigniew Jędrzejewski-Szmek db38be
index 98c67829b7..7416f82193 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/systemd/sd-dhcp-client.h
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/systemd/sd-dhcp-client.h
Zbigniew Jędrzejewski-Szmek db38be
@@ -49,8 +49,8 @@ int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
Zbigniew Jędrzejewski-Szmek db38be
                                        const struct in_addr *last_address);
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast);
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index);
Zbigniew Jędrzejewski-Szmek db38be
-int sd_dhcp_client_set_mac(sd_dhcp_client *client,
Zbigniew Jędrzejewski-Szmek db38be
-                           const struct ether_addr *addr);
Zbigniew Jędrzejewski-Szmek db38be
+int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
Zbigniew Jędrzejewski-Szmek db38be
+                           size_t addr_len, uint16_t arp_type);
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu);
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname);
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci);
Zbigniew Jędrzejewski-Szmek db38be
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
Zbigniew Jędrzejewski-Szmek db38be
index a4409e8d4e..c7f168fe21 100644
Zbigniew Jędrzejewski-Szmek db38be
--- a/src/systemd/sd-dhcp6-client.h
Zbigniew Jędrzejewski-Szmek db38be
+++ b/src/systemd/sd-dhcp6-client.h
Zbigniew Jędrzejewski-Szmek db38be
@@ -43,8 +43,8 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
Zbigniew Jędrzejewski-Szmek db38be
                                  sd_dhcp6_client_cb_t cb, void *userdata);
Zbigniew Jędrzejewski-Szmek db38be
 
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
Zbigniew Jędrzejewski-Szmek db38be
-int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
Zbigniew Jędrzejewski-Szmek db38be
-                            const struct ether_addr *mac_addr);
Zbigniew Jędrzejewski-Szmek db38be
+int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
Zbigniew Jędrzejewski-Szmek db38be
+                            size_t addr_len, uint16_t arp_type);
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
Zbigniew Jędrzejewski-Szmek db38be
                              size_t duid_len);
Zbigniew Jędrzejewski-Szmek db38be
 int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,