summaryrefslogtreecommitdiff
path: root/src/EthIpUdp.zig
blob: 472e42169333e11aa4a6b82a9367329d1fcfafce (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
pub const EthIpUdp = packed struct(u336) { // 42 bytes * 8 bits = 336
    // --- UDP (Last in memory, defined first for LSB->MSB) ---
    udp: packed struct {
        checksum: u16 = 0,
        len: u16,
        dst_port: u16,
        src_port: u16,
    },

    // --- IP ---
    ip: packed struct {
        dst_addr: u32,
        src_addr: u32,
        header_checksum: u16 = 0,
        protocol: u8 = 17, // udp
        ttl: u8 = 0x40,

        // fragment_offset (13 bits) + flags (3 bits) = 16 bits
        // In Big Endian, flags are the high bits of the first byte.
        // To have flags appear first in the stream, define them last here.
        fragment_offset: u13 = 0,
        flags: packed struct(u3) {
            reserved: u1 = 0,
            dont_fragment: u1 = 1,
            more_fragments: u1 = 0,
        } = .{},

        id: u16,
        len: u16,
        tos: u8 = undefined,

        // ip_version (4 bits) + ihl (4 bits) = 8 bits
        // To have version appear first (high nibble), define it last.
        ihl: u4 = 5,
        ip_version: u4 = 4,
    },

    // --- Ethernet ---
    eth_type: u16 = std.os.linux.ETH.P.IP,
    src_mac: @Vector(6, u8),
    dst_mac: @Vector(6, u8) = @splat(0xff),

    pub fn toBytes(self: @This()) [336 / 8]u8 {
        var res: [336 / 8]u8 = undefined;
        var w: Writer = .fixed(&res);
        w.writeStruct(self, .big) catch unreachable;
        return res;
    }

    pub fn setPayloadLen(self: *@This(), len: usize) void {
        self.ip.len = @intCast(len + (@bitSizeOf(@TypeOf(self.udp)) / 8) + (@bitSizeOf(@TypeOf(self.ip)) / 8));
        self.udp.len = @intCast(len + (@bitSizeOf(@TypeOf(self.udp)) / 8));
    }
};

const std = @import("std");
const Writer = std.Io.Writer;