Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1760 → Rev 1761

/kernel/branches/net/network/tcp_output.inc
33,7 → 33,7
 
.not_idle:
.again:
mov ebx, [eax + TCP_SOCKET.SND_NXT] ; calculate offset
mov ebx, [eax + TCP_SOCKET.SND_NXT] ; calculate offset (71)
sub ebx, [eax + TCP_SOCKET.SND_UNA] ;
 
mov ecx, [eax + TCP_SOCKET.SND_WND] ; determine window
42,14 → 42,17
mov ecx, [eax + TCP_SOCKET.SND_CWND] ;
@@: ;
 
call TCP_outflags ; in dl
call TCP_outflags ; flags in dl
 
;------------------------
; data being forced out ?
 
; If in persist timeout with window of 0, send 1 byte.
; Otherwise, if window is small but nonzero, and timer expired,
; we will send what we can and go to transmit state
 
test [eax + TCP_SOCKET.t_force], -1
jz .no_persist_timeout
jz .no_force
 
test ecx, ecx
jnz .no_zero_window
61,16 → 64,16
 
@@:
inc ecx
jmp .no_persist_timeout
jmp .no_force
 
.no_zero_window:
 
mov [eax + TCP_SOCKET.timer_persist], 0
mov [eax + TCP_SOCKET.t_rxtshift], 0
 
.no_persist_timeout:
.no_force:
 
;;;106
;--------------------------------
; Calculate how much data to send (106)
 
mov esi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
cmp esi, ecx
79,73 → 82,84
@@:
sub esi, ebx
 
cmp esi, -1
jne .not_minus_one
;------------------------
; check for window shrink (107)
 
; If FIN has been set, but not ACKed, and we havent been called to retransmit,
; len (esi) will be -1
; If FIN has been set, but not ACKed, but we havent been called to retransmit, esi will be -1
; Otherwise, window shrank after we sent into it.
; If window shrank to 0, cancel pending retransmit and pull SND_NXT back to (closed) window
; We will enter persist state below.
; If window didn't close completely, just wait for an ACK
 
jnc .bigger_than_zero
 
; enter persist state
xor esi, esi
 
; If window shrank to 0
test ecx, ecx
jnz @f
 
mov [eax + TCP_SOCKET.timer_retransmission], 0 ; cancel retransmit
; cancel pending retransmit
mov [eax + TCP_SOCKET.timer_retransmission], 0
 
; pull SND_NXT back to (closed) window, We will enter persist state below.
push [eax + TCP_SOCKET.SND_UNA]
pop [eax + TCP_SOCKET.SND_NXT]
 
@@:
 
.not_minus_one:
; If window didn't close completely, just wait for an ACK
 
;;; 124
.bigger_than_zero:
 
;---------------------------
; Send one segment at a time (124)
 
cmp esi, [eax + TCP_SOCKET.t_maxseg]
jle @f
 
mov esi, [eax + TCP_SOCKET.t_maxseg]
;sendalot = 1
 
;;; sendalot = 1
 
@@:
 
;;; 128
;--------------------------------------------
; Turn of FIN flag if send buffer not emptied (128)
 
mov edi, [eax + TCP_SOCKET.SND_NXT]
add edi, esi ; len
add edi, esi
sub edi, [eax + TCP_SOCKET.SND_UNA]
add edi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
sub edi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
 
cmp edi, 0
jle @f
jge @f
 
and dl, not (TH_FIN) ; clear the FIN flag
and dl, not (TH_FIN)
 
@@:
 
;-------------------------------
; calculate window advertisement (130)
 
; set ecx to space available in receive buffer
; From now on, ecx will be the window we advertise to the other end
 
mov ecx, SOCKET_MAXDATA
sub ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size]
 
;------------------------------
; Sender silly window avoidance
; Sender silly window avoidance (131)
 
cmp ecx, [eax + TCP_SOCKET.t_maxseg]
test esi, esi
jz .len_zero
 
cmp esi, [eax + TCP_SOCKET.t_maxseg]
je .send
 
;;; TODO: 144-145
;;; if (idle or TF_NODELAY) && (esi + ebx >= so_snd.sb_cc), send
 
test [eax + TCP_SOCKET.t_force], -1
test [eax + TCP_SOCKET.t_force], -1 ;;;
jnz .send
 
mov ebx, [eax + TCP_SOCKET.max_sndwnd]
shr ebx, 1
cmp ecx, ebx
cmp esi, ebx
jge .send
 
mov ebx, [eax + TCP_SOCKET.SND_NXT]
152,32 → 166,36
cmp ebx, [eax + TCP_SOCKET.SND_MAX]
jl .send
 
.len_zero:
 
;----------------------------------------
; Check if a window update should be sent
; Check if a window update should be sent (154)
 
test ecx, ecx ; window
test ecx, ecx
jz .no_window
 
;;; TODO 154-172
;;; TODO 167-172
 
.no_window:
 
;--------------------------
; Should a segment be sent?
; Should a segment be sent? (174)
 
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW ; we need to ACK
jnz .send
 
test dl, TH_SYN + TH_RST
test dl, TH_SYN + TH_RST ; we need to send a SYN or RST
jnz .send
 
mov ebx, [eax + TCP_SOCKET.SND_UP]
mov ebx, [eax + TCP_SOCKET.SND_UP] ; when urgent pointer is beyond start of send bufer
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
jg .send
 
test dl, TH_FIN
jz .enter_persist
jz .enter_persist ; no reason to send, enter persist state
 
; FIN was set, only send if not already sent, or on retransmit
 
