1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2013 Intel Corporation. All rights reserved.
7 #include <net/ethernet.h>
8 #include <net/if_arp.h>
11 #include "dhcp-internal.h"
12 #include "dhcp-protocol.h"
14 #define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
16 int dhcp_message_init(DHCPMessage
*message
, uint8_t op
, uint32_t xid
,
17 uint8_t type
, uint16_t arp_type
, size_t optlen
,
22 assert(IN_SET(op
, BOOTREQUEST
, BOOTREPLY
));
23 assert(IN_SET(arp_type
, ARPHRD_ETHER
, ARPHRD_INFINIBAND
));
26 message
->htype
= arp_type
;
27 message
->hlen
= (arp_type
== ARPHRD_ETHER
) ? ETHER_ADDR_LEN
: 0;
28 message
->xid
= htobe32(xid
);
29 message
->magic
= htobe32(DHCP_MAGIC_COOKIE
);
31 r
= dhcp_option_append(message
, optlen
, &offset
, 0,
32 SD_DHCP_OPTION_MESSAGE_TYPE
, 1, &type
);
41 uint16_t dhcp_packet_checksum(uint8_t *buf
, size_t len
) {
42 uint64_t *buf_64
= (uint64_t*)buf
;
43 uint64_t *end_64
= buf_64
+ (len
/ sizeof(uint64_t));
48 while (buf_64
< end_64
) {
51 /* wrap around in one's complement */
57 if (len
% sizeof(uint64_t)) {
58 /* If the buffer is not aligned to 64-bit, we need
59 to zero-pad the last few bytes and add them in */
60 uint64_t buf_tail
= 0;
62 memcpy(&buf_tail
, buf_64
, len
% sizeof(uint64_t));
71 sum
= (sum
& 0xffff) + (sum
>> 16);
76 void dhcp_packet_append_ip_headers(DHCPPacket
*packet
, be32_t source_addr
,
77 uint16_t source_port
, be32_t destination_addr
,
78 uint16_t destination_port
, uint16_t len
) {
79 packet
->ip
.version
= IPVERSION
;
80 packet
->ip
.ihl
= DHCP_IP_SIZE
/ 4;
81 packet
->ip
.tot_len
= htobe16(len
);
83 packet
->ip
.tos
= IPTOS_CLASS_CS6
;
85 packet
->ip
.protocol
= IPPROTO_UDP
;
86 packet
->ip
.saddr
= source_addr
;
87 packet
->ip
.daddr
= destination_addr
;
89 packet
->udp
.source
= htobe16(source_port
);
90 packet
->udp
.dest
= htobe16(destination_port
);
92 packet
->udp
.len
= htobe16(len
- DHCP_IP_SIZE
);
94 packet
->ip
.check
= packet
->udp
.len
;
95 packet
->udp
.check
= dhcp_packet_checksum((uint8_t*)&packet
->ip
.ttl
, len
- 8);
97 packet
->ip
.ttl
= IPDEFTTL
;
99 packet
->ip
.check
= dhcp_packet_checksum((uint8_t*)&packet
->ip
, DHCP_IP_SIZE
);
102 int dhcp_packet_verify_headers(DHCPPacket
*packet
, size_t len
, bool checksum
, uint16_t port
) {
109 if (packet
->ip
.version
!= IPVERSION
) {
110 log_debug("ignoring packet: not IPv4");
114 if (packet
->ip
.ihl
< 5) {
115 log_debug("ignoring packet: IPv4 IHL (%u words) invalid",
120 hdrlen
= packet
->ip
.ihl
* 4;
122 log_debug("ignoring packet: IPv4 IHL (%zu bytes) "
123 "smaller than minimum (20 bytes)", hdrlen
);
128 log_debug("ignoring packet: packet (%zu bytes) "
129 "smaller than expected (%zu) by IP header", len
,
136 if (packet
->ip
.protocol
!= IPPROTO_UDP
) {
137 log_debug("ignoring packet: not UDP");
141 if (len
< hdrlen
+ be16toh(packet
->udp
.len
)) {
142 log_debug("ignoring packet: packet (%zu bytes) "
143 "smaller than expected (%zu) by UDP header", len
,
144 hdrlen
+ be16toh(packet
->udp
.len
));
148 if (be16toh(packet
->udp
.dest
) != port
) {
149 log_debug("ignoring packet: to port %u, which "
150 "is not the DHCP client port (%u)",
151 be16toh(packet
->udp
.dest
), port
);
155 /* checksums - computing these is relatively expensive, so only do it
156 if all the other checks have passed
159 if (dhcp_packet_checksum((uint8_t*)&packet
->ip
, hdrlen
)) {
160 log_debug("ignoring packet: invalid IP checksum");
164 if (checksum
&& packet
->udp
.check
) {
165 packet
->ip
.check
= packet
->udp
.len
;
168 if (dhcp_packet_checksum((uint8_t*)&packet
->ip
.ttl
,
169 be16toh(packet
->udp
.len
) + 12)) {
170 log_debug("ignoring packet: invalid UDP checksum");