summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobby Zambito <contact@robbyzambito.me>2026-01-23 23:04:59 -0500
committerRobby Zambito <contact@robbyzambito.me>2026-01-23 23:05:20 -0500
commita81c4b3175a688fb634d754e37f58b605e83fc3d (patch)
treec7a361f2150ab61f86763ba1da747cfd1e605220 /src
parent43f7497424b58df28e96ffd7418642a951ffec1d (diff)
Calculate IPv4 checksum header
This was causing an issue because virtual networks were dropping packets without this being set
Diffstat (limited to 'src')
-rw-r--r--src/EthIpUdp.zig36
1 files changed, 36 insertions, 0 deletions
diff --git a/src/EthIpUdp.zig b/src/EthIpUdp.zig
index 472e421..27fc611 100644
--- a/src/EthIpUdp.zig
+++ b/src/EthIpUdp.zig
@@ -49,9 +49,45 @@ pub const EthIpUdp = packed struct(u336) { // 42 bytes * 8 bits = 336
pub fn setPayloadLen(self: *@This(), len: usize) void {
self.ip.len = @intCast(len + (@bitSizeOf(@TypeOf(self.udp)) / 8) + (@bitSizeOf(@TypeOf(self.ip)) / 8));
+
+ // Zero the checksum field before calculation
+ self.ip.header_checksum = 0;
+
+ // Serialize IP header to big-endian bytes
+ var ip_bytes: [@bitSizeOf(@TypeOf(self.ip)) / 8]u8 = undefined;
+ var w: Writer = .fixed(&ip_bytes);
+ w.writeStruct(self.ip, .big) catch unreachable;
+
+ // Calculate checksum over serialized bytes
+ self.ip.header_checksum = onesComplement16(&ip_bytes);
+
self.udp.len = @intCast(len + (@bitSizeOf(@TypeOf(self.udp)) / 8));
}
};
+fn onesComplement16(data: []const u8) u16 {
+ var sum: u32 = 0;
+
+ // Process pairs of bytes as 16-bit words
+ var i: usize = 0;
+ while (i + 1 < data.len) : (i += 2) {
+ const word: u16 = (@as(u16, data[i]) << 8) | data[i + 1];
+ sum += word;
+ }
+
+ // Handle odd byte if present
+ if (data.len % 2 == 1) {
+ sum += @as(u32, data[data.len - 1]) << 8;
+ }
+
+ // Fold 32-bit sum to 16 bits
+ while (sum >> 16 != 0) {
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ }
+
+ // Return ones' complement
+ return ~@as(u16, @truncate(sum));
+}
+
const std = @import("std");
const Writer = std.Io.Writer;