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

Tom Gundersen teg at jklm.no
Sat Oct 11 03:20:56 PDT 2014


Applied. Thanks!

Tom

On Wed, Oct 8, 2014 at 9:15 PM, Dan Williams <dcbw at redhat.com> wrote:
> 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.
> ---
> v3: use arp_type for identifying client MAC address types, and
> fix non-Ethernet hardware addresses in sd-dhcp6-client
>
>  src/libsystemd-network/dhcp-internal.h     | 10 ++--
>  src/libsystemd-network/dhcp-network.c      | 54 ++++++++++++++++++----
>  src/libsystemd-network/dhcp-packet.c       |  8 ++--
>  src/libsystemd-network/sd-dhcp-client.c    | 74 +++++++++++++++++++++++-------
>  src/libsystemd-network/sd-dhcp-server.c    |  8 ++--
>  src/libsystemd-network/sd-dhcp6-client.c   | 34 ++++++++++----
>  src/libsystemd-network/test-dhcp-client.c  | 14 ++++--
>  src/libsystemd-network/test-dhcp-option.c  |  2 +-
>  src/libsystemd-network/test-dhcp6-client.c |  8 +++-
>  src/network/networkd-dhcp4.c               |  4 +-
>  src/network/networkd-link.c                | 12 +++--
>  src/systemd/sd-dhcp-client.h               |  4 +-
>  src/systemd/sd-dhcp6-client.h              |  4 +-
>  13 files changed, 178 insertions(+), 58 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..29e9993 100644
> --- a/src/libsystemd-network/dhcp-network.c
> +++ b/src/libsystemd-network/dhcp-network.c
> @@ -18,27 +18,31 @@
>  ***/
>
>  #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"
>
> -int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
> -                                 uint32_t xid, struct ether_addr mac_addr) {
> -
> +static int _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,
> +                            const struct ether_addr *eth_mac,
> +                            uint16_t arp_type, uint8_t dhcp_hlen) {
>          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 ? */
>                  BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
> @@ -53,29 +57,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,27 +107,59 @@ 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;
> +        memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
>
>          r = bind(s, &link->sa, sizeof(link->ll));
>          if (r < 0)
>                  return -errno;
>
>          r = s;
>          s = -1;
>
>          return r;
>  }
>
> +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) {
> +        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;
> +        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);
> +                bcast_addr = eth_bcast;
> +                dhcp_hlen = ETH_ALEN;
> +        } else if (arp_type == ARPHRD_INFINIBAND) {
> +                assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL);
> +                bcast_addr = ib_bcast;
> +        } else
> +                return -EINVAL;
> +
> +        return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len,
> +                                bcast_addr, &eth_mac, arp_type, dhcp_hlen);
> +}
> +
>  int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) {
>          union sockaddr_union src = {
>                  .in.sin_family = AF_INET,
>                  .in.sin_port = htobe16(port),
>                  .in.sin_addr.s_addr = address,
>          };
>          _cleanup_close_ int 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 2f94c16..0eba4c3 100644
> --- a/src/libsystemd-network/sd-dhcp-client.c
> +++ b/src/libsystemd-network/sd-dhcp-client.c
> @@ -19,28 +19,31 @@
>
>  #include <stdlib.h>
>  #include <errno.h>
>  #include <string.h>
>  #include <stdio.h>
>  #include <net/ethernet.h>
>  #include <net/if_arp.h>
> +#include <linux/if_infiniband.h>
>  #include <netinet/ether.h>
>  #include <sys/param.h>
>  #include <sys/ioctl.h>
>
>  #include "util.h"
>  #include "list.h"
>  #include "refcnt.h"
>  #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 INFINIBAND_ALEN
> +
>  struct sd_dhcp_client {
>          RefCount n_ref;
>
>          DHCPState state;
>          sd_event *event;
>          int event_priority;
>          sd_event_source *timeout_resend;
> @@ -53,14 +56,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 +165,46 @@ 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 (arp_type == ARPHRD_ETHER)
> +                assert_return(addr_len == ETH_ALEN, -EINVAL);
> +        else if (arp_type == ARPHRD_INFINIBAND)
> +                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
> +        else
> +                return -EINVAL;
> +
> +        if (client->mac_addr_len == addr_len &&
> +            memcmp(&client->mac_addr, addr, addr_len) == 0)
>                  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 +334,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);
>
> @@ -333,22 +353,25 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
>             DHCPREQUEST messages that client sends.  The BROADCAST bit will
>             provide a hint to the DHCP server and BOOTP relay agent to broadcast
>             any messages to the client on the client's subnet.
>
>             Note: some interfaces needs this to be enabled, but some networks
>             needs this to be disabled as broadcasts are filteretd, so this
>             needs to be configurable */
> -        if (client->request_broadcast)
> +        if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
>                  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->arp_type == ARPHRD_ETHER)
> +                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)
> @@ -839,15 +862,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) {
> @@ -883,15 +908,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);
> @@ -1327,14 +1354,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;
> @@ -1363,21 +1393,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) {
> @@ -1451,31 +1494,28 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
>
>          len -= DHCP_IP_UDP_SIZE;
>
>          return client_handle_message(client, &packet->dhcp, len);
>  }
>
>  int sd_dhcp_client_start(sd_dhcp_client *client) {
> -        char buffer[ETHER_ADDR_TO_STRING_MAX];
>          int r;
>
>          assert_return(client, -EINVAL);
>
>          r = client_initialize(client);
>          if (r < 0)
>                  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_addr_to_string(&client->client_id.mac_addr, buffer));
> +                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 a6d6178..24fedd2 100644
> --- a/src/libsystemd-network/sd-dhcp-server.c
> +++ b/src/libsystemd-network/sd-dhcp-server.c
> @@ -388,16 +388,16 @@ 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);
> +                              be32toh(req->message->xid), 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);
>
> @@ -509,16 +509,16 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
>          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/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
> index 6ea68c9..fa4f9b5 100644
> --- a/src/libsystemd-network/sd-dhcp6-client.c
> +++ b/src/libsystemd-network/sd-dhcp6-client.c
> @@ -18,14 +18,15 @@
>    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 <errno.h>
>  #include <string.h>
>  #include <sys/ioctl.h>
> +#include <linux/if_infiniband.h>
>
>  #include "udev.h"
>  #include "udev-util.h"
>  #include "virt.h"
>  #include "siphash24.h"
>  #include "util.h"
>  #include "refcnt.h"
> @@ -40,22 +41,26 @@
>  #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
>
>  /* RFC 3315 section 9.1:
>   *      A DUID can be no more than 128 octets long (not including the type code).
>   */
>  #define MAX_DUID_LEN 128
>
> +#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
> +
>  struct sd_dhcp6_client {
>          RefCount n_ref;
>
>          enum DHCP6State state;
>          sd_event *event;
>          int event_priority;
>          int index;
> -        struct ether_addr mac_addr;
> +        uint8_t mac_addr[MAX_MAC_ADDR_LEN];
> +        size_t mac_addr_len;
> +        uint16_t arp_type;
>          DHCP6IA ia_na;
>          be32_t transaction_id;
>          usec_t transaction_start;
>          struct sd_dhcp6_lease *lease;
>          int fd;
>          be16_t *req_opts;
>          size_t req_opts_allocated;
> @@ -156,23 +161,36 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
>          assert_return(interface_index >= -1, -EINVAL);
>
>          client->index = interface_index;
>
>          return 0;
>  }
>
> -int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
> -                            const struct ether_addr *mac_addr)
> +int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
> +                            size_t addr_len, uint16_t arp_type)
>  {
>          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 (mac_addr)
> -                memcpy(&client->mac_addr, mac_addr, sizeof(client->mac_addr));
> +        if (arp_type == ARPHRD_ETHER)
> +                assert_return(addr_len == ETH_ALEN, -EINVAL);
> +        else if (arp_type == ARPHRD_INFINIBAND)
> +                assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
>          else
> -                memset(&client->mac_addr, 0x00, sizeof(client->mac_addr));
> +                return -EINVAL;
> +
> +        if (client->mac_addr_len == addr_len &&
> +            memcmp(&client->mac_addr, addr, addr_len) == 0)
> +                return 0;
> +
> +        memcpy(&client->mac_addr, addr, addr_len);
> +        client->mac_addr_len = addr_len;
> +        client->arp_type = arp_type;
>
>          return 0;
>  }
>
>  int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
>                               size_t duid_len)
>  {
> @@ -642,16 +660,16 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
>                  name = net_get_name(device);
>          }
>
>          if (name)
>                  siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
>          else
>                  /* fall back to mac address if no predictable name available */
> -                siphash24((uint8_t*)&id, &client->mac_addr, ETH_ALEN,
> -                          HASH_KEY.bytes);
> +                siphash24((uint8_t*)&id, &client->mac_addr,
> +                          client->mac_addr_len, HASH_KEY.bytes);
>
>          /* fold into 32 bits */
>          client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
>
>          return 0;
>  }
>
> 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 63cdc7a..eac3844 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/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
> index 37ddfc2..26b28a2 100644
> --- a/src/libsystemd-network/test-dhcp6-client.c
> +++ b/src/libsystemd-network/test-dhcp6-client.c
> @@ -62,15 +62,17 @@ static int test_client_basic(sd_event *e) {
>          assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
>
>          assert_se(sd_dhcp6_client_set_index(client, 15) == 0);
>          assert_se(sd_dhcp6_client_set_index(client, -42) == -EINVAL);
>          assert_se(sd_dhcp6_client_set_index(client, -1) == 0);
>          assert_se(sd_dhcp6_client_set_index(client, 42) >= 0);
>
> -        assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
> +        assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
> +                                          sizeof (mac_addr),
> +                                          ARPHRD_ETHER) >= 0);
>
>          assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_CLIENTID) == -EINVAL);
>          assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
>          assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_NTP_SERVER) == -EEXIST);
>          assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_SNTP_SERVERS) == 0);
>          assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
>          assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
> @@ -568,15 +570,17 @@ static int test_client_solicit(sd_event *e) {
>
>          assert_se(sd_dhcp6_client_new(&client) >= 0);
>          assert_se(client);
>
>          assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
>
>          assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
> -        assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
> +        assert_se(sd_dhcp6_client_set_mac(client, (const uint8_t *) &mac_addr,
> +                                          sizeof (mac_addr),
> +                                          ARPHRD_ETHER) >= 0);
>
>          assert_se(sd_dhcp6_client_set_callback(client,
>                                                 test_client_solicit_cb, e) >= 0);
>
>          assert_se(sd_event_add_time(e, &hangcheck, clock_boottime_or_monotonic(),
>                                      time_now + 2 * USEC_PER_SEC, 0,
>                                      test_hangcheck, NULL) >= 0);
> diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
> index e451af8..63bfa86 100644
> --- a/src/network/networkd-dhcp4.c
> +++ b/src/network/networkd-dhcp4.c
> @@ -595,15 +595,17 @@ int dhcp4_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;
>
> diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
> index dcbe38a..c6e173f 100644
> --- a/src/network/networkd-link.c
> +++ b/src/network/networkd-link.c
> @@ -905,15 +905,17 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
>
>          r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
>          if (r < 0) {
>                  link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
>                  return;
>          }
>
> -        r = sd_dhcp6_client_set_mac(link->dhcp6_client, &link->mac);
> +        r = sd_dhcp6_client_set_mac(link->dhcp6_client,
> +                                    (const uint8_t *) &link->mac,
> +                                    sizeof (link->mac), ARPHRD_ETHER);
>          if (r < 0) {
>                  link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
>                  return;
>          }
>
>          r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
>          if (r < 0) {
> @@ -1643,26 +1645,30 @@ int link_update(Link *link, sd_rtnl_message *m) {
>                                                           strerror(-r));
>                                          return r;
>                                  }
>                          }
>
>                          if (link->dhcp_client) {
>                                  r = sd_dhcp_client_set_mac(link->dhcp_client,
> -                                                           &link->mac);
> +                                                           (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;
>                                  }
>                          }
>
>                          if (link->dhcp6_client) {
>                                  r = sd_dhcp6_client_set_mac(link->dhcp6_client,
> -                                                            &link->mac);
> +                                                            (const uint8_t *) &link->mac,
> +                                                            sizeof (link->mac),
> +                                                            ARPHRD_ETHER);
>                                  if (r < 0) {
>                                          log_warning_link(link,
>                                                           "Could not update MAC address in DHCPv6 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);
> diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
> index a4409e8..c7f168f 100644
> --- a/src/systemd/sd-dhcp6-client.h
> +++ b/src/systemd/sd-dhcp6-client.h
> @@ -39,16 +39,16 @@ typedef struct sd_dhcp6_client sd_dhcp6_client;
>
>  typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event,
>                                       void *userdata);
>  int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
>                                   sd_dhcp6_client_cb_t cb, void *userdata);
>
>  int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
> -int sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
> -                            const struct ether_addr *mac_addr);
> +int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
> +                            size_t addr_len, uint16_t arp_type);
>  int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
>                               size_t duid_len);
>  int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
>                                         uint16_t option);
>
>  int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
>
> --
> 1.9.3
>
>
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel


More information about the systemd-devel mailing list