Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 2929 → Rev 2930

/kernel/branches/net/network/tcp_input.inc
36,8 → 36,14
 
DEBUGF 1,"TCP_input: size=%u\n", ecx
 
; First, re-calculate the checksum
; First, record the current time
mov eax, [timer_ticks]
mov [esp+4], eax
 
; then, re-calculate the checksum (if not already done by hw)
; test [ebx + NET_DEVICE.hwacc], HWACC_TCP_IPv4_IN
; jnz .checksum_ok
 
push ecx esi
pushw [esi + TCP_header.Checksum]
mov [esi + TCP_header.Checksum], 0
46,9 → 52,9
cmp cx, dx
pop edx ecx
jne .drop_no_socket
.checksum_ok:
 
DEBUGF 1,"TCP_input: Checksum ok\n"
 
; Verify the data offset
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
59,30 → 65,6
jb .drop_no_socket ; If total segment size is less then the advertised header size, drop packet
DEBUGF 1,"TCP_input: %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 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
 
cmp dword [edx + sizeof.TCP_header], 0x0101080a ; Timestamp header
jne .no_timestamp
 
DEBUGF 1,"TCP_input: timestamp ok\n"
 
; TODO: Parse the option
; TODO: Set a Bit in the TCP to tell all options are parsed
 
.no_timestamp:
 
;-------------------------------------------
; Convert Big-endian values to little endian
 
94,8 → 76,8
ntohw [edx + TCP_header.SourcePort]
ntohw [edx + TCP_header.DestinationPort]
 
;------------------------------------------------------------
; Next thing to do is find the TCPS (thus, the socket pointer)
;------------------------
; Find the socket pointer
 
; IP Packet TCP Destination Port = local Port
; (IP Packet SenderAddress = Remote IP) OR (Remote IP = 0)
133,7 → 115,9
.found_socket: ; ebx now contains the socketpointer
DEBUGF 1,"TCP_input: socket ptr=%x state=%u flags=%x\n", ebx, [ebx + TCP_SOCKET.t_state], [edx + TCP_header.Flags]:2
 
;-------------
; update stats
 
inc [TCP_segments_rx] ; FIXME: correct interface?
 
;----------------------------
170,39 → 154,12
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?
;---------------------------------------
; Are we accepting incoming connections?
 
test [ebx + SOCKET.options], SO_ACCEPTCON
jz .no_listening_socket
jnz .accept_connection
 
DEBUGF 1,"TCP_input: Accepting new connection\n"
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
 
push ecx edx esi edi ;;;
call SOCKET_fork
pop edi esi edx ecx
 
test eax, eax
jz .drop
 
push dword [edi + 4] ; Ipv4 destination addres
pop [eax + IP_SOCKET.LocalIP]
 
push [edx + TCP_header.DestinationPort]
pop [eax + TCP_SOCKET.LocalPort]
 
mov [eax + TCP_SOCKET.t_state], TCPS_LISTEN
mov ebx, eax
 
jmp .LISTEN
 
.no_listening_socket:
 
;-------------------------------------
; Reset idle timer and keepalive timer
 
246,7 → 203,7
jmp .no_options ; If we reach here, some unknown options were received, skip them all!
 
.opt_nop:
inc edi
inc esi
jmp .opt_loop
 
.opt_maxseg:
263,7 → 220,7
mov [ebx + TCP_SOCKET.t_maxseg], eax
 
@@:
add edi, 4
add esi, 4
jmp .opt_loop
 
 
278,18 → 235,22
 
;;;;;
@@:
add edi, 3
add esi, 3
jmp .opt_loop
 
 
.opt_timestamp:
cmp byte [esi+1], 10
cmp byte [esi+1], 10 ; length must be 10
jne .no_options
 
DEBUGF 1,"TCP_input: Got timestamp option\n"
 
;;;;;
push dword [esi + 2] ; timestamp
pop [ebx + TCP_SOCKET.ts_recent]
 
push dword [esi + 6] ; timestamp echo reply
pop [ebx + TCP_SOCKET.ts_ecr]
 
add esi, 10
jmp .opt_loop
 
360,10 → 321,6
;---------------------------------
; Packet is a pure ACK, process it
 
