kernel/net: honour the window scale factor advertised by the peer #619

Merged
Leency merged 1 commits from kernel-tcp-window-scale-snd into main 2026-07-30 02:26:40 +00:00
Owner

Summary: the received window scale option was stored into SND_SCALE, which
the connection setup code then immediately overwrote with zero, so every
peer window was interpreted unscaled.

Details:
RFC 1323 negotiation is completed in two places -- the SYN_RECEIVED branch
and the active-open branch of tcp_input. Both do

    mov     ax, word[ebx + TCP_SOCKET.requested_s_scale]
    mov     word[ebx + TCP_SOCKET.SND_SCALE], ax

relying on the declared order of the four adjacent bytes SND_SCALE,
RCV_SCALE, requested_s_scale, request_r_scale to move both factors at once.
requested_s_scale, however, was never filled in: the option parser wrote the
peer's shift count into SND_SCALE directly, and that value was then clobbered
by the word move with the zero left in requested_s_scale by socket_alloc.

The result was that SND_SCALE ended up 0 on every connection while
TF_RCVD_SCALE was set, so a peer advertising, say, 64 KiB with a shift of 7
was read as advertising 512 bytes. Sending to any modern host was throttled
to a fraction of the real window.

The parser now stores into requested_s_scale, where the setup code expects
it, and clamps the value to TCP_max_winshift (14) as required by RFC 1323 --
a peer sending a larger shift must not be allowed to make our SND_WND
computation shift out of range.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

Summary: the received window scale option was stored into SND_SCALE, which the connection setup code then immediately overwrote with zero, so every peer window was interpreted unscaled. Details: RFC 1323 negotiation is completed in two places -- the SYN_RECEIVED branch and the active-open branch of tcp_input. Both do mov ax, word[ebx + TCP_SOCKET.requested_s_scale] mov word[ebx + TCP_SOCKET.SND_SCALE], ax relying on the declared order of the four adjacent bytes SND_SCALE, RCV_SCALE, requested_s_scale, request_r_scale to move both factors at once. requested_s_scale, however, was never filled in: the option parser wrote the peer's shift count into SND_SCALE directly, and that value was then clobbered by the word move with the zero left in requested_s_scale by socket_alloc. The result was that SND_SCALE ended up 0 on every connection while TF_RCVD_SCALE was set, so a peer advertising, say, 64 KiB with a shift of 7 was read as advertising 512 bytes. Sending to any modern host was throttled to a fraction of the real window. The parser now stores into requested_s_scale, where the setup code expects it, and clamps the value to TCP_max_winshift (14) as required by RFC 1323 -- a peer sending a larger shift must not be allowed to make our SND_WND computation shift out of range. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
hidnplayr approved these changes 2026-07-29 15:46:44 +00:00
Owner

Good find, proper solution.

Good find, proper solution.
Doczom approved these changes 2026-07-29 17:54:33 +00:00
Leency added 1 commit 2026-07-30 02:24:13 +00:00
kernel/net: honour the window scale factor advertised by the peer
Check kernel codestyle / Check kernel codestyle (pull_request) Successful in 21s
Test PR / Build (ru_RU) (pull_request) Successful in 2m9s
Test PR / Build (es_ES) (pull_request) Successful in 2m13s
Test PR / Build (en_US) (pull_request) Successful in 2m21s
8d33c6fa37
Summary: the received window scale option was stored into SND_SCALE, which
the connection setup code then immediately overwrote with zero, so every
peer window was interpreted unscaled.

Подробно:
RFC 1323 negotiation is completed in two places -- the SYN_RECEIVED branch
and the active-open branch of tcp_input. Both do

        mov     ax, word[ebx + TCP_SOCKET.requested_s_scale]
        mov     word[ebx + TCP_SOCKET.SND_SCALE], ax

relying on the declared order of the four adjacent bytes SND_SCALE,
RCV_SCALE, requested_s_scale, request_r_scale to move both factors at once.
requested_s_scale, however, was never filled in: the option parser wrote the
peer's shift count into SND_SCALE directly, and that value was then clobbered
by the word move with the zero left in requested_s_scale by socket_alloc.

The result was that SND_SCALE ended up 0 on every connection while
TF_RCVD_SCALE was set, so a peer advertising, say, 64 KiB with a shift of 7
was read as advertising 512 bytes. Sending to any modern host was throttled
to a fraction of the real window.

The parser now stores into requested_s_scale, where the setup code expects
it, and clamps the value to TCP_max_winshift (14) as required by RFC 1323 --
a peer sending a larger shift must not be allowed to make our SND_WND
computation shift out of range.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Leency force-pushed kernel-tcp-window-scale-snd from da046a79ca to 8d33c6fa37 2026-07-30 02:24:13 +00:00 Compare
Leency scheduled this pull request to auto merge when all checks succeed 2026-07-30 02:24:34 +00:00
Leency merged commit f7dd4033ba into main 2026-07-30 02:26:40 +00:00
Leency deleted branch kernel-tcp-window-scale-snd 2026-07-30 02:26:40 +00:00
Sign in to join this conversation.
No Reviewers
No labels
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: KolibriOS/kolibrios#619