diff options
| author | Robby Zambito <contact@robbyzambito.me> | 2026-01-23 23:04:59 -0500 |
|---|---|---|
| committer | Robby Zambito <contact@robbyzambito.me> | 2026-01-23 23:05:20 -0500 |
| commit | a81c4b3175a688fb634d754e37f58b605e83fc3d (patch) | |
| tree | c7a361f2150ab61f86763ba1da747cfd1e605220 | |
| parent | 43f7497424b58df28e96ffd7418642a951ffec1d (diff) | |
Calculate IPv4 checksum header
This was causing an issue because virtual networks were dropping packets
without this being set
| -rw-r--r-- | src/EthIpUdp.zig | 36 |
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; |
