From 46d92cd3050325b05813107c4fe1d0573f6f0c05 Mon Sep 17 00:00:00 2001 From: hidnplayr Date: Tue, 26 Feb 2013 20:17:02 +0000 Subject: [PATCH] Cleanup in TCP, fixed possible deadlock in TCP_input. git-svn-id: svn://kolibrios.org@3275 a494cfbc-eb01-0410-851d-a64ba20cac60 --- kernel/branches/net/network/IPv4.inc | 21 +-- kernel/branches/net/network/tcp.inc | 18 ++- kernel/branches/net/network/tcp_input.inc | 149 ++++++++++----------- kernel/branches/net/network/tcp_output.inc | 6 +- kernel/branches/net/network/tcp_subr.inc | 2 +- 5 files changed, 105 insertions(+), 91 deletions(-) diff --git a/kernel/branches/net/network/IPv4.inc b/kernel/branches/net/network/IPv4.inc index 98e774e10f..321162ab9b 100644 --- a/kernel/branches/net/network/IPv4.inc +++ b/kernel/branches/net/network/IPv4.inc @@ -64,8 +64,9 @@ uglobal GATEWAY_LIST rd MAX_NET_DEVICES BROADCAST_LIST rd MAX_NET_DEVICES - IP_PACKETS_TX rd MAX_NET_DEVICES - IP_PACKETS_RX rd MAX_NET_DEVICES + IP_packets_tx rd MAX_NET_DEVICES + IP_packets_rx rd MAX_NET_DEVICES + IP_packets_dumped rd MAX_NET_DEVICES FRAGMENT_LIST rb MAX_FRAGMENTS * sizeof.FRAGMENT_slot endg @@ -228,12 +229,12 @@ IPv4_input: ; TODO: add IPv4 ; check if it matches local ip (Using RFC1122 strong end system model) mov eax, [edx + IPv4_header.DestinationAddress] - cmp eax, [IP_LIST+edi] + cmp eax, [IP_LIST + edi] je .ip_ok ; check for broadcast (IP or (not SUBNET)) - cmp eax, [BROADCAST_LIST+edi] + cmp eax, [BROADCAST_LIST + edi] je .ip_ok ; or a special broadcast (255.255.255.255) @@ -262,7 +263,7 @@ IPv4_input: ; TODO: add IPv4 ; Now we can update stats .ip_ok: - inc [IP_PACKETS_RX+edi] + inc [IP_packets_rx + edi] ;---------------------------------- ; Check if the packet is fragmented @@ -303,7 +304,7 @@ IPv4_input: ; TODO: add IPv4 .dump: DEBUGF 1,"IPv4_input: dumping\n" -; inc [dumped_rx_count] ;;; TODO + inc [IP_packets_dumped] ; FIXME: use correct interface call kernel_free add esp, 4 ; pop (balance stack) ret @@ -584,7 +585,7 @@ IPv4_output: push ebx ; push the mac onto the stack push ax - inc [IP_PACKETS_TX + edi] ; update stats + inc [IP_packets_tx + edi] ; update stats mov ebx, [NET_DRV_LIST + edi] lea eax, [ebx + ETH_DEVICE.mac] @@ -674,7 +675,7 @@ IPv4_output_raw: push ebx ; push the mac push ax - inc [IP_PACKETS_TX + edi] + inc [IP_packets_tx + edi] mov ebx, [NET_DRV_LIST + edi] lea eax, [ebx + ETH_DEVICE.mac] mov edx, esp @@ -951,11 +952,11 @@ IPv4_api: ret .packets_tx: - mov eax, [IP_PACKETS_TX + eax] + mov eax, [IP_packets_tx + eax] ret .packets_rx: - mov eax, [IP_PACKETS_RX + eax] + mov eax, [IP_packets_rx + eax] ret .read_ip: diff --git a/kernel/branches/net/network/tcp.inc b/kernel/branches/net/network/tcp.inc index f5e87cf40d..6c261650c0 100644 --- a/kernel/branches/net/network/tcp.inc +++ b/kernel/branches/net/network/tcp.inc @@ -131,8 +131,10 @@ align 4 uglobal TCP_segments_tx rd MAX_NET_DEVICES TCP_segments_rx rd MAX_NET_DEVICES - TCP_bytes_rx rq MAX_NET_DEVICES - TCP_bytes_tx rq MAX_NET_DEVICES + TCP_segments_missed rd MAX_NET_DEVICES + TCP_segments_dumped rd MAX_NET_DEVICES +; TCP_bytes_rx rq MAX_NET_DEVICES +; TCP_bytes_tx rq MAX_NET_DEVICES TCP_sequence_num dd ? TCP_queue rd TCP_QUEUE_SIZE*sizeof.TCP_queue_entry/4 endg @@ -190,6 +192,10 @@ TCP_api: jz .packets_tx ; 0 dec bl jz .packets_rx ; 1 + dec bl + jz .packets_missed ; 2 + dec bl + jz .packets_dumped ; 3 .error: mov eax, -1 @@ -202,3 +208,11 @@ TCP_api: .packets_rx: mov eax, [TCP_segments_rx + eax] ret + + .packets_missed: + mov eax, [TCP_segments_missed + eax] + ret + + .packets_dumped: + mov eax, [TCP_segments_dumped + eax] + ret diff --git a/kernel/branches/net/network/tcp_input.inc b/kernel/branches/net/network/tcp_input.inc index 23777a1875..f318aa771a 100644 --- a/kernel/branches/net/network/tcp_input.inc +++ b/kernel/branches/net/network/tcp_input.inc @@ -54,6 +54,8 @@ TCP_input: .fail: DEBUGF 2, "TCP incoming queue is full, discarding packet!\n" + inc [TCP_segments_missed] ; FIXME: use correct interface + add esp, sizeof.TCP_queue_entry - 8 call kernel_free add esp, 4 @@ -140,7 +142,7 @@ TCP_process_input: .socket_loop: mov ebx, [ebx + SOCKET.NextPtr] or ebx, ebx - jz .drop_with_reset_no_socket + jz .respond_seg_reset cmp [ebx + SOCKET.Domain], AF_INET4 jne .socket_loop @@ -245,7 +247,7 @@ TCP_process_input: ;-------------------- ; Process TCP options - push ecx ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + push ecx movzx ecx, [edx + TCP_header.DataOffset] cmp ecx, sizeof.TCP_header ; Does header contain any options? @@ -376,7 +378,7 @@ TCP_process_input: .no_options: - pop ecx;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + pop ecx ;----------------------------------------------------------------------- ; Time to do some header prediction (Original Principle by Van Jacobson) @@ -478,12 +480,13 @@ TCP_process_input: ; Stop retransmit timer mov [ebx + TCP_SOCKET.timer_retransmission], 0 -; Awaken waiting processes +; Unlock the socket pusha lea ecx, [ebx + SOCKET.mutex] call mutex_unlock popa +; Awaken waiting processes mov eax, ebx call SOCKET_notify @@ -527,11 +530,6 @@ TCP_process_input: jmp .drop - - - - - ;-------------------------------------------------- ; Header prediction failed, do it the slow way @@ -554,7 +552,7 @@ TCP_process_input: mov [ebx + TCP_SOCKET.RCV_WND], eax pop edx -; If listen or Syn sent, go to that specific code right away +; If we are in listen or syn_sent state, go to that specific code right away cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN je .LISTEN @@ -562,8 +560,6 @@ TCP_process_input: cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT je .SYN_SENT - DEBUGF 1,"TCP_input: state is not listen or syn_sent\n" - ;---------------------------- ; trim any data not in window @@ -639,7 +635,7 @@ TCP_process_input: mov eax, ebx call TCP_close ;;;TODO: update stats - jmp .drop_with_reset_no_socket + jmp .respond_seg_reset ;---------------------------------------- ; Remove data beyond right edge of window (700-736) @@ -897,14 +893,25 @@ TCP_process_input: mov eax, [ebx + TCP_SOCKET.t_maxseg] mov [ebx + TCP_SOCKET.SND_CWND], eax - mov eax, ebx - call TCP_output ; retransmit missing segment +; Unlock the socket + push ebx + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock - push edx +; retransmit missing segment + mov eax, [esp] + call TCP_output + +; Lock the socket again + mov ecx, [esp] + add ecx, SOCKET.mutex + call mutex_lock + pop ebx + +; Continue processing 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 @@ -925,9 +932,21 @@ TCP_process_input: mov eax, [ebx + TCP_SOCKET.t_maxseg] add [ebx + TCP_SOCKET.SND_CWND], eax - mov eax, ebx +; Unlock the socket + push ebx + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + +; retransmit missing segment + mov eax, [esp] call TCP_output +; Lock the socket again + mov ecx, [esp] + add ecx, SOCKET.mutex + call mutex_lock + pop ebx + jmp .drop @@ -1077,7 +1096,7 @@ TCP_process_input: .wakeup: - pushf ; Why? + pushf ; Keep the flags (Carry flag) mov eax, ebx call SOCKET_notify @@ -1094,6 +1113,7 @@ TCP_process_input: ; General ACK handling complete ; Now do the state-specific ones +; Carry flag is set when our FIN is acked mov eax, [ebx + TCP_SOCKET.t_state] jmp dword [eax*4 + .ACK_sw_list] @@ -1150,11 +1170,10 @@ TCP_process_input: mov [ebx + TCP_SOCKET.t_dupacks], 0 jmp .ack_processed +;------- +; LISTEN - - - - +align 4 .LISTEN: DEBUGF 1,"TCP_input: state=listen\n" @@ -1202,15 +1221,6 @@ TCP_process_input: ;;; call SOCKET_notify_owner jmp .trim_then_step6 - - - - - - - - - ;------------ ; Active Open @@ -1324,9 +1334,10 @@ align 4 dec eax mov [ebx + TCP_SOCKET.SND_WL1], eax +;------- +; step 6 - - .ack_processed: ; (step 6) + .ack_processed: DEBUGF 1,"TCP_input: ACK processed\n" @@ -1496,8 +1507,6 @@ align 4 or [eax + TCP_SOCKET.t_flags], TF_ACKNOW jmp .need_output - - .drop_with_reset: DEBUGF 1,"TCP_input: Drop with reset\n" @@ -1538,7 +1547,6 @@ align 4 .need_output: DEBUGF 1,"TCP_input: need output\n" - call TCP_output .dumpit: @@ -1546,9 +1554,10 @@ align 4 call kernel_free add esp, 4 - ret +;--------- +; Respond .respond_ack: push ebx @@ -1557,7 +1566,6 @@ align 4 pop ebx jmp .destroy_new_socket - .respond_syn: push ebx mov cl, TH_RST + TH_ACK @@ -1565,39 +1573,7 @@ align 4 pop ebx jmp .destroy_new_socket - - -;----- -; Drop - - .drop: - - DEBUGF 1,"TCP_input: Dropping packet\n" - - pusha - lea ecx, [ebx + SOCKET.mutex] - call mutex_unlock - popa - - .destroy_new_socket: - - test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET - jz .drop_no_socket - - mov eax, ebx - call SOCKET_free - - .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" - + .respond_seg_reset: test [edx + TCP_header.Flags], TH_RST jnz .drop_no_socket @@ -1612,13 +1588,36 @@ align 4 jmp .drop_no_socket .respond_seg_ack: - mov cl, TH_RST call TCP_respond_segment jmp .drop_no_socket .respond_seg_syn: - mov cl, TH_RST + TH_ACK call TCP_respond_segment - jmp .drop_no_socket \ No newline at end of file + jmp .drop_no_socket + +;----- +; Drop + + .drop: + DEBUGF 1,"TCP_input: Dropping segment\n" + + pusha + lea ecx, [ebx + SOCKET.mutex] + call mutex_unlock + popa + + .destroy_new_socket: + test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET + jz .drop_no_socket + + mov eax, ebx + call SOCKET_free + + .drop_no_socket: + DEBUGF 1,"TCP_input: Drop (no socket)\n" + + call kernel_free + add esp, 4 + ret diff --git a/kernel/branches/net/network/tcp_output.inc b/kernel/branches/net/network/tcp_output.inc index 713bfd05a9..ccb7c696fe 100644 --- a/kernel/branches/net/network/tcp_output.inc +++ b/kernel/branches/net/network/tcp_output.inc @@ -28,12 +28,12 @@ $Revision$ align 4 TCP_output: - DEBUGF 1,"TCP_output: socket=%x\n", eax + DEBUGF 1,"TCP_output: socket=%x\n", eax - pusha + push eax lea ecx, [eax + SOCKET.mutex] call mutex_lock - popa + pop 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 diff --git a/kernel/branches/net/network/tcp_subr.inc b/kernel/branches/net/network/tcp_subr.inc index 73572c40c1..6dd8a8e577 100644 --- a/kernel/branches/net/network/tcp_subr.inc +++ b/kernel/branches/net/network/tcp_subr.inc @@ -355,7 +355,7 @@ TCP_respond_segment: stosd xor eax, eax stosd - mov al, 0x50 ; Dataoffset: 20 bytes (sizeof.TCP_header) + mov al, 0x50 ; Dataoffset: 20 bytes (sizeof.TCP_header/4 shl 4) stosb mov al, cl stosb