forked from KolibriOS/kolibrios
* Updates in TCP code
* Splitted TCP code into multiple files * cleanup git-svn-id: svn://kolibrios.org@1733 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
e0fed2fb2e
commit
1dd8c78cbd
@ -205,11 +205,6 @@ ETH_API:
|
|||||||
movzx eax, bh
|
movzx eax, bh
|
||||||
shl eax, 2
|
shl eax, 2
|
||||||
|
|
||||||
cmp bl, 7
|
|
||||||
jz .out_queue
|
|
||||||
cmp bl, 6
|
|
||||||
jz .in_queue
|
|
||||||
|
|
||||||
mov eax, dword [NET_DRV_LIST + eax]
|
mov eax, dword [NET_DRV_LIST + eax]
|
||||||
cmp [eax + NET_DEVICE.type], NET_TYPE_ETH
|
cmp [eax + NET_DEVICE.type], NET_TYPE_ETH
|
||||||
jne .error
|
jne .error
|
||||||
@ -266,20 +261,3 @@ ETH_API:
|
|||||||
call [eax + ETH_DEVICE.set_MAC]
|
call [eax + ETH_DEVICE.set_MAC]
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.in_queue:
|
|
||||||
if ETH_QUEUE
|
|
||||||
add eax, ETH_IN_QUEUE
|
|
||||||
mov eax, [eax + queue.size]
|
|
||||||
else
|
|
||||||
or eax, -1
|
|
||||||
end if
|
|
||||||
ret
|
|
||||||
|
|
||||||
.out_queue:
|
|
||||||
if ETH_QUEUE
|
|
||||||
add eax, ETH_OUT_QUEUE
|
|
||||||
mov eax, [eax + queue.size]
|
|
||||||
else
|
|
||||||
or eax, -1
|
|
||||||
end if
|
|
||||||
ret
|
|
@ -508,19 +508,15 @@ align 4
|
|||||||
|
|
||||||
mov [eax + TCP_SOCKET.timer_persist], 0
|
mov [eax + TCP_SOCKET.timer_persist], 0
|
||||||
mov [eax + TCP_SOCKET.t_state], TCB_SYN_SENT
|
mov [eax + TCP_SOCKET.t_state], TCB_SYN_SENT
|
||||||
mov ebx, [TCP_sequence_num]
|
push [TCP_sequence_num]
|
||||||
add [TCP_sequence_num], 6400
|
add [TCP_sequence_num], 6400
|
||||||
mov [eax + TCP_SOCKET.ISS], ebx
|
pop [eax + TCP_SOCKET.ISS]
|
||||||
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init
|
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init
|
||||||
|
|
||||||
TCP_sendseqinit eax
|
TCP_sendseqinit eax
|
||||||
|
|
||||||
; mov [ebx + TCP_SOCKET.timer_retransmission], ;; todo: create macro to set retransmission timer
|
; mov [ebx + TCP_SOCKET.timer_retransmission], ;; todo: create macro to set retransmission timer
|
||||||
|
|
||||||
push eax
|
|
||||||
call TCP_output
|
|
||||||
pop eax
|
|
||||||
|
|
||||||
mov ebx, eax
|
mov ebx, eax
|
||||||
|
|
||||||
lea eax, [ebx + STREAM_SOCKET.snd]
|
lea eax, [ebx + STREAM_SOCKET.snd]
|
||||||
@ -530,6 +526,10 @@ align 4
|
|||||||
call SOCKET_ring_create
|
call SOCKET_ring_create
|
||||||
|
|
||||||
mov [ebx + SOCKET.lock], 0
|
mov [ebx + SOCKET.lock], 0
|
||||||
|
|
||||||
|
mov eax, ebx
|
||||||
|
call TCP_output
|
||||||
|
|
||||||
mov dword [esp+32], 0
|
mov dword [esp+32], 0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
$Revision$
|
$Revision$
|
||||||
|
|
||||||
__DEBUG_LEVEL_OLD__ equ __DEBUG_LEVEL__
|
__DEBUG_LEVEL_OLD__ equ __DEBUG_LEVEL__
|
||||||
|
|
||||||
__DEBUG_LEVEL__ equ 1 ; this sets the debug level for network part of kernel
|
__DEBUG_LEVEL__ equ 1 ; this sets the debug level for network part of kernel
|
||||||
|
|
||||||
uglobal
|
uglobal
|
||||||
@ -29,14 +30,12 @@ endg
|
|||||||
|
|
||||||
MAX_NET_DEVICES equ 16
|
MAX_NET_DEVICES equ 16
|
||||||
|
|
||||||
ETH_QUEUE equ 0 ; 1 = enable / 0 = disable
|
|
||||||
|
|
||||||
MIN_EPHEMERAL_PORT equ 49152
|
MIN_EPHEMERAL_PORT equ 49152
|
||||||
MAX_EPHEMERAL_PORT equ 61000
|
MAX_EPHEMERAL_PORT equ 61000
|
||||||
|
|
||||||
; Ethernet protocol numbers
|
; Ethernet protocol numbers
|
||||||
ETHER_ARP equ 0x0608
|
ETHER_ARP equ 0x0608
|
||||||
ETHER_IPv4 equ 0x0008 ; Reversed from 0800 for intel
|
ETHER_IPv4 equ 0x0008
|
||||||
ETHER_PPP_DISCOVERY equ 0x6388
|
ETHER_PPP_DISCOVERY equ 0x6388
|
||||||
ETHER_PPP_SESSION equ 0x6488
|
ETHER_PPP_SESSION equ 0x6488
|
||||||
|
|
||||||
@ -52,7 +51,6 @@ AF_INET4 equ 2
|
|||||||
;AF_AAL5 equ 8
|
;AF_AAL5 equ 8
|
||||||
;AF_X25 equ 9
|
;AF_X25 equ 9
|
||||||
AF_INET6 equ 10
|
AF_INET6 equ 10
|
||||||
;AF_MAX equ 12
|
|
||||||
|
|
||||||
; Internet protocol numbers
|
; Internet protocol numbers
|
||||||
IP_PROTO_IP equ 0
|
IP_PROTO_IP equ 0
|
||||||
|
File diff suppressed because it is too large
Load Diff
1371
kernel/branches/net/network/tcp_input.inc
Normal file
1371
kernel/branches/net/network/tcp_input.inc
Normal file
File diff suppressed because it is too large
Load Diff
409
kernel/branches/net/network/tcp_output.inc
Normal file
409
kernel/branches/net/network/tcp_output.inc
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
;-----------------------------------------------------------------
|
||||||
|
;
|
||||||
|
; TCP_output
|
||||||
|
;
|
||||||
|
; IN: eax = socket pointer
|
||||||
|
;
|
||||||
|
; OUT: /
|
||||||
|
;
|
||||||
|
;-----------------------------------------------------------------
|
||||||
|
align 4
|
||||||
|
TCP_output:
|
||||||
|
|
||||||
|
DEBUGF 1,"TCP_output, socket: %x\n", eax
|
||||||
|
|
||||||
|
|
||||||
|
; We'll detect the length of the data to be transmitted, and flags to be used
|
||||||
|
; If there is some data, or any critical controls to send (SYN / RST), then transmit
|
||||||
|
; Otherwise, investigate further
|
||||||
|
|
||||||
|
mov ebx, [eax + TCP_SOCKET.SND_MAX]
|
||||||
|
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
|
||||||
|
jne .not_idle
|
||||||
|
|
||||||
|
mov ebx, [eax + TCP_SOCKET.t_idle]
|
||||||
|
cmp ebx, [eax + TCP_SOCKET.t_rxtcur]
|
||||||
|
jle .not_idle
|
||||||
|
|
||||||
|
; We have been idle for a while and no ACKS are expected to clock out any data we send..
|
||||||
|
; Slow start to get ack "clock" running again.
|
||||||
|
|
||||||
|
mov ebx, [eax + TCP_SOCKET.t_maxseg]
|
||||||
|
mov [eax + TCP_SOCKET.SND_CWND], ebx
|
||||||
|
|
||||||
|
.not_idle:
|
||||||
|
.again:
|
||||||
|
mov ebx, [eax + TCP_SOCKET.SND_NXT] ; calculate offset
|
||||||
|
sub ebx, [eax + TCP_SOCKET.SND_UNA] ;
|
||||||
|
|
||||||
|
mov ecx, [eax + TCP_SOCKET.SND_WND] ; determine window
|
||||||
|
cmp ecx, [eax + TCP_SOCKET.SND_CWND] ;
|
||||||
|
jl @f ;
|
||||||
|
mov ecx, [eax + TCP_SOCKET.SND_CWND] ;
|
||||||
|
@@: ;
|
||||||
|
|
||||||
|
call TCP_outflags ; in dl
|
||||||
|
|
||||||
|
; 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
|
||||||
|
|
||||||
|
test ecx, ecx
|
||||||
|
jnz .no_zero_window
|
||||||
|
|
||||||
|
cmp ebx, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
|
||||||
|
jge @f
|
||||||
|
|
||||||
|
and dl, not (TH_FIN) ; clear the FIN flag ??? how can it be set before?
|
||||||
|
|
||||||
|
@@:
|
||||||
|
inc ecx
|
||||||
|
jmp .no_persist_timeout
|
||||||
|
|
||||||
|
.no_zero_window:
|
||||||
|
|
||||||
|
mov [eax + TCP_SOCKET.timer_persist], 0
|
||||||
|
mov [eax + TCP_SOCKET.t_rxtshift], 0
|
||||||
|
|
||||||
|
.no_persist_timeout:
|
||||||
|
|
||||||
|
;;;106
|
||||||
|
|
||||||
|
mov esi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
|
||||||
|
cmp esi, ecx
|
||||||
|
jl @f
|
||||||
|
mov esi, ecx
|
||||||
|
@@:
|
||||||
|
sub esi, ebx
|
||||||
|
|
||||||
|
cmp esi, -1
|
||||||
|
jne .not_minus_one
|
||||||
|
|
||||||
|
; If FIN has been set, but not ACKed, and we havent been called to retransmit,
|
||||||
|
; len (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
|
||||||
|
|
||||||
|
xor esi, esi
|
||||||
|
|
||||||
|
test ecx, ecx
|
||||||
|
jnz @f
|
||||||
|
|
||||||
|
mov [eax + TCP_SOCKET.timer_retransmission], 0 ; cancel retransmit
|
||||||
|
|
||||||
|
push [eax + TCP_SOCKET.SND_UNA]
|
||||||
|
pop [eax + TCP_SOCKET.SND_NXT]
|
||||||
|
@@:
|
||||||
|
|
||||||
|
.not_minus_one:
|
||||||
|
|
||||||
|
;;; 124
|
||||||
|
|
||||||
|
cmp esi, [eax + TCP_SOCKET.t_maxseg]
|
||||||
|
jle @f
|
||||||
|
|
||||||
|
mov esi, [eax + TCP_SOCKET.t_maxseg]
|
||||||
|
;sendalot = 1
|
||||||
|
|
||||||
|
@@:
|
||||||
|
|
||||||
|
;;; 128
|
||||||
|
|
||||||
|
mov edi, [eax + TCP_SOCKET.SND_NXT]
|
||||||
|
add edi, esi ; len
|
||||||
|
sub edi, [eax + TCP_SOCKET.SND_UNA]
|
||||||
|
add edi, [eax + STREAM_SOCKET.snd + RING_BUFFER.size]
|
||||||
|
cmp edi, 0
|
||||||
|
jle @f
|
||||||
|
|
||||||
|
and dl, not (TH_FIN) ; clear the FIN flag
|
||||||
|
|
||||||
|
@@:
|
||||||
|
|
||||||
|
|
||||||
|
; 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
|
||||||
|
|
||||||
|
cmp ecx, [eax + TCP_SOCKET.t_maxseg]
|
||||||
|
je .send
|
||||||
|
|
||||||
|
;;; TODO: 144-145
|
||||||
|
|
||||||
|
test [eax + TCP_SOCKET.t_force], -1
|
||||||
|
jnz .send
|
||||||
|
|
||||||
|
mov ebx, [eax + TCP_SOCKET.max_sndwnd]
|
||||||
|
shr ebx, 1
|
||||||
|
cmp ecx, ebx
|
||||||
|
jge .send
|
||||||
|
|
||||||
|
mov ebx, [eax + TCP_SOCKET.SND_NXT]
|
||||||
|
cmp ebx, [eax + TCP_SOCKET.SND_MAX]
|
||||||
|
jl .send
|
||||||
|
|
||||||
|
;----------------------------------------
|
||||||
|
; Check if a window update should be sent
|
||||||
|
|
||||||
|
test ecx, ecx ; window
|
||||||
|
jz .no_window
|
||||||
|
|
||||||
|
;;; TODO 154-172
|
||||||
|
|
||||||
|
.no_window:
|
||||||
|
|
||||||
|
;--------------------------
|
||||||
|
; Should a segment be sent?
|
||||||
|
|
||||||
|
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||||
|
jnz .send
|
||||||
|
|
||||||
|
test dl, TH_SYN + TH_RST
|
||||||
|
jnz .send
|
||||||
|
|
||||||
|
mov ebx, [eax + TCP_SOCKET.SND_UP]
|
||||||
|
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
|
||||||
|
jg .send
|
||||||
|
|
||||||
|
test dl, TH_FIN
|
||||||
|
jz .enter_persist
|
||||||
|
|
||||||
|
test [eax + TCP_SOCKET.t_flags], TF_SENTFIN
|
||||||
|
jnz .send
|
||||||
|
|
||||||
|
mov ebx, [eax + TCP_SOCKET.SND_NXT]
|
||||||
|
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
|
||||||
|
je .send
|
||||||
|
|
||||||
|
;--------------------
|
||||||
|
; Enter persist state
|
||||||
|
|
||||||
|
.enter_persist:
|
||||||
|
|
||||||
|
DEBUGF 1,"Entering persist state\n"
|
||||||
|
|
||||||
|
;--------------------------------------
|
||||||
|
; No reason to send a segment, just ret
|
||||||
|
|
||||||
|
DEBUGF 1,"No reason to send a segment\n"
|
||||||
|
|
||||||
|
mov [ebx + SOCKET.lock], 0
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;-----------------------------------------------
|
||||||
|
;
|
||||||
|
; Send a segment
|
||||||
|
;
|
||||||
|
; eax = socket pointer
|
||||||
|
; dl = flags
|
||||||
|
;
|
||||||
|
;-----------------------------------------------
|
||||||
|
|
||||||
|
.send:
|
||||||
|
|
||||||
|
DEBUGF 1,"Preparing to send a segment\n"
|
||||||
|
|
||||||
|
mov edi, TCP_segment.Data ; edi will contain headersize
|
||||||
|
|
||||||
|
sub esp, 8 ; create some space on stack
|
||||||
|
push eax ; save this too..
|
||||||
|
|
||||||
|
;------------------------------------
|
||||||
|
; Send options with first SYN segment
|
||||||
|
|
||||||
|
test dl, TH_SYN
|
||||||
|
jz .no_options
|
||||||
|
|
||||||
|
push [eax + TCP_SOCKET.ISS]
|
||||||
|
pop [eax + TCP_SOCKET.SND_NXT]
|
||||||
|
|
||||||
|
test [eax + TCP_SOCKET.t_flags], TF_NOOPT
|
||||||
|
jnz .no_options
|
||||||
|
|
||||||
|
mov ecx, 1460
|
||||||
|
or ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
|
||||||
|
bswap ecx
|
||||||
|
push ecx
|
||||||
|
add di, 4
|
||||||
|
|
||||||
|
test [eax + TCP_SOCKET.t_flags], TF_REQ_SCALE
|
||||||
|
jz .no_syn
|
||||||
|
|
||||||
|
test dl, TH_ACK
|
||||||
|
jnz .scale_opt
|
||||||
|
|
||||||
|
test [eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE
|
||||||
|
jz .no_syn
|
||||||
|
|
||||||
|
.scale_opt:
|
||||||
|
movzx ecx, byte [eax + TCP_SOCKET.request_r_scale]
|
||||||
|
or ecx, TCP_OPT_WINDOW shl 24 + 4 shl 16 + TCP_OPT_NOP shl 8
|
||||||
|
bswap ecx
|
||||||
|
pushd ecx
|
||||||
|
add di, 4
|
||||||
|
|
||||||
|
.no_syn:
|
||||||
|
|
||||||
|
;------------------------------------
|
||||||
|
; Make the timestamp option if needed
|
||||||
|
|
||||||
|
test [eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP
|
||||||
|
jz .no_timestamp
|
||||||
|
|
||||||
|
test dl, TH_RST
|
||||||
|
jnz .no_timestamp
|
||||||
|
|
||||||
|
test dl, TH_ACK
|
||||||
|
jz .timestamp
|
||||||
|
|
||||||
|
test [eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
|
||||||
|
jz .no_timestamp
|
||||||
|
|
||||||
|
.timestamp:
|
||||||
|
mov esi, [timer_ticks]
|
||||||
|
bswap esi
|
||||||
|
push esi
|
||||||
|
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:
|
||||||
|
; eax = socket ptr
|
||||||
|
; edx = flags
|
||||||
|
; ecx = data size
|
||||||
|
; edi = header size
|
||||||
|
; esi = snd ring buff ptr
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
; Start by pushing all TCP header values in reverse order on stack
|
||||||
|
; (essentially, creating the tcp header!)
|
||||||
|
|
||||||
|
pushw 0 ; .UrgentPointer dw ?
|
||||||
|
pushw 0 ; .Checksum dw ?
|
||||||
|
pushw 0x00a0 ; .Window dw ? ;;;;;;;
|
||||||
|
shl edi, 2 ; .DataOffset db ? only 4 left-most bits
|
||||||
|
shl dx, 8
|
||||||
|
or dx, di ; .Flags db ?
|
||||||
|
pushw dx
|
||||||
|
shr edi, 2 ; .DataOffset db ? ;;;;
|
||||||
|
|
||||||
|
push [eax + TCP_SOCKET.RCV_NXT] ; .AckNumber dd ?
|
||||||
|
ntohd [esp]
|
||||||
|
|
||||||
|
push [eax + TCP_SOCKET.SND_NXT] ; .SequenceNumber dd ?
|
||||||
|
ntohd [esp]
|
||||||
|
|
||||||
|
push [eax + TCP_SOCKET.RemotePort] ; .DestinationPort dw ?
|
||||||
|
ntohw [esp]
|
||||||
|
|
||||||
|
push [eax + TCP_SOCKET.LocalPort] ; .SourcePort dw ?
|
||||||
|
ntohw [esp]
|
||||||
|
|
||||||
|
push edi ; header size
|
||||||
|
|
||||||
|
; Create the IP packet
|
||||||
|
mov ebx, [eax + IP_SOCKET.LocalIP] ; source ip
|
||||||
|
mov eax, [eax + IP_SOCKET.RemoteIP] ; dest ip
|
||||||
|
mov di, IP_PROTO_TCP shl 8 + 128
|
||||||
|
call IPv4_output
|
||||||
|
jz .fail
|
||||||
|
|
||||||
|
;-----------------------------------------
|
||||||
|
; Move TCP header from stack to TCP packet
|
||||||
|
|
||||||
|
push ecx
|
||||||
|
mov ecx, [esp+4]
|
||||||
|
lea esi, [esp+4+4]
|
||||||
|
shr ecx, 2
|
||||||
|
rep movsd
|
||||||
|
pop ecx ; full TCP packet size
|
||||||
|
|
||||||
|
pop esi ; headersize
|
||||||
|
add esp, esi
|
||||||
|
|
||||||
|
mov [esp + 4], eax ; packet ptr
|
||||||
|
mov [esp + 4+4], edx ; packet size
|
||||||
|
|
||||||
|
mov edx, edi ; begin of data
|
||||||
|
sub edx, esi ; begin of packet (edi = begin of data)
|
||||||
|
push ecx
|
||||||
|
sub ecx, esi ; data size
|
||||||
|
|
||||||
|
;--------------
|
||||||
|
; Copy the data
|
||||||
|
|
||||||
|
; eax = ptr to ring struct
|
||||||
|
; ecx = buffer size
|
||||||
|
; edi = ptr to buffer
|
||||||
|
|
||||||
|
; test ecx, ecx
|
||||||
|
mov eax, [esp+4] ; socket ptr
|
||||||
|
add [eax + TCP_SOCKET.SND_NXT], ecx
|
||||||
|
add eax, STREAM_SOCKET.snd
|
||||||
|
push edx
|
||||||
|
call SOCKET_ring_read
|
||||||
|
pop esi
|
||||||
|
pop ecx
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
test [esi + TCP_segment.Flags], TH_SYN + TH_FIN
|
||||||
|
jz @f
|
||||||
|
inc [eax + TCP_SOCKET.SND_NXT]
|
||||||
|
;;; TODO: update sentfin flag
|
||||||
|
@@:
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
|
||||||
|
mov [esi+TCP_segment.Checksum], dx
|
||||||
|
|
||||||
|
;----------------
|
||||||
|
; Send the packet
|
||||||
|
|
||||||
|
DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
|
||||||
|
call [ebx + NET_DEVICE.transmit]
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
.fail:
|
||||||
|
pop ecx
|
||||||
|
add esp, ecx
|
||||||
|
add esp, 4+8
|
||||||
|
DEBUGF 1,"TCP_output: failed\n"
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
365
kernel/branches/net/network/tcp_subr.inc
Normal file
365
kernel/branches/net/network/tcp_subr.inc
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
macro TCP_checksum IP1, IP2 {
|
||||||
|
|
||||||
|
;-------------
|
||||||
|
; Pseudoheader
|
||||||
|
|
||||||
|
; protocol type
|
||||||
|
mov edx, IP_PROTO_TCP
|
||||||
|
|
||||||
|
; source address
|
||||||
|
add dl, byte [IP1+1]
|
||||||
|
adc dh, byte [IP1+0]
|
||||||
|
adc dl, byte [IP1+3]
|
||||||
|
adc dh, byte [IP1+2]
|
||||||
|
|
||||||
|
; destination address
|
||||||
|
adc dl, byte [IP2+1]
|
||||||
|
adc dh, byte [IP2+0]
|
||||||
|
adc dl, byte [IP2+3]
|
||||||
|
adc dh, byte [IP2+2]
|
||||||
|
|
||||||
|
; size
|
||||||
|
adc dl, cl
|
||||||
|
adc dh, ch
|
||||||
|
|
||||||
|
;---------------------
|
||||||
|
; Real header and data
|
||||||
|
|
||||||
|
push esi
|
||||||
|
call checksum_1
|
||||||
|
call checksum_2
|
||||||
|
pop esi
|
||||||
|
|
||||||
|
} ; 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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------
|
||||||
|
;
|
||||||
|
; TCP_pull_out_of_band
|
||||||
|
;
|
||||||
|
; IN: eax =
|
||||||
|
; ebx = socket ptr
|
||||||
|
; edx = tcp packet ptr
|
||||||
|
;
|
||||||
|
; OUT: /
|
||||||
|
;
|
||||||
|
;---------------------------
|
||||||
|
|
||||||
|
align 4
|
||||||
|
TCP_pull_out_of_band:
|
||||||
|
|
||||||
|
DEBUGF 1,"TCP_pull_out_of_band\n"
|
||||||
|
|
||||||
|
;;;; 1282-1305
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;-------------------------
|
||||||
|
;
|
||||||
|
; TCP_drop
|
||||||
|
;
|
||||||
|
; IN: eax = socket ptr
|
||||||
|
; ebx = error number
|
||||||
|
;
|
||||||
|
; OUT: eax = socket ptr
|
||||||
|
;
|
||||||
|
;-------------------------
|
||||||
|
align 4
|
||||||
|
TCP_drop:
|
||||||
|
|
||||||
|
DEBUGF 1,"TCP_drop\n"
|
||||||
|
|
||||||
|
cmp [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED
|
||||||
|
jl .no_syn_received
|
||||||
|
|
||||||
|
mov [eax + TCP_SOCKET.t_state], TCB_CLOSED
|
||||||
|
|
||||||
|
call TCP_output
|
||||||
|
|
||||||
|
;;; TODO: update stats
|
||||||
|
|
||||||
|
jmp TCP_close
|
||||||
|
|
||||||
|
.no_syn_received:
|
||||||
|
|
||||||
|
;;; TODO: update stats
|
||||||
|
|
||||||
|
;;; TODO: check if error code is "Connection timed out' and handle accordingly
|
||||||
|
|
||||||
|
mov [eax + SOCKET.errorcode], ebx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;-------------------------
|
||||||
|
;
|
||||||
|
; TCP_close
|
||||||
|
;
|
||||||
|
; IN: eax = socket ptr
|
||||||
|
; OUT: eax = socket ptr
|
||||||
|
;
|
||||||
|
;-------------------------
|
||||||
|
align 4
|
||||||
|
TCP_close:
|
||||||
|
|
||||||
|
DEBUGF 1,"TCP_close\n"
|
||||||
|
|
||||||
|
;;; TODO: update RTT and mean deviation
|
||||||
|
;;; TODO: update slow start threshold
|
||||||
|
;;; TODO: release connection resources
|
||||||
|
|
||||||
|
; Now, mark the socket as being disconnected
|
||||||
|
|
||||||
|
mov [eax + SOCKET.state], 0 ;;; FIXME
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;-------------------------
|
||||||
|
;
|
||||||
|
; TCP_outflags
|
||||||
|
;
|
||||||
|
; IN: eax = socket ptr
|
||||||
|
;
|
||||||
|
; OUT: edx = flags
|
||||||
|
;
|
||||||
|
;-------------------------
|
||||||
|
align 4
|
||||||
|
TCP_outflags:
|
||||||
|
|
||||||
|
mov edx, [eax + TCP_SOCKET.t_state]
|
||||||
|
movzx edx, byte [edx + .flaglist]
|
||||||
|
|
||||||
|
DEBUGF 1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
.flaglist:
|
||||||
|
|
||||||
|
db TH_RST + TH_ACK ; TCB_CLOSED
|
||||||
|
db 0 ; TCB_LISTEN
|
||||||
|
db TH_SYN ; TCB_SYN_SENT
|
||||||
|
db TH_SYN + TH_ACK ; TCB_SYN_RECEIVED
|
||||||
|
db TH_ACK ; TCB_ESTABLISHED
|
||||||
|
db TH_ACK ; TCB_CLOSE_WAIT
|
||||||
|
db TH_SYN + TH_ACK ; TCB_FIN_WAIT_1
|
||||||
|
db TH_SYN + TH_ACK ; TCB_CLOSING
|
||||||
|
db TH_SYN + TH_ACK ; TCB_LAST_ACK
|
||||||
|
db TH_ACK ; TCB_FIN_WAIT_2
|
||||||
|
db TH_ACK ; TCB_TIMED_WAIT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;---------------------------------------
|
||||||
|
;
|
||||||
|
; The easy way to send an ACK/RST/keepalive segment
|
||||||
|
;
|
||||||
|
; TCP_respond_socket:
|
||||||
|
;
|
||||||
|
; IN: ebx = socket ptr
|
||||||
|
; cl = flags
|
||||||
|
;
|
||||||
|
;--------------------------------------
|
||||||
|
align 4
|
||||||
|
TCP_respond_socket:
|
||||||
|
|
||||||
|
DEBUGF 1,"TCP_respond_socket\n"
|
||||||
|
|
||||||
|
;---------------------
|
||||||
|
; Create the IP packet
|
||||||
|
|
||||||
|
push cx ebx
|
||||||
|
mov eax, [ebx + IP_SOCKET.RemoteIP]
|
||||||
|
mov ebx, [ebx + IP_SOCKET.LocalIP]
|
||||||
|
mov ecx, TCP_segment.Data
|
||||||
|
mov di , IP_PROTO_TCP shl 8 + 128
|
||||||
|
call IPv4_output
|
||||||
|
test edi, edi
|
||||||
|
jz .error
|
||||||
|
pop esi cx
|
||||||
|
push edx eax
|
||||||
|
|
||||||
|
;-----------------------------------------------
|
||||||
|
; Fill in the TCP header by using the socket ptr
|
||||||
|
|
||||||
|
mov ax, [esi + TCP_SOCKET.LocalPort]
|
||||||
|
rol ax, 8
|
||||||
|
stosw
|
||||||
|
mov ax, [esi + TCP_SOCKET.RemotePort]
|
||||||
|
rol ax, 8
|
||||||
|
stosw
|
||||||
|
mov eax, [esi + TCP_SOCKET.SND_NXT]
|
||||||
|
bswap eax
|
||||||
|
stosd
|
||||||
|
mov eax, [esi + TCP_SOCKET.RCV_NXT]
|
||||||
|
bswap eax
|
||||||
|
stosd
|
||||||
|
mov al, 0x50 ; Dataoffset: 20 bytes
|
||||||
|
stosb
|
||||||
|
mov al, cl
|
||||||
|
stosb
|
||||||
|
mov ax, [esi + TCP_SOCKET.RCV_WND]
|
||||||
|
rol ax, 8
|
||||||
|
stosw ; window
|
||||||
|
xor eax, eax
|
||||||
|
stosd ; checksum + urgentpointer
|
||||||
|
|
||||||
|
;---------------------
|
||||||
|
; Fill in the checksum
|
||||||
|
|
||||||
|
.checksum:
|
||||||
|
sub edi, TCP_segment.Data
|
||||||
|
mov ecx, TCP_segment.Data
|
||||||
|
xchg esi, edi
|
||||||
|
TCP_checksum (edi + IP_SOCKET.LocalIP), (esi + IP_SOCKET.RemoteIP)
|
||||||
|
mov [esi+TCP_segment.Checksum], dx
|
||||||
|
|
||||||
|
;--------------------
|
||||||
|
; And send the segment
|
||||||
|
|
||||||
|
call [ebx + NET_DEVICE.transmit]
|
||||||
|
ret
|
||||||
|
|
||||||
|
.error:
|
||||||
|
DEBUGF 1,"TCP_respond failed\n"
|
||||||
|
add esp, 2+4
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;-------------------------
|
||||||
|
; TCP_respond.segment:
|
||||||
|
;
|
||||||
|
; IN: edx = segment ptr (a previously received segment)
|
||||||
|
; cl = flags
|
||||||
|
|
||||||
|
align 4
|
||||||
|
TCP_respond_segment:
|
||||||
|
|
||||||
|
DEBUGF 1,"TCP_respond_segment\n"
|
||||||
|
|
||||||
|
;---------------------
|
||||||
|
; Create the IP packet
|
||||||
|
|
||||||
|
push cx edx
|
||||||
|
mov ebx, [edx - 20 + IPv4_Packet.SourceAddress] ;;;; and what if ip packet had options?!
|
||||||
|
mov eax, [edx - 20 + IPv4_Packet.DestinationAddress] ;;;
|
||||||
|
mov ecx, TCP_segment.Data
|
||||||
|
mov di , IP_PROTO_TCP shl 8 + 128
|
||||||
|
call IPv4_output
|
||||||
|
jz .error
|
||||||
|
pop esi cx
|
||||||
|
|
||||||
|
push edx eax
|
||||||
|
|
||||||
|
;---------------------------------------------------
|
||||||
|
; Fill in the TCP header by using a received segment
|
||||||
|
|
||||||
|
mov ax, [esi + TCP_segment.DestinationPort]
|
||||||
|
rol ax, 8
|
||||||
|
stosw
|
||||||
|
mov ax, [esi + TCP_segment.SourcePort]
|
||||||
|
rol ax, 8
|
||||||
|
stosw
|
||||||
|
mov eax, [esi + TCP_segment.AckNumber]
|
||||||
|
bswap eax
|
||||||
|
stosd
|
||||||
|
xor eax, eax
|
||||||
|
stosd
|
||||||
|
mov al, 0x50 ; Dataoffset: 20 bytes
|
||||||
|
stosb
|
||||||
|
mov al, cl
|
||||||
|
stosb
|
||||||
|
mov ax, 1280
|
||||||
|
rol ax, 8
|
||||||
|
stosw ; window
|
||||||
|
xor eax, eax
|
||||||
|
stosd ; checksum + urgentpointer
|
||||||
|
|
||||||
|
;---------------------
|
||||||
|
; Fill in the checksum
|
||||||
|
|
||||||
|
.checksum:
|
||||||
|
lea esi, [edi - TCP_segment.Data]
|
||||||
|
mov ecx, TCP_segment.Data
|
||||||
|
TCP_checksum (esi - 20 + IPv4_Packet.DestinationAddress), (esi - 20 + IPv4_Packet.DestinationAddress)
|
||||||
|
mov [esi+TCP_segment.Checksum], dx
|
||||||
|
|
||||||
|
;--------------------
|
||||||
|
; And send the segment
|
||||||
|
|
||||||
|
call [ebx + NET_DEVICE.transmit]
|
||||||
|
ret
|
||||||
|
|
||||||
|
.error:
|
||||||
|
DEBUGF 1,"TCP_respond failed\n"
|
||||||
|
add esp, 2+4
|
||||||
|
|
||||||
|
ret
|
108
kernel/branches/net/network/tcp_timer.inc
Normal file
108
kernel/branches/net/network/tcp_timer.inc
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
|
||||||
|
;----------------------
|
||||||
|
; 160 ms timer
|
||||||
|
;----------------------
|
||||||
|
macro TCP_timer_160ms {
|
||||||
|
|
||||||
|
local .loop
|
||||||
|
local .exit
|
||||||
|
|
||||||
|
mov eax, net_sockets
|
||||||
|
.loop:
|
||||||
|
mov eax, [eax + SOCKET.NextPtr]
|
||||||
|
or eax, eax
|
||||||
|
jz .exit
|
||||||
|
|
||||||
|
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP ;;; We should also check if family is AF_INET
|
||||||
|
jne .loop
|
||||||
|
|
||||||
|
dec [eax + TCP_SOCKET.timer_ack]
|
||||||
|
jnz .loop
|
||||||
|
|
||||||
|
DEBUGF 1,"TCP ack for socket %x expired, time to piggyback!\n", eax
|
||||||
|
|
||||||
|
push eax
|
||||||
|
call TCP_respond_socket
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.exit:
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
;----------------------
|
||||||
|
; 640 ms timer
|
||||||
|
;----------------------
|
||||||
|
macro TCP_timer_640ms {
|
||||||
|
|
||||||
|
local .loop
|
||||||
|
local .exit
|
||||||
|
|
||||||
|
; Update TCP sequence number
|
||||||
|
|
||||||
|
add [TCP_sequence_num], 64000
|
||||||
|
|
||||||
|
; scan through all the active TCP sockets, decrementing ALL timers
|
||||||
|
; timers do not have the chance to wrap because the keepalive timer will kill the socket when it expires
|
||||||
|
|
||||||
|
mov eax, net_sockets
|
||||||
|
.loop:
|
||||||
|
mov eax, [eax + SOCKET.NextPtr]
|
||||||
|
.check_only:
|
||||||
|
or eax, eax
|
||||||
|
jz .exit
|
||||||
|
|
||||||
|
cmp [eax + SOCKET.Domain], AF_INET4
|
||||||
|
jne .loop
|
||||||
|
|
||||||
|
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
|
||||||
|
jne .loop
|
||||||
|
|
||||||
|
|
||||||
|
;---------------
|
||||||
|
|
||||||
|
cmp [eax + SOCKET.lock], 0
|
||||||
|
jz @f
|
||||||
|
|
||||||
|
DEBUGF 1,"\nlocked\n"
|
||||||
|
@@:
|
||||||
|
|
||||||
|
;-----------
|
||||||
|
|
||||||
|
inc [eax + TCP_SOCKET.t_idle]
|
||||||
|
dec [eax + TCP_SOCKET.timer_retransmission]
|
||||||
|
jnz .check_more2
|
||||||
|
|
||||||
|
DEBUGF 1,"socket %x: Retransmission timer expired\n", eax
|
||||||
|
|
||||||
|
push eax
|
||||||
|
call TCP_output
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
.check_more2:
|
||||||
|
dec [eax + TCP_SOCKET.timer_keepalive]
|
||||||
|
jnz .check_more3
|
||||||
|
|
||||||
|
DEBUGF 1,"socket %x: Keepalive expired\n", eax
|
||||||
|
|
||||||
|
call TCP_close
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.check_more3:
|
||||||
|
dec [eax + TCP_SOCKET.timer_timed_wait]
|
||||||
|
jnz .check_more5
|
||||||
|
|
||||||
|
DEBUGF 1,"socket %x: 2MSL timer expired\n", eax
|
||||||
|
|
||||||
|
.check_more5:
|
||||||
|
dec [eax + TCP_SOCKET.timer_persist]
|
||||||
|
jnz .loop
|
||||||
|
|
||||||
|
DEBUGF 1,"socket %x: persist timer expired\n", eax
|
||||||
|
|
||||||
|
jmp .loop
|
||||||
|
.exit:
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user