159,8 → 159,36 |
; Are we accepting incoming connections? |
|
test [ebx + SOCKET.options], SO_ACCEPTCON |
jnz .accept_connection |
jz .no_accept |
|
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_no_socket |
|
mov ebx, eax |
|
mov [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET ;;; FIXME: should we take over bits from previous socket? |
|
push dword [edi + 4] ; Ipv4 destination addres |
pop [ebx + IP_SOCKET.LocalIP] |
|
push [edx + TCP_header.DestinationPort] |
pop [ebx + TCP_SOCKET.LocalPort] |
|
mov [ebx + TCP_SOCKET.t_state], TCPS_LISTEN |
.no_accept: |
|
|
;------------------------------------- |
; Reset idle timer and keepalive timer |
|
170,85 → 198,108 |
;-------------------- |
; Process TCP options |
|
movzx eax, [edx + TCP_header.DataOffset] |
cmp eax, sizeof.TCP_header ; Does header contain any options? |
push ecx |
|
movzx ecx, [edx + TCP_header.DataOffset] |
cmp ecx, sizeof.TCP_header ; Does header contain any options? |
je .no_options |
|
DEBUGF 1,"TCP_input: 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 |
;;; FIXME: for LISTEN, options should be called after we determined route, we need it for MSS |
;;; 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 |
add ecx, edx |
lea esi, [edx + sizeof.TCP_header] |
|
.opt_loop: |
cmp esi, eax ; are we scanning outside of header? |
cmp esi, ecx ; 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_NOP ; nop ? |
jz .opt_nop |
|
cmp byte [esi], TCP_OPT_MAXSEG |
lodsb |
cmp al, TCP_OPT_EOL ; end of option list? |
je .no_options |
cmp al, TCP_OPT_NOP |
je .opt_loop |
cmp al, TCP_OPT_MAXSEG |
je .opt_maxseg |
|
cmp byte [esi], TCP_OPT_WINDOW |
cmp al, TCP_OPT_WINDOW |
je .opt_window |
|
cmp byte [esi], TCP_OPT_TIMESTAMP |
cmp al, TCP_OPT_SACK_PERMIT |
je .opt_sack_permit |
; cmp al, TCP_OPT_SACK |
; je .opt_sack |
cmp al, TCP_OPT_TIMESTAMP |
je .opt_timestamp |
|
DEBUGF 1,"TCP_input: unknown option:%u\n", al |
jmp .no_options ; If we reach here, some unknown options were received, skip them all! |
|
.opt_nop: |
inc esi |
jmp .opt_loop |
|
.opt_maxseg: |
cmp byte [esi+1], 4 |
lodsb |
cmp al, 4 |
jne .no_options ; error occured, ignore all options! |
|
test [edx + TCP_header.Flags], TH_SYN |
jz @f |
|
movzx eax, word[esi+2] |
lodsw |
rol ax, 8 |
DEBUGF 1,"TCP_input: Maxseg=%u\n", ax |
mov [ebx + TCP_SOCKET.t_maxseg], eax |
|
@@: |
add esi, 4 |
jmp .opt_loop |
|
|
.opt_window: |
cmp byte [esi+1], 3 |
lodsb |
cmp al, 3 |
jne .no_options |
|
test [edx + TCP_header.Flags], TH_SYN |
jz @f |
|
DEBUGF 1,"TCP_input: Got window option\n" |
DEBUGF 1,"TCP_input: Got window scale option\n" |
or [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE |
|
;;;;; |
lodsb |
mov [ebx + TCP_SOCKET.SND_SCALE], al |
;;;;; TODO |
|
@@: |
add esi, 3 |
jmp .opt_loop |
|
|
.opt_sack_permit: |
lodsb |
cmp al, 2 |
jne .no_options |
|
test [edx + TCP_header.Flags], TH_SYN |
jz @f |
|
DEBUGF 1,"TCP_input: Selective Acknowledgement permitted\n" |
or [ebx + TCP_SOCKET.t_flags], TF_SACK_PERMIT |
|
@@: |
jmp .opt_loop |
|
|
.opt_timestamp: |
cmp byte [esi+1], 10 ; length must be 10 |
lodsb |
cmp al, 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_val] |
push dword [esi + 6] ; timestamp echo reply |
pop [ebx + TCP_SOCKET.ts_ecr] |
test [edx + TCP_header.Flags], TH_SYN |
jz @f |
or [ebx + TCP_SOCKET.t_flags], TF_RCVD_TSTMP |
@@: |
|
lodsd |
mov [ebx + TCP_SOCKET.ts_val], eax |
lodsd ; timestamp echo reply |
mov [ebx + TCP_SOCKET.ts_ecr], eax |
or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP |
|
; Since we have a timestamp, lets do the paws test right away! |
264,7 → 315,7 |
|
DEBUGF 1,"TCP_input: PAWS: detected an old segment\n" |
|
mov eax, [esp+4+4] ; tcp_now |
mov eax, [esp+4+4+4] ; tcp_now |
sub eax, [ebx + TCP_SOCKET.ts_recent_age] |
cmp eax, TCP_PAWS_IDLE |
jle .drop_after_ack ; TODO: update stats |
271,12 → 322,12 |
|
mov [ebx + TCP_SOCKET.ts_recent], 0 ; timestamp was invalid, fix it. |
.no_paws: |
|
add esi, 10 |
jmp .opt_loop |
|
.no_options: |
|
pop ecx |
|
;----------------------------------------------------------------------- |
; Time to do some header prediction (Original Principle by Van Jacobson) |
|
1038,38 → 1089,9 |
|
|
|
;------------- |
; 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 |
|
mov [eax + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET ;;; FIXME: should we take over bits from previous socket? |
|
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" |
1262,10 → 1284,6 |
ja .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 |
1272,7 → 1290,7 |
|
.update_window: |
|
;;; TODO: Keep track of pure window updates |
;;; TODO: update stats (Keep track of pure window updates) |
|
mov eax, dword [edx + TCP_header.Window] |
cmp eax, [ebx + TCP_SOCKET.max_sndwnd] |
1293,12 → 1311,6 |
|
.no_window_update: |
|
|
|
|
|
|
|
;----------------- |
; process URG flag |
|
1464,6 → 1476,7 |
DEBUGF 1,"TCP_input: ACK now!\n" |
|
.need_output: |
DEBUGF 1,"TCP_input: need output\n" |
call TCP_output |
|
.dumpit: |