diff options
Diffstat (limited to 'src')
| -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; |
