Cleanup in TCP, fixed possible deadlock in TCP_input.

git-svn-id: svn://kolibrios.org@3275 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2013-02-26 20:17:02 +00:00
parent 9069d7e9ca
commit 46d92cd305
5 changed files with 105 additions and 91 deletions

View File

@ -64,8 +64,9 @@ uglobal
GATEWAY_LIST rd MAX_NET_DEVICES GATEWAY_LIST rd MAX_NET_DEVICES
BROADCAST_LIST rd MAX_NET_DEVICES BROADCAST_LIST rd MAX_NET_DEVICES
IP_PACKETS_TX rd MAX_NET_DEVICES IP_packets_tx rd MAX_NET_DEVICES
IP_PACKETS_RX 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 FRAGMENT_LIST rb MAX_FRAGMENTS * sizeof.FRAGMENT_slot
endg endg
@ -262,7 +263,7 @@ IPv4_input: ; TODO: add IPv4
; Now we can update stats ; Now we can update stats
.ip_ok: .ip_ok:
inc [IP_PACKETS_RX+edi] inc [IP_packets_rx + edi]
;---------------------------------- ;----------------------------------
; Check if the packet is fragmented ; Check if the packet is fragmented
@ -303,7 +304,7 @@ IPv4_input: ; TODO: add IPv4
.dump: .dump:
DEBUGF 1,"IPv4_input: dumping\n" DEBUGF 1,"IPv4_input: dumping\n"
; inc [dumped_rx_count] ;;; TODO inc [IP_packets_dumped] ; FIXME: use correct interface
call kernel_free call kernel_free
add esp, 4 ; pop (balance stack) add esp, 4 ; pop (balance stack)
ret ret
@ -584,7 +585,7 @@ IPv4_output:
push ebx ; push the mac onto the stack push ebx ; push the mac onto the stack
push ax push ax
inc [IP_PACKETS_TX + edi] ; update stats inc [IP_packets_tx + edi] ; update stats
mov ebx, [NET_DRV_LIST + edi] mov ebx, [NET_DRV_LIST + edi]
lea eax, [ebx + ETH_DEVICE.mac] lea eax, [ebx + ETH_DEVICE.mac]
@ -674,7 +675,7 @@ IPv4_output_raw:
push ebx ; push the mac push ebx ; push the mac
push ax push ax
inc [IP_PACKETS_TX + edi] inc [IP_packets_tx + edi]
mov ebx, [NET_DRV_LIST + edi] mov ebx, [NET_DRV_LIST + edi]
lea eax, [ebx + ETH_DEVICE.mac] lea eax, [ebx + ETH_DEVICE.mac]
mov edx, esp mov edx, esp
@ -951,11 +952,11 @@ IPv4_api:
ret ret
.packets_tx: .packets_tx:
mov eax, [IP_PACKETS_TX + eax] mov eax, [IP_packets_tx + eax]
ret ret
.packets_rx: .packets_rx:
mov eax, [IP_PACKETS_RX + eax] mov eax, [IP_packets_rx + eax]
ret ret
.read_ip: .read_ip:

View File

@ -131,8 +131,10 @@ align 4
uglobal uglobal
TCP_segments_tx rd MAX_NET_DEVICES TCP_segments_tx rd MAX_NET_DEVICES
TCP_segments_rx rd MAX_NET_DEVICES TCP_segments_rx rd MAX_NET_DEVICES
TCP_bytes_rx rq MAX_NET_DEVICES TCP_segments_missed rd MAX_NET_DEVICES
TCP_bytes_tx rq 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_sequence_num dd ?
TCP_queue rd TCP_QUEUE_SIZE*sizeof.TCP_queue_entry/4 TCP_queue rd TCP_QUEUE_SIZE*sizeof.TCP_queue_entry/4
endg endg
@ -190,6 +192,10 @@ TCP_api:
jz .packets_tx ; 0 jz .packets_tx ; 0
dec bl dec bl
jz .packets_rx ; 1 jz .packets_rx ; 1
dec bl
jz .packets_missed ; 2
dec bl
jz .packets_dumped ; 3
.error: .error:
mov eax, -1 mov eax, -1
@ -202,3 +208,11 @@ TCP_api:
.packets_rx: .packets_rx:
mov eax, [TCP_segments_rx + eax] mov eax, [TCP_segments_rx + eax]
ret ret
.packets_missed:
mov eax, [TCP_segments_missed + eax]
ret
.packets_dumped:
mov eax, [TCP_segments_dumped + eax]
ret

View File