; Update RTT estimators
 
;;; TODO
 
; Delete acknowledged bytes from send buffer
pusha
mov ecx, eax
371,6 → 328,19
call SOCKET_ring_free
popa
 
; Update RTT estimators
 
; if ts_present
; mov eax, [esp + 4] ; timestamp when this segment was received
; sub eax, [ebx + TCP_SOCKET.ts_ecr]
; inc eax
; call TCP_xmit_timer
 
; else if (t_rtt && SEG_GT(ti_ack - t_rtsec))
; mov eax, [ebx + t_rtt]
; call TCP_xmit_timer
; end if
 
; update window pointers
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
407,7 → 377,7
 
;;; TODO
 
jnz .not_uni_xfer
; jnz .not_uni_xfer
 
; Complete processing of received data
 
457,188 → 427,6
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT
je .SYN_SENT
 
jmp .NOT_LISTEN_OR_SYN_SENT
 
 
 
;-------------
; Passive Open
 
align 4
.LISTEN:
 
DEBUGF 1,"TCP_input: state=listen\n"
 
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_SYN
jz .drop
 
;;; TODO: check if it's a broadcast or multicast, and drop if so
 
push dword [edi] ; Ipv4 source addres
pop [ebx + IP_SOCKET.RemoteIP]
 
push [edx + TCP_header.SourcePort]
pop [ebx + TCP_SOCKET.RemotePort]
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
 
mov eax, [TCP_sequence_num]
add [TCP_sequence_num], 64000 / 2
mov [ebx + TCP_SOCKET.ISS], eax
mov [ebx + TCP_SOCKET.SND_NXT], eax
 
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
 
lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_create
 
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_create
 
;;; call SOCKET_notify_owner
 
jmp .trim_then_step6
 
 
 
 
 
 
 
 
 
;------------
; Active Open
 
align 4
.SYN_SENT:
 
DEBUGF 1,"TCP_input: state=syn_sent\n"
 
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
 
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_ACK
jz .drop
 
mov eax, ebx
mov ebx, ECONNREFUSED
call TCP_drop
 
jmp .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
 
; 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
@@:
 
.no_syn_ack:
 
mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; disable retransmission
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
 
TCP_rcvseqinit ebx
 
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
 
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
 
DEBUGF 1,"TCP_input: active open\n"
 
;;; TODO: update stats
 
; set socket state to connected
mov [ebx + SOCKET.state], SS_ISCONNECTED
mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
 
;;; TODO: check if we should scale the connection (567-572)
mov [ebx + TCP_SOCKET.SND_SCALE], 0
 
;;; TODO: update RTT estimators
 
jmp .trim_then_step6
 
.simultaneous_open:
 
DEBUGF 1,"TCP_input: 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
 
 
 
 
 
 
 
;-------------------------------------
; Common processing for receipt of SYN
 
.trim_then_step6:
 
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
 
jmp .ack_processed
 
 
 
 
 
 
 
 
.NOT_LISTEN_OR_SYN_SENT:
 
DEBUGF 1,"TCP_input: state is not listen or syn_sent\n"
 
;--------------------------------------------
729,7 → 517,6
 
cmp [edx + TCP_header.Flags], TH_ACK
jz .drop_after_ack
 
.duplicate:
 
DEBUGF 1,"TCP_input: Duplicate received\n"
740,7 → 527,6
;;; TODO
 
jmp .drop_after_ack
 
.no_duplicate:
 
;-----------------------------------------------
857,7 → 643,6
 
.no_rst:
 
 
;--------------------------------------
; handle SYN-full and ACK-less segments
 
