Skip to main content

turmoil_net/kernel/
packet.rs

1//! Structured packet types.
2//!
3//! Packets are not byte-encoded — the fields carry the same demux
4//! information (src/dst addrs, ports, TCP flags/seq/ack) a real kernel
5//! would read from IP + transport headers, but as typed data. This
6//! preserves state-machine fidelity without a parser. Byte-level framing
7//! can be added later if packet-corruption fault injection is needed.
8//!
9//! Header sizes below are used for MTU accounting only — no bytes
10//! actually exist on the wire.
11
12use std::net::IpAddr;
13
14use bytes::Bytes;
15
16/// IPv4 header size in bytes, no options.
17pub const IPV4_HEADER_SIZE: u16 = 20;
18/// IPv6 header size in bytes, no extension headers.
19pub const IPV6_HEADER_SIZE: u16 = 40;
20/// UDP header size in bytes.
21pub const UDP_HEADER_SIZE: u16 = 8;
22/// TCP header size in bytes, no options.
23pub const TCP_HEADER_SIZE: u16 = 20;
24
25/// An IP-layer packet. UDS lives outside this model — Unix sockets
26/// bypass the network stack and deliver socket-to-socket.
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub struct Packet {
29    pub src: IpAddr,
30    pub dst: IpAddr,
31    pub ttl: u8,
32    pub payload: Transport,
33}
34
35impl Packet {
36    /// Total size in bytes if this packet were actually serialized —
37    /// IP header + transport header + payload. Used to enforce MTU.
38    pub fn size(&self) -> u32 {
39        let ip_hdr = match self.dst {
40            IpAddr::V4(_) => IPV4_HEADER_SIZE,
41            IpAddr::V6(_) => IPV6_HEADER_SIZE,
42        } as u32;
43        ip_hdr + self.payload.size()
44    }
45}
46
47/// Transport-layer payload of a [`Packet`].
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum Transport {
50    Udp(UdpDatagram),
51    Tcp(TcpSegment),
52}
53
54impl Transport {
55    /// Transport header + payload size.
56    pub fn size(&self) -> u32 {
57        match self {
58            Transport::Udp(d) => UDP_HEADER_SIZE as u32 + d.payload.len() as u32,
59            Transport::Tcp(s) => TCP_HEADER_SIZE as u32 + s.payload.len() as u32,
60        }
61    }
62}
63
64/// UDP datagram — `(src_port, dst_port, payload)`. Addresses live on the
65/// enclosing [`Packet`].
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub struct UdpDatagram {
68    pub src_port: u16,
69    pub dst_port: u16,
70    pub payload: Bytes,
71}
72
73/// TCP segment. Fields mirror what a real kernel needs for state-machine
74/// decisions; anything not listed here (urgent pointer, options beyond
75/// MSS, checksum) is intentionally omitted.
76#[derive(Debug, Clone, PartialEq, Eq)]
77pub struct TcpSegment {
78    pub src_port: u16,
79    pub dst_port: u16,
80    pub seq: u32,
81    pub ack: u32,
82    pub flags: TcpFlags,
83    pub window: u16,
84    pub payload: Bytes,
85}
86
87/// TCP control flags.
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
89pub struct TcpFlags {
90    pub syn: bool,
91    pub ack: bool,
92    pub fin: bool,
93    pub rst: bool,
94    pub psh: bool,
95    pub urg: bool,
96}