@ -54,6 +54,8 @@ TCP_input:
.fail: .fail:
DEBUGF 2, "TCP incoming queue is full, discarding packet!\n" 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 add esp, sizeof.TCP_queue_entry - 8
call kernel_free call kernel_free
add esp, 4 add esp, 4
@ -140,7 +142,7 @@ TCP_process_input:
.socket_loop: .socket_loop:
mov ebx, [ebx + SOCKET.NextPtr] mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx or ebx, ebx
jz .drop_with_reset_no_socket jz .respond_seg_reset
cmp [ebx + SOCKET.Domain], AF_INET4 cmp [ebx + SOCKET.Domain], AF_INET4
jne .socket_loop jne .socket_loop
@ -245,7 +247,7 @@ TCP_process_input:
;-------------------- ;--------------------
; Process TCP options ; Process TCP options
push ecx ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; push ecx
movzx ecx, [edx + TCP_header.DataOffset] movzx ecx, [edx + TCP_header.DataOffset]
cmp ecx, sizeof.TCP_header ; Does header contain any options? cmp ecx, sizeof.TCP_header ; Does header contain any options?
@ -376,7 +378,7 @@ TCP_process_input:
.no_options: .no_options:
pop ecx;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; pop ecx
;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
; Time to do some header prediction (Original Principle by Van Jacobson) ; Time to do some header prediction (Original Principle by Van Jacobson)
@ -478,12 +480,13 @@ TCP_process_input:
; Stop retransmit timer ; Stop retransmit timer
mov [ebx + TCP_SOCKET.timer_retransmission], 0 mov [ebx + TCP_SOCKET.timer_retransmission], 0
; Awaken waiting processes ; Unlock the socket
pusha pusha
lea ecx, [ebx + SOCKET.mutex] lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock call mutex_unlock
popa popa
; Awaken waiting processes
mov eax, ebx mov eax, ebx
call SOCKET_notify call SOCKET_notify
@ -527,11 +530,6 @@ TCP_process_input:
jmp .drop jmp .drop
;-------------------------------------------------- ;--------------------------------------------------
; Header prediction failed, do it the slow way ; Header prediction failed, do it the slow way
@ -554,7 +552,7 @@ TCP_process_input:
mov [ebx + TCP_SOCKET.RCV_WND], eax mov [ebx + TCP_SOCKET.RCV_WND], eax
pop edx 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 cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
je .LISTEN je .LISTEN
@ -562,8 +560,6 @@ TCP_process_input:
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT
je .SYN_SENT je .SYN_SENT
DEBUGF 1,"TCP_input: state is not listen or syn_sent\n"
;---------------------------- ;----------------------------
; trim any data not in window ; trim any data not in window
@ -639,7 +635,7 @@ TCP_process_input:
mov eax, ebx mov eax, ebx
call TCP_close call TCP_close
;;;TODO: update stats ;;;TODO: update stats
jmp .drop_with_reset_no_socket jmp .respond_seg_reset
;---------------------------------------- ;----------------------------------------
; Remove data beyond right edge of window (700-736) ; Remove data beyond right edge of window (700-736)
@ -897,14 +893,25 @@ TCP_process_input:
mov eax, [ebx + TCP_SOCKET.t_maxseg] mov eax, [ebx + TCP_SOCKET.t_maxseg]
mov [ebx + TCP_SOCKET.SND_CWND], eax mov [ebx + TCP_SOCKET.SND_CWND], eax
mov eax, ebx ; Unlock the socket
call TCP_output ; retransmit missing segment 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 xor edx, edx
mov eax, [ebx + TCP_SOCKET.t_maxseg] mov eax, [ebx + TCP_SOCKET.t_maxseg]
mul [ebx + TCP_SOCKET.t_dupacks] mul [ebx + TCP_SOCKET.t_dupacks]
pop edx
add eax, [ebx + TCP_SOCKET.SND_SSTHRESH] add eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
mov [ebx + TCP_SOCKET.SND_CWND], eax mov [ebx + TCP_SOCKET.SND_CWND], eax
@ -925,9 +932,21 @@ TCP_process_input:
mov eax, [ebx + TCP_SOCKET.t_maxseg] mov eax, [ebx + TCP_SOCKET.t_maxseg]
add [ebx + TCP_SOCKET.SND_CWND], eax 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 call TCP_output
; Lock the socket again
mov ecx, [esp]
add ecx, SOCKET.mutex
call mutex_lock
pop ebx
jmp .drop jmp .drop
@ -1077,7 +1096,7 @@ TCP_process_input:
.wakeup: .wakeup:
pushf ; Why? pushf ; Keep the flags (Carry flag)
mov eax, ebx mov eax, ebx
call SOCKET_notify call SOCKET_notify
@ -1094,6 +1113,7 @@ TCP_process_input:
; General ACK handling complete ; General ACK handling complete
; Now do the state-specific ones ; Now do the state-specific ones
; Carry flag is set when our FIN is acked
mov eax, [ebx + TCP_SOCKET.t_state] mov eax, [ebx + TCP_SOCKET.t_state]
jmp dword [eax*4 + .ACK_sw_list] jmp dword [eax*4 + .ACK_sw_list]
@ -1150,11 +1170,10 @@ TCP_process_input:
mov [ebx + TCP_SOCKET.t_dupacks], 0 mov [ebx + TCP_SOCKET.t_dupacks], 0
jmp .ack_processed jmp .ack_processed
;-------
; LISTEN
align 4
.LISTEN: .LISTEN:
DEBUGF 1,"TCP_input: state=listen\n" DEBUGF 1,"TCP_input: state=listen\n"
@ -1203,15 +1222,6 @@ TCP_process_input:
jmp .trim_then_step6 jmp .trim_then_step6
;------------ ;------------
; Active Open ; Active Open
@ -1324,9 +1334,10 @@ align 4
dec eax dec eax
mov [ebx + TCP_SOCKET.SND_WL1], eax mov [ebx + TCP_SOCKET.SND_WL1], eax
;-------
; step 6
.ack_processed:
.ack_processed: ; (step 6)
DEBUGF 1,"TCP_input: ACK processed\n" DEBUGF 1,"TCP_input: ACK processed\n"
@ -1496,8 +1507,6 @@ align 4
or [eax + TCP_SOCKET.t_flags], TF_ACKNOW or [eax + TCP_SOCKET.t_flags], TF_ACKNOW
jmp .need_output jmp .need_output
.drop_with_reset: .drop_with_reset:
DEBUGF 1,"TCP_input: Drop with reset\n" DEBUGF 1,"TCP_input: Drop with reset\n"
@ -1538,7 +1547,6 @@ align 4
.need_output: .need_output:
DEBUGF 1,"TCP_input: need output\n" DEBUGF 1,"TCP_input: need output\n"
call TCP_output call TCP_output
.dumpit: .dumpit:
@ -1546,9 +1554,10 @@ align 4
call kernel_free call kernel_free
add esp, 4 add esp, 4
ret ret
;---------
; Respond
.respond_ack: .respond_ack:
push ebx push ebx
@ -1557,7 +1566,6 @@ align 4
pop ebx pop ebx
jmp .destroy_new_socket jmp .destroy_new_socket
.respond_syn: .respond_syn:
push ebx push ebx
mov cl, TH_RST + TH_ACK mov cl, TH_RST + TH_ACK
@ -1565,39 +1573,7 @@ align 4
pop ebx pop ebx
jmp .destroy_new_socket jmp .destroy_new_socket
.respond_seg_reset:
;-----
; 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"
test [edx + TCP_header.Flags], TH_RST test [edx + TCP_header.Flags], TH_RST
jnz .drop_no_socket jnz .drop_no_socket
@ -1612,13 +1588,36 @@ align 4
jmp .drop_no_socket jmp .drop_no_socket
.respond_seg_ack: .respond_seg_ack:
mov cl, TH_RST mov cl, TH_RST
call TCP_respond_segment call TCP_respond_segment
jmp .drop_no_socket jmp .drop_no_socket
.respond_seg_syn: .respond_seg_syn:
mov cl, TH_RST + TH_ACK mov cl, TH_RST + TH_ACK
call TCP_respond_segment call TCP_respond_segment
jmp .drop_no_socket 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

View File

@ -30,10 +30,10 @@ 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] lea ecx, [eax + SOCKET.mutex]
call mutex_lock call mutex_lock
popa pop eax
; We'll detect the length of the data to be transmitted, and flags to be used ; 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 ; If there is some data, or any critical controls to send (SYN / RST), then transmit

View File

@ -355,7 +355,7 @@ TCP_respond_segment:
stosd stosd
xor eax, eax xor eax, eax
stosd stosd
mov al, 0x50 ; Dataoffset: 20 bytes (sizeof.TCP_header) mov al, 0x50 ; Dataoffset: 20 bytes (sizeof.TCP_header/4 shl 4)
stosb stosb
mov al, cl mov al, cl
stosb stosb