test [eax + TCP_SOCKET.t_flags], TF_SENTFIN
jnz .send
 
186,27 → 204,38
je .send
 
;--------------------
; Enter persist state
; Enter persist state (191)
 
.enter_persist:
 
DEBUGF 1,"Entering persist state\n"
 
;--------------------------------------
; No reason to send a segment, just ret
 
;;; 213 - 217
 
;----------------------------
; No reason to send a segment (219)
 
DEBUGF 1,"No reason to send a segment\n"
 
mov [ebx + SOCKET.lock], 0
mov [eax + SOCKET.lock], 0
 
ret
 
 
 
 
 
 
 
 
 
;-----------------------------------------------
;
; Send a segment
; Send a segment (222)
;
; eax = socket pointer
; esi = data len
; dl = flags
;
;-----------------------------------------------
218,19 → 247,19
mov edi, TCP_segment.Data ; edi will contain headersize
 
sub esp, 8 ; create some space on stack
push eax ; save this too..
push eax ; save socket pointer
 
;------------------------------------
; Send options with first SYN segment
 
test dl, TH_SYN
jz .no_options
jz .options_done
 
push [eax + TCP_SOCKET.ISS]
pop [eax + TCP_SOCKET.SND_NXT]
 
test [eax + TCP_SOCKET.t_flags], TF_NOOPT
jnz .no_options
jnz .options_done
 
mov ecx, 1460
or ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
272,32 → 301,47
jz .no_timestamp
 
.timestamp:
mov esi, [timer_ticks]
bswap esi
push esi
mov ebx, [timer_ticks]
bswap ebx
push ebx
pushw 0
pushd TCP_OPT_TIMESTAMP + 10 shl 8 + TCP_OPT_NOP shl 16 + TCP_OPT_NOP shl 24
add di, 10
 
.no_timestamp:
;; TODO: check if we dont exceed the max segment size
 
.no_options:
; <Add additional options here>
 
 
 
 
 
 
 
 
.options_done:
 
; eax = socket ptr
; edx = flags
; ecx = data size
; edi = header size
; esi = snd ring buff ptr
; esi = data len
 
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
;---------------------------------------------
; check if we dont exceed the max segment size (270)
 
add esi, edi ; total TCP segment size
cmp esi, [eax + TCP_SOCKET.t_maxseg]
jle .no_overflow
 
mov esi, [eax + TCP_SOCKET.t_maxseg]
 
;;; sendalot = 1
 
.no_overflow:
 
;-----------------------------------------------------------------
; Start by pushing all TCP header values in reverse order on stack
; (essentially, creating the tcp header!)
; (essentially, creating the tcp header on the stack!)
 
pushw 0 ; .UrgentPointer dw ?
pushw 0 ; .Checksum dw ?
322,7 → 366,11
 
push edi ; header size
 
;---------------------
; Create the IP packet
 
mov ecx, esi
 
mov ebx, [eax + IP_SOCKET.LocalIP] ; source ip
mov eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
mov di, IP_PROTO_TCP shl 8 + 128
357,20 → 405,26
; ecx = buffer size
; edi = ptr to buffer
 
; test ecx, ecx
mov eax, [esp+4] ; socket ptr
add [eax + TCP_SOCKET.SND_NXT], ecx
mov eax, [esp+4] ; get socket ptr
 
add [eax + TCP_SOCKET.SND_NXT], ecx ; update sequence number
 
add eax, STREAM_SOCKET.snd
push edx
call SOCKET_ring_read
pop esi
pop ecx
pop eax
pop esi ; begin of data
pop ecx ; full packet size
pop eax ; socket ptr
 
;----------------------------------
; update sequence number and timers (400)
 
test [esi + TCP_segment.Flags], TH_SYN + TH_FIN
jz @f
inc [eax + TCP_SOCKET.SND_NXT]
;;; TODO: update sentfin flag
inc [eax + TCP_SOCKET.SND_NXT] ; syn and fin take a sequence number
test [esi + TCP_segment.Flags], TH_FIN
jz @f
or [eax + TCP_SOCKET.t_flags], TF_SENTFIN ; if we sent a fin, set the sentfin flag
@@:
 
mov edx, [eax + TCP_SOCKET.SND_NXT]
379,10 → 433,26
mov [eax + TCP_SOCKET.SND_MAX], edx
 
;;;; TODO: time transmission (420)
 
@@:
 
;;; TODO: set retransmission timer
; set retransmission timer if not already set, and not doing an ACK or keepalive probe
 
cmp [eax + TCP_SOCKET.timer_retransmission], 1000 ;;;;
jl .retransmit_set
 
cmp edx, [eax + TCP_SOCKET.SND_UNA] ; edx = [eax + TCP_SOCKET.SND_NXT]
je .retransmit_set
 
mov edx, [eax + TCP_SOCKET.t_rxtcur]
mov [eax + TCP_SOCKET.timer_retransmission], dx
 
mov [eax + TCP_SOCKET.timer_persist], 0
mov [eax + TCP_SOCKET.t_rxtshift], 0 ;;; TODO: only do this if timer_persist was set
 
 
.retransmit_set:
 
;--------------------
; Create the checksum
 
391,6 → 461,10
TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
mov [esi+TCP_segment.Checksum], dx
 
; unlock socket
 
mov [eax + SOCKET.lock], 0
 
;----------------
; Send the packet
 
403,6 → 477,7
pop ecx
add esp, ecx
add esp, 4+8
mov [eax + SOCKET.lock], 0
DEBUGF 1,"TCP_output: failed\n"
ret