Subversion Repositories Kolibri OS

Compare Revisions

Ignore whitespace Rev 2389 → Rev 2390

/kernel/branches/net/network/tcp_input.inc
34,53 → 34,52
align 4
TCP_input:
 
DEBUGF 1,"TCP_input size=%u\n", ecx
DEBUGF 1,"TCP_input size=%u\n", ecx
 
and [esi + TCP_header.DataOffset], 0xf0 ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header)
shr [esi + TCP_header.DataOffset], 2
cmp [esi + TCP_header.DataOffset], sizeof.TCP_header ; Now see if it's at least the size of a standard TCP header
jb .drop_not_locked ; If not, drop the packet
; First, re-calculate the checksum
 
;-------------------------------
; Now, re-calculate the checksum
push ecx esi
pushw [esi + TCP_header.Checksum]
mov [esi + TCP_header.Checksum], 0
TCP_checksum (edi), (edi+4)
pop cx ; previous checksum
cmp cx, dx
pop edx ecx
jne .drop_not_locked
 
push ecx esi
pushw [esi + TCP_header.Checksum]
mov [esi + TCP_header.Checksum], 0
TCP_checksum (edi), (edi+4)
pop cx ; previous checksum
cmp cx, dx
pop edx ecx
jnz .drop_not_locked
DEBUGF 1,"Checksum ok\n"
 
DEBUGF 1,"Checksum ok\n"
and [edx + TCP_header.DataOffset], 0xf0 ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header)
shr [edx + TCP_header.DataOffset], 2
cmp [edx + TCP_header.DataOffset], sizeof.TCP_header ; Now see if it's at least the size of a standard TCP header
jb .drop_not_locked ; If not, drop the packet
 
movzx eax, [edx + TCP_header.DataOffset]
sub ecx, eax ; substract TCP header size from total segment size
jb .drop_not_locked ; If total segment size is less then the advertised header size, drop packet
DEBUGF 1,"we got %u bytes of data\n", ecx
movzx eax, [edx + TCP_header.DataOffset]
sub ecx, eax ; substract TCP header size from total segment size
jb .drop_not_locked ; If total segment size is less then the advertised header size, drop packet
DEBUGF 1,"we got %u bytes of data\n", ecx
 
;-----------------------------------------------------------------------------------------
; Check if this packet has a timestamp option (We do it here so we can process it quickly)
 
cmp eax, sizeof.TCP_header + 12 ; Timestamp option is 12 bytes
jb .no_timestamp
je .is_ok
cmp eax, sizeof.TCP_header + 12 ; Timestamp option is 12 bytes
jb .no_timestamp
je .is_ok
 
cmp byte [edx + sizeof.TCP_header + 12], TCP_OPT_EOL ; end of option list
jne .no_timestamp
cmp byte [edx + sizeof.TCP_header + 12], TCP_OPT_EOL ; end of option list
jne .no_timestamp
 
.is_ok:
test [edx + TCP_header.Flags], TH_SYN ; SYN flag must not be set
jnz .no_timestamp
test [edx + TCP_header.Flags], TH_SYN ; SYN flag must not be set
jnz .no_timestamp
 
cmp dword [edx + sizeof.TCP_header], 0x0101080a ; Timestamp header
jne .no_timestamp
cmp dword [edx + sizeof.TCP_header], 0x0101080a ; Timestamp header
jne .no_timestamp
 
DEBUGF 1,"timestamp ok\n"
DEBUGF 1,"timestamp ok\n"
 
; TODO: Parse the option
; TODO: Set a Bit in the TCP to tell all options are parsed
; TODO: Parse the option
; TODO: Set a Bit in the TCP to tell all options are parsed
 
.no_timestamp:
 
87,13 → 86,13
;-------------------------------------------
; Convert Big-endian values to little endian
 
ntohd [edx + TCP_header.SequenceNumber]
ntohd [edx + TCP_header.AckNumber]
ntohd [edx + TCP_header.SequenceNumber]
ntohd [edx + TCP_header.AckNumber]
 
ntohw [edx + TCP_header.Window]
ntohw [edx + TCP_header.UrgentPointer]
ntohw [edx + TCP_header.SourcePort]
ntohw [edx + TCP_header.DestinationPort]
ntohw [edx + TCP_header.Window]
ntohw [edx + TCP_header.UrgentPointer]
ntohw [edx + TCP_header.SourcePort]
ntohw [edx + TCP_header.DestinationPort]
 
;------------------------------------------------------------
; Next thing to do is find the TCPS (thus, the socket pointer)
102,96 → 101,96
; (IP Packet SenderAddress = Remote IP) OR (Remote IP = 0)
; (IP Packet TCP Source Port = remote Port) OR (remote Port = 0)
 
mov ebx, net_sockets
mov si, [edx + TCP_header.DestinationPort]
mov ebx, net_sockets
mov si, [edx + TCP_header.DestinationPort]
 
.socket_loop:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .drop_with_reset_not_locked
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .drop_with_reset_not_locked
 
cmp [ebx + SOCKET.Domain], AF_INET4
jne .socket_loop
cmp [ebx + SOCKET.Domain], AF_INET4
jne .socket_loop
 
cmp [ebx + SOCKET.Protocol], IP_PROTO_TCP
jne .socket_loop
cmp [ebx + SOCKET.Protocol], IP_PROTO_TCP
jne .socket_loop
 
cmp [ebx + TCP_SOCKET.LocalPort], si
jne .socket_loop
cmp [ebx + TCP_SOCKET.LocalPort], si
jne .socket_loop
 
mov eax, [ebx + IP_SOCKET.RemoteIP]
cmp eax, [edi] ; Ipv4 source addres
je @f
test eax, eax
jnz .socket_loop
mov eax, [ebx + IP_SOCKET.RemoteIP]
cmp eax, [edi] ; Ipv4 source addres
je @f
test eax, eax
jnz .socket_loop
@@:
 
mov ax, [ebx + TCP_SOCKET.RemotePort]
cmp [edx + TCP_header.SourcePort] , ax
je .found_socket
test ax, ax
jnz .socket_loop
.found_socket: ; ebx now contains the socketpointer
DEBUGF 1,"Socket ptr: %x\n", ebx
mov ax, [ebx + TCP_SOCKET.RemotePort]
cmp [edx + TCP_header.SourcePort], ax
je .found_socket
test ax, ax
jnz .socket_loop
.found_socket: ; ebx now contains the socketpointer
DEBUGF 1,"Socket ptr: %x\n", ebx
 
 
;----------------------------
; Check if socket isnt closed
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
je .drop_not_locked
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
je .drop_not_locked
 
;----------------
; Lock the socket
 
cmp [ebx + SOCKET.lock], 0
jne .drop_not_locked ;;; HACK ! HACK ! dirty fucking HACK ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
cmp [ebx + SOCKET.lock], 0
jne .drop_not_locked ;;; HACK ! HACK ! dirty fucking HACK ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
add ebx, SOCKET.lock
DEBUGF 1,"lock: %x\n", [ebx]
call wait_mutex
sub ebx, SOCKET.lock
add ebx, SOCKET.lock
DEBUGF 1,"lock: %x\n", [ebx]
call wait_mutex
sub ebx, SOCKET.lock
 
DEBUGF 1,"Socket locked\n"
DEBUGF 1,"Socket locked\n"
 
;---------------------------------------
; unscale the window into a 32 bit value
 
movzx eax, [edx + TCP_header.Window]
push ecx
mov cl, [ebx + TCP_SOCKET.SND_SCALE]
shl eax, cl
mov dword [edx + TCP_header.Window], eax ; word after window is checksum, we dont need checksum anymore
pop ecx
movzx eax, [edx + TCP_header.Window]
push ecx
mov cl, [ebx + TCP_SOCKET.SND_SCALE]
shl eax, cl
mov dword [edx + TCP_header.Window], eax ; word after window is checksum, we dont need checksum anymore
pop ecx
 
;-----------------------------------
; Is this socket a listening socket?
 
test [ebx + SOCKET.options], SO_ACCEPTCON
jz .no_listening_socket
test [ebx + SOCKET.options], SO_ACCEPTCON
jz .no_listening_socket
 
DEBUGF 1,"Accepting new connection\n"
DEBUGF 1,"Accepting new connection\n"
 
mov [ebx + SOCKET.lock], 0
push ecx edx esi edi ;;;
call SOCKET_fork
pop edi esi edx ecx
mov [ebx + SOCKET.lock], 0
push ecx edx esi edi ;;;
call SOCKET_fork
pop edi esi edx ecx
 
