aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/socket.asm46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/socket.asm b/src/socket.asm
index 51179b4..a9e9ef3 100644
--- a/src/socket.asm
+++ b/src/socket.asm
@@ -1343,6 +1343,40 @@ sk_add_seq:
inc [hl]
ret
+; sk_seq_in_order -> Z set iff the incoming segment's SEQ == rcv_nxt.
+; A retransmitted (or out-of-order) segment fails this; accepting it anyway
+; would render the same data twice AND over-advance rcv_nxt, after which every
+; ACK we send is beyond the peer's snd_nxt - real stacks then drop our data
+; segments (RFC 793 bogus-ACK rule) and the session wedges silently.
+sk_seq_in_order:
+ ld a, [wNetIhl]
+ add 4
+ ld e, a
+ ld d, 0
+ ld hl, wNetRxBuf
+ add hl, de ; HL = &their_seq (big-endian, 4 bytes)
+ push hl
+ call sock_ptr_hl
+ ld a, l
+ add SK_RCV
+ ld l, a
+ ld a, h
+ adc 0
+ ld h, a
+ ld d, h
+ ld e, l ; DE = &rcv_nxt
+ pop hl
+ ld b, 4
+.cmp
+ ld a, [de]
+ cp [hl]
+ ret nz ; mismatch -> NZ
+ inc de
+ inc hl
+ dec b
+ jr nz, .cmp
+ ret ; all 4 equal -> Z (from dec b)
+
; sk_set_rcv_from_seq(A = addend) - rcv_nxt = their_seq(from packet) + addend
sk_set_rcv_from_seq:
push af
@@ -1869,6 +1903,11 @@ tcp_in:
ld [wNetTcpDlen2], a
or a
jr z, .checkfin
+ ; Only accept data that starts exactly at rcv_nxt. A dup/out-of-order
+ ; segment is dropped, but re-ACKed with our current rcv_nxt so the peer
+ ; converges instead of retransmitting forever.
+ call sk_seq_in_order
+ jr nz, .reack
call tcp_buffer_data
ld a, [wNetTcpDlen2]
call sk_add_rcv
@@ -1891,3 +1930,10 @@ tcp_in:
ld a, TCP_DONE
call sock_state_set
ret
+.reack
+ ld a, TF_ACK ; dup segment: repeat our ACK, take no data
+ ld [wNetTcpFlags], a
+ xor a
+ ld [wNetTcpDlen], a
+ call tcp_send_seg
+ ret