diff options
| -rw-r--r-- | src/socket.asm | 46 |
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 |
