TCP
TCP (src/net/tcp.cpp) is a client-oriented implementation with a full connection state machine, windowed send, and RFC 5681-style congestion control. The congestion-control policy lives socket-free in include/kernel/net/tcp_congestion.h so it is unit-testable.
Constants
| Constant | Value |
|---|---|
| Sockets | 32 |
| MSS | 1460 |
| Advertised window | 65535 (fixed) |
| Receive ring | 64 KiB per socket |
| Send ring | 5840 bytes (4 segments) |
| In-flight descriptors | 8 |
| SYN/FIN retries | 5 |
| Data RTO retries | 5 |
| TIME_WAIT | 5000 ms |
| Ephemeral ports | 49152-65535 |
| Initial cwnd | 2 segments |
| Initial ssthresh | 65535 |
| Duplicate ACK threshold | 3 |
| RTO | 500 ms initial, 200 ms floor, 10 s ceiling |
State Machine
All states are handled: CLOSED, LISTEN, SYN SENT, SYN RECEIVED, ESTABLISHED, FIN WAIT 1/2, CLOSE WAIT, CLOSING, LAST ACK, TIME WAIT. RST in any state resets immediately. Simultaneous close is supported (CLOSING); simultaneous open is not.
Listening works internally: a LISTEN socket that receives a SYN allocates a new socket in SYN RECEIVED and keeps listening. However, listen/accept are not exposed to userspace, so from applications TCP is client-only.
ISNs are FNV-1a hashes of the four-tuple mixed with a boot-seeded secret and the tick count.
Send Path
tcp_send() copies application bytes into the send ring (blocking on net_poll() + yield while full) and returns the bytes accepted. tcp_try_send() transmits while unsent data exists and flight is below the flight limit:
flight_limit = min(cwnd, peer_window, send_ring_size)
Segments are MSS-sized; a partial tail segment is held back while other data is in flight (Nagle-style). Each transmitted segment owns one of the 8 in-flight descriptors {seq, length, sent_time, retransmitted}. SYN/FIN travel as a single control segment outside the ring with their own retry/RTO state. Headers are always exactly 20 bytes — no TCP options are sent or parsed.
Congestion Control
RFC 5681-style rules:
- Forward progress (new ACK): exit fast recovery (
cwnd = ssthresh), slow start (cwnd += MSS) below ssthresh, congestion avoidance (cwnd += MSS*MSS/cwnd) above it. - Three duplicate ACKs: enter fast recovery, fast-retransmit the oldest unacked segment; further duplicates inflate cwnd without re-triggering.
- Fast retransmit:
ssthresh = max(flight/2, 2*MSS),cwnd = ssthresh + 3*MSS. - RTO timeout:
ssthresh = max(flight/2, 2*MSS),cwnd = MSS(collapse to one segment), backoff doubles the RTO capped at 10 s.
There is no SACK — recovery retransmits the oldest unacked segment.
RTT Estimation
Jacobson/Karels: first sample seeds srtt with rttvar = sample/2; thereafter rttvar = (3*rttvar + |sample - srtt|)/4 and srtt = (7*srtt + sample)/8. RTO = srtt + 4*rttvar, clamped to 200..10000 ms. Karn's rule: RTT is sampled only from newly-acked, never-retransmitted segments.
Receive Path
In-order only: a segment is accepted when it covers the expected edge; covered prefixes are skipped; bytes append to the 64 KiB ring until full (excess dropped). Out-of-order and duplicate segments are dropped and re-ACKed — those duplicate ACKs drive the peer's fast retransmit. ACKs are immediate (no delayed ACK). The advertised window is the constant 65535 and never shrinks, even when the receive ring is full.
Timers
tcp_poll() (run from net_poll()):
- Control segments retransmit after their RTO (doubling, capped), up to 5 retries, then reset.
- Data retransmits the oldest in-flight segment after
rto_ms; each timeout applies the RTO policy and backoff; 5 retries without forward progress reset the socket. - TIME_WAIT expires 5 s after last activity, re-ACKing retransmitted FINs meanwhile.
- Close is deferred until flight and unsent data drain (flush-before-FIN).
Not Supported
No window scaling, SACK, timestamps, or MSS negotiation (no options at all). No simultaneous open, keep-alives, zero-window probing, dynamic advertised window, or delayed ACKs. Receive overflow drops data while still advertising 65535. Listen/accept exist internally but have no syscall surface.
Validation
src/net/tcp_congestion_tests.cpp covers slow start into congestion avoidance, 3-dup-ACK fast retransmit, fast-recovery exit, RTO collapse, flight limiting, RTT convergence/backoff, and the zero-sample floor. src/net/dns_tests.cpp covers the DNS parser.