]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp-client,sd-dhcp-client-server: set chaddr in dhcp_message_init()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 22 Jan 2022 17:14:31 +0000 (02:14 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 23 Jan 2022 19:18:20 +0000 (04:18 +0900)
And also set chaddr and hlen for packets on non-Ethernet interfaces,
except for InfiniBand.

src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-packet.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/test-dhcp-option.c

index 6538f05bdb44b559473139b9176e2b50b28a607d..466d8e4b3f1403f4889ef1f3a5a7d77802d9ab65 100644 (file)
@@ -53,8 +53,8 @@ typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
 int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message);
 
 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);
+                      uint8_t type, uint16_t arp_type, uint8_t hlen, const uint8_t *chaddr,
+                      size_t optlen, size_t *optoffset);
 
 uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
 
index cace916f4413b6beca58589ac0b3b1e642d7fa3a..d1a1cf57f3d9b1b2e627cdb168587d0740ac14ad 100644 (file)
 
 #include "dhcp-internal.h"
 #include "dhcp-protocol.h"
+#include "memory-util.h"
 
 #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
 
-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) {
+int dhcp_message_init(
+                DHCPMessage *message,
+                uint8_t op,
+                uint32_t xid,
+                uint8_t type,
+                uint16_t arp_type,
+                uint8_t hlen,
+                const uint8_t *chaddr,
+                size_t optlen,
+                size_t *optoffset) {
+
         size_t offset = 0;
         int r;
 
         assert(IN_SET(op, BOOTREQUEST, BOOTREPLY));
-        assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND));
+        assert(chaddr || hlen == 0);
 
         message->op = op;
         message->htype = arp_type;
-        message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0;
+
+        /* RFC2131 section 4.1.1:
+           The client MUST include its hardware address in the ’chaddr’ field, if
+           necessary for delivery of DHCP reply messages.
+
+           RFC 4390 section 2.1:
+           A DHCP client, when working over an IPoIB interface, MUST follow the
+           following rules:
+           "htype" (hardware address type) MUST be 32 [ARPPARAM].
+           "hlen" (hardware address length) MUST be 0.
+           "chaddr" (client hardware address) field MUST be zeroed.
+         */
+        message->hlen = (arp_type == ARPHRD_INFINIBAND) ? 0 : hlen;
+        memcpy_safe(message->chaddr, chaddr, message->hlen);
+
         message->xid = htobe32(xid);
         message->magic = htobe32(DHCP_MAGIC_COOKIE);
 
index c89d9f3f2bf1cc71e4eaa25aede766d0a468ac0b..7b296ae4a0402951df329bafd56232ad6d01003c 100644 (file)
@@ -832,7 +832,8 @@ static int client_message_init(
                 return -ENOMEM;
 
         r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
-                              client->arp_type, optlen, &optoffset);
+                              client->arp_type, client->mac_addr_len, client->mac_addr,
+                              optlen, &optoffset);
         if (r < 0)
                 return r;
 
@@ -862,15 +863,6 @@ static int client_message_init(
         if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
                 packet->dhcp.flags = htobe16(0x8000);
 
-        /* RFC2131 section 4.1.1:
-           The client MUST include its hardware address in the ’chaddr’ field, if
-           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).
-         */
-        if (client->arp_type == ARPHRD_ETHER)
-                memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
-
         /* If no client identifier exists, construct an RFC 4361-compliant one */
         if (client->client_id_len == 0) {
                 size_t duid_len;
index f00a1754e2baaaad95a220fb55e53dfbf0565653..91069c078288252333cfb48d1a1e5f902715cb15 100644 (file)
@@ -482,14 +482,14 @@ static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
                 return -ENOMEM;
 
         r = dhcp_message_init(&packet->dhcp, BOOTREPLY,
-                              be32toh(req->message->xid), type, ARPHRD_ETHER,
+                              be32toh(req->message->xid), type,
+                              req->message->htype, req->message->hlen, req->message->chaddr,
                               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);
 
         *_optoffset = optoffset;
         *ret = TAKE_PTR(packet);
@@ -621,7 +621,7 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
                 return -ENOMEM;
 
         r = dhcp_message_init(&packet->dhcp, BOOTREPLY, 0,
-                              DHCP_FORCERENEW, ARPHRD_ETHER,
+                              DHCP_FORCERENEW, ARPHRD_ETHER, ETH_ALEN, chaddr,
                               DHCP_MIN_OPTIONS_SIZE, &optoffset);
         if (r < 0)
                 return r;
@@ -631,8 +631,6 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
         if (r < 0)
                 return r;
 
-        memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
-
         return dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
                                     &packet->dhcp,
                                     sizeof(DHCPMessage) + optoffset);
index 800a6641e357bc43c3e326891f694733407440d7..b01b1f57a3ad4bc2c02b89c1209688398c15f11b 100644 (file)
@@ -89,7 +89,8 @@ static void test_message_init(void) {
         message = malloc0(len);
 
         assert_se(dhcp_message_init(message, BOOTREQUEST, 0x12345678,
-                  DHCP_DISCOVER, ARPHRD_ETHER, optlen, &optoffset) >= 0);
+                                    DHCP_DISCOVER, ARPHRD_ETHER, ETH_ALEN, (uint8_t[16]){},
+                                    optlen, &optoffset) >= 0);
 
         assert_se(message->xid == htobe32(0x12345678));
         assert_se(message->op == BOOTREQUEST);