Updates in TCP code of net branch

git-svn-id: svn://kolibrios.org@1533 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2010-07-28 23:59:42 +00:00
parent b2bef64328
commit b90d3b7f56
3 changed files with 288 additions and 219 deletions

View File

@ -506,16 +506,18 @@ ARP_IP_to_MAC:
;; TODO: check if driver could transmit packet ;; TODO: check if driver could transmit packet
pop eax pop esi
imul eax, ARP_ENTRY.size imul esi, ARP_ENTRY.size
add eax, ARP_table add esi, ARP_table
mov ecx, 25 mov ecx, 25
.wait_loop: .wait_loop:
cmp [eax + ARP_ENTRY.Status], 1 cmp [esi + ARP_ENTRY.Status], 1
je .got_it je .got_it
push esi
mov esi, 10 mov esi, 10
call delay_ms call delay_ms
pop esi
loop .wait_loop loop .wait_loop
mov eax, -2 ; request send mov eax, -2 ; request send

View File

@ -169,6 +169,7 @@ struc RING_BUFFER {
.read_ptr dd ? ; Read pointer .read_ptr dd ? ; Read pointer
.write_ptr dd ? ; Write pointer .write_ptr dd ? ; Write pointer
.size dd ? ; Number of bytes buffered .size dd ? ; Number of bytes buffered
.end:
} }
virtual at 0 virtual at 0
@ -179,10 +180,9 @@ end virtual
virtual at TCP_SOCKET.end virtual at TCP_SOCKET.end
rcv RING_BUFFER
snd RING_BUFFER
STREAM_SOCKET: STREAM_SOCKET:
.rcv rd RING_BUFFER.end/4
.snd rd RING_BUFFER.end/4
.end: .end:
end virtual end virtual
@ -221,21 +221,12 @@ macro SOCKET_init {
mov ecx, 4 mov ecx, 4
rep stosd rep stosd
;--- for random port --
mov al, 0x0 ; set up 1s timer
out 0x70, al
in al, 0x71
;----------------------
@@: @@:
pseudo_random eax pseudo_random eax
cmp ax, MIN_EPHEMERAL_PORT cmp ax, MIN_EPHEMERAL_PORT
jl @r jl @r
cmp ax, MAX_EPHEMERAL_PORT cmp ax, MAX_EPHEMERAL_PORT
jg @r jg @r
mov [last_UDP_port], ax mov [last_UDP_port], ax
@@: @@:
@ -244,7 +235,6 @@ macro SOCKET_init {
jl @r jl @r
cmp ax, MAX_EPHEMERAL_PORT cmp ax, MAX_EPHEMERAL_PORT
jg @r jg @r
mov [last_TCP_port], ax mov [last_TCP_port], ax
} }
@ -318,22 +308,13 @@ SOCKET_open:
cmp edx, IP_PROTO_TCP cmp edx, IP_PROTO_TCP
jnz .no_stream jnz .no_stream
mov esi, eax mov ebx, eax
stdcall kernel_alloc, SOCKET_MAXDATA
mov [esi + rcv.start_ptr], eax
mov [esi + rcv.write_ptr], eax
mov [esi + rcv.read_ptr], eax
mov [esi + rcv.size], 0
add eax, SOCKET_MAXDATA
mov [esi + rcv.end_ptr], eax
stdcall kernel_alloc, SOCKET_MAXDATA lea eax, [ebx + STREAM_SOCKET.snd]
mov [esi + snd.start_ptr], eax call SOCKET_ring_create
mov [esi + snd.write_ptr], eax
mov [esi + snd.read_ptr], eax lea eax, [ebx + STREAM_SOCKET.rcv]
mov [esi + snd.size], 0 call SOCKET_ring_create
add eax, SOCKET_MAXDATA
mov [esi + snd.end_ptr], eax
ret ret
@ -497,9 +478,11 @@ SOCKET_connect:
mov ebx, [TCP_sequence_num] mov ebx, [TCP_sequence_num]
add [TCP_sequence_num], 6400 add [TCP_sequence_num], 6400
mov [eax + TCP_SOCKET.ISS], ebx mov [eax + TCP_SOCKET.ISS], ebx
mov [eax + TCP_SOCKET.timer_keepalive], 120 ; 120*640ms => 75,6 seconds mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init
;;;; mov [ebx + TCP_SOCKET.timer_retransmission], TCP_sendseqinit eax
;;;; mov [ebx + TCP_SOCKET.timer_retransmission], ;; todo: create macro to set retransmission timer
push eax push eax
call TCP_output call TCP_output
@ -671,6 +654,9 @@ SOCKET_receive:
call SOCKET_num_to_ptr call SOCKET_num_to_ptr
jz s_error jz s_error
cmp [eax + SOCKET.Type], IP_PROTO_TCP ;;;;;;;;
je .tcp
mov ebx, esi mov ebx, esi
get_from_queue (eax + SOCKET_QUEUE_LOCATION),\ get_from_queue (eax + SOCKET_QUEUE_LOCATION),\
SOCKET_QUEUE_SIZE,\ SOCKET_QUEUE_SIZE,\
@ -707,9 +693,17 @@ SOCKET_receive:
.nd: .nd:
; remove the packet ;;; TODO: only if it is empty!! ; remove the packet ;;; TODO: only if it is empty!!
;;;; call TCP_output ; only if it is tcp
call kernel_free call kernel_free
ret
.tcp:
mov ecx, esi
mov edi, edx
add eax, STREAM_SOCKET.rcv
call SOCKET_ring_read
mov dword[esp+32], ecx ; return number of bytes copied in ebx
ret ret
@ -787,8 +781,13 @@ SOCKET_send:
jz s_error jz s_error
@@: @@:
;;;; TODO: queue the data
push eax
mov ecx, esi
mov esi, edx
add eax, STREAM_SOCKET.snd
call SOCKET_ring_write
pop eax
call TCP_output call TCP_output
mov [esp+32], eax mov [esp+32], eax
@ -1028,58 +1027,86 @@ SOCKET_input:
ret ret
;--------------------------
;
; eax = ptr to ring struct (just a buffer of the right size)
;
align 4
SOCKET_ring_create:
mov esi, eax
stdcall create_ring_buffer, SOCKET_MAXDATA, PG_SW
DEBUGF 1,"SOCKET_ring_created: %x\n", eax
mov [esi + RING_BUFFER.start_ptr], eax
mov [esi + RING_BUFFER.write_ptr], eax
mov [esi + RING_BUFFER.read_ptr], eax
mov [esi + RING_BUFFER.size], 0
add eax, SOCKET_MAXDATA
mov [esi + RING_BUFFER.end_ptr], eax
ret
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;
; SOCKET_ring_add ; SOCKET_ring_write
; ;
; Adds data to a stream socket ; Adds data to a stream socket, and updates write pointer and size
; ;
; IN: eax = ptr to ring struct ; IN: eax = ptr to ring struct
; ecx = data size ; ecx = data size
; esi = ptr to data ; esi = ptr to data
; ;
; OUT: eax = number of bytes stored ; OUT: ecx = number of bytes stored
; ;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 align 4
SOCKET_ring_add: SOCKET_ring_write:
DEBUGF 1,"SOCKET_ring_add: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx DEBUGF 1,"SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
mov edi, [eax + RING_BUFFER.size] add [eax + RING_BUFFER.size], ecx
add edi, ecx cmp [eax + RING_BUFFER.size], SOCKET_MAXDATA
cmp edi, SOCKET_MAXDATA
jg .too_large jg .too_large
mov [eax + RING_BUFFER.size], edi ; update size
.copy: .copy:
push ecx ;<<<< 1 mov edi, [eax + RING_BUFFER.write_ptr]
mov edi, [eax + RING_BUFFER.write_ptr] ; set write ptr in edi DEBUGF 2,"Copying %u bytes from %x to %x\n", ecx, esi, edi
add [eax + RING_BUFFER.write_ptr], ecx ; update write pointer
mov edx, [eax + RING_BUFFER.end_ptr]
cmp edx, [eax + RING_BUFFER.write_ptr]
jg .copy_in_2
je .wrap_write_ptr
.copy_more:
push ecx push ecx
and ecx, 3 shr ecx, 1
rep movsb jnc .nb
pop ecx movsb
shr ecx, 2 .nb:
shr ecx, 1
jnc .nw
movsw
.nw:
test ecx, ecx
jz .nd
rep movsd rep movsd
pop ecx ; >>>> 1/2 .nd:
DEBUGF 2,"Copied %u bytes\n", ecx pop ecx
cmp edi, [eax + RING_BUFFER.end_ptr]
jge .wrap
mov [eax + RING_BUFFER.write_ptr], edi
ret
.wrap:
sub edi, SOCKET_MAXDATA
mov [eax + RING_BUFFER.write_ptr], edi
ret ret
.too_large: .too_large:
mov ecx, SOCKET_MAXDATA ; calculate number of bytes available in buffer mov ecx, SOCKET_MAXDATA ; calculate number of bytes available in buffer
sub ecx, [eax + RING_BUFFER.size] sub ecx, [eax + RING_BUFFER.size]
jz .full jge .full
mov [eax + RING_BUFFER.size], SOCKET_MAXDATA ; update size, we will fill buffer completely mov [eax + RING_BUFFER.size], SOCKET_MAXDATA ; update size, we will fill buffer completely
jmp .copy jmp .copy
.full: .full:
@ -1087,87 +1114,56 @@ SOCKET_ring_add:
xor ecx, ecx xor ecx, ecx
ret ret
.copy_in_2:
DEBUGF 1,"Copying in 2 passes\n"
mov edx, ecx
mov ecx, [eax + RING_BUFFER.end_ptr] ; find number of bytes till end of buffer
sub ecx, edi
sub edx, ecx
push edx ; <<<< 2
mov edi, [eax + RING_BUFFER.start_ptr]
call .copy_more
.wrap_write_ptr:
sub [eax + RING_BUFFER.write_ptr], SOCKET_MAXDATA ; update write pointer
jmp .copy_more
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;
; SOCKET_ring_read ; SOCKET_ring_read
; ;
; reads the data, but let the data remain in the buffer ; reads the data, BUT DOES NOT CLEAR IT FROM MEMORY YET
; ;
; IN: eax = ptr to ring struct ; IN: eax = ptr to ring struct
; ecx = buffer size ; ecx = buffer size
; edi = ptr to buffer ; edi = ptr to buffer
; ;
; OUT: eax = number of bytes read ; OUT: ecx = number of bytes read
; ;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 align 4
SOCKET_ring_read: SOCKET_ring_read:
DEBUGF 1,"SOCKET_ring_read: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx DEBUGF 1,"SOCKET_ring_read: ringbuff=%x ptr=%x size=%u\n", eax, edi, ecx
cmp [eax + RING_BUFFER.size], ecx ; update size cmp ecx, [eax + RING_BUFFER.size]
jl .too_large jg .less_data
mov esi, [eax + RING_BUFFER.read_ptr] ; update read ptr
.copy: .copy:
push ecx ;<<<< 1 mov esi, [eax + RING_BUFFER.read_ptr]
mov edx, [eax + RING_BUFFER.read_ptr]
add edx, ecx
cmp edx, [eax + RING_BUFFER.end_ptr]
jg .copy_in_2
.copy_more: DEBUGF 2,"Copying %u bytes from %x to %x\n", ecx, esi, edi
push ecx push ecx
and ecx, 3 shr ecx, 1
rep movsb jnc .nb
pop ecx movsb
shr ecx, 2 .nb:
shr ecx, 1
jnc .nw
movsw
.nw:
test ecx, ecx
jz .nd
rep movsd rep movsd
pop ecx ; >>>> 1/2 .nd:
DEBUGF 2,"Copied %u bytes\n", ecx pop ecx
; .no_data_at_all:
ret ret
.too_large: .less_data:
mov ecx, [eax + RING_BUFFER.size] mov ecx, [eax + RING_BUFFER.size]
test ecx, ecx
; jz .no_data_at_all
jmp .copy jmp .copy
.full:
DEBUGF 2,"Ring buffer is full!\n"
xor ecx, ecx
ret
.copy_in_2:
DEBUGF 1,"Copying in 2 passes\n"
mov edx, ecx
mov ecx, [eax + RING_BUFFER.end_ptr] ; find number of bytes till end of buffer
sub ecx, edi
sub edx, ecx
push edx ; <<<< 2
mov esi, [eax + RING_BUFFER.start_ptr]
call .copy_more
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;
@ -1186,26 +1182,19 @@ SOCKET_ring_free:
DEBUGF 1,"Trying to free %u bytes of data from ring %x\n", ecx, eax DEBUGF 1,"Trying to free %u bytes of data from ring %x\n", ecx, eax
cmp ecx, [eax + RING_BUFFER.size]
jle .go_for_it
cmp ecx, SOCKET_MAXDATA ;;;;
jg .moron_input
mov ecx, [eax + RING_BUFFER.size]
.go_for_it:
sub [eax + RING_BUFFER.size], ecx sub [eax + RING_BUFFER.size], ecx
jl .sumthinwong
add [eax + RING_BUFFER.read_ptr], ecx add [eax + RING_BUFFER.read_ptr], ecx
mov edx, [eax + RING_BUFFER.end_ptr] mov edx, [eax + RING_BUFFER.end_ptr]
cmp [eax + RING_BUFFER.read_ptr], edx cmp [eax + RING_BUFFER.read_ptr], edx
jl @f jl @f
sub [eax + RING_BUFFER.read_ptr], SOCKET_MAXDATA ;;;;; sub [eax + RING_BUFFER.read_ptr], SOCKET_MAXDATA
@@: @@:
ret ret
.moron_input: .sumthinwong: ; we could free all available bytes, but that would be stupid, i guess..
add [eax + RING_BUFFER.size], ecx
xor ecx, ecx xor ecx, ecx
ret ret
@ -1371,8 +1360,8 @@ SOCKET_free:
cmp [eax + SOCKET.Type], IP_PROTO_TCP cmp [eax + SOCKET.Type], IP_PROTO_TCP
jnz .no_stream jnz .no_stream
stdcall kernel_free, [eax + rcv.start_ptr] stdcall kernel_free, [eax + STREAM_SOCKET.rcv + RING_BUFFER.start_ptr]
stdcall kernel_free, [eax + snd.start_ptr] stdcall kernel_free, [eax + STREAM_SOCKET.snd + RING_BUFFER.start_ptr]
.no_stream: .no_stream:
push eax ; this will be passed to kernel_free push eax ; this will be passed to kernel_free
@ -1400,9 +1389,9 @@ SOCKET_free:
ret ret
; socket nr in ebx ; IN: socket nr in ebx
; new socket nr in eax ; OUT: socket nr in eax
; preserver edx ; preserves edx
align 4 align 4
SOCKET_fork: SOCKET_fork:
@ -1440,7 +1429,7 @@ SOCKET_fork:
; Get socket structure address by its number ; Get socket structure address by its number
; ;
; IN: ecx = socket number ; IN: ecx = socket number
; OUT: ecx = 0 on error, socket ptr otherwise ; OUT: eax = 0 on error, socket ptr otherwise
; ZF = set on error ; ZF = set on error
; ;
;--------------------------------------------------- ;---------------------------------------------------

