summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-01-23 02:14:31 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-01-24 04:18:20 +0900
commit97fa338dceb8c59f9dd5047d327c819aca328e5c (patch)
tree14def8f02362663cc6d8c203ecf4a79a2d047a98
parenta6508f37c9321c93f5d0b0184611d0fd5e85e2fe (diff)
downloadsystemd-97fa338dceb8c59f9dd5047d327c819aca328e5c.tar.gz
sd-dhcp-client,sd-dhcp-client-server: set chaddr in dhcp_message_init()
And also set chaddr and hlen for packets on non-Ethernet interfaces, except for InfiniBand.
-rw-r--r--src/libsystemd-network/dhcp-internal.h4
-rw-r--r--src/libsystemd-network/dhcp-packet.c33
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c12
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c8
-rw-r--r--src/libsystemd-network/test-dhcp-option.c3
5 files changed, 37 insertions, 23 deletions
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index 6538f05bdb..466d8e4b3f 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -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);
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index cace916f44..d1a1cf57f3 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -10,21 +10,44 @@
#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);
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index c89d9f3f2b..7b296ae4a0 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -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;
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index f00a1754e2..91069c0782 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -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);
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
index 800a6641e3..b01b1f57a3 100644
--- a/src/libsystemd-network/test-dhcp-option.c
+++ b/src/libsystemd-network/test-dhcp-option.c
@@ -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);