test eax, eax
jz .drop
test eax, eax
jz .drop
 
push dword [edi + 4] ; Ipv4 destination addres
pop [eax + IP_SOCKET.LocalIP]
push dword [edi + 4] ; Ipv4 destination addres
pop [eax + IP_SOCKET.LocalIP]
 
push [edx + TCP_header.DestinationPort]
pop [eax + TCP_SOCKET.LocalPort]
push [edx + TCP_header.DestinationPort]
pop [eax + TCP_SOCKET.LocalPort]
 
mov [eax + TCP_SOCKET.t_state], TCPS_LISTEN
mov [eax + TCP_SOCKET.t_state], TCPS_LISTEN
 
; mov [ebx + SOCKET.lock], 0
mov ebx, eax
mov ebx, eax
 
jmp .LISTEN
jmp .LISTEN
 
.no_listening_socket:
 
198,92 → 197,92
;-------------------------------------
; Reset idle timer and keepalive timer
 
mov [ebx + TCP_SOCKET.t_idle], 0
mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval
mov [ebx + TCP_SOCKET.t_idle], 0
mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval
 
;--------------------
; Process TCP options
 
movzx eax, [edx + TCP_header.DataOffset]
cmp eax, sizeof.TCP_header ; Does header contain any options?
je .no_options
movzx eax, [edx + TCP_header.DataOffset]
cmp eax, sizeof.TCP_header ; Does header contain any options?
je .no_options
 
DEBUGF 1,"Segment has options\n"
DEBUGF 1,"Segment has options\n"
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN ; no options when in listen state
jz .not_uni_xfer ; also no header prediction
cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN ; no options when in listen state
jz .not_uni_xfer ; also no header prediction
 
add eax, edx
lea esi, [edx + sizeof.TCP_header]
add eax, edx
lea esi, [edx + sizeof.TCP_header]
 
.opt_loop:
cmp esi, eax ; are we scanning outside of header?
jae .no_options
cmp esi, eax ; are we scanning outside of header?
jae .no_options
 
cmp byte [esi], TCP_OPT_EOL ; end of option list?
jz .no_options
cmp byte [esi], TCP_OPT_EOL ; end of option list?
jz .no_options
 
cmp byte [esi], TCP_OPT_NOP ; nop ?
jz .opt_nop
cmp byte [esi], TCP_OPT_NOP ; nop ?
jz .opt_nop
 
cmp byte [esi], TCP_OPT_MAXSEG
je .opt_maxseg
cmp byte [esi], TCP_OPT_MAXSEG
je .opt_maxseg
 
cmp byte [esi], TCP_OPT_WINDOW
je .opt_window
cmp byte [esi], TCP_OPT_WINDOW
je .opt_window
 
cmp byte [esi], TCP_OPT_TIMESTAMP
je .opt_timestamp
cmp byte [esi], TCP_OPT_TIMESTAMP
je .opt_timestamp
 
jmp .no_options ; If we reach here, some unknown options were received, skip them all!
jmp .no_options ; If we reach here, some unknown options were received, skip them all!
 
.opt_nop:
inc edi
jmp .opt_loop
inc edi
jmp .opt_loop
 
.opt_maxseg:
cmp byte [esi+1], 4
jne .no_options ; error occured, ignore all options!
cmp byte [esi+1], 4
jne .no_options ; error occured, ignore all options!
 
test [edx + TCP_header.Flags], TH_SYN
jz @f
test [edx + TCP_header.Flags], TH_SYN
jz @f
 
movzx eax, word[esi+2]
rol ax, 8
DEBUGF 1,"Maxseg: %u\n", ax
movzx eax, word[esi+2]
rol ax, 8
DEBUGF 1,"Maxseg: %u\n", ax
 
mov [ebx + TCP_SOCKET.t_maxseg], eax
mov [ebx + TCP_SOCKET.t_maxseg], eax
 
@@:
add edi, 4
jmp .opt_loop
add edi, 4
jmp .opt_loop
 
 
.opt_window:
cmp byte [esi+1], 3
jne .no_options
cmp byte [esi+1], 3
jne .no_options
 
test [edx + TCP_header.Flags], TH_SYN
jz @f
test [edx + TCP_header.Flags], TH_SYN
jz @f
 
DEBUGF 1,"Got window option\n"
DEBUGF 1,"Got window option\n"
 
;;;;;
;;;;;
@@:
add edi, 3
jmp .opt_loop
add edi, 3
jmp .opt_loop
 
 
.opt_timestamp:
cmp byte [esi+1], 10
jne .no_options
cmp byte [esi+1], 10
jne .no_options
 
DEBUGF 1,"Got timestamp option\n"
DEBUGF 1,"Got timestamp option\n"
 
;;;;;
;;;;;
 
add esi, 10
jmp .opt_loop
add esi, 10
jmp .opt_loop
 
.no_options:
 
