Dear systemd-networkd developers,
I think there is an issue with the generation of the UDP checksums on
big-endian systems, which I already posted as an issue to the bugtracker
(https://bugs.freedesktop.org/show_bug.cgi?id=78082) but since there was
not reaction I'll give it a try in this List.
I run the latest systemd on x86 (LE) and powerpc (BE) machines, and the
powerpc never aquired a lease - checking with wireshark it complains on
incorrect UDP checksums.
Changing the checksum calculation to the code it borrowed from busybox
(see attachment) fixed this issue for me.
Since the code from busybox is less efficient I guess it is not a direct
replacement, but it would be great having systemd-networkd also running
on BE systems.
Best regards,
Thomas Ritter
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index d72d7a6..de63217 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -60,53 +60,33 @@ int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
}
uint16_t dhcp_packet_checksum(void *buf, size_t len) {
-uint64_t *buf_64 = buf;
-uint64_t *end_64 = (uint64_t*)buf + (len / sizeof(uint64_t));
-uint32_t *buf_32;
-uint16_t *buf_16;
-uint8_t *buf_8;
-uint64_t sum = 0;
-
-while (buf_64 end_64) {
-sum += *buf_64;
-if (sum *buf_64)
-sum++;
-
-buf_64 ++;
-}
-
-buf_32 = (uint32_t*)buf_64;
-
-if (len sizeof(uint32_t)) {
-sum += *buf_32;
-if (sum *buf_32)
-sum++;
-
-buf_32 ++;
-}
-
-buf_16 = (uint16_t*)buf_32;
-
-if (len sizeof(uint16_t)) {
-sum += *buf_16;
-if (sum *buf_16)
-sum ++;
-
-buf_16 ++;
-}
-
-buf_8 = (uint8_t*)buf_16;
-
-if (len sizeof(uint8_t)) {
-sum += *buf_8;
-if (sum *buf_8)
-sum++;
-}
-
-while (sum 16)
-sum = (sum 0x) + (sum 16);
-
-return ~sum;
+/*
+ * Our algorithm is simple, using a 32 bit accumulator,
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+uint16_t *addr = (uint16_t*)buf;
+unsigned sum = 0;
+while (nleft 1) {
+sum += *addr++;
+nleft -= 2;
+}
+
+/* Mop up an odd byte, if necessary */
+if (nleft == 1) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+sum += *(uint8_t*)addr;
+#else
+sum += *(uint8_t*)addr 8;
+#endif
+}
+
+/* Add back carry outs from top 16 bits to low 16 bits */
+sum = (sum 16) + (sum 0x); /* add hi 16 to low 16 */
+sum += (sum 16); /* add carry */
+
+return (uint16_t)~sum;
}
void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
___
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/systemd-devel