1163,7 → 948,6
mov [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
jmp .ack_processed
 
 
.ack_c:
jnc .ack_processed
 
1175,26 → 959,214
call SOCKET_is_disconnected
jmp .ack_processed
 
 
.ack_la:
jnc .ack_processed
 
 
mov eax, ebx
call TCP_disconnect
jmp .drop
 
 
.ack_tw:
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
jmp .drop_after_ack
 
.reset_dupacks: ; We got a new ACK, reset duplicate ACK counter
mov [ebx + TCP_SOCKET.t_dupacks], 0
jmp .ack_processed
 
 
.reset_dupacks: ; We got a new ACK, reset duplicate ACK counter
 
mov [ebx + TCP_SOCKET.t_dupacks], 0
;-------------
; Passive Open
 
align 4
 
.accept_connection:
 
DEBUGF 1,"TCP_input: Accepting new connection\n"
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
 
push ecx edx esi edi ;;;
call SOCKET_fork
pop edi esi edx ecx
 
test eax, eax
jz .drop
 
push dword [edi + 4] ; Ipv4 destination addres
pop [eax + IP_SOCKET.LocalIP]
 
push [edx + TCP_header.DestinationPort]
pop [eax + TCP_SOCKET.LocalPort]
 
mov [eax + TCP_SOCKET.t_state], TCPS_LISTEN
mov ebx, eax
 
.LISTEN:
 
DEBUGF 1,"TCP_input: state=listen\n"
 
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_SYN
jz .drop
 
;;; TODO: check if it's a broadcast or multicast, and drop if so
 
push dword [edi] ; Ipv4 source addres
pop [ebx + IP_SOCKET.RemoteIP]
 
push [edx + TCP_header.SourcePort]
pop [ebx + TCP_SOCKET.RemotePort]
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
 
mov eax, [TCP_sequence_num]
add [TCP_sequence_num], 64000 / 2
mov [ebx + TCP_SOCKET.ISS], eax
mov [ebx + TCP_SOCKET.SND_NXT], eax
 
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
 
lea eax, [ebx + STREAM_SOCKET.snd]
call SOCKET_ring_create
 
lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_create
 
;;; call SOCKET_notify_owner
 
jmp .trim_then_step6
 
 
 
 
 
 
 
 
 
;------------
; Active Open
 
align 4
.SYN_SENT:
 
DEBUGF 1,"TCP_input: state=syn_sent\n"
 
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
 
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_ACK
jz .drop
 
mov eax, ebx
mov ebx, ECONNREFUSED
call TCP_drop
 
jmp .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
 
; 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
@@:
 
.no_syn_ack:
 
mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; disable retransmission
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
 
TCP_rcvseqinit ebx
 
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
 
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
 
DEBUGF 1,"TCP_input: active open\n"
 
;;; TODO: update stats
 
; set socket state to connected
mov [ebx + SOCKET.state], SS_ISCONNECTED
mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
 
;;; TODO: check if we should scale the connection (567-572)
mov [ebx + TCP_SOCKET.SND_SCALE], 0
 
;;; TODO: update RTT estimators
 
jmp .trim_then_step6
 
.simultaneous_open:
 
DEBUGF 1,"TCP_input: 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
 
;-------------------------------------
; Common processing for receipt of SYN
 
.trim_then_step6:
 
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
 
jmp .ack_processed
 
 
 
.ack_processed: ; (step 6)
 
DEBUGF 1,"TCP_input: ACK processed\n"
1306,7 → 1278,7
; FIN processing
 
test [edx + TCP_header.Flags], TH_FIN
jz .no_fin
jz .final_processing
 
DEBUGF 1,"TCP_input: Processing FIN\n"
 
1327,15 → 1299,15
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 .final_processing ; TCPS_CLOSED
dd .final_processing ; TCPS_LISTEN
dd .final_processing ; TCPS_SYN_SENT
dd .fin_syn_est ; TCPS_SYN_RECEIVED
dd .fin_syn_est ; TCPS_ESTABLISHED
dd .no_fin ; TCPS_CLOSE_WAIT
dd .final_processing ; TCPS_CLOSE_WAIT
dd .fin_wait1 ; TCPS_FIN_WAIT_1
dd .no_fin ; TCPS_CLOSING
dd .no_fin ; TCPS_LAST_ACK
dd .final_processing ; TCPS_CLOSING
dd .final_processing ; TCPS_LAST_ACK
dd .fin_wait2 ; TCPS_FIN_WAIT_2
dd .fin_timed ; TCPS_TIMED_WAIT
 
1342,12 → 1314,12
.fin_syn_est:
 
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jmp .no_fin
jmp .final_processing
 
.fin_wait1:
 
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
jmp .no_fin
jmp .final_processing
 
.fin_wait2:
 
1356,92 → 1328,73
call TCP_cancel_timers
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
call SOCKET_is_disconnected
jmp .no_fin
jmp .final_processing
 
.fin_timed:
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
jmp .no_fin
jmp .final_processing
 
.no_fin:
 
.drop_after_ack:
DEBUGF 1,"TCP_input: Drop after ACK\n"
 
 
 
;-----------------
; Final processing
 
.final_processing:
 
DEBUGF 1,"TCP_input: Final processing\n"
 
cmp [ebx + TCP_SOCKET.sendalot], 0
jne .need_output
 
test [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
jz .dumpit
 
DEBUGF 1,"TCP_input: ACK now!\n"
 
.need_output:
 
pusha
push edx ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
pop eax edx
 
push ebx
mov eax, ebx
call TCP_output
pop ebx
test [edx + TCP_header.Flags], TH_RST
jnz .dumpit
 
call kernel_free
add esp, 4
ret
or [eax + TCP_SOCKET.t_flags], TF_ACKNOW
jmp .need_output
 
.dumpit:
 
DEBUGF 1,"TCP_input: dumping\n"
 
pusha
.drop_with_reset:
DEBUGF 1,"TCP_input: Drop with reset\n"
 
push ebx edx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
pop edx ebx
 
call kernel_free
add esp, 4
ret
test [edx + TCP_header.Flags], TH_RST
jnz .dumpit
 
;;; if its a multicast/broadcast, also drop
 
test [edx + TCP_header.Flags], TH_ACK
jnz .respond_ack
 
test [edx + TCP_header.Flags], TH_SYN
jnz .respond_syn
jmp .dumpit
 
;-----------------
; Final processing
 
.final_processing:
DEBUGF 1,"TCP_input: Final processing\n"
 
push ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
pop eax
 
;------------------------------------------
; Generate an ACK, droping incoming segment
cmp [eax + TCP_SOCKET.sendalot], 0
jne .need_output
 
align 4
.drop_after_ack:
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW
jz .dumpit
DEBUGF 1,"TCP_input: ACK now!\n"
 
DEBUGF 1,"TCP_input: Drop after ACK\n"
.need_output:
call TCP_output
 
test [edx + TCP_header.Flags], TH_RST
jnz .drop
.dumpit:
DEBUGF 1,"TCP_input: dumping\n"
 
and [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
 
push ebx
; mov cl, TH_ACK
; call TCP_respond_socket
mov eax, ebx
call TCP_output
pop ebx
 
call kernel_free
add esp, 4
ret
1450,37 → 1403,6
 
 
 
 
 
 
;-------------------------------------------
; Generate an RST, dropping incoming segment
 
align 4
.drop_with_reset:
 
DEBUGF 1,"TCP_input: Drop with reset\n"
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
 
test [edx + TCP_header.Flags], TH_RST
jnz .drop
 
;;; if its a multicast/broadcast, also drop
 
test [edx + TCP_header.Flags], TH_ACK
jnz .respond_ack
 
test [edx + TCP_header.Flags], TH_SYN
jnz .respond_syn
 
call kernel_free
add esp, 4
ret
 
.respond_ack:
 
push ebx
1505,7 → 1427,6
;-----
; Drop
 
align 4
.drop:
 
pusha
1523,13 → 1444,13
 
;;;; kill the newly created socket
 
.drop_no_socket:
DEBUGF 1,"TCP_input: Drop (no socket)\n"
 
call kernel_free
add esp, 4
ret
 
 
 
 
.drop_with_reset_no_socket:
 
DEBUGF 1,"TCP_input: Drop with reset (no socket)\n"
1545,14 → 1466,8
test [edx + TCP_header.Flags], TH_SYN
jnz .respond_seg_syn
 
.drop_no_socket:
jmp .drop_no_socket
 
DEBUGF 1,"TCP_input: Drop (no socket)\n"
 
call kernel_free
add esp, 4
ret
 
.respond_seg_ack:
 
mov cl, TH_RST
/kernel/branches/net/network/tcp_subr.inc
487,3 → 487,13
; tp->t_rxtshift++;
 
}
 
; eax = rtt
; ebx = socket ptr
 
align 4
TCP_xmit_timer:
 
;TODO: update srtt and rttvar
 
ret