3 Commits
Author SHA1 Message Date
d00fandd00f 4ff009dbfc uip: cap TCP MSS to 1460 to survive jumbo-MTU clients (#298)
* uip: parenthesise UIP_LLH_LEN

The macro expands to a bare sum, so wherever it is subtracted the second term
gets added instead. UIP_TCP_MSS - and with it UIP_RECEIVE_WINDOW - therefore
comes out 24 bytes above the buffer's real capacity. UIP_APPDATA_SIZE and
UIP_REASS_BUFSIZE are wrong the same way, though neither is reachable today.

The additions, uip_buf[UIP_LLH_LEN] and friends, were right by luck.

* uip: keep the advertised MSS below the buffer edge

Deriving the MSS straight from the buffer size makes the switch advertise
exactly the segment that fills uip_buf to its last byte, and a peer that takes
it literally corrupts every large upload: the firmware image arrives fully
acknowledged, with no retransmissions on the wire, yet the CRC over the
streamed body never matches and the flash write is abandoned.

Isolated by changing nothing but the segment size, same buffer and same file:
1490-byte segments fail four times out of four, 1460-byte segments succeed,
745-byte segments succeed. Linux halves its segments against a window this
small, so only macOS on a jumbo link ever produces a full-size segment - which
is why the failure hides so well.

Where exactly the full segment breaks the stream is not pinned down yet; until
it is, the advertised MSS stays a step below the edge.

* uip: size the buffer to the largest frame the CPU port accepts

UIP_TCP_MSS derives from UIP_CONF_BUFFER_SIZE, and the buffer was large enough
for frames the hardware will never deliver, so the switch advertised a segment
size no peer could usefully reach. A client on a jumbo-MTU link took it at its
word and the oversized replies went nowhere.

Size the buffer to the ingress limit instead. ICMP bypasses MSS and so probes
the hardware directly: on a SWTGW218AS a 1502-byte payload is answered and 1503
never arrives, which puts the largest frame the NIC hands us at 1556 bytes of
uip_buf. UIP_TCP_MSS then derives to 1490, the same edge measured over TCP.

Frames above the limit are dropped by the NIC rather than written to the
buffer - an 8 kB ping leaves the switch untouched - so nothing overruns it.
Frees 644 bytes of XDATA.

* uip: trim these comments, one of which had stopped being true

The note above UIP_CONF_BUFFER_SIZE claimed the MSS derives from it as 1490.
It does not: the commit that follows pins the MSS at 1460 on purpose, a step
below that ceiling, because a segment filling the buffer to its last byte
corrupts large uploads. Left as it was, the file argued with itself.

Both blocks are shorter now. What justifies the numbers stays, which is the
ICMP measurement behind 1556 and the four-out-of-four failure behind 1460.
What went is the storytelling around them, which belongs in this thread rather
than in a config header.

* uip: derive the MSS from the buffer again, minus explicit headroom

The review asked why the buffer size and the MSS are both set by hand when one
used to follow from the other. They answer different questions, but the gap
between them is a number in its own right, so it gets a name now:
UIP_CONF_BUFFER_EXTRA, and UIP_TCP_MSS goes back to being derived.

The headroom is where the measurement lives. A segment that fills uip_buf to
its last byte corrupts large uploads: with nothing but the segment size
changing, 1490 fails four times out of four and 1460 succeeds. With the buffer
sized to the frame the NIC accepts, an extra of 30 lands on 1460.

Deriving it the other way round does not work. Sizing the buffer from a 1460
byte MSS gives 1526, which is 30 bytes under the frame the NIC actually
delivers. A 1502 byte ICMP payload occupies 1556 bytes of uip_buf and is
answered today, and it would stop fitting.

The generated image is byte for byte the same as the one with 1460 written out,
so the expression lands on the value that was measured.

---------

Co-authored-by: d00f <tokyusho@chatik.pl>
2026-08-14 06:42:36 +02:00
logicog e280ccd2f9 Use RTL descriptor definition 2026-04-24 08:42:00 +02:00
logicog e486c04186 Add initial port of uip TCP/IP stack 2025-07-11 14:16:08 +02:00