View File

@ -266,6 +266,30 @@ macro TCP_checksum IP1, IP2 {
} ; returns in dx only } ; returns in dx only
macro TCP_sendseqinit ptr {
push edi ;;;; i dont like this static use of edi
mov edi, [ptr + TCP_SOCKET.ISS]
mov [ptr + TCP_SOCKET.SND_UP], edi
mov [ptr + TCP_SOCKET.SND_MAX], edi
mov [ptr + TCP_SOCKET.SND_NXT], edi
mov [ptr + TCP_SOCKET.SND_UNA], edi
pop edi
}
macro TCP_rcvseqinit ptr {
push edi
mov edi, [ptr + TCP_SOCKET.IRS]
inc edi
mov [ptr + TCP_SOCKET.RCV_NXT], edi
mov [ptr + TCP_SOCKET.RCV_ADV], edi
pop edi
}
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;
@ -420,7 +444,7 @@ TCP_input:
;----------------------------------- ;-----------------------------------
; Is this socket a listening socket? ; Is this socket a listening socket?
; test [ebx + SOCKET.options], SO_ACCEPTCON test [ebx + SOCKET.options], SO_ACCEPTCON
; jnz .listening_socket ;;;;; TODO ; jnz .listening_socket ;;;;; TODO
;------------------------------------- ;-------------------------------------
@ -477,7 +501,7 @@ TCP_input:
movzx eax, word[edi+2] movzx eax, word[edi+2]
rol ax, 8 rol ax, 8
DEBUGF 1,"Maxseg: %u", ax DEBUGF 1,"Maxseg: %u\n", ax
mov [ebx + TCP_SOCKET.t_maxseg], eax mov [ebx + TCP_SOCKET.t_maxseg], eax
@ -493,7 +517,7 @@ TCP_input:
test [edx + TCP_segment.Flags], TH_SYN test [edx + TCP_segment.Flags], TH_SYN
jz @f jz @f
DEBUGF 1,"Got window option" DEBUGF 1,"Got window option\n"
;;;;; ;;;;;
@@: @@:
@ -505,7 +529,7 @@ TCP_input:
cmp byte [edi+1], 10 cmp byte [edi+1], 10
jne .no_options jne .no_options
DEBUGF 1,"Got timestamp option" DEBUGF 1,"Got timestamp option\n"
;;;;; ;;;;;
@ -532,19 +556,29 @@ TCP_input:
cmp [ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED cmp [ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
jnz .not_uni_xfer jnz .not_uni_xfer
DEBUGF 1,"1\n"
test [edx + TCP_segment.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG test [edx + TCP_segment.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
jnz .not_uni_xfer jnz .not_uni_xfer
DEBUGF 1,"2\n"
test [edx + TCP_segment.Flags], TH_ACK test [edx + TCP_segment.Flags], TH_ACK
jz .not_uni_xfer jz .not_uni_xfer
DEBUGF 1,"3\n"
mov eax, [edx + TCP_segment.SequenceNumber] mov eax, [edx + TCP_segment.SequenceNumber]
cmp eax, [ebx + TCP_SOCKET.RCV_NXT] cmp eax, [ebx + TCP_SOCKET.RCV_NXT]
jne .not_uni_xfer jne .not_uni_xfer
movzx eax, [edx + TCP_segment.Window] ;;;;; (should use pre-calculated value isntead: todo: figure out where to store it) DEBUGF 1,"4\n"
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jne .not_uni_xfer ;; movzx eax, [edx + TCP_segment.Window] ;;;;; (should use pre-calculated value isntead: todo: figure out where to store it)
;; cmp eax, [ebx + TCP_SOCKET.SND_WND]
;; jne .not_uni_xfer
DEBUGF 1,"5\n"
mov eax, [ebx + TCP_SOCKET.SND_NXT] mov eax, [ebx + TCP_SOCKET.SND_NXT]
cmp eax, [ebx + TCP_SOCKET.SND_MAX] cmp eax, [ebx + TCP_SOCKET.SND_MAX]
@ -584,7 +618,7 @@ TCP_input:
; Delete acknowledged bytes from send buffer ; Delete acknowledged bytes from send buffer
; notice how ecx already holds number of bytes ack-ed ; notice how ecx already holds number of bytes ack-ed
lea eax, [ebx + snd] lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_free call SOCKET_ring_free
; Stop retransmit timer ; Stop retransmit timer
@ -620,8 +654,11 @@ TCP_input:
DEBUGF 1,"header prediction: we are receiver\nreceiving %u bytes of data\n", ecx DEBUGF 1,"header prediction: we are receiver\nreceiving %u bytes of data\n", ecx
add esi, edx add esi, edx
lea eax, [ebx + rcv] lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_add ; Add the data to the socket buffer call SOCKET_ring_write ; Add the data to the socket buffer
mov eax, ebx
call SOCKET_notify_owner
add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied
or [ebx + TCP_SOCKET.t_flags], TF_DELACK ; Set delayed ack flag or [ebx + TCP_SOCKET.t_flags], TF_DELACK ; Set delayed ack flag
@ -633,18 +670,13 @@ TCP_input:
.not_uni_xfer: .not_uni_xfer:
DEBUGF 1,"Header prediction failed\n" DEBUGF 1,"Header prediction failed\n" ; time to do it the "slow" way :)
;------------------------------ ;------------------------------
; Calculate receive window size ; Calculate receive window size
;;;; ;;;;
;-------------------------
; TCP slow input procedure
DEBUGF 1,"TCP slow input procedure\n"
cmp [ebx + TCP_SOCKET.t_state], TCB_LISTEN cmp [ebx + TCP_SOCKET.t_state], TCB_LISTEN
je .LISTEN je .LISTEN
@ -654,7 +686,7 @@ TCP_input:
;-------------------------------------------- ;--------------------------------------------
; Protection Against Wrapped Sequence Numbers ; Protection Against Wrapped Sequence Numbers
; First, check timestamp if present ; First, check if timestamp is present
;;;; TODO ;;;; TODO
@ -681,7 +713,9 @@ align 4
test [edx + TCP_segment.Flags], TH_SYN test [edx + TCP_segment.Flags], TH_SYN
jz .drop jz .drop
; TODO: find sender ip address somewhere! cmp esi, 0xffffff ; destination ip = 255.255.255.255 ?
jz .drop
; TODO: check if it's a broadcast or multicast, and drop if so ; TODO: check if it's a broadcast or multicast, and drop if so
call SOCKET_fork call SOCKET_fork
@ -706,7 +740,6 @@ align 4
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval
mov ebx, eax mov ebx, eax
jmp .trim_then_step6 jmp .trim_then_step6
@ -725,11 +758,9 @@ align 4
cmp eax, [ebx + TCP_SOCKET.ISS] cmp eax, [ebx + TCP_SOCKET.ISS]
jle .drop_with_reset jle .drop_with_reset
DEBUGF 1,"snd_max = %x\n", [ebx + TCP_SOCKET.SND_MAX] ;;; TODO: set this, but where?
; mov eax, [edx + TCP_segment.AckNumber] ; mov eax, [edx + TCP_segment.AckNumber]
;; cmp eax, [ebx + TCP_SOCKET.SND_MAX] cmp eax, [ebx + TCP_SOCKET.SND_MAX]
;; jg .drop_with_reset jg .drop_with_reset
@@: @@:
test [edx + TCP_segment.Flags], TH_RST test [edx + TCP_segment.Flags], TH_RST
@ -767,7 +798,7 @@ align 4
push [edx + TCP_segment.SequenceNumber] push [edx + TCP_segment.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS] pop [ebx + TCP_SOCKET.IRS]
;;; TODO: tcp_rcvseqinit TCP_rcvseqinit ebx
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
@ -781,7 +812,7 @@ align 4
DEBUGF 1,"TCP: active open\n" DEBUGF 1,"TCP: active open\n"
; TODO: update stats ; TODO: update stats
; TODO: set socket state to connected ; TODO: set general socket state to connected
mov [ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED mov [ebx + TCP_SOCKET.t_state], TCB_ESTABLISHED
@ -821,16 +852,16 @@ align 4
.trim_then_step6: .trim_then_step6:
DEBUGF 1,"Trimming window\n"
;---------------------------- ;----------------------------
; trim any data not in window ; trim any data not in window
DEBUGF 1,"Trimming window\n"
mov eax, [ebx + TCP_SOCKET.RCV_NXT] mov eax, [ebx + TCP_SOCKET.RCV_NXT]
sub eax, [edx + TCP_segment.SequenceNumber] sub eax, [edx + TCP_segment.SequenceNumber]
test eax, eax test eax, eax
jz .no_drop jz .no_duplicate
test [edx + TCP_segment.Flags], TH_SYN test [edx + TCP_segment.Flags], TH_SYN
jz .no_drop jz .no_drop
@ -848,10 +879,10 @@ align 4
and [edx + TCP_segment.Flags], not (TH_URG) and [edx + TCP_segment.Flags], not (TH_URG)
dec eax dec eax
jz .no_duplicate
.no_drop: .no_drop:
DEBUGF 1,"Going to drop %u bytes of data", eax DEBUGF 1,"Going to drop %u out of %u bytes\n", eax, ecx
; eax holds number of bytes to drop ; eax holds number of bytes to drop
@ -895,7 +926,7 @@ align 4
.duplicate: .duplicate:
DEBUGF 1,"Duplicate received" DEBUGF 1,"Duplicate received\n"
;---------------------------------------- ;----------------------------------------
; Update statistics for duplicate packets ; Update statistics for duplicate packets
@ -924,7 +955,7 @@ align 4
; Handle data that arrives after process terminates ; Handle data that arrives after process terminates
cmp [ebx + SOCKET.PID], 0 cmp [ebx + SOCKET.PID], 0
jge @f jg @f
cmp [ebx + TCP_SOCKET.t_state], TCB_CLOSE_WAIT cmp [ebx + TCP_SOCKET.t_state], TCB_CLOSE_WAIT
jle @f jle @f
@ -936,7 +967,6 @@ align 4
;;; update stats ;;; update stats
jmp .drop_with_reset jmp .drop_with_reset
@@: @@:
;---------------------------------------- ;----------------------------------------
@ -1039,16 +1069,22 @@ align 4
jg .ack_dup jg .ack_dup
jl .ack_nodup jl .ack_nodup
DEBUGF 1,"TCP state = syn received"
;;;;; ;;;;;
.ack_dup: .ack_dup:
DEBUGF 1,"Duplicate ACK"
;;;; ;;;;
.ack_nodup: .ack_nodup:
;;;; 887 ;;;; 887
DEBUGF 1,"New ACK"
;------------------------------------------------- ;-------------------------------------------------
; If the congestion window was inflated to account ; If the congestion window was inflated to account
; for the other side's cached packets, retrace it ; for the other side's cached packets, retrace it
@ -1069,7 +1105,6 @@ align 4
mov [ebx + TCP_SOCKET.timer_retransmission], 120 ;;;; TODO: correct this value mov [ebx + TCP_SOCKET.timer_retransmission], 120 ;;;; TODO: correct this value
.all_outstanding: .all_outstanding:
;------------------------------------------- ;-------------------------------------------
; Open congestion window in response to ACKs ; Open congestion window in response to ACKs
@ -1079,9 +1114,9 @@ align 4
;------------------------------------------ ;------------------------------------------
; Remove acknowledged data from send buffer ; Remove acknowledged data from send buffer
lea eax, [ebx + snd] xor ecx, ecx ;;;;;;
mov ecx, ecx ;;;; 943 - 956 lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_free call SOCKET_ring_free ;;;; 943 - 956
;--------------------------------------- ;---------------------------------------
; Wake up process waiting on send buffer ; Wake up process waiting on send buffer
@ -1196,7 +1231,7 @@ align 4
;;; 1040-1050 ;;; 1040-1050
movzx eax, [edx + TCP_segment.UrgentPointer] movzx eax, [edx + TCP_segment.UrgentPointer]
add eax, [ebx + rcv.size] add eax, [ebx + STREAM_SOCKET.rcv + RING_BUFFER.size]
cmp eax, SOCKET_MAXDATA cmp eax, SOCKET_MAXDATA
jle .not_urgent jle .not_urgent
@ -1216,17 +1251,35 @@ align 4
.do_data: .do_data:
DEBUGF 1,"TCP: do data:\n" DEBUGF 1,"TCP: do data\n"
test [edx + TCP_segment.Flags], TH_FIN test [edx + TCP_segment.Flags], TH_FIN
jnz .process_fin jnz .process_fin
test [ebx + TCP_SOCKET.t_state], TCB_FIN_WAIT_1 cmp [ebx + TCP_SOCKET.t_state], TCB_FIN_WAIT_1
jge .dont_do_data jge .dont_do_data
test ecx, ecx
jz .final_processing
DEBUGF 1,"Processing data in segment\n" DEBUGF 1,"Processing data in segment\n"
;;; NOW, process the data ;; TODO: check if data is in sequence !
movzx eax, [edx + TCP_segment.DataOffset] ;;; todo: remember this in.. edi ?
and eax, 0xf0
shr al, 2
lea esi, [edx + eax]
or [ebx + TCP_SOCKET.t_flags], TF_DELACK
add [ebx + TCP_SOCKET.RCV_NXT], ecx ;;; right ?
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_write
mov eax, ebx
call SOCKET_notify_owner
jmp .final_processing jmp .final_processing
@ -1248,25 +1301,32 @@ align 4
dd .no_fin ;TCB_CLOSED dd .no_fin ;TCB_CLOSED
dd .no_fin ;TCB_LISTEN dd .no_fin ;TCB_LISTEN
dd .no_fin ;TCB_SYN_SENT dd .no_fin ;TCB_SYN_SENT
dd ._1131 ;TCB_SYN_RECEIVED dd .fin_syn_est ;TCB_SYN_RECEIVED
dd ._1131 ;TCB_ESTABLISHED dd .fin_syn_est ;TCB_ESTABLISHED
dd .no_fin ;TCB_CLOSE_WAIT dd .no_fin ;TCB_CLOSE_WAIT
dd ._1139 ;TCB_FIN_WAIT_1 dd .fin_wait1 ;TCB_FIN_WAIT_1
dd .no_fin ;TCB_CLOSING dd .no_fin ;TCB_CLOSING
dd .no_fin ;TCB_LAST_ACK dd .no_fin ;TCB_LAST_ACK
dd ._1147 ;TCB_FIN_WAIT_2 dd .fin_wait2 ;TCB_FIN_WAIT_2
dd ._1156 ;TCB_TIMED_WAIT dd .fin_timed ;TCB_TIMED_WAIT
._1131: .fin_syn_est:
._1139: jmp .final_processing
._1147: .fin_wait1:
._1156: jmp .final_processing
.fin_wait2:
jmp .final_processing
.fin_timed:
jmp .final_processing
.no_fin: .no_fin:
@ -1277,6 +1337,8 @@ align 4
DEBUGF 1,"Final processing\n" DEBUGF 1,"Final processing\n"
mov [ebx + SOCKET.lock], 0
;;; if debug enabled, output packet ;;; if debug enabled, output packet
;test ;;;needoutput = 1 ;test ;;;needoutput = 1
@ -1285,7 +1347,6 @@ align 4
test [ebx + TCP_SOCKET.t_flags], TF_ACKNOW test [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
jnz .ack_now jnz .ack_now
mov [ebx + SOCKET.lock], 0
call kernel_free call kernel_free
add esp, 4 add esp, 4
ret ret
@ -1299,7 +1360,6 @@ align 4
call TCP_output call TCP_output
pop ebx pop ebx
mov [ebx + SOCKET.lock], 0
call kernel_free call kernel_free
add esp, 4 add esp, 4
ret ret
@ -1322,7 +1382,6 @@ align 4
call TCP_output call TCP_output
pop ebx pop ebx
mov [ebx + SOCKET.lock], 0
call kernel_free call kernel_free
add esp, 4 add esp, 4
ret ret
@ -1347,25 +1406,28 @@ align 4
test [edx + TCP_segment.Flags], TH_SYN test [edx + TCP_segment.Flags], TH_SYN
jnz .respond_syn jnz .respond_syn
mov [ebx + SOCKET.lock], 0
call kernel_free call kernel_free
add esp, 4 add esp, 4
ret ret
.respond_ack: .respond_ack:
;;;; mov dl, TH_RST
push ebx
call TCP_respond_segment call TCP_respond_segment
pop ebx
jmp .destroy_new_socket jmp .destroy_new_socket
.respond_syn: .respond_syn:
;;;; mov dl, TH_RST + TH_ACK
call TCP_respond_segment push ebx
call TCP_respond_socket
pop ebx
jmp .destroy_new_socket jmp .destroy_new_socket
@ -1383,7 +1445,6 @@ align 4
;;;; kill the newly created socket ;;;; kill the newly created socket
mov [ebx + SOCKET.lock], 0
call kernel_free call kernel_free
add esp, 4 add esp, 4
ret ret
@ -1473,7 +1534,7 @@ TCP_output:
test ecx, ecx test ecx, ecx
jnz .no_zero_window jnz .no_zero_window
cmp ebx, [eax + snd.size] cmp ebx, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
jge @f jge @f
and dl, not (TH_FIN) ; clear the FIN flag ??? how can it be set before? and dl, not (TH_FIN) ; clear the FIN flag ??? how can it be set before?
@ -1491,7 +1552,7 @@ TCP_output:
;;;106 ;;;106
mov esi, [eax + snd.size] mov esi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
cmp esi, ecx cmp esi, ecx
jl @f jl @f
mov esi, ecx mov esi, ecx
@ -1536,7 +1597,7 @@ TCP_output:
mov edi, [eax + TCP_SOCKET.SND_NXT] mov edi, [eax + TCP_SOCKET.SND_NXT]
add edi, esi ; len add edi, esi ; len
sub edi, [eax + TCP_SOCKET.SND_UNA] sub edi, [eax + TCP_SOCKET.SND_UNA]
add edi, [eax + snd.size] add edi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
cmp edi, 0 cmp edi, 0
jle @f jle @f
@ -1549,7 +1610,7 @@ TCP_output:
; From now on, ecx will be the window we advertise to the other end ; From now on, ecx will be the window we advertise to the other end
mov ecx, SOCKET_MAXDATA mov ecx, SOCKET_MAXDATA
sub ecx, [eax + rcv.size] sub ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size]
;------------------------------ ;------------------------------
; Sender silly window avoidance ; Sender silly window avoidance
@ -1706,7 +1767,11 @@ TCP_output:
; edi = header size ; edi = header size
; esi = snd ring buff ptr ; esi = snd ring buff ptr
xor ecx, ecx ;;;;; mov ecx, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
cmp ecx, [eax + TCP_SOCKET.t_maxseg] ;;; right?
jle @f
mov ecx, [eax + TCP_SOCKET.t_maxseg]
@@:
add ecx, edi ; total TCP segment size add ecx, edi ; total TCP segment size
; Start by pushing all TCP header values in reverse order on stack ; Start by pushing all TCP header values in reverse order on stack
@ -1733,13 +1798,11 @@ TCP_output:
push [eax + TCP_SOCKET.LocalPort] ; .SourcePort dw ? push [eax + TCP_SOCKET.LocalPort] ; .SourcePort dw ?
ntohlw [esp] ntohlw [esp]
push edi ; header size push edi ; header size
; Create the IP packet ; Create the IP packet
mov ebx, [eax + IP_SOCKET.LocalIP] ; source ip mov ebx, [eax + IP_SOCKET.LocalIP] ; source ip
mov eax, [eax + IP_SOCKET.RemoteIP] ; dest ip mov eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
; mov ecx, ; data length
; mov dx, ; fragment id
mov di, IP_PROTO_TCP shl 8 + 128 mov di, IP_PROTO_TCP shl 8 + 128
call IPv4_output call IPv4_output
jz .fail jz .fail
@ -1747,25 +1810,23 @@ TCP_output:
;----------------------------------------- ;-----------------------------------------
; Move TCP header from stack to TCP packet ; Move TCP header from stack to TCP packet
; pop ecx ; header size push ecx
; mov esi, esp mov ecx, [esp+4]
; add esp, ecx lea esi, [esp+4+4]
; shr ecx, 2
; rep movsd
mov ecx, [esp]
lea esi, [esp+4]
shr ecx, 2 shr ecx, 2
rep movsd rep movsd
pop ecx ; full TCP packet size
pop ecx pop esi ; headersize
add esp, ecx add esp, esi
mov [esp + 4+4], edx ; packet size
mov [esp + 4], eax ; packet ptr mov [esp + 4], eax ; packet ptr
mov [esp + 4+4], edx ; packet size
mov edx, edi mov edx, edi ; begin of data
sub edx, ecx sub edx, esi ; begin of packet (edi = begin of data)
push ecx
sub ecx, esi ; data size
;-------------- ;--------------
; Copy the data ; Copy the data
@ -1774,15 +1835,33 @@ TCP_output:
; ecx = buffer size ; ecx = buffer size
; edi = ptr to buffer ; edi = ptr to buffer
mov eax, [esp] ; socket ptr mov eax, [esp+4] ; socket ptr
push ecx edx push edx
add eax, snd add eax, STREAM_SOCKET.snd
call SOCKET_ring_read call SOCKET_ring_read
pop esi ecx pop esi ecx
pop eax pop eax
;------------------------------------------------------------- test [esi + TCP_segment.Flags], TH_SYN + TH_FIN
; Create the checksum (we have already pushed IPs onto stack) jz @f
inc [eax + TCP_SOCKET.SND_NXT]
;;; TODO: update sentfin flag
@@:
;; add [eax + TCP_SOCKET.SND_NXT], ecx
mov edx, [eax + TCP_SOCKET.SND_NXT]
cmp edx, [eax + TCP_SOCKET.SND_MAX]
jle @f
mov [eax + TCP_SOCKET.SND_MAX], edx
;;;; TODO: time transmission (420)
@@:
;;; TODO: set retransmission timer
;--------------------
; Create the checksum
DEBUGF 1,"checksum: ptr=%x size=%u\n", esi, ecx DEBUGF 1,"checksum: ptr=%x size=%u\n", esi, ecx
@ -1969,10 +2048,9 @@ TCP_respond_segment:
mov ecx, TCP_segment.Data mov ecx, TCP_segment.Data
mov di , IP_PROTO_TCP shl 8 + 128 mov di , IP_PROTO_TCP shl 8 + 128
call IPv4_output call IPv4_output
test edi, edi
jz .error jz .error
pop esi cx pop esi cx
push edx eax push edx eax
;--------------------------------------------------- ;---------------------------------------------------