***/
#include <net/if_arp.h>
-#include <string.h>
#include "dhcp-option.h"
#include "dhcp-packet.h"
+#include "ip-util.h"
#include "log.h"
#include "memory-util.h"
return 0;
}
-uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
- uint64_t *buf_64 = (uint64_t*)buf;
- uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t));
- uint64_t sum = 0;
-
- /* See RFC1071 */
-
- while (buf_64 < end_64) {
- sum += *buf_64;
- if (sum < *buf_64)
- /* wrap around in one's complement */
- sum++;
-
- buf_64++;
- }
-
- if (len % sizeof(uint64_t)) {
- /* If the buffer is not aligned to 64-bit, we need
- to zero-pad the last few bytes and add them in */
- uint64_t buf_tail = 0;
-
- memcpy(&buf_tail, buf_64, len % sizeof(uint64_t));
-
- sum += buf_tail;
- if (sum < buf_tail)
- /* wrap around */
- sum++;
- }
-
- while (sum >> 16)
- sum = (sum & 0xffff) + (sum >> 16);
-
- return ~sum;
-}
-
void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
uint16_t source_port, be32_t destination_addr,
uint16_t destination_port, uint16_t len, int ip_service_type) {
packet->udp.len = htobe16(len - DHCP_IP_SIZE);
packet->ip.check = packet->udp.len;
- packet->udp.check = dhcp_packet_checksum(&packet->ip.ttl, len - 8);
+ packet->udp.check = ip_checksum(&packet->ip.ttl, len - 8);
packet->ip.ttl = IPDEFTTL;
packet->ip.check = 0;
- packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE);
+ packet->ip.check = ip_checksum(&packet->ip, DHCP_IP_SIZE);
}
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) {
if all the other checks have passed
*/
- if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen))
+ if (ip_checksum(&packet->ip, hdrlen))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: invalid IP checksum");
packet->ip.check = packet->udp.len;
packet->ip.ttl = 0;
- if (dhcp_packet_checksum(&packet->ip.ttl,
- be16toh(packet->udp.len) + 12))
+ if (ip_checksum(&packet->ip.ttl, be16toh(packet->udp.len) + 12))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: invalid UDP checksum");
}
size_t optlen,
size_t *ret_optoffset);
-uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
-
void dhcp_packet_append_ip_headers(
DHCPPacket *packet,
be32_t source_addr,
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <string.h>
+
+#include "iovec-util.h"
+#include "ip-util.h"
+
+static uint64_t complement_sum(uint64_t a, uint64_t b) {
+ /* This performs one's complement addition (end-around carry). See RFC1071. */
+ if (a <= UINT64_MAX - b)
+ return a + b;
+
+ return a - (UINT64_MAX - b);
+}
+
+static uint64_t checksum_iov(uint64_t sum, const struct iovec *iov) {
+ assert(iov);
+
+ for (struct iovec i = *iov; iovec_is_set(&i); iovec_inc(&i, sizeof(uint64_t))) {
+ uint64_t t = 0;
+ memcpy(&t, i.iov_base, MIN(i.iov_len, sizeof(uint64_t)));
+ sum = complement_sum(sum, t);
+ }
+
+ return sum;
+}
+
+static uint16_t checksum_finalize(uint64_t sum) {
+ while ((sum >> 16) != 0)
+ sum = (sum & 0xffffu) + (sum >> 16);
+
+ return ~sum;
+}
+
+uint16_t ip_checksum(const void *buf, size_t len) {
+ /* See RFC1071 */
+ return checksum_finalize(checksum_iov(0, &IOVEC_MAKE(buf, len)));
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "sd-forward.h"
+
+uint16_t ip_checksum(const void *buf, size_t len);
'dhcp6-protocol.c',
'icmp6-packet.c',
'icmp6-util.c',
+ 'ip-util.c',
'lldp-neighbor.c',
'lldp-network.c',
'ndisc-option.c',
network_test_template + {
'sources' : files('test-dhcp6-client.c'),
},
+ network_test_template + {
+ 'sources' : files('test-ip-util.c'),
+ },
network_test_template + {
'sources' : files('test-ipv4ll-manual.c'),
'type' : 'manual',
#include "dhcp-duid-internal.h"
#include "dhcp-network.h"
#include "dhcp-option.h"
-#include "dhcp-packet.h"
#include "ether-addr-util.h"
#include "fd-util.h"
+#include "ip-util.h"
#include "log.h"
#include "tests.h"
ASSERT_OK_ZERO(sd_dhcp_client_set_request_option(client, 101));
}
-TEST(dhcp_packet_checksum) {
- uint8_t buf[20] = {
- 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff
- };
-
- ASSERT_EQ(dhcp_packet_checksum(buf, 20), be16toh(0x78ae));
-}
-
TEST(dhcp_identifier_set_iaid) {
uint32_t iaid_legacy;
be32_t iaid;
discover->ip.ttl = 0;
discover->ip.check = discover->udp.len;
- udp_check = ~dhcp_packet_checksum(&discover->ip.ttl, len - 8);
+ udp_check = ~ip_checksum(&discover->ip.ttl, len - 8);
ASSERT_EQ(udp_check, 0xffff);
discover->ip.ttl = IPDEFTTL;
discover->ip.check = ip_check;
- ip_check = ~dhcp_packet_checksum((uint8_t*) &discover->ip, sizeof(discover->ip));
+ ip_check = ~ip_checksum((uint8_t*) &discover->ip, sizeof(discover->ip));
ASSERT_EQ(ip_check, 0xffff);
ASSERT_NE(discover->dhcp.xid, 0u);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "ip-util.h"
+#include "tests.h"
+
+TEST(ip_checksum) {
+ uint8_t buf[20] = {
+ 0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff
+ };
+
+ ASSERT_EQ(ip_checksum(buf, 20), be16toh(0x78ae));
+}
+
+DEFINE_TEST_MAIN(LOG_DEBUG);