Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
658a3bc5dd | ||
|
|
134f6c1936 |
No files matched your search
@@ -142,6 +142,7 @@ struct TCP_SOCKET IP_SOCKET
|
|||||||
ts_val dd ?
|
ts_val dd ?
|
||||||
|
|
||||||
seg_next dd ? ; re-assembly queue
|
seg_next dd ? ; re-assembly queue
|
||||||
|
seg_count dd ? ; number of segments queued in it
|
||||||
|
|
||||||
ends
|
ends
|
||||||
|
|
||||||
@@ -2132,6 +2133,13 @@ socket_free:
|
|||||||
je @f
|
je @f
|
||||||
stdcall free_kernel_space, [ebx + STREAM_SOCKET.snd.start_ptr]
|
stdcall free_kernel_space, [ebx + STREAM_SOCKET.snd.start_ptr]
|
||||||
@@:
|
@@:
|
||||||
|
; free the TCP out-of-order reassembly queue, if any
|
||||||
|
.free_reasm:
|
||||||
|
cmp [ebx + TCP_SOCKET.seg_next], 0
|
||||||
|
je .reasm_done
|
||||||
|
call tcp_reasm_free_head
|
||||||
|
jmp .free_reasm
|
||||||
|
.reasm_done:
|
||||||
mov eax, ebx
|
mov eax, ebx
|
||||||
.no_stream:
|
.no_stream:
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ NET_HWACC_TCP_IPv4_OUT = 1 shl 1
|
|||||||
; Network frame types
|
; Network frame types
|
||||||
NET_BUFF_LOOPBACK = 0
|
NET_BUFF_LOOPBACK = 0
|
||||||
NET_BUFF_ETH = 1
|
NET_BUFF_ETH = 1
|
||||||
|
NET_BUFF_TCP_REASM = 2 ; held in a TCP reassembly queue, offset/length = TCP payload
|
||||||
|
|
||||||
struct NET_DEVICE
|
struct NET_DEVICE
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,17 @@ TCP_QUEUE_SIZE = 50
|
|||||||
|
|
||||||
TCP_ISSINCR = 128000
|
TCP_ISSINCR = 128000
|
||||||
|
|
||||||
|
; A NET_BUFF queued for reassembly (TCP_SOCKET.seg_next): offset/length = TCP payload
|
||||||
|
struct TCP_reasm_buff NET_BUFF
|
||||||
|
|
||||||
|
Seq dd ? ; sequence number of the first payload byte
|
||||||
|
Flags dd ? ; TH_FIN if the segment carried a FIN
|
||||||
|
|
||||||
|
ends
|
||||||
|
|
||||||
|
TCP_reasm_maxsegs = 64 ; max queued segments per socket
|
||||||
|
TCP_reasm_maxbuffs = NET_BUFFERS / 4 ; max queued segments, all sockets together
|
||||||
|
|
||||||
struct TCP_header
|
struct TCP_header
|
||||||
|
|
||||||
SourcePort dw ?
|
SourcePort dw ?
|
||||||
@@ -137,6 +148,7 @@ align 4
|
|||||||
TCP_queue rd (TCP_QUEUE_SIZE*sizeof.TCP_queue_entry + sizeof.queue)/4
|
TCP_queue rd (TCP_QUEUE_SIZE*sizeof.TCP_queue_entry + sizeof.queue)/4
|
||||||
TCP_input_event dd ?
|
TCP_input_event dd ?
|
||||||
TCP_timer1_event dd ?
|
TCP_timer1_event dd ?
|
||||||
|
TCP_reasm_buffs dd ? ; NET_BUFFs held by all reassembly queues
|
||||||
endg
|
endg
|
||||||
|
|
||||||
uglobal
|
uglobal
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ TCP_BIT_NEEDOUTPUT = 1 shl 0
|
|||||||
TCP_BIT_TIMESTAMP = 1 shl 1
|
TCP_BIT_TIMESTAMP = 1 shl 1
|
||||||
TCP_BIT_DROPSOCKET = 1 shl 2
|
TCP_BIT_DROPSOCKET = 1 shl 2
|
||||||
TCP_BIT_FIN_IS_ACKED = 1 shl 3
|
TCP_BIT_FIN_IS_ACKED = 1 shl 3
|
||||||
|
TCP_BIT_BUFF_QUEUED = 1 shl 4 ; the reassembly queue owns the buffer
|
||||||
|
|
||||||
;-----------------------------------------------------------------;
|
;-----------------------------------------------------------------;
|
||||||
; ;
|
; ;
|
||||||
@@ -927,7 +928,7 @@ endl
|
|||||||
pop word[ebx + TCP_SOCKET.SND_SCALE]
|
pop word[ebx + TCP_SOCKET.SND_SCALE]
|
||||||
@@:
|
@@:
|
||||||
|
|
||||||
call tcp_reassemble
|
call tcp_reassemble_drain
|
||||||
|
|
||||||
mov eax, [edx + TCP_header.SequenceNumber]
|
mov eax, [edx + TCP_header.SequenceNumber]
|
||||||
dec eax
|
dec eax
|
||||||
@@ -1691,16 +1692,22 @@ endl
|
|||||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP data is out of order!\nSequencenumber is %u, we expected %u.\n", \
|
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP data is out of order!\nSequencenumber is %u, we expected %u.\n", \
|
||||||
[edx + TCP_header.SequenceNumber], [ebx + TCP_SOCKET.RCV_NXT]
|
[edx + TCP_header.SequenceNumber], [ebx + TCP_SOCKET.RCV_NXT]
|
||||||
|
|
||||||
; Uh-oh, some data is out of order, let's call TCP reassemble for help
|
; The reassembly queue takes over the buffer: edx is invalid from here on
|
||||||
|
|
||||||
call tcp_reassemble ;;; TODO!
|
mov esi, [dataoffset]
|
||||||
|
add esi, edx
|
||||||
|
mov eax, [esp] ; the NET_BUFF
|
||||||
|
call tcp_reassemble
|
||||||
|
or [temp_bits], TCP_BIT_BUFF_QUEUED
|
||||||
|
|
||||||
; Generate ACK immediately, to let the other end know that a segment was received out of order,
|
; Generate ACK immediately, to let the other end know that a segment was received out of order,
|
||||||
; and to tell it what sequence number is expected. This aids the fast-retransmit algorithm.
|
; and to tell it what sequence number is expected. This aids the fast-retransmit algorithm.
|
||||||
|
|
||||||
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||||
|
|
||||||
jmp .final_processing ;;; HACK because of unimplemented reassembly queue!
|
test eax, TH_FIN
|
||||||
|
jnz .process_fin
|
||||||
|
jmp .final_processing
|
||||||
.data_done:
|
.data_done:
|
||||||
|
|
||||||
;-----------------------------------------------------------------------------------
|
;-----------------------------------------------------------------------------------
|
||||||
@@ -1711,6 +1718,7 @@ endl
|
|||||||
|
|
||||||
test [edx + TCP_header.Flags], TH_FIN
|
test [edx + TCP_header.Flags], TH_FIN
|
||||||
jz .final_processing
|
jz .final_processing
|
||||||
|
.process_fin: ; must not use edx from here on
|
||||||
|
|
||||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Processing FIN\n"
|
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Processing FIN\n"
|
||||||
|
|
||||||
@@ -1797,11 +1805,18 @@ endl
|
|||||||
call tcp_output
|
call tcp_output
|
||||||
|
|
||||||
.done:
|
.done:
|
||||||
|
test [temp_bits], TCP_BIT_BUFF_QUEUED
|
||||||
|
jnz .buff_queued
|
||||||
|
|
||||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: dumping\n"
|
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: dumping\n"
|
||||||
|
|
||||||
call net_buff_free
|
call net_buff_free
|
||||||
jmp .loop
|
jmp .loop
|
||||||
|
|
||||||
|
.buff_queued:
|
||||||
|
add esp, 4 ; the queue has the buffer
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
;-----------------------------------------------------------------------------------
|
;-----------------------------------------------------------------------------------
|
||||||
;
|
;
|
||||||
; Drop segment, reply with an RST segment when needed
|
; Drop segment, reply with an RST segment when needed
|
||||||
|
|||||||
@@ -601,17 +601,200 @@ tcp_mss:
|
|||||||
|
|
||||||
;-----------------------------------------------------------------;
|
;-----------------------------------------------------------------;
|
||||||
; ;
|
; ;
|
||||||
; tcp_reassemble ;
|
; tcp_reassemble: queue an out-of-order segment, deliver what is ;
|
||||||
|
; contiguous with RCV_NXT. The queue owns the NET_BUFF from here. ;
|
||||||
; ;
|
; ;
|
||||||
; IN: ebx = socket ptr ;
|
; IN: eax = NET_BUFF ptr ;
|
||||||
; edx = segment ptr ;
|
; ebx = socket ptr (locked) ;
|
||||||
|
; edx = TCP header ptr ;
|
||||||
|
; esi = ptr to segment data ;
|
||||||
|
; ecx = segment data length ;
|
||||||
; ;
|
; ;
|
||||||
; OUT: / ;
|
; OUT: eax = TH_FIN if the FIN is next in sequence, else 0 ;
|
||||||
|
; other registers preserved ;
|
||||||
|
; ;
|
||||||
|
; tcp_reassemble_drain: delivery only ;
|
||||||
; ;
|
; ;
|
||||||
;-----------------------------------------------------------------;
|
;-----------------------------------------------------------------;
|
||||||
align 4
|
align 4
|
||||||
tcp_reassemble:
|
tcp_reassemble:
|
||||||
|
|
||||||
;;;;; TODO
|
pushad
|
||||||
|
call tcp_reasm_insert
|
||||||
|
call tcp_reasm_deliver
|
||||||
|
mov [esp + 28], eax ; eax slot of pushad
|
||||||
|
popad
|
||||||
|
ret
|
||||||
|
|
||||||
|
align 4
|
||||||
|
tcp_reassemble_drain:
|
||||||
|
|
||||||
|
pushad
|
||||||
|
call tcp_reasm_deliver
|
||||||
|
popad
|
||||||
|
ret
|
||||||
|
|
||||||
|
; IN: eax = NET_BUFF, ebx = socket, edx = TCP header, esi = data, ecx = length
|
||||||
|
align 4
|
||||||
|
tcp_reasm_insert:
|
||||||
|
|
||||||
|
mov edi, eax ; edi = buffer
|
||||||
|
mov eax, [edx + TCP_header.SequenceNumber]
|
||||||
|
movzx ebp, [edx + TCP_header.Flags]
|
||||||
|
and ebp, TH_FIN
|
||||||
|
|
||||||
|
test ecx, ecx
|
||||||
|
jnz @f
|
||||||
|
test ebp, ebp
|
||||||
|
jz .drop ; neither data nor FIN
|
||||||
|
@@:
|
||||||
|
|
||||||
|
; trim data below RCV_NXT
|
||||||
|
mov edx, eax
|
||||||
|
sub edx, [ebx + TCP_SOCKET.RCV_NXT]
|
||||||
|
jns .no_head_trim
|
||||||
|
neg edx
|
||||||
|
cmp edx, ecx
|
||||||
|
ja .drop ; complete duplicate
|
||||||
|
jb @f
|
||||||
|
test ebp, ebp ; only the FIN is new?
|
||||||
|
jz .drop
|
||||||
|
@@:
|
||||||
|
add esi, edx
|
||||||
|
add eax, edx ; seq = RCV_NXT now
|
||||||
|
sub ecx, edx
|
||||||
|
xor edx, edx
|
||||||
|
.no_head_trim:
|
||||||
|
|
||||||
|
cmp edx, SOCKET_BUFFER_SIZE
|
||||||
|
ja .drop
|
||||||
|
|
||||||
|
; limits do not apply to the segment at RCV_NXT: it drains the queue
|
||||||
|
test edx, edx
|
||||||
|
jnz .check_limits
|
||||||
|
cmp [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
|
||||||
|
jae .limits_ok
|
||||||
|
.check_limits:
|
||||||
|
cmp [ebx + TCP_SOCKET.seg_count], TCP_reasm_maxsegs
|
||||||
|
jae .drop
|
||||||
|
cmp [TCP_reasm_buffs], TCP_reasm_maxbuffs
|
||||||
|
jae .drop
|
||||||
|
.limits_ok:
|
||||||
|
|
||||||
|
mov [edi + NET_BUFF.type], NET_BUFF_TCP_REASM
|
||||||
|
mov [edi + NET_BUFF.length], ecx
|
||||||
|
sub esi, edi
|
||||||
|
mov [edi + NET_BUFF.offset], esi
|
||||||
|
mov [edi + TCP_reasm_buff.Seq], eax
|
||||||
|
mov [edi + TCP_reasm_buff.Flags], ebp
|
||||||
|
|
||||||
|
; find the insertion point, esi = link to update
|
||||||
|
lea esi, [ebx + TCP_SOCKET.seg_next]
|
||||||
|
.find:
|
||||||
|
mov edx, [esi] ; edx = successor candidate
|
||||||
|
test edx, edx
|
||||||
|
jz .found
|
||||||
|
mov ebp, [edx + TCP_reasm_buff.Seq]
|
||||||
|
sub ebp, eax
|
||||||
|
jg .found ; successor starts past us
|
||||||
|
mov esi, edx
|
||||||
|
jmp .find
|
||||||
|
.found:
|
||||||
|
|
||||||
|
; drop the segment if the previous node already covers it
|
||||||
|
lea ebp, [ebx + TCP_SOCKET.seg_next]
|
||||||
|
cmp esi, ebp
|
||||||
|
je .link ; inserting at the head
|
||||||
|
mov ebp, [esi + TCP_reasm_buff.Seq]
|
||||||
|
add ebp, [esi + NET_BUFF.length]
|
||||||
|
sub ebp, eax
|
||||||
|
sub ebp, ecx ; prev end - our end
|
||||||
|
js .link
|
||||||
|
jnz .drop ; covered, and then some
|
||||||
|
cmp [edi + TCP_reasm_buff.Flags], 0
|
||||||
|
je .drop ; covered exactly, no FIN to add
|
||||||
|
|
||||||
|
.link:
|
||||||
|
mov [edi + NET_BUFF.NextPtr], edx
|
||||||
|
mov [esi + NET_BUFF.NextPtr], edi
|
||||||
|
inc [ebx + TCP_SOCKET.seg_count]
|
||||||
|
lock inc [TCP_reasm_buffs]
|
||||||
|
inc [TCPS_rcvoopack]
|
||||||
|
add [TCPS_rcvoobyte], ecx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.drop:
|
||||||
|
stdcall net_buff_free, edi
|
||||||
|
ret
|
||||||
|
|
||||||
|
; IN: ebx = socket, OUT: eax = TH_FIN or 0
|
||||||
|
align 4
|
||||||
|
tcp_reasm_deliver:
|
||||||
|
|
||||||
|
xor ebp, ebp ; 'delivered anything' flag
|
||||||
|
|
||||||
|
cmp [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
|
||||||
|
jb .done
|
||||||
|
|
||||||
|
.loop:
|
||||||
|
mov edx, [ebx + TCP_SOCKET.seg_next]
|
||||||
|
test edx, edx
|
||||||
|
jz .done
|
||||||
|
mov eax, [edx + TCP_reasm_buff.Seq]
|
||||||
|
sub eax, [ebx + TCP_SOCKET.RCV_NXT]
|
||||||
|
jg .done ; hole before this node
|
||||||
|
neg eax ; node bytes below RCV_NXT
|
||||||
|
mov ecx, [edx + NET_BUFF.length]
|
||||||
|
sub ecx, eax ; fresh bytes in the node
|
||||||
|
jg .deliver
|
||||||
|
jl .unlink ; ends before RCV_NXT
|
||||||
|
|
||||||
|
cmp [edx + TCP_reasm_buff.Flags], 0
|
||||||
|
jne .fin
|
||||||
|
|
||||||
|
.unlink:
|
||||||
|
call tcp_reasm_free_head
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.deliver:
|
||||||
|
mov esi, [edx + NET_BUFF.offset]
|
||||||
|
add esi, edx
|
||||||
|
add esi, eax
|
||||||
|
lea eax, [ebx + STREAM_SOCKET.rcv]
|
||||||
|
call socket_ring_write ; -> ecx = bytes stored
|
||||||
|
test ecx, ecx
|
||||||
|
jz .done ; receive buffer full
|
||||||
|
add [ebx + TCP_SOCKET.RCV_NXT], ecx
|
||||||
|
mov ebp, 1
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.fin:
|
||||||
|
call tcp_reasm_free_head
|
||||||
|
cmp [ebx + TCP_SOCKET.seg_next], 0
|
||||||
|
jne .fin
|
||||||
|
mov eax, TH_FIN
|
||||||
|
jmp .notify
|
||||||
|
|
||||||
|
.done:
|
||||||
|
xor eax, eax
|
||||||
|
.notify:
|
||||||
|
test ebp, ebp
|
||||||
|
jz .nothing
|
||||||
|
push eax
|
||||||
|
mov eax, ebx
|
||||||
|
call socket_notify
|
||||||
|
pop eax
|
||||||
|
.nothing:
|
||||||
|
ret
|
||||||
|
|
||||||
|
; IN: ebx = socket (locked), OUT: eax destroyed
|
||||||
|
align 4
|
||||||
|
tcp_reasm_free_head:
|
||||||
|
|
||||||
|
mov eax, [ebx + TCP_SOCKET.seg_next]
|
||||||
|
push [eax + NET_BUFF.NextPtr]
|
||||||
|
pop [ebx + TCP_SOCKET.seg_next]
|
||||||
|
dec [ebx + TCP_SOCKET.seg_count]
|
||||||
|
lock dec [TCP_reasm_buffs]
|
||||||
|
stdcall net_buff_free, eax
|
||||||
ret
|
ret
|
||||||
Reference in new issue
Block a user