307,26 → 306,26
; - If the length is not 0 and the ACK didn't move, we're the receiver side of the transfer.
; If the packets are in order (data queue is empty), add the data to the socket buffer and request a delayed ACK
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
jnz .not_uni_xfer
cmp [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
jnz .not_uni_xfer
 
test [edx + TCP_header.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
jnz .not_uni_xfer
test [edx + TCP_header.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
jnz .not_uni_xfer
 
test [edx + TCP_header.Flags], TH_ACK
jz .not_uni_xfer
test [edx + TCP_header.Flags], TH_ACK
jz .not_uni_xfer
 
mov eax, [edx + TCP_header.SequenceNumber]
cmp eax, [ebx + TCP_SOCKET.RCV_NXT]
jne .not_uni_xfer
mov eax, [edx + TCP_header.SequenceNumber]
cmp eax, [ebx + TCP_SOCKET.RCV_NXT]
jne .not_uni_xfer
 
mov eax, dword [edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jne .not_uni_xfer
mov eax, dword [edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jne .not_uni_xfer
 
mov eax, [ebx + TCP_SOCKET.SND_NXT]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
jne .not_uni_xfer
mov eax, [ebx + TCP_SOCKET.SND_NXT]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
jne .not_uni_xfer
 
;---------------------------------------
; check if we are sender in the uni-xfer
334,25 → 333,25
; If the following 4 conditions are all true, this segment is a pure ACK.
;
; - The segment contains no data.
test ecx, ecx
jnz .not_sender
test ecx, ecx
jnz .not_sender
 
; - The congestion window is greater than or equal to the current send window.
; This test is true only if the window is fully open, that is, the connection is not in the middle of slow start or congestion avoidance.
mov eax, [ebx + TCP_SOCKET.SND_CWND]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jb .not_uni_xfer
mov eax, [ebx + TCP_SOCKET.SND_CWND]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jb .not_uni_xfer
 
; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent.
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .not_uni_xfer
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .not_uni_xfer
 
; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number.
sub eax, [ebx + TCP_SOCKET.SND_UNA]
jbe .not_uni_xfer
sub eax, [ebx + TCP_SOCKET.SND_UNA]
jbe .not_uni_xfer
 
DEBUGF 1,"Header prediction: we are sender\n"
DEBUGF 1,"Header prediction: we are sender\n"
 
;---------------------------------
; Packet is a pure ACK, process it
362,28 → 361,28
;;; TODO
 
; Delete acknowledged bytes from send buffer
pusha
mov ecx, eax
lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_free
popa
pusha
mov ecx, eax
lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_free
popa
 
; update window pointers
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
 
; Stop retransmit timer
mov [ebx + TCP_SOCKET.timer_retransmission], 0
mov [ebx + TCP_SOCKET.timer_retransmission], 0
 
; Awaken waiting processes
mov [ebx + SOCKET.lock], 0
mov eax, ebx
call SOCKET_notify_owner
mov [ebx + SOCKET.lock], 0
mov eax, ebx
call SOCKET_notify_owner
 
; Generate more output
call TCP_output
call TCP_output
 
jmp .drop_not_locked
jmp .drop_not_locked
 
;-------------------------------------------------
; maybe we are the receiver in the uni-xfer then..
392,33 → 391,33
; - The amount of data in the segment is greater than 0 (data count is in ecx)
 
; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment.
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
jne .not_uni_xfer
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
jne .not_uni_xfer
 
; - The reassembly list of out-of-order segments for the connection is empty (seg_next equals tp).
 
;;; TODO
 
jnz .not_uni_xfer
jnz .not_uni_xfer
 
; Complete processing of received data
 
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 [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
 
movzx esi, [edx + TCP_header.DataOffset]
add esi, edx
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_write ; Add the data to the socket buffer
movzx esi, [edx + TCP_header.DataOffset]
add esi, edx
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_write ; Add the data to the socket buffer
 
mov eax, ebx
call SOCKET_notify_owner
mov eax, ebx
call SOCKET_notify_owner
 
or [ebx + TCP_SOCKET.t_flags], TF_DELACK ; Set delayed ack flag
or [ebx + TCP_SOCKET.t_flags], TF_DELACK ; Set delayed ack flag
 
jmp .drop
jmp .drop
 
 
 
430,7 → 429,7
 
.not_uni_xfer:
 
DEBUGF 1,"Header prediction failed\n"
DEBUGF 1,"Header prediction failed\n"
 
; Calculate receive window size
 
444,13 → 443,13
; mov eax, edx
; @@:
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
je .LISTEN
cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
je .LISTEN
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT
je .SYN_SENT
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT
je .SYN_SENT
 
jmp .NOT_LISTEN_OR_SYN_SENT
jmp .NOT_LISTEN_OR_SYN_SENT
 
 
 
460,52 → 459,52
align 4
.LISTEN:
 
DEBUGF 1,"TCP state: listen\n"
DEBUGF 1,"TCP state: listen\n"
 
test [edx + TCP_header.Flags], TH_RST ;;; TODO: kill new socket on error
jnz .drop
test [edx + TCP_header.Flags], TH_RST ;;; TODO: kill new socket on error
jnz .drop
 
test [edx + TCP_header.Flags], TH_ACK
jnz .drop_with_reset
test [edx + TCP_header.Flags], TH_ACK
jnz .drop_with_reset
 
test [edx + TCP_header.Flags], TH_SYN
jz .drop
test [edx + TCP_header.Flags], TH_SYN
jz .drop
 
;;; TODO: check if it's a broadcast or multicast, and drop if so
 
push dword [edi + 4] ; Ipv4 destination addres
pop [ebx + IP_SOCKET.RemoteIP]
push dword [edi + 4] ; Ipv4 destination addres
pop [ebx + IP_SOCKET.RemoteIP]
 
push [edx + TCP_header.SourcePort]
pop [ebx + TCP_SOCKET.RemotePort]
push [edx + TCP_header.SourcePort]
pop [ebx + TCP_SOCKET.RemotePort]
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
 
push [TCP_sequence_num] ;;;;;
add [TCP_sequence_num], 64000 / 2
pop [ebx + TCP_SOCKET.ISS]
push [TCP_sequence_num] ;;;;;
add [TCP_sequence_num], 64000 / 2
pop [ebx + TCP_SOCKET.ISS]
 
push [ebx + TCP_SOCKET.ISS]
pop [ebx + TCP_SOCKET.SND_NXT]
push [ebx + TCP_SOCKET.ISS]
pop [ebx + TCP_SOCKET.SND_NXT]
 
TCP_sendseqinit ebx
TCP_rcvseqinit ebx
TCP_sendseqinit ebx
TCP_rcvseqinit ebx
 
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval ;;;; macro
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval ;;;; macro
 
lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_create
lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_create
 
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_create
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_create
 
;;; call SOCKET_notify_owner
 
jmp .trim_then_step6
jmp .trim_then_step6
 
 
 
521,87 → 520,87
align 4
.SYN_SENT:
 
DEBUGF 1,"TCP state: syn_sent\n"
DEBUGF 1,"TCP state: syn_sent\n"
 
test [edx + TCP_header.Flags], TH_ACK
jz @f
test [edx + TCP_header.Flags], TH_ACK
jz @f
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.ISS]
jbe .drop_with_reset
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.ISS]
jbe .drop_with_reset
 
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .drop_with_reset
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .drop_with_reset
@@:
 
test [edx + TCP_header.Flags], TH_RST
jz @f
test [edx + TCP_header.Flags], TH_RST
jz @f
 
test [edx + TCP_header.Flags], TH_ACK
jz .drop
test [edx + TCP_header.Flags], TH_ACK
jz .drop
 
mov eax, ebx
mov ebx, ECONNREFUSED
call TCP_drop
mov eax, ebx
mov ebx, ECONNREFUSED
call TCP_drop
 
jmp .drop
jmp .drop
@@:
 
test [edx + TCP_header.Flags], TH_SYN
jz .drop
test [edx + TCP_header.Flags], TH_SYN
jz .drop
 
; at this point, segment seems to be valid
 
test [edx + TCP_header.Flags], TH_ACK
jz .no_syn_ack
test [edx + TCP_header.Flags], TH_ACK
jz .no_syn_ack
 
; now, process received SYN in response to an active open
 
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jbe @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jbe @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
@@:
 
.no_syn_ack:
 
mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; disable retransmission
mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; disable retransmission
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
 
TCP_rcvseqinit ebx
TCP_rcvseqinit ebx
 
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
 
mov eax, [ebx + TCP_SOCKET.SND_UNA]
cmp eax, [ebx + TCP_SOCKET.ISS]
jbe .simultaneous_open
mov eax, [ebx + TCP_SOCKET.SND_UNA]
cmp eax, [ebx + TCP_SOCKET.ISS]
jbe .simultaneous_open
 
test [edx + TCP_header.Flags], TH_ACK
jz .simultaneous_open
test [edx + TCP_header.Flags], TH_ACK
jz .simultaneous_open
 
DEBUGF 1,"TCP: active open\n"
DEBUGF 1,"TCP: active open\n"
 
;;; TODO: update stats
 
; set socket state to connected
 
mov [ebx + SOCKET.state],1 ;;;; FIXME
mov [ebx + SOCKET.state],1 ;;;; FIXME
 
mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
 
;;; TODO: check if we should scale the connection (567-572)
;;; TODO: update RTT estimators
 
jmp .trim_then_step6
jmp .trim_then_step6
 
.simultaneous_open:
 
DEBUGF 1,"TCP: simultaneous open\n"
DEBUGF 1,"TCP: simultaneous open\n"
; We have received a syn but no ACK, so we are having a simultaneous open..
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
 
 
 
614,16 → 613,16
 
.trim_then_step6:
 
inc [edx + TCP_header.SequenceNumber]
inc [edx + TCP_header.SequenceNumber]
 
;;; TODO: Drop any received data that follows receive window (590)
 
mov eax, [edx + TCP_header.SequenceNumber]
mov [ebx + TCP_SOCKET.RCV_UP], eax
dec eax
mov [ebx + TCP_SOCKET.SND_WL1], eax
mov eax, [edx + TCP_header.SequenceNumber]
mov [ebx + TCP_SOCKET.RCV_UP], eax
dec eax
mov [ebx + TCP_SOCKET.SND_WL1], eax
 
jmp .ack_processed
jmp .ack_processed
 
 
 
634,7 → 633,7
 
.NOT_LISTEN_OR_SYN_SENT:
 
DEBUGF 1,"Slow TCP input: not listen or syn_sent state\n"
DEBUGF 1,"Slow TCP input: not listen or syn_sent state\n"
 
;--------------------------------------------
; Protection Against Wrapped Sequence Numbers
659,28 → 658,28
 
; check for duplicate data at beginning of segment
 
mov eax, [ebx + TCP_SOCKET.RCV_NXT]
sub eax, [edx + TCP_header.SequenceNumber]
jbe .no_duplicate
mov eax, [ebx + TCP_SOCKET.RCV_NXT]
sub eax, [edx + TCP_header.SequenceNumber]
jbe .no_duplicate
 
DEBUGF 1,"Uh oh.. %u bytes of duplicate data!\n", eax
DEBUGF 1,"Uh oh.. %u bytes of duplicate data!\n", eax
 
test [edx + TCP_header.Flags], TH_SYN
jz .no_dup_syn
test [edx + TCP_header.Flags], TH_SYN
jz .no_dup_syn
 
; remove duplicate syn
 
and [edx + TCP_header.Flags], not (TH_SYN)
inc [edx + TCP_header.SequenceNumber]
and [edx + TCP_header.Flags], not (TH_SYN)
inc [edx + TCP_header.SequenceNumber]
 
cmp [edx + TCP_header.UrgentPointer], 1
jbe @f
dec [edx + TCP_header.UrgentPointer]
jmp .dup_syn
cmp [edx + TCP_header.UrgentPointer], 1
jbe @f
dec [edx + TCP_header.UrgentPointer]
jmp .dup_syn
@@:
and [edx + TCP_header.Flags], not (TH_URG)
and [edx + TCP_header.Flags], not (TH_URG)
.dup_syn:
dec eax
dec eax
.no_dup_syn:
 
; eax holds number of bytes to drop
687,26 → 686,26
 
; Check for entire duplicate packet
 
cmp eax, ecx
jae .duplicate
cmp eax, ecx
jae .duplicate
 
DEBUGF 1,"Going to drop %u out of %u bytes\n", eax, ecx
DEBUGF 1,"Going to drop %u out of %u bytes\n", eax, ecx
 
;;; TODO: apply figure 28.30
 
; Check for duplicate FIN
 
test [edx + TCP_header.Flags], TH_FIN
jz @f
inc ecx
cmp eax, ecx
dec ecx
jne @f
test [edx + TCP_header.Flags], TH_FIN
jz @f
inc ecx
cmp eax, ecx
dec ecx
jne @f
 
mov eax, ecx
and [edx + TCP_header.Flags], not TH_FIN
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
jmp .no_duplicate
mov eax, ecx
and [edx + TCP_header.Flags], not TH_FIN
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
jmp .no_duplicate
@@:
 
; Handle the case when a bound socket connects to itself
717,15 → 716,15
 
; This code also handles simultaneous half-open or self-connects
 
test eax, eax
jnz .drop_after_ack
test eax, eax
jnz .drop_after_ack
 
cmp [edx + TCP_header.Flags], TH_ACK
jz .drop_after_ack
cmp [edx + TCP_header.Flags], TH_ACK
jz .drop_after_ack
 
.duplicate:
 
DEBUGF 1,"Duplicate received\n"
DEBUGF 1,"Duplicate received\n"
 
;----------------------------------------
; Update statistics for duplicate packets
732,7 → 731,7
 
;;; TODO
 
jmp .drop_after_ack
jmp .drop_after_ack
 
.no_duplicate:
 
739,51 → 738,51
;-----------------------------------------------
; Remove duplicate data and update urgent offset
 
add [edx + TCP_header.SequenceNumber], eax
add [edx + TCP_header.SequenceNumber], eax
 
;;; TODO
 
sub [edx + TCP_header.UrgentPointer], ax
ja @f
sub [edx + TCP_header.UrgentPointer], ax
ja @f
 
and [edx + TCP_header.Flags], not (TH_URG)
mov [edx + TCP_header.UrgentPointer], 0
and [edx + TCP_header.Flags], not (TH_URG)
mov [edx + TCP_header.UrgentPointer], 0
@@:
 
;--------------------------------------------------
; Handle data that arrives after process terminates
 
cmp [ebx + SOCKET.PID], 0
ja @f
cmp [ebx + SOCKET.PID], 0
ja @f
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jbe @f
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jbe @f
 
test ecx, ecx
jz @f
test ecx, ecx
jz @f
 
;;; Close the socket
;;; update stats
 
jmp .drop_with_reset
jmp .drop_with_reset
@@:
 
;----------------------------------------
; Remove data beyond right edge of window
 
mov eax, [edx + TCP_header.SequenceNumber]
add eax, ecx
sub eax, [ebx + TCP_SOCKET.RCV_NXT]
sub ax, [ebx + TCP_SOCKET.RCV_WND]
mov eax, [edx + TCP_header.SequenceNumber]
add eax, ecx
sub eax, [ebx + TCP_SOCKET.RCV_NXT]
sub ax, [ebx + TCP_SOCKET.RCV_WND]
 
; eax now holds the number of bytes to drop
 
jbe .no_excess_data
jbe .no_excess_data
 
;;; TODO: update stats
 
cmp eax, ecx
jb .dont_drop_all
cmp eax, ecx
jb .dont_drop_all
 
;;; TODO 700-736
 
810,54 → 809,54
;------------------
; Process RST flags
 
test [edx + TCP_header.Flags], TH_RST
jz .rst_skip
test [edx + TCP_header.Flags], TH_RST
jz .rst_skip
 
DEBUGF 1,"Got an RST flag"
DEBUGF 1,"Got an RST flag"
 
mov eax, [ebx + TCP_SOCKET.t_state]
shl eax, 2
jmp dword [eax + .rst_sw_list]
mov eax, [ebx + TCP_SOCKET.t_state]
shl eax, 2
jmp dword [eax + .rst_sw_list]
 
.rst_sw_list:
dd .rst_skip ;TCPS_CLOSED
dd .rst_skip ;TCPS_LISTEN
dd .rst_skip ;TCPS_SYN_SENT
dd .econnrefused ;TCPS_SYN_RECEIVED
dd .econnreset ;TCPS_ESTABLISHED
dd .econnreset ;TCPS_CLOSE_WAIT
dd .econnreset ;TCPS_FIN_WAIT_1
dd .rst_close ;TCPS_CLOSING
dd .rst_close ;TCPS_LAST_ACK
dd .econnreset ;TCPS_FIN_WAIT_2
dd .rst_close ;TCPS_TIMED_WAIT
dd .rst_skip ;TCPS_CLOSED
dd .rst_skip ;TCPS_LISTEN
dd .rst_skip ;TCPS_SYN_SENT
dd .econnrefused ;TCPS_SYN_RECEIVED
dd .econnreset ;TCPS_ESTABLISHED
dd .econnreset ;TCPS_CLOSE_WAIT
dd .econnreset ;TCPS_FIN_WAIT_1
dd .rst_close ;TCPS_CLOSING
dd .rst_close ;TCPS_LAST_ACK
dd .econnreset ;TCPS_FIN_WAIT_2
dd .rst_close ;TCPS_TIMED_WAIT
 
.econnrefused:
DEBUGF 1,"Connection refused"
DEBUGF 1,"Connection refused"
 
mov [ebx + SOCKET.errorcode], ECONNREFUSED
jmp .close
mov [ebx + SOCKET.errorcode], ECONNREFUSED
jmp .close
 
.econnreset:
DEBUGF 1,"Connection reset"
DEBUGF 1,"Connection reset"
 
mov [ebx + SOCKET.errorcode], ECONNRESET
mov [ebx + SOCKET.errorcode], ECONNRESET
 
.close:
DEBUGF 1,"Closing connection"
DEBUGF 1,"Closing connection"
 
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
;;; TODO: update stats
mov eax, ebx
call TCP_close
jmp .drop
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
;;; TODO: update stats
mov eax, ebx
call TCP_close
jmp .drop
 
.rst_close:
DEBUGF 1,"Closing with reset\n"
DEBUGF 1,"Closing with reset\n"
 
mov eax, ebx
call TCP_close
jmp .drop
mov eax, ebx
call TCP_close
jmp .drop
 
 
 
871,16 → 870,16
;--------------------------------------
; handle SYN-full and ACK-less segments
 
test [edx + TCP_header.Flags], TH_SYN
jz @f
test [edx + TCP_header.Flags], TH_SYN
jz @f
 
mov eax, ebx
mov ebx, ECONNRESET
call TCP_drop
jmp .drop_with_reset
mov eax, ebx
mov ebx, ECONNRESET
call TCP_drop
jmp .drop_with_reset
 
test [edx + TCP_header.Flags], TH_ACK
jz .drop
test [edx + TCP_header.Flags], TH_ACK
jz .drop
@@:
 
 
892,130 → 891,130
;---------------
; ACK processing
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
jnz .no_syn_rcv
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
jnz .no_syn_rcv
 
DEBUGF 1,"TCP state = syn received\n"
DEBUGF 1,"TCP state = syn received\n"
 
mov eax, [edx + TCP_header.AckNumber]
cmp [ebx + TCP_SOCKET.SND_UNA], eax
ja .drop_with_reset
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .drop_with_reset
mov eax, [edx + TCP_header.AckNumber]
cmp [ebx + TCP_SOCKET.SND_UNA], eax
ja .drop_with_reset
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .drop_with_reset
 
;;; TODO: update stats
 
mov eax, ebx
call SOCKET_is_connected
mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
mov eax, ebx
call SOCKET_is_connected
mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
 
; Do window scaling?
 
test [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
jz @f
test [ebx + TCP_SOCKET.t_flags], TF_REQ_SCALE
jz @f
test [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
jz @f
test [ebx + TCP_SOCKET.t_flags], TF_REQ_SCALE
jz @f
 
push word [ebx + TCP_SOCKET.requested_s_scale] ; Set send and receive scale factors to the received values
pop word [ebx + TCP_SOCKET.SND_SCALE]
push word [ebx + TCP_SOCKET.requested_s_scale] ; Set send and receive scale factors to the received values
pop word [ebx + TCP_SOCKET.SND_SCALE]
@@:
 
;;; TODO: copy the data (if any) into the socket
 
mov eax, [edx + TCP_header.SequenceNumber]
dec eax
mov [ebx + TCP_SOCKET.SND_WL1], eax
jmp .not_dup_ack
mov eax, [edx + TCP_header.SequenceNumber]
dec eax
mov [ebx + TCP_SOCKET.SND_WL1], eax
jmp .not_dup_ack
 
.no_syn_rcv:
 
; check for duplicate ACK
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
ja .not_dup_ack
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
ja .not_dup_ack
 
test ecx, ecx
jnz .reset_dupacks
test ecx, ecx
jnz .reset_dupacks
 
mov eax, dword [edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jne .reset_dupacks
mov eax, dword [edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jne .reset_dupacks
 
DEBUGF 1,"Processing a duplicate ACK..\n"
DEBUGF 1,"Processing a duplicate ACK..\n"
 
cmp [ebx + TCP_SOCKET.timer_retransmission], 10000 ;;;; FIXME
ja @f
cmp [ebx + TCP_SOCKET.timer_retransmission], 10000 ;;;; FIXME
ja @f
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
je .dup_ack
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
je .dup_ack
 
@@:
mov [ebx + TCP_SOCKET.t_dupacks], 0
jmp .not_dup_ack
mov [ebx + TCP_SOCKET.t_dupacks], 0
jmp .not_dup_ack
 
.dup_ack:
inc [ebx + TCP_SOCKET.t_dupacks]
cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh
jne .no_re_xmit
inc [ebx + TCP_SOCKET.t_dupacks]
cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh
jne .no_re_xmit
 
push [ebx + TCP_SOCKET.SND_NXT] ; >>>>
push [ebx + TCP_SOCKET.SND_NXT] ; >>>>
 
mov eax, [ebx + TCP_SOCKET.SND_WND]
cmp eax, [ebx + TCP_SOCKET.SND_CWND]
cmovg eax, [ebx + TCP_SOCKET.SND_CWND]
shr eax, 1
push edx
xor edx, edx
div [ebx + TCP_SOCKET.t_maxseg]
cmp eax, 2
jae @f
mov ax, 2
mov eax, [ebx + TCP_SOCKET.SND_WND]
cmp eax, [ebx + TCP_SOCKET.SND_CWND]
cmovg eax, [ebx + TCP_SOCKET.SND_CWND]
shr eax, 1
push edx
xor edx, edx
div [ebx + TCP_SOCKET.t_maxseg]
cmp eax, 2
jae @f
mov ax, 2
@@:
mul [ebx + TCP_SOCKET.t_maxseg]
pop edx
mov [ebx + TCP_SOCKET.SND_SSTHRESH], eax
mul [ebx + TCP_SOCKET.t_maxseg]
pop edx
mov [ebx + TCP_SOCKET.SND_SSTHRESH], eax
 
mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; turn off retransmission timer
mov [ebx + TCP_SOCKET.t_rtt], 0
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_NXT], eax
mov eax, [ebx + TCP_SOCKET.t_maxseg]
mov [ebx + TCP_SOCKET.SND_CWND], eax
mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; turn off retransmission timer
mov [ebx + TCP_SOCKET.t_rtt], 0
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_NXT], eax
mov eax, [ebx + TCP_SOCKET.t_maxseg]
mov [ebx + TCP_SOCKET.SND_CWND], eax
 
mov eax, ebx
call TCP_output ; retransmit missing segment
mov eax, ebx
call TCP_output ; retransmit missing segment
 
push edx
xor edx, edx
mov eax, [ebx + TCP_SOCKET.t_maxseg]
mul [ebx + TCP_SOCKET.t_dupacks]
pop edx
add eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
mov [ebx + TCP_SOCKET.SND_CWND], eax
push edx
xor edx, edx
mov eax, [ebx + TCP_SOCKET.t_maxseg]
mul [ebx + TCP_SOCKET.t_dupacks]
pop edx
add eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
mov [ebx + TCP_SOCKET.SND_CWND], eax
 
pop eax ; <<<<
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jb @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
pop eax ; <<<<
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jb @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
@@:
 
jmp .drop
jmp .drop
 
 
.no_re_xmit:
jbe .not_dup_ack
jbe .not_dup_ack
 
DEBUGF 1,"Increasing congestion window\n"
DEBUGF 1,"Increasing congestion window\n"
 
mov eax, [ebx + TCP_SOCKET.t_maxseg]
add [ebx + TCP_SOCKET.SND_CWND], eax
mov eax, [ebx + TCP_SOCKET.t_maxseg]
add [ebx + TCP_SOCKET.SND_CWND], eax
 
mov eax, ebx
call TCP_output
mov eax, ebx
call TCP_output
 
jmp .drop
jmp .drop
 
 
 
1028,32 → 1027,32
; If the congestion window was inflated to account
; for the other side's cached packets, retract it
 
mov eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
cmp eax, [ebx + TCP_SOCKET.SND_CWND]
ja @f
cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh
jbe @f
mov [ebx + TCP_SOCKET.SND_CWND], eax
mov eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
cmp eax, [ebx + TCP_SOCKET.SND_CWND]
ja @f
cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh
jbe @f
mov [ebx + TCP_SOCKET.SND_CWND], eax
@@:
 
mov [ebx + TCP_SOCKET.t_dupacks], 0
mov [ebx + TCP_SOCKET.t_dupacks], 0
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
jbe @f
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
jbe @f
 
;;; TODO: update stats
jmp .drop_after_ack
;;; TODO: update stats
jmp .drop_after_ack
 
@@:
 
mov edi, [edx + TCP_header.AckNumber]
sub edi, [ebx + TCP_SOCKET.SND_UNA] ; now we got the number of acked bytes in edi
mov edi, [edx + TCP_header.AckNumber]
sub edi, [ebx + TCP_SOCKET.SND_UNA] ; now we got the number of acked bytes in edi
 
;;; TODO: update stats
;;; TODO: update stats
 
 
DEBUGF 1,"We have an acceptable ACK of %x bytes\n", esi
DEBUGF 1,"We have an acceptable ACK of %x bytes\n", esi
 
 
 
1063,14 → 1062,14
;------------------------------------------
; RTT measurements and retransmission timer
 
;;;;; 912 - 926
;;;;; 912 - 926
 
mov [ebx + TCP_SOCKET.timer_retransmission], 0
mov [ebx + TCP_SOCKET.timer_retransmission], 0
 
mov eax, [ebx + TCP_SOCKET.SND_MAX]
cmp eax, [edx + TCP_header.AckNumber]
je .all_outstanding
mov [ebx + TCP_SOCKET.timer_retransmission], 120 ;;;; TODO: correct this value (use a macro for it)
mov eax, [ebx + TCP_SOCKET.SND_MAX]
cmp eax, [edx + TCP_header.AckNumber]
je .all_outstanding
mov [ebx + TCP_SOCKET.timer_retransmission], 120 ;;;; TODO: correct this value (use a macro for it)
.all_outstanding:
 
 
1082,32 → 1081,32
;-------------------------------------------
; Open congestion window in response to ACKs
 
mov esi, [ebx + TCP_SOCKET.SND_CWND]
mov eax, [ebx + TCP_SOCKET.t_maxseg]
mov esi, [ebx + TCP_SOCKET.SND_CWND]
mov eax, [ebx + TCP_SOCKET.t_maxseg]
 
cmp esi, [ebx + TCP_SOCKET.SND_SSTHRESH]
jbe @f
push edx
push eax
mul eax
div esi
pop edx
shr edx, 3
add eax, edx
pop edx
cmp esi, [ebx + TCP_SOCKET.SND_SSTHRESH]
jbe @f
push edx
push eax
mul eax
div esi
pop edx
shr edx, 3
add eax, edx
pop edx
@@:
 
add esi, eax
add esi, eax
 
push ecx
mov cl, [ebx + TCP_SOCKET.SND_SCALE]
mov eax, TCP_max_win
shl eax, cl
pop ecx
push ecx
mov cl, [ebx + TCP_SOCKET.SND_SCALE]
mov eax, TCP_max_win
shl eax, cl
pop ecx
 
cmp esi, eax
cmovg esi, eax
mov [ebx + TCP_SOCKET.SND_CWND], esi
cmp esi, eax
cmovg esi, eax
mov [ebx + TCP_SOCKET.SND_CWND], esi
 
 
 
1118,31 → 1117,31
;------------------------------------------
; Remove acknowledged data from send buffer
 
push ecx edx ebx
mov ecx, edi
lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_free
pop ebx
sub [ebx + TCP_SOCKET.SND_WND], ecx
pop edx ecx
push ecx edx ebx
mov ecx, edi
lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_free
pop ebx
sub [ebx + TCP_SOCKET.SND_WND], ecx
pop edx ecx
 
; Wake up process waiting on send buffer
 
mov eax, ebx
call SOCKET_notify_owner
mov eax, ebx
call SOCKET_notify_owner
 
; Update TCPS
 
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
 
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jb @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jb @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
@@:
 
 
;; TODO: use zero flag as 'ourfinisacked'
;; TODO: use zero flag as 'ourfinisacked'
 
 
 
1150,61 → 1149,61
; General ACK handling complete
; Now do the state-specific ones
 
mov eax, [ebx + TCP_SOCKET.t_state]
jmp dword [eax*4 + .ACK_sw_list]
mov eax, [ebx + TCP_SOCKET.t_state]
jmp dword [eax*4 + .ACK_sw_list]
 
.ACK_sw_list:
dd .ack_processed ;TCPS_CLOSED
dd .ack_processed ;TCPS_LISTEN
dd .ack_processed ;TCPS_SYN_SENT
dd .ack_processed ;TCPS_SYN_RECEIVED
dd .ack_processed ;TCPS_ESTABLISHED
dd .ack_processed ;TCPS_CLOSE_WAIT
dd .ack_fw1 ;TCPS_FIN_WAIT_1
dd .ack_c ;TCPS_CLOSING
dd .ack_la ;TCPS_LAST_ACK
dd .ack_processed ;TCPS_FIN_WAIT_2
dd .ack_tw ;TCPS_TIMED_WAIT
dd .ack_processed ;TCPS_CLOSED
dd .ack_processed ;TCPS_LISTEN
dd .ack_processed ;TCPS_SYN_SENT
dd .ack_processed ;TCPS_SYN_RECEIVED
dd .ack_processed ;TCPS_ESTABLISHED
dd .ack_processed ;TCPS_CLOSE_WAIT
dd .ack_fw1 ;TCPS_FIN_WAIT_1
dd .ack_c ;TCPS_CLOSING
dd .ack_la ;TCPS_LAST_ACK
dd .ack_processed ;TCPS_FIN_WAIT_2
dd .ack_tw ;TCPS_TIMED_WAIT
 
 
.ack_fw1:
jz .ack_processed
jz .ack_processed
 
test [ebx + SOCKET.state], SS_CANTRCVMORE
jnz @f
mov eax, ebx
call SOCKET_is_disconnected
test [ebx + SOCKET.state], SS_CANTRCVMORE
jnz @f
mov eax, ebx
call SOCKET_is_disconnected
;;; mov [ebx + TCP_SOCKET.timer_timed_wait], TCP_time_max_idle
@@:
 
mov [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
jmp .ack_processed
mov [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
jmp .ack_processed
 
 
.ack_c:
jz .ack_processed
jz .ack_processed
 
mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
mov eax, ebx
call TCP_cancel_timers
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
mov eax, ebx
call SOCKET_is_disconnected
jmp .ack_processed
mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
mov eax, ebx
call TCP_cancel_timers
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
mov eax, ebx
call SOCKET_is_disconnected
jmp .ack_processed
 
 
.ack_la:
jz .ack_processed
jz .ack_processed
 
 
mov eax, ebx
call TCP_close
jmp .drop
mov eax, ebx
call TCP_close
jmp .drop
 
 
.ack_tw:
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
jmp .drop_after_ack
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
jmp .drop_after_ack
 
 
 
1212,42 → 1211,42
 
 
 
.reset_dupacks: ; We got a new ACK, reset duplicate ACK counter
.reset_dupacks: ; We got a new ACK, reset duplicate ACK counter
 
mov [ebx + TCP_SOCKET.t_dupacks], 0
mov [ebx + TCP_SOCKET.t_dupacks], 0
 
.ack_processed: ; (step 6)
.ack_processed: ; (step 6)
 
DEBUGF 1,"ACK processed\n"
DEBUGF 1,"ACK processed\n"
 
;----------------------------------------------
; check if we need to update window information
 
test [edx + TCP_header.Flags], TH_ACK
jz .no_window_update
test [edx + TCP_header.Flags], TH_ACK
jz .no_window_update
 
mov eax, [ebx + TCP_SOCKET.SND_WL1]
cmp eax, [edx + TCP_header.SequenceNumber]
jb .update_window
ja @f
mov eax, [ebx + TCP_SOCKET.SND_WL1]
cmp eax, [edx + TCP_header.SequenceNumber]
jb .update_window
ja @f
 
mov eax, [ebx + TCP_SOCKET.SND_WL2]
cmp eax, [edx + TCP_header.AckNumber]
jb .update_window
ja .no_window_update
mov eax, [ebx + TCP_SOCKET.SND_WL2]
cmp eax, [edx + TCP_header.AckNumber]
jb .update_window
ja .no_window_update
@@:
 
mov eax, [ebx + TCP_SOCKET.SND_WL2]
cmp eax, [edx + TCP_header.AckNumber]
jne .no_window_update
mov eax, [ebx + TCP_SOCKET.SND_WL2]
cmp eax, [edx + TCP_header.AckNumber]
jne .no_window_update
 
mov eax, dword [edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jbe .no_window_update
mov eax, dword [edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jbe .no_window_update
 
.update_window:
 
DEBUGF 1,"Updating window\n"
DEBUGF 1,"Updating window\n"
 
; Keep track of pure window updates
 
1266,20 → 1265,20
;
; @@:
 
mov eax, dword [edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.max_sndwnd]
jbe @f
mov [ebx + TCP_SOCKET.max_sndwnd], eax
mov eax, dword [edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.max_sndwnd]
jbe @f
mov [ebx + TCP_SOCKET.max_sndwnd], eax
@@:
mov [ebx + TCP_SOCKET.SND_WND], eax
mov [ebx + TCP_SOCKET.SND_WND], eax
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.SND_WL1]
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.SND_WL1]
 
push [edx + TCP_header.AckNumber]
pop [ebx + TCP_SOCKET.SND_WL2]
push [edx + TCP_header.AckNumber]
pop [ebx + TCP_SOCKET.SND_WL2]
 
;;; needoutput = 1
;;; needoutput = 1
 
.no_window_update:
 
1292,33 → 1291,33
;-----------------
; process URG flag
 
test [edx + TCP_header.Flags], TH_URG
jz .not_urgent
test [edx + TCP_header.Flags], TH_URG
jz .not_urgent
 
cmp [edx + TCP_header.UrgentPointer], 0
jz .not_urgent
cmp [edx + TCP_header.UrgentPointer], 0
jz .not_urgent
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
je .not_urgent
cmp [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
je .not_urgent
 
; Ignore bogus urgent offsets
 
;;; 1040-1050
;;; 1040-1050
 
movzx eax, [edx + TCP_header.UrgentPointer]
add eax, [ebx + STREAM_SOCKET.rcv.size]
cmp eax, SOCKET_MAXDATA
jbe .not_urgent
movzx eax, [edx + TCP_header.UrgentPointer]
add eax, [ebx + STREAM_SOCKET.rcv.size]
cmp eax, SOCKET_MAXDATA
jbe .not_urgent
 
mov [edx + TCP_header.UrgentPointer], 0
and [edx + TCP_header.Flags], not (TH_URG)
jmp .do_data
mov [edx + TCP_header.UrgentPointer], 0
and [edx + TCP_header.Flags], not (TH_URG)
jmp .do_data
 
.not_urgent:
 
; processing of received urgent pointer
 
;;; TODO (1051-1093)
;;; TODO (1051-1093)
 
 
 
1332,34 → 1331,34
 
.do_data:
 
DEBUGF 1,"TCP: do data (%u)\n", ecx
DEBUGF 1,"TCP: do data (%u)\n", ecx
 
test [edx + TCP_header.Flags], TH_FIN
jnz .process_fin
test [edx + TCP_header.Flags], TH_FIN
jnz .process_fin
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1
jae .dont_do_data
cmp [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1
jae .dont_do_data
 
test ecx, ecx
jz .final_processing
test ecx, ecx
jz .final_processing
 
DEBUGF 1,"Processing data in segment\n"
DEBUGF 1,"Processing data in segment\n"
 
;; TODO: check if data is in sequence !
 
movzx esi, [edx + TCP_header.DataOffset]
add esi, edx
movzx esi, [edx + TCP_header.DataOffset]
add esi, edx
 
or [ebx + TCP_SOCKET.t_flags], TF_DELACK
add [ebx + TCP_SOCKET.RCV_NXT], ecx
or [ebx + TCP_SOCKET.t_flags], TF_DELACK
add [ebx + TCP_SOCKET.RCV_NXT], ecx
 
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_write
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_write
 
mov eax, ebx
call SOCKET_notify_owner
mov eax, ebx
call SOCKET_notify_owner
 
jmp .final_processing
jmp .final_processing
 
 
.dont_do_data:
1375,63 → 1374,63
 
.process_fin:
 
DEBUGF 1,"Processing FIN\n"
DEBUGF 1,"Processing FIN\n"
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
je .not_first_fin
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
je .not_first_fin
cmp [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
je .not_first_fin
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
je .not_first_fin
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
je .not_first_fin
cmp [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
je .not_first_fin
 
DEBUGF 1,"First FIN for this connection\n"
DEBUGF 1,"First FIN for this connection\n"
 
mov eax, ebx
call SOCKET_cant_recv_more
mov eax, ebx
call SOCKET_cant_recv_more
 
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
inc [ebx + TCP_SOCKET.RCV_NXT]
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
inc [ebx + TCP_SOCKET.RCV_NXT]
 
.not_first_fin:
mov eax, [ebx + TCP_SOCKET.t_state]
shl eax, 2
jmp dword [eax + .FIN_sw_list]
mov eax, [ebx + TCP_SOCKET.t_state]
shl eax, 2
jmp dword [eax + .FIN_sw_list]
 
.FIN_sw_list:
dd .no_fin ;TCPS_CLOSED
dd .no_fin ;TCPS_LISTEN
dd .no_fin ;TCPS_SYN_SENT
dd .fin_syn_est ;TCPS_SYN_RECEIVED
dd .fin_syn_est ;TCPS_ESTABLISHED
dd .no_fin ;TCPS_CLOSE_WAIT
dd .fin_wait1 ;TCPS_FIN_WAIT_1
dd .no_fin ;TCPS_CLOSING
dd .no_fin ;TCPS_LAST_ACK
dd .fin_wait2 ;TCPS_FIN_WAIT_2
dd .fin_timed ;TCPS_TIMED_WAIT
dd .no_fin ;TCPS_CLOSED
dd .no_fin ;TCPS_LISTEN
dd .no_fin ;TCPS_SYN_SENT
dd .fin_syn_est ;TCPS_SYN_RECEIVED
dd .fin_syn_est ;TCPS_ESTABLISHED
dd .no_fin ;TCPS_CLOSE_WAIT
dd .fin_wait1 ;TCPS_FIN_WAIT_1
dd .no_fin ;TCPS_CLOSING
dd .no_fin ;TCPS_LAST_ACK
dd .fin_wait2 ;TCPS_FIN_WAIT_2
dd .fin_timed ;TCPS_TIMED_WAIT
 
.fin_syn_est:
 
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jmp .no_fin
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jmp .no_fin
 
.fin_wait1:
 
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
jmp .no_fin
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
jmp .no_fin
 
.fin_wait2:
 
mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
mov eax, ebx
call TCP_cancel_timers
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
call SOCKET_is_disconnected
jmp .no_fin
mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
mov eax, ebx
call TCP_cancel_timers
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
call SOCKET_is_disconnected
jmp .no_fin
 
.fin_timed:
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
jmp .no_fin
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
jmp .no_fin
 
.no_fin:
 
1447,30 → 1446,30
 
.final_processing:
 
DEBUGF 1,"Final processing\n"
DEBUGF 1,"Final processing\n"
 
;;; if debug enabled, output packet
;;; if debug enabled, output packet
 
;test needoutput, needoutput
;jz .dumpit
;test needoutput, needoutput
;jz .dumpit
 
test [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
jz .dumpit
test [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
jz .dumpit
 
DEBUGF 1,"ACK now!\n"
DEBUGF 1,"ACK now!\n"
 
push ebx
mov eax, ebx
call TCP_output
pop ebx
push ebx
mov eax, ebx
call TCP_output
pop ebx
 
.dumpit:
 
mov [ebx + SOCKET.lock], 0
mov [ebx + SOCKET.lock], 0
 
call kernel_free
add esp, 4
ret
call kernel_free
add esp, 4
ret
 
 
 
1484,25 → 1483,25
align 4
.drop_after_ack:
 
DEBUGF 1,"Drop after ACK\n"
DEBUGF 1,"Drop after ACK\n"
 
test [edx + TCP_header.Flags], TH_RST
jnz .drop
test [edx + TCP_header.Flags], TH_RST
jnz .drop
 
and [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
and [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
 
mov [ebx + SOCKET.lock], 0
mov [ebx + SOCKET.lock], 0
 
push ebx
push ebx
; mov cl, TH_ACK
; call TCP_respond_socket
mov eax, ebx
call TCP_output
pop ebx
mov eax, ebx
call TCP_output
pop ebx
 
call kernel_free
add esp, 4
ret
call kernel_free
add esp, 4
ret
 
 
 
1517,45 → 1516,45
align 4
.drop_with_reset:
 
mov [ebx + SOCKET.lock], 0
mov [ebx + SOCKET.lock], 0
 
.drop_with_reset_not_locked:
 
DEBUGF 1,"Drop with reset\n"
DEBUGF 1,"Drop with reset\n"
 
test [edx + TCP_header.Flags], TH_RST
jnz .drop
test [edx + TCP_header.Flags], TH_RST
jnz .drop
 
;;; if its a multicast/broadcast, also drop
;;; if its a multicast/broadcast, also drop
 
test [edx + TCP_header.Flags], TH_ACK
jnz .respond_ack
test [edx + TCP_header.Flags], TH_ACK
jnz .respond_ack
 
test [edx + TCP_header.Flags], TH_SYN
jnz .respond_syn
test [edx + TCP_header.Flags], TH_SYN
jnz .respond_syn
 
call kernel_free
add esp, 4
ret
call kernel_free
add esp, 4
ret
 
.respond_ack:
 
push ebx
mov cl, TH_RST
call TCP_respond_socket
pop ebx
push ebx
mov cl, TH_RST
call TCP_respond_socket
pop ebx
 
jmp .destroy_new_socket
jmp .destroy_new_socket
 
 
.respond_syn:
 
push ebx
mov cl, TH_RST + TH_ACK
call TCP_respond_socket
pop ebx
push ebx
mov cl, TH_RST + TH_ACK
call TCP_respond_socket
pop ebx
 
jmp .destroy_new_socket
jmp .destroy_new_socket
 
 
 
1569,18 → 1568,18
align 4
.drop:
 
mov [ebx + SOCKET.lock], 0
mov [ebx + SOCKET.lock], 0
 
.drop_not_locked:
 
DEBUGF 1,"Dropping packet\n"
DEBUGF 1,"Dropping packet\n"
 
;;;; If debugging options are enabled, output the packet somwhere
;;;; If debugging options are enabled, output the packet somwhere
 
.destroy_new_socket:
 
;;;; kill the newly created socket
;;;; kill the newly created socket
 
call kernel_free
add esp, 4
ret
call kernel_free
add esp, 4
ret
/kernel/branches/net/network/tcp_subr.inc
16,65 → 16,67
 
$Revision$
 
macro TCP_checksum IP1, IP2 {
macro TCP_checksum IP1, IP2 {
 
;-------------
; Pseudoheader
 
; protocol type
mov edx, IP_PROTO_TCP
; 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]
; 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]
; 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
; size
adc dl, cl
adc dh, ch
 
adc edx, 0
 
;---------------------
; Real header and data
 
push esi
call checksum_1
call checksum_2
pop esi
push esi
call checksum_1
call checksum_2
pop esi
 
} ; returns in dx only
} ; returns in dx only
 
 
 
 
macro TCP_sendseqinit ptr {
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
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 {
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
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
 
}
 
102,11 → 104,11
align 4
TCP_pull_out_of_band:
 
DEBUGF 1,"TCP_pull_out_of_band\n"
DEBUGF 1,"TCP_pull_out_of_band\n"
 
;;;; 1282-1305
;;;; 1282-1305
 
ret
ret
 
 
 
128,18 → 130,18
align 4
TCP_drop:
 
DEBUGF 1,"TCP_drop\n"
DEBUGF 1,"TCP_drop\n"
 
cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
jb .no_syn_received
cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
jb .no_syn_received
 
mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED
mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED
 
call TCP_output
call TCP_output
 
;;; TODO: update stats
 
jmp TCP_close
jmp TCP_close
 
.no_syn_received:
 
147,7 → 149,7
 
;;; TODO: check if error code is "Connection timed out' and handle accordingly
 
mov [eax + SOCKET.errorcode], ebx
mov [eax + SOCKET.errorcode], ebx
 
 
 
167,15 → 169,15
align 4
TCP_close:
 
DEBUGF 1,"TCP_close\n"
DEBUGF 1,"TCP_close\n"
 
;;; TODO: update RTT and mean deviation
;;; TODO: update slow start threshold
;;; TODO: release connection resources
 
call SOCKET_is_disconnected
call SOCKET_is_disconnected
 
ret
ret
 
 
 
198,26 → 200,26
align 4
TCP_outflags:
 
mov edx, [eax + TCP_SOCKET.t_state]
movzx edx, byte [edx + .flaglist]
mov edx, [eax + TCP_SOCKET.t_state]
movzx edx, byte [edx + .flaglist]
 
DEBUGF 1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl
DEBUGF 1,"TCP_outflags, socket: %x, flags: %x\n", eax, dl
 
ret
ret
 
.flaglist:
 
db TH_RST + TH_ACK ; TCPS_CLOSED
db 0 ; TCPS_LISTEN
db TH_SYN ; TCPS_SYN_SENT
db TH_SYN + TH_ACK ; TCPS_SYN_RECEIVED
db TH_ACK ; TCPS_ESTABLISHED
db TH_ACK ; TCPS_CLOSE_WAIT
db TH_SYN + TH_ACK ; TCPS_FIN_WAIT_1
db TH_SYN + TH_ACK ; TCPS_CLOSING
db TH_SYN + TH_ACK ; TCPS_LAST_ACK
db TH_ACK ; TCPS_FIN_WAIT_2
db TH_ACK ; TCPS_TIMED_WAIT
db TH_RST + TH_ACK ; TCPS_CLOSED
db 0 ; TCPS_LISTEN
db TH_SYN ; TCPS_SYN_SENT
db TH_SYN + TH_ACK ; TCPS_SYN_RECEIVED
db TH_ACK ; TCPS_ESTABLISHED
db TH_ACK ; TCPS_CLOSE_WAIT
db TH_SYN + TH_ACK ; TCPS_FIN_WAIT_1
db TH_SYN + TH_ACK ; TCPS_CLOSING
db TH_SYN + TH_ACK ; TCPS_LAST_ACK
db TH_ACK ; TCPS_FIN_WAIT_2
db TH_ACK ; TCPS_TIMED_WAIT
 
 
 
237,69 → 239,69
align 4
TCP_respond_socket:
 
DEBUGF 1,"TCP_respond_socket\n"
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, sizeof.TCP_header
mov di , IP_PROTO_TCP shl 8 + 128
call IPv4_output
test edi, edi
jz .error
pop esi cx
push edx eax
push cx ebx
mov eax, [ebx + IP_SOCKET.RemoteIP]
mov ebx, [ebx + IP_SOCKET.LocalIP]
mov ecx, sizeof.TCP_header
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 (TCP_header.DataOffset)
stosb
mov al, cl
stosb
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 (TCP_header.DataOffset)
stosb
mov al, cl
stosb
; mov ax, [esi + TCP_SOCKET.RCV_WND]
; rol ax, 8
mov ax, 0x00a0 ;;;;;;; FIXME
stosw ; window
xor eax, eax
stosd ; checksum + urgentpointer
mov ax, 0x00a0 ;;;;;;; FIXME
stosw ; window
xor eax, eax
stosd ; checksum + urgentpointer
 
;---------------------
; Fill in the checksum
 
.checksum:
sub edi, sizeof.TCP_header
mov ecx, sizeof.TCP_header
xchg esi, edi
TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP)
mov [esi+TCP_header.Checksum], dx
sub edi, sizeof.TCP_header
mov ecx, sizeof.TCP_header
xchg esi, edi
TCP_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP)
mov [esi+TCP_header.Checksum], dx
 
;--------------------
; And send the segment
 
call [ebx + NET_DEVICE.transmit]
ret
call [ebx + NET_DEVICE.transmit]
ret
 
.error:
DEBUGF 1,"TCP_respond failed\n"
add esp, 2+4
DEBUGF 1,"TCP_respond failed\n"
add esp, 2+4
 
ret
ret
 
 
 
319,67 → 321,67
align 4
TCP_respond_segment:
 
DEBUGF 1,"TCP_respond_segment\n"
DEBUGF 1,"TCP_respond_segment\n"
 
;---------------------
; Create the IP packet
 
push cx edx ebx
mov ebx, [edi + 4]
mov eax, [edi]
mov ecx, sizeof.TCP_header
mov di , IP_PROTO_TCP shl 8 + 128
call IPv4_output
jz .error
pop ebx esi cx
push cx edx ebx
mov ebx, [edi + 4]
mov eax, [edi]
mov ecx, sizeof.TCP_header
mov di , IP_PROTO_TCP shl 8 + 128
call IPv4_output
jz .error
pop ebx esi cx
 
push edx eax
push edx eax
 
;---------------------------------------------------
; Fill in the TCP header by using a received segment
 
mov ax, [esi + TCP_header.DestinationPort]
rol ax, 8
stosw
mov ax, [esi + TCP_header.SourcePort]
rol ax, 8
stosw
mov eax, [esi + TCP_header.AckNumber]
bswap eax
stosd
xor eax, eax
stosd
mov al, 0x50 ; Dataoffset: 20 bytes (sizeof.TCP_header)
stosb
mov al, cl
stosb
mov ax, 1280
rol ax, 8
stosw ; window
xor eax, eax
stosd ; checksum + urgentpointer
mov ax, [esi + TCP_header.DestinationPort]
rol ax, 8
stosw
mov ax, [esi + TCP_header.SourcePort]
rol ax, 8
stosw
mov eax, [esi + TCP_header.AckNumber]
bswap eax
stosd
xor eax, eax
stosd
mov al, 0x50 ; Dataoffset: 20 bytes (sizeof.TCP_header)
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 - sizeof.TCP_header]
mov ecx, sizeof.TCP_header
TCP_checksum (esi - sizeof.IPv4_header + IPv4_header.DestinationAddress),\ ; FIXME
(esi - sizeof.IPv4_header + IPv4_header.SourceAddress)
mov [esi+TCP_header.Checksum], dx
lea esi, [edi - sizeof.TCP_header]
mov ecx, sizeof.TCP_header
TCP_checksum (esi - sizeof.IPv4_header + IPv4_header.DestinationAddress),\ ; FIXME
(esi - sizeof.IPv4_header + IPv4_header.SourceAddress)
mov [esi+TCP_header.Checksum], dx
 
;--------------------
; And send the segment
 
call [ebx + NET_DEVICE.transmit]
ret
call [ebx + NET_DEVICE.transmit]
ret
 
.error:
DEBUGF 1,"TCP_respond failed\n"
add esp, 2+4
DEBUGF 1,"TCP_respond failed\n"
add esp, 2+4
 
ret
ret
 
 
 
/kernel/branches/net/network/udp.inc
118,14 → 118,15
 
DEBUGF 1,"UDP_input, size:%u\n", ecx
 
; First validate, checksum
; First validate, checksum
 
neg [esi + UDP_header.Checksum] ; substract checksum from 0
jz .no_checksum ; if checksum is zero, it is considered valid and we continue processing
; otherwise, we will re-calculate the checksum and add it to this value, thus creating 0 when it is correct
jz .no_checksum ; if checksum is zero, it is considered valid
 
; otherwise, we will re-calculate the checksum and add it to this value, thus creating 0 when it is correct
 
UDP_checksum (edi), (edi+4)
;;; jnz .checksum_mismatch
jnz .checksum_mismatch
 
.no_checksum:
DEBUGF 1,"UDP Checksum is correct\n"
287,7 → 288,7
.fail:
DEBUGF 1,"UDP_output: failed\n"
add esp, 4+4+8
xor eax, eax
or eax, -1
ret