- Home
- Kernel Internals
- Networking
- Protocols
Protocol Layer¶
All protocol helpers are stateless, pure functions — they take input slices and write into caller-supplied output buffers. No global state, no heap allocation. The only exception is TcpConnection, which is a state-machine struct owned by userland.
Ethernet II (ethernet.rs)¶
Frame Layout¶
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
├───────────────────────────────────────────────────────────────┤
│ Destination MAC (6 bytes) │
├───────────────────────────────────────────────────────────────┤
│ Source MAC (6 bytes) │
├───────────────────────────────────────────────────────────────┤
│ EtherType (2 bytes) │ Payload ... │
└───────────────────────────────────────────────────────────────┘
| EtherType | Value |
|---|---|
| IPv4 | 0x0800 |
| ARP | 0x0806 |
API¶
EthernetFrame::parse(frame)— borrows a frame slice, returnsdest_mac,src_mac,ethertype, and apayloadsub-slice.EthernetFrame::write(buffer, dest, src, ethertype, payload)— serialises a frame intobuffer; returns total byte count.build_ethernet_frame(dst, src, ethertype, payload)— convenience wrapper, returns a fixed[u8; 1514].
Minimum frame size enforcement (60 bytes) is done at the RTL8139 send_frame level, not here.
ARP (arp.rs)¶
ARP is used to resolve an IPv4 address to a MAC address on the local Ethernet segment.
Packet Layout (28 bytes, Ethernet/IPv4)¶
offset size field
0 2 hw_type (1 = Ethernet)
2 2 proto_type (0x0800 = IPv4)
4 1 hw_len (6)
5 1 proto_len (4)
6 2 op (1 = Request, 2 = Reply)
8 6 sender_mac
14 4 sender_ip
18 6 target_mac (zeros for a request)
24 4 target_ip
API¶
ArpPacket::parse(payload)— parses an ARP payload (14 bytes after the Ethernet header); returnssender_mac,sender_ip,target_mac,target_ip,op.ArpPacket::build(buf, op, sender_mac, sender_ip, target_mac, target_ip)— writes 28 bytes intobuf.
IPv4 (ipv4.rs)¶
Header Layout (20 bytes, no options)¶
offset size field
0 1 version (4) | IHL (5)
1 1 DSCP/ECN (0)
2 2 total_length (big-endian)
4 2 identification (0x1337)
6 2 flags | fragment_offset (DF=1, offset=0)
8 1 TTL (64)
9 1 protocol (ICMP=1, TCP=6, UDP=17)
10 2 header_checksum
12 4 source_ip
16 4 dest_ip
Checksum is the one's complement of the one's complement sum of all 16-bit words in the header (standard RFC 791 algorithm). Set to 0 before calculation.
API¶
create_packet(src, dst, protocol, payload, out)— writes header + payload intoout; fills checksum; returns total byte count.parse_packet(packet)— returns a copy ofIpv4Headerand a sub-slice pointing at the payload (past the IHL-derived header end).send_packet(packet)— SLIP-encodes and writes to UART. This is the legacy serial path, not the RTL8139 path.
ICMP (icmp.rs)¶
Implements Echo Request/Reply (type 8 / type 0).
Header Layout (8 bytes)¶
offset size field
0 1 type (8 = Echo Request, 0 = Echo Reply)
1 1 code (0)
2 2 checksum
4 2 identifier
6 2 sequence_number
Checksum covers the full ICMP message (header + payload) with the checksum field treated as 0.
API¶
create_packet(type, id, seq, payload, out)— writes ICMP header + payload, fills checksum; returns byte count.parse_packet(packet)— returns a copy ofIcmpHeaderand a payload sub-slice.
TCP (tcp.rs)¶
Header Layout (20 bytes, no options)¶
offset size field
0 2 source_port
2 2 dest_port
4 4 seq_num
8 4 ack_num
12 2 data_offset (top 4 bits = 5) | reserved | flags
14 2 window_size
16 2 checksum
18 2 urgent_pointer
Flag constants:
| Name | Bit |
|---|---|
FIN |
0x01 |
SYN |
0x02 |
PSH |
0x08 |
ACK |
0x10 |
Checksum uses the IPv4 pseudo-header (src IP, dst IP, zero, protocol=6, TCP length) prepended before the one's complement sum. The checksum field at offset 16 is skipped during calculation.
Connection State Machine¶
TcpConnection holds the per-connection state needed for a simple server:
Closed → Listen → SynReceived → Established → FinWait1/FinWait2/Closing/TimeWait
→ CloseWait → LastAck
State transitions are driven by userland code — the kernel does not run a TCP state machine. The kernel only provides packet construction and checksum helpers.
API¶
create_packet(src_port, dst_port, seq, ack, flags, window, payload, src_ip, dst_ip, out)— writes TCP header + payload, fills pseudo-header checksum.parse_packet(packet)— returnsTcpHeaderand payload sub-slice (respects variable data_offset).parse_flags(header)— returns(syn, ack, fin, rst)booleans.get_checksum(src_ip, dst_ip, tcp_packet)— standalone checksum computation.
UDP (udp.rs)¶
Header Layout (8 bytes)¶
offset size field
0 2 source_port
2 2 dest_port
4 2 length (header + payload, big-endian)
6 2 checksum (0 = not computed, currently)
UDP checksum computation is implemented (get_checksum) but not called by create_packet — the checksum field is left as 0, which is legal for IPv4 UDP (RFC 768).
API¶
create_packet(src_ip, dst_ip, src_port, dst_port, payload, out)— writes 8-byte header + payload; returns byte count. Checksum is 0.parse_packet(packet)— returns(src_port, dst_port, payload_slice).get_checksum(src_ip, dst_ip, udp_packet)— IPv4 pseudo-header checksum (available for callers that need it).
SLIP (slip.rs)¶
SLIP (Serial Line IP, RFC 1055) is a byte-stuffing framing protocol that delimits IP packets over a serial link.
Special Bytes¶
| Constant | Value | Meaning |
|---|---|---|
SLIP_END |
0xC0 |
Frame delimiter |
SLIP_ESC |
0xDB |
Escape prefix |
SLIP_ESC_END |
0xDC |
Escaped 0xC0 |
SLIP_ESC_ESC |
0xDD |
Escaped 0xDB |
Encoding¶
output = SLIP_END
for each byte b in input:
if b == 0xC0: output += [SLIP_ESC, SLIP_ESC_END]
if b == 0xDB: output += [SLIP_ESC, SLIP_ESC_ESC]
else: output += [b]
output += SLIP_END
Decoding¶
Accumulate bytes until SLIP_END is seen with out_pos > 0; handle escape sequences. Returns Some(len) when a complete frame is received, None while still accumulating.
Usage¶
ipv4::send_packet calls slip::encode then feeds each byte to serial::write. The receive path (ipv4::receive_loop) accumulates UART bytes and calls slip::decode on each new byte until a complete IP packet is decoded, then passes it to a callback.
WireGuard (userland)¶
WireGuard is implemented by the standalone C daemon wgd, alongside eth. Its encrypted outer transport is IPv4 UDP; supported inner traffic is IPv4 ICMP and TCP. The portable protocol/crypto core is vendored from wireguard-lwip, without linking lwIP.
The kernel does not perform cryptography: tunnel.rs supplies one owned registration, prefix routing, authenticated-frame injection and shell ICMP probe delivery through syscall 0x44. AllowedIPs contains up to 16 IPv4 prefixes and checks outgoing destinations and authenticated incoming sources. The daemon supports replay protection, preshared keys, endpoint roaming, keepalives, rekeying and expiry.
See WireGuard for setup, ping/traceroute, entropy on CPUs without RDSEED/RDRAND, and the fixed 1420-byte MTU. Inner UDP, IPv6, fragmented IP reassembly, forwarding and NAT are not implemented.
Related documentation: Networking Overview, Kernel Internals, Hardware Layer, Ports and Networking ABI.