;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RDOS operating system
; Copyright (C) 1988-2000, Leif Ekblad
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version. The only exception to this rule
; is for commercial usage in embedded systems. For information on
; usage in commercial embedded systems, contact embedded@rdos.net
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
;
; The author of this program may be contacted at leif@rdos.net
;
; TCP.ASM
; TCP protocol
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

INCLUDE protseg.def
INCLUDE ..\driver.def
INCLUDE ..\user.def
INCLUDE ..\os.def
INCLUDE ..\user.inc
INCLUDE ..\os.inc
include ..\handle.inc
include ..\wait.inc
INCLUDE exec.def
INCLUDE system.inc
INCLUDE ip.inc
INCLUDE tcp.inc
INCLUDE ..\apicheck.inc

Reverse MACRO
    xchg al,ah
    rol eax,16
    xchg al,ah
        ENDM

tcp_wait_header STRUC

tw_obj          wait_obj_header <>
tw_handle           DW ?

tcp_wait_header ENDS

tcp_handle_seg      STRUC

tcp_handle_base     handle_header <>
tcp_handle_sel      DW ?

tcp_handle_seg      ENDS

listen_handle_seg           STRUC

listen_handle_base      handle_header <>
listen_handle_sel       DW ?

listen_handle_seg           ENDS

data    SEGMENT byte public 'DATA'

ConnSpinlock        spinlock_typ <>
ListSection         section_typ <>
Handle              DW ?
ConnectionList      DW ?
ConnectionCount     DW ?
ListenList          DW ?
TcpThread           DW ?
LastPort            DW ?
PortMap             DB 2000h DUP(?)

data    ENDS


code    SEGMENT byte public 'CODE'

IFDEF __WASM__
    .686p
    .xmm2
ELSE
    .386p
ENDIF
    
    assume cs:code


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CheckConnectionList
;
;       Purpose:        Check connection list integrity
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckConnectionList     Proc near
    push ds
    pushad
;    
    xor cx,cx
    mov ax,SEG data
    mov ds,ax
    mov ax,ds:ConnectionList
    or ax,ax
    jz cclCheck

cclLoop:
    inc cx
    mov ds,ax
    mov ax, ds:tcp_next
    or ax,ax
    jnz cclLoop

cclCheck:
    mov ax,SEG data
    mov ds,ax
;
    cmp cx,ds:ConnectionCount
    je cclDone
;
    int 3

cclDone:    
    popad
    pop ds
    ret
CheckConnectionList Endp    

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           AllocatePort
;
;       Purpose:        Allocate a dynamic port
;
;       Returns:        SI          Local port #
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

AllocatePort    Proc near
    push ds
    push eax
    push ebx
    push ecx
    push edx
;
    mov ax,SEG data
    mov ds,ax

allocate_port_loop:
    GetSystemTime
    mov ebx,edx
    movzx ecx,ds:LastPort
    mul ecx
    add eax,ebx
    xor edx,edx
    mov ecx,0F800h
    div ecx
    mov ax,dx
    mov ds:LastPort,ax
;       
    mov bx,ax
    shr bx,3
    add bx,OFFSET PortMap
    and ax,7
    btr [bx],ax
    jnc allocate_port_loop
;
    mov si,800h
    add si,dx
    clc
;
    pop edx
    pop ecx
    pop ebx
    pop eax
    pop ds
    ret
AllocatePort    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           FreePort
;
;       Purpose:        Free a dynamic port
;
;       Parameters:         SI          Local port #
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FreePort    Proc near
    push ds
    push ax
;
    mov ax,SEG data
    mov ds,ax
    mov ax,si
    sub ax,800h
    jc free_port_done
;       
    mov bx,ax
    shr bx,3
    add bx,OFFSET PortMap
    and ax,7
    bts [bx],ax

free_port_done:
    pop ax
    pop ds
    ret
FreePort    Endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           CalcChecksum
;
;           DESCRIPTION:    Calculate checksum for TCP
;
;           PARAMETERS:         AX          Checksum in
;                           CX          Size of data
;                           ES:DI   Data
;
;           RETURNS:        AX          Checksum ut
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CalcChecksum    Proc near
    push ds
    push cx
    push dx
    push si
;
    mov si,es
    mov ds,si
    mov si,di
    mov dx,ax
    shr cx,1
    pushf
    clc
checksum_loop:
    lodsw
    adc dx,ax
    loop checksum_loop
    adc dx,0
    adc dx,0
    popf
    jnc calc_checksum_done
    xor ah,ah
    lodsb
    add dx,ax
    adc dx,0
    adc dx,0
calc_checksum_done:
    mov ax,dx
;
    pop si
    pop dx
    pop cx
    pop ds
    ret
CalcChecksum    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           GetIss
;
;       Purpose:        Get initial ISS value
;
;       Parameters:         DS          connection selector
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

GetIss  Proc near
    push edx
    push eax
;
    GetSystemTime
    mov ds:tcp_time_val,eax
    rcr edx,1
    rcr eax,1
    rcr edx,1
    rcr eax,1
    rcr edx,1
    rcr eax,1
    mov ds:tcp_iss,eax
    mov ds:tcp_time_seq,eax
    mov ds:tcp_id,ax
;
    pop eax
    pop edx
    ret
GetIss  Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CreateSegment
;
;       Purpose:        Create a tcp segment
;
;       Parameters:         DS          connection selector
;                       ECX         size of data portion
;
;       Returns:        ES:DI   segment
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CreateSegment   Proc near
    push ax
    push bx
    push ecx
    push edx
    push esi
;
    mov al,6
    mov ah,60
    mov bx,ds:tcp_id
    inc bx
    mov ds:tcp_id,bx
    xchg bl,bh
    add ecx,SIZE tcp_header
    mov edx,ds:tcp_remote_ip
    mov esi,OFFSET tcp_options
    CreateIpHeader
    jc csDone
;
    mov ax,ds:tcp_port
    xchg al,ah
    mov es:[di].tcp_source,ax
    mov ax,ds:tcp_remote_port
    xchg al,ah
    mov es:[di].tcp_dest,ax
    mov es:[di].tcp_seq,0
    mov es:[di].tcp_ack,0
    mov es:[di].tcp_header_len,50h
    mov es:[di].tcp_flags,0
    mov ax,ds:tcp_rcv_wnd
    xchg al,ah
    mov es:[di].tcp_window,ax
    mov es:[di].tcp_urgent,0
    clc

csDone:
    pop esi
    pop edx
    pop ecx
    pop bx
    pop ax
    ret
CreateSegment   Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           SendSegment
;
;       Purpose:        Send a tcp segment
;
;       Parameters:         DS          connection selector
;                       ES:DI   TCP data
;                       ECX         size of data portion
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SendSegment     Proc near
    push ax
    push cx
;
    mov ax,ds:tcp_checksum_base
    add cx,SIZE tcp_header
    xchg cl,ch
    add ax,cx
    adc ax,0
    adc ax,0
    xchg cl,ch
    mov es:[di].tcp_checksum,0
    call CalcChecksum
    not ax
    mov es:[di].tcp_checksum,ax
    SendIp
;
    pop cx
    pop ax
    ret
SendSegment     Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CreateBuffer
;
;       Purpose:        Create a buffer
;
;       Parameters:         ECX     Buffer size
;
;       Returns:        AX      Buffer selector     
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CreateBuffer    Proc near
    push es
    push bx
    push ecx
    push edx
    push esi
    push edi
    push ebp
;
    mov edi,ecx
    add ecx,ecx
    mov eax,ecx
    AllocateBigLinear
    mov ebp,edx
    AllocateGdt
    mov ecx,eax
    CreateDataSelector16    
;
    mov ecx,edi
    push ecx
    mov es,bx   
    xor edi,edi
    shr ecx,2
    xor eax,eax
    rep stos dword ptr es:[edi]
    pop ecx
;
    shr ecx,12
    xor esi,esi
;
    push ebx    

cbAlias:
    lea edx,[esi+ebp]
    GetPageEntry
;
    lea edx,[edi+ebp]
    SetPageEntry
;
    add esi,1000h
    add edi,1000h
    loop cbAlias    
;
    pop ebx    
;
    mov ax,bx    
    pop ebp
    pop edi
    pop esi
    pop edx
    pop ecx
    pop bx
    pop es
    ret
CreateBuffer    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           FreeBuffer
;
;       Purpose:        Free buffer
;
;       Parameters:         AX      Buffer selector
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FreeBuffer    Proc near
    push es
    push eax
    push bx
    push ecx
    push edx
;
    mov bx,ax
    GetSelectorBaseSize
;
    shr ecx,1
    add edx,ecx
    shr ecx,12
;
    push ebx
    
fbAlias:
    xor eax,eax
    xor ebx,ebx
    SetPageEntry
    add edx,1000h
    loop fbAlias    
;
    pop ebx
;    
    mov es,bx
    FreeMem
;    
    pop edx
    pop ecx
    pop bx
    pop eax
    pop es
    ret
FreeBuffer    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CopyFromBuffer
;
;       Purpose:        Copy from buffer
;
;       Parameters:         CX      Number of bytes
;           FS:BX       Buffer pointer
;           ES:EDI      Destination address
;
;   Returns:    BX      New buffer pointer
;           EDI     New destination
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CopyFromBuffer    Proc near
    push cx
;
    cmp cx,10h
    jb cfbSmall
;
    push esi
    movzx ecx,cx
    movzx esi,bx
    push cx
    shr cx,2
    rep movs dword ptr es:[edi],fs:[esi]
    pop cx
    and cx,3
    rep movs byte ptr es:[edi],fs:[esi]
    mov bx,si
    pop esi
    cmp bx,ds:tcp_buffer_size
    jb cfbDone
;
    sub bx,ds:tcp_buffer_size
    jmp cfbDone

cfbSmall:
    or cx,cx
    jz cfbDone
;    
    push eax

cfbLoop:
    mov al,fs:[bx]
    mov es:[edi],al
    inc bx
    inc edi
    cmp bx,ds:tcp_buffer_size
    jnz cfbWrapDone
    
    xor bx,bx
    
cfbWrapDone:
    loop cfbLoop
;       
    pop eax

cfbDone:
    pop cx
    ret
CopyFromBuffer  Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CopyToBuffer
;
;       Purpose:        Copy to buffer
;
;       Parameters:         CX      Number of bytes
;           FS:BX       Buffer pointer
;           ES:ESI      Source address
;
;   Returns:    BX      New buffer pointer
;           ESI     New source
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


CopyToBuffer    Proc near
    push eax
    push cx
;
    cmp cx,10h
    jb ctbSmall
;
    push ds
    push es
    push edi
;    
    movzx edi,bx
    movzx ecx,cx
    mov ax,es
    mov ds,ax
    mov ax,fs
    mov es,ax
;
    push cx
    shr cx,2
    rep movs dword ptr es:[edi],ds:[esi]
    pop cx
    and cx,3
    rep movs byte ptr es:[edi],ds:[esi]
    mov bx,di
;
    pop edi
    pop es
    pop ds
;    
    cmp bx,ds:tcp_buffer_size
    jb ctbDone
;
    sub bx,ds:tcp_buffer_size
    jmp ctbDone

ctbSmall:
    or cx,cx
    jz ctbDone    

ctbLoop:
    mov al,es:[esi]
    mov fs:[bx],al
    inc bx
    inc esi
    cmp bx,ds:tcp_buffer_size
    jnz ctbWrapDone
;
    xor bx,bx
    
ctbWrapDone:
    loop ctbLoop

ctbDone:
    pop cx
    pop eax
    ret
CopyToBuffer    Endp    

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CreateConnection
;
;       Purpose:        Create a connection and link it
;
;       Parameters:         EAX         Timeout in seconds for connection
;                       CX          buffer size
;                       EDX         ip address
;                       SI          local port
;                       DI          remote port
;
;       Returns:        DS          connection selector
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CreateConnection    Proc near
    push es
    push ax
    push ecx
    push edx
;
    dec ecx
    and cx,0F000h
    add ecx,1000h
;
    push eax
    mov eax,SIZE tcp_connection
    AllocateSmallGlobalMem
    pop eax
    mov es:tcp_owner,0
    mov es:tcp_writer,0
    mov es:tcp_wait,0
    mov es:tcp_options,0
    mov es:tcp_port,si
    mov es:tcp_remote_ip,edx
    mov es:tcp_remote_port,di
    mov es:tcp_timeout,eax
    mov es:tcp_buffer_size,cx
    mov es:tcp_rcv_wnd,cx
    mov es:tcp_state,-1
    mov es:tcp_mtu,1400
    mov es:tcp_pending,0
    mov es:tcp_push_timeout,0
    mov es:tcp_rtt,119300
    mov es:tcp_rto,1193000 * 3
    mov es:tcp_rts,1193000 * 3
    mov es:tcp_rtm,0
    mov es:tcp_reorder_count,0
    mov es:tcp_send_timeout,0
    mov es:tcp_delete_timeout,0
;
    call CreateBuffer
    mov es:tcp_receive_buffer,ax
    mov es:tcp_receive_count,0
    mov es:tcp_receive_head,0
    mov es:tcp_receive_tail,0
;
    call CreateBuffer
    mov es:tcp_send_buffer,ax
    mov es:tcp_send_count,0
    mov es:tcp_send_head,0
    mov es:tcp_send_tail,0
;       
    mov ax,es
    mov ds,ax
    InitSection ds:tcp_section
    EnterSection ds:tcp_section
;
    mov ax,SEG data
    mov ds,ax
    EnterSection ds:ListSection
    mov dx,ds:ConnectionList
    mov es:tcp_next,dx
    mov ds:ConnectionList,es
    inc ds:ConnectionCount
    call CheckConnectionList
    LeaveSection ds:ListSection
    mov ax,es
    mov ds,ax
    call GetIss
;
    GetIpAddress
    push edx
    pop ax
    pop dx
;
    add dx,ax
    adc dx,word ptr ds:tcp_remote_ip
    adc dx,word ptr ds:tcp_remote_ip+2
    adc dx,600h
    adc dx,0
    adc dx,0
    mov ds:tcp_checksum_base,dx
;
    mov ax,SEG data
    mov es,ax
    mov bx,es:TcpThread
    Signal
;
    pop edx
    pop ecx
    pop ax
    pop es
    ret
CreateConnection    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           DeleteConnection
;
;       Purpose:        Delete a connection. ListSection & connection section
;                       must be taken prior to call
;
;       Parameters:         DS          connection selector
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DeleteConnection    Proc near
    push es
    push ax
    push bx
    push ecx
    push edx
    push esi
;    
    mov si,ds:tcp_port
    call FreePort
;
    mov ax,ds:tcp_receive_buffer
    call FreeBuffer
;
    mov ax,ds:tcp_send_buffer
    call FreeBuffer
;
    mov dx,ds:tcp_next
    mov bx,ds
    mov es,bx
;
    mov ax,SEG data
    mov ds,ax
;
    mov ax,ds:ConnectionList
    cmp ax,bx
    jne delete_connect_loop
;
    mov ds:ConnectionList,dx
    dec ds:ConnectionCount
    jmp delete_connect_unlinked

delete_connect_loop:
    or ax,ax
    jz delete_connect_unlinked
;       
    mov ds,ax
    mov cx,ax
    mov ax,ds:tcp_next
    cmp ax,bx
    jne delete_connect_loop
;
    mov ds,ax
    mov ax,ds:tcp_next
    mov ds,cx
    mov ds:tcp_next,ax
;       
    mov ax,SEG data
    mov ds,ax
    dec ds:ConnectionCount

delete_connect_unlinked:
    mov ax,SEG data
    mov ds,ax
    RequestSpinlock ds:ConnSpinlock
    ReleaseSpinlock ds:ConnSpinlock
    call CheckConnectionList       
    FreeMem
;
    pop esi
    pop edx
    pop ecx
    pop bx
    pop ax
    pop es
    ret
DeleteConnection    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           FindConnection
;
;       Purpose:        Look for a connection
;
;       Parameters:         EDX         remote ip
;                       SI          local port
;                       DI          remote port
;
;       Returns:        NC          connection found
;                       DS          connection, locked
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FindConnection  Proc near
    push es
    push ax
;
    mov ax,SEG data
    mov ds,ax
    EnterSection ds:ListSection
    mov ax,ds:ConnectionList

find_connection_loop:
    or ax,ax
    jz find_connection_fail
    mov es,ax
    cmp edx,es:tcp_remote_ip
    jne find_connection_next
    cmp si,es:tcp_port
    jne find_connection_next
    cmp di,es:tcp_remote_port
    je find_connection_ok
find_connection_next:
    mov ax,es:tcp_next
    jmp find_connection_loop

find_connection_fail:
    LeaveSection ds:ListSection
    stc
    jmp find_connection_done

find_connection_ok:
    mov ax,es
    push ax
    mov ds,ax
    EnterSection ds:tcp_section
    test ds:tcp_pending,FLAG_DELETE_NET
    jz find_connection_not_deleted
;
    pop ax
    LeaveSection ds:tcp_section
    mov ax,SEG data
    mov ds,ax
    LeaveSection ds:ListSection
    stc
    jmp find_connection_done

find_connection_not_deleted:
    mov ax,SEG data
    mov ds,ax
    LeaveSection ds:ListSection
    pop ds
    clc

find_connection_done:
    pop ax
    pop es
    ret
FindConnection  Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           FindWildConnection
;
;       Purpose:        Look for a connection with zero in remote port
;
;       Parameters:         EDX         remote ip
;                       SI          local port
;
;       Returns:        NC          connection found
;                       DS          connection, locked
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FindWildConnection      Proc near
    push es
    push ax
;
    mov ax,SEG data
    mov ds,ax
    EnterSection ds:ListSection
    mov ax,ds:ConnectionList

find_wild_connection_loop:
    or ax,ax
    jz find_wild_connection_fail
    mov es,ax
    cmp edx,es:tcp_remote_ip
    jne find_wild_connection_next
    cmp si,es:tcp_port
    jne find_wild_connection_next
    mov ax,es:tcp_remote_port
    or ax,ax
    je find_wild_connection_ok

find_wild_connection_next:
    mov ax,es:tcp_next
    jmp find_wild_connection_loop

find_wild_connection_fail:
    LeaveSection ds:ListSection
    stc
    jmp find_wild_connection_done

find_wild_connection_ok:
    mov ax,es
    push ax
    mov ds,ax
    EnterSection ds:tcp_section
    test ds:tcp_pending,FLAG_DELETE_NET
    jz find_wild_connection_not_deleted
;
    pop ax
    LeaveSection ds:tcp_section
    mov ax,SEG data
    mov ds,ax
    LeaveSection ds:ListSection
    stc
    jmp find_wild_connection_done

find_wild_connection_not_deleted:
    mov ax,SEG data
    mov ds,ax
    LeaveSection ds:ListSection
    pop ds
    clc

find_wild_connection_done:
    pop ax
    pop es
    ret
FindWildConnection      Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CreateListen
;
;       Purpose:        Create a listen and link it
;
;       Parameters:         AX      Max connections
;                       ECX         buffer size
;                       SI          local port
;
;       Returns:        DS          listen selector
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CreateListen    Proc near
    push es
    push dx
;
    push eax
    mov eax,SIZE tcp_listen
    AllocateSmallGlobalMem
    pop eax
;       
    push si
    mov si,es
    mov ds,si
    InitSection ds:tcp_listen_section
    pop si
;       
    mov es:tcp_listen_port,si
    mov es:tcp_listen_max_conn,ax
    mov es:tcp_listen_conn_count,0
    mov es:tcp_listen_buffer_size,ecx
    mov es:tcp_listen_list,0
    mov es:tcp_listen_wait,0
    mov dx,SEG data
    mov ds,dx
    EnterSection ds:ListSection
    mov dx,ds:ListenList
    mov es:tcp_listen_next,dx
    mov ds:ListenList,es
    LeaveSection ds:ListSection
    mov dx,es
    mov ds,dx
;
    pop dx
    pop es
    ret 
CreateListen    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           DeleteListen
;
;       Purpose:        Delete a listen. Listen section
;           must be taken prior to call
;
;       Parameters:         DS          listen selector
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DeleteListen    Proc near
    push es
    push ax
    push bx
    push ecx
    push edx
;
    mov dx,ds:tcp_listen_next
    mov bx,ds
    mov es,bx
;
    mov ax,SEG data
    mov ds,ax
    EnterSection ds:ListSection
;       
    mov ax,ds:ListenList
    cmp ax,bx
    jne delete_listen_loop
;
    mov ds:ListenList,dx
    jmp delete_listen_unlinked

delete_listen_loop:
    or ax,ax
    jz delete_listen_unlinked
;       
    mov ds,ax
    mov cx,ax
    mov ax,ds:tcp_listen_next
    cmp ax,bx
    jne delete_listen_loop
;
    mov ds,cx
    mov ds:tcp_listen_next,bx
;
    mov ax,ds:tcp_listen_list
    or ax,ax
    jz delete_listen_unlinked
;
    mov ds,ax

delete_listen_connections:
    mov dx,ds:tcp_next
;
    mov ax,ds:tcp_receive_buffer
    call FreeBuffer
;
    mov ax,ds:tcp_send_buffer
    call FreeBuffer
;
    push es
    mov ax,ds
    mov es,ax
    mov ds,dx
    FreeMem
    pop es
    jmp delete_listen_connections    

delete_listen_unlinked:
    mov ax,SEG data
    mov ds,ax
    LeaveSection ds:ListSection
    FreeMem
;
    pop edx
    pop ecx
    pop bx
    pop ax
    pop es
    ret
DeleteListen    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           FindListen
;
;       Purpose:        Look for a listen request
;
;       Parameters:         SI          local port
;                       
;       Returns:        NC          connection found
;                       DS          listen request
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FindListen      Proc near
    push es
    push ax
;
    mov ax,SEG data
    mov ds,ax
    EnterSection ds:ListSection
    mov ax,ds:ListenList

find_listen_loop:
    or ax,ax
    jz find_listen_fail
    mov es,ax
    cmp si,es:tcp_listen_port
    je find_listen_ok
find_listen_next:
    mov ax,es:tcp_listen_next
    jmp find_listen_loop

find_listen_fail:
    LeaveSection ds:ListSection
    stc
    jmp find_listen_done

find_listen_ok:
    LeaveSection ds:ListSection
    mov ax,es
    mov ds,ax
    clc

find_listen_done:
    pop ax
    pop es
    ret
FindListen      Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           UpdateRto
;
;       Purpose:        Update Round trip time meassurement
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

UpdateRto       Proc near
    GetSystemTime
    sub eax,ds:tcp_time_val
    cmp eax,1193000
    ja update_rto_rtt_ok
;       
    mov edx,ds:tcp_rtt
    add edx,eax
    sar edx,1
    mov ds:tcp_rtt,edx

update_rto_rtt_ok:
    sub eax,ds:tcp_rts
    mov edx,eax
    jae update_rto_err_ok
    neg eax
update_rto_err_ok:
    mov ecx,ds:tcp_rtm
    sub eax,ecx
    sar eax,2
    add ds:tcp_rtm,eax
;
    sar edx,3
    add ds:tcp_rts,edx
;
    mov eax,ds:tcp_rtm
    sal eax,2
    add eax,ds:tcp_rts
    cmp eax,240 * 1193000
    jb update_rto_small
    mov eax,240 * 1193000
update_rto_small:
    mov ds:tcp_rto,eax
    ret
UpdateRto       Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           IgnoreDummy
;
;       Purpose:        Igonre (dummy proc)
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

IgnoreDummy     Proc near
    ret
IgnoreDummy     Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           SetResendTimeout
;
;       Purpose:        Setup resend timeout
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SetResendTimeout    Proc near
    push ecx
    mov eax,ds:tcp_rto
    add eax,119300 / 2
    xor edx,edx
    mov ecx,119300
    div ecx
    add ax,1
    mov ds:tcp_resend_timeout,ax
    pop ecx
    ret
SetResendTimeout    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           SetSendTimeout
;
;       Purpose:        Setup send timeout
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SetSendTimeout  Proc near
    push eax
    push ecx
    push edx
;
    mov ax,ds:tcp_send_timeout
    or ax,ax
    jnz set_send_timeout_done
;
    mov eax,ds:tcp_rtt
    add eax,119300 / 2
    xor edx,edx
    mov ecx,119300
    div ecx
    add ax,1
    mov ds:tcp_send_timeout,ax

set_send_timeout_done:
    pop edx
    pop ecx
    pop eax
    ret
SetSendTimeout  Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           SendAck
;
;       Purpose:        Send an ACK segment (possibly with data)
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SendAck Proc near
    push es
    push di
;
    mov ds:tcp_send_timeout,0
    and ds:tcp_pending,NOT FLAG_DELAY_ACK
    movzx ecx,ds:tcp_send_count
    or cx,cx
    jnz send_ack_and_data
;
    and ds:tcp_pending, NOT FLAG_RESENT
    call CreateSegment
    mov es:[di].tcp_flags, ACK
    mov eax,ds:tcp_send_next
    Reverse
    mov es:[di].tcp_seq,eax
    mov eax,ds:tcp_rcv_next
    Reverse
    mov es:[di].tcp_ack,eax
    test ds:tcp_pending,FLAG_CLOSING
    jz send_ack_no_fin
;
    and ds:tcp_pending,NOT FLAG_CLOSING
    inc ds:tcp_send_next
    mov es:[di].tcp_flags, ACK OR FIN

send_ack_no_fin:
    test ds:tcp_pending,FLAG_SEND_PUSH
    jz send_ack_no_push
;
    and ds:tcp_pending, NOT FLAG_SEND_PUSH
    or es:[di].tcp_flags, PSH

send_ack_no_push:
    call SendSegment
    jmp send_ack_done

send_ack_and_data:
    test ds:tcp_pending,FLAG_RESENT
    jnz send_ack_no_rtt
;
    mov eax,ds:tcp_time_seq
    sub eax,ds:tcp_send_una
    jg send_ack_no_rtt
;
    call UpdateRto
    GetSystemTime
    mov ds:tcp_time_val,eax 
    mov eax,ds:tcp_send_next
    mov ds:tcp_time_seq,eax

send_ack_no_rtt:
    movzx ecx,ds:tcp_send_count
    movzx eax,ds:tcp_send_wnd
    cmp eax,ds:tcp_cwnd
    jb send_ack_cong_ok
    mov eax,ds:tcp_cwnd
send_ack_cong_ok:
    add eax,ds:tcp_send_una
    sub eax,ds:tcp_send_next
;
    cmp ecx,eax
    jb send_ack_check_mtu
;
    mov ecx,eax

send_ack_check_mtu:
    movzx eax,ds:tcp_mtu
    cmp ecx,eax
    jc send_ack_size_ok
;
    mov ecx,eax

send_ack_size_ok:
    call CreateSegment
    mov es:[di].tcp_flags, ACK
    mov eax,ds:tcp_send_next
    Reverse
    mov es:[di].tcp_seq,eax
    mov eax,ds:tcp_rcv_next
    Reverse
    mov es:[di].tcp_ack,eax
    add ds:tcp_send_next,ecx
;
    test ds:tcp_pending,FLAG_CLOSING
    jz send_ack_data_no_fin
;
    cmp cx,ds:tcp_send_count
    jne send_ack_data_no_fin
;
    and ds:tcp_pending,NOT FLAG_CLOSING
    inc ds:tcp_send_next
    mov es:[di].tcp_flags, ACK OR FIN

send_ack_data_no_fin:
    cmp cx,ds:tcp_send_count
    jne send_ack_data_no_push
;
    test ds:tcp_pending,FLAG_SEND_PUSH
    jz send_ack_data_no_push
;
    and ds:tcp_pending, NOT FLAG_SEND_PUSH
    or es:[di].tcp_flags, PSH

send_ack_data_no_push:
    push fs
    push cx
    push di
;
    add di,SIZE tcp_header
    mov fs,ds:tcp_send_buffer
    or cx,cx
    jz send_ack_do
;
    movzx edi,di
    sub ds:tcp_send_count,cx
    mov bx,ds:tcp_send_head
    call CopyFromBuffer
    mov ds:tcp_send_head,bx

send_ack_do:
    pop di
    pop cx
    pop fs
    call SendSegment

send_ack_done:
    pop di
    pop es
    ret
SendAck Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           SendData
;
;       Purpose:        Send a data segment if Nagle permits
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SendData    Proc near
    test ds:tcp_pending,FLAG_DELETE_NET
    jnz send_data_done
;    
    test ds:tcp_pending,FLAG_CLOSING
    jnz send_data_do
;
    movzx ecx,ds:tcp_send_count
    movzx eax,ds:tcp_send_wnd
    add eax,ds:tcp_send_una
    sub eax,ds:tcp_send_next
    movzx edx,ds:tcp_mtu
    cmp edx,eax
    ja send_data_check2
    cmp dx,cx
    jbe send_data_do

send_data_check2:
    cmp eax,ecx
    jb send_data_check3
;
    test ds:tcp_pending,FLAG_SEND_PUSH
    jz send_data_check3
;
    mov eax,ds:tcp_send_una
    cmp eax,ds:tcp_send_next
    je send_data_do

send_data_check3:
    movzx edx,ds:tcp_send_max_wnd
    shr edx,1
    cmp edx,eax
    ja send_data_check4
    cmp dx,cx
    jbe send_data_do

send_data_check4:
    test ds:tcp_pending,FLAG_SEND_PUSH
    jz send_data_done
;
    cmp ds:tcp_push_timeout,0
    jnz send_data_done

send_data_do:
    movzx eax,ds:tcp_send_wnd
    cmp eax,ds:tcp_cwnd
    jb send_data_cong_ok
    mov eax,ds:tcp_cwnd
send_data_cong_ok:
    add eax,ds:tcp_send_una
    sub eax,ds:tcp_send_next
    jbe send_data_done
;
    call SendAck
    
send_data_done:
    ret
SendData    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           RetransmitSynSent
;
;       Purpose:        Retransmit in SYN-SENT state
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RetransmitSynSent       Proc near
    mov ax,ds:tcp_remote_port
    or ax,ax
    jz rssDone
;
    xor ecx,ecx
    call CreateSegment
    jc rssDone
;       
    mov es:[di].tcp_flags, SYN
    mov eax,ds:tcp_iss
    Reverse
    mov es:[di].tcp_seq,eax
    call SendSegment

rssDone:
    ret
RetransmitSynSent       Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           RetransmitSynRcvd
;
;       Purpose:        Retransmit in SYN-RCVD state
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RetransmitSynRcvd       Proc near
    xor ecx,ecx
    call CreateSegment
    mov es:[di].tcp_flags, SYN OR ACK
    mov eax,ds:tcp_iss
    Reverse
    mov es:[di].tcp_seq,eax
    mov eax,ds:tcp_rcv_next
    Reverse
    mov es:[di].tcp_ack,eax
    call SendSegment
    ret
RetransmitSynRcvd       Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           RetransmitData
;
;       Purpose:        Retransmit data
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RetransmitData  Proc near
    mov ecx,ds:tcp_send_next
    sub ecx,ds:tcp_send_una
    movzx eax,ds:tcp_mtu
    cmp ecx,eax
    jb retrans_data_mtu_ok
;
    mov ecx,eax

retrans_data_mtu_ok:
    call CreateSegment
    mov es:[di].tcp_flags, ACK
;
    test ds:tcp_pending,FLAG_CLOSING
    jz retrans_data_no_fin
;
    mov ax,ds:tcp_send_count
    or ax,ax
    jnz retrans_data_no_fin
;
    mov eax,ds:tcp_send_next
    sub eax,ds:tcp_send_una
    cmp eax,ecx
    jne retrans_data_no_fin
;
    mov es:[di].tcp_flags, ACK OR FIN

retrans_data_no_fin:
    mov eax,ds:tcp_send_una
    Reverse
    mov es:[di].tcp_seq,eax
    mov eax,ds:tcp_rcv_next
    Reverse
    mov es:[di].tcp_ack,eax
;
    push fs
    push cx
    push di
;
    add di,SIZE tcp_header
    mov fs,ds:tcp_send_buffer
    mov bx,ds:tcp_send_head
    mov eax,ds:tcp_send_next
    sub eax,ds:tcp_send_una
    sub bx,ax
    jnc retrans_data_copy
;
    add bx,ds:tcp_buffer_size

retrans_data_copy:
    or cx,cx
    jz retrans_data_do
;
    movzx edi,di
    call CopyFromBuffer

retrans_data_do:
    pop di
    pop cx
    pop fs
    call SendSegment

retrans_data_done:
    ret
RetransmitData  Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           Retransmit
;
;       Purpose:        Retransmit data
;
;       Parameters:         DS          Connection
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

retransmit_tab:
rt0     DW OFFSET RetransmitSynSent
rt1 DW OFFSET RetransmitSynRcvd
rt2 DW OFFSET RetransmitData
rt3     DW OFFSET RetransmitData
rt4     DW OFFSET IgnoreDummy
rt5 DW OFFSET RetransmitData
rt6 DW OFFSET RetransmitData
rt7 DW OFFSET IgnoreDummy
rt8 DW OFFSET IgnoreDummy

Retransmit      Proc near
    push es
    push cx
    push di
;
    test ds:tcp_pending,FLAG_DELETE_NET OR FLAG_DELETE_USER
    jnz retrans_done
;    
    test ds:tcp_pending,FLAG_RETRY
    jz retrans_first
;
    mov ax,ds:tcp_retries
    cmp ax,10
    ja retrans_close
;
    inc ax
    mov ds:tcp_retries,ax
    jmp retrans_do    

retrans_close:    
    or ds:tcp_pending,FLAG_DELETE_NET
    mov bx,ds:tcp_owner
    Signal
;
    mov bx,ds:tcp_writer
    or bx,bx
    jz retrans_no_writer
;
    Signal

retrans_no_writer:
    mov bx,ds:tcp_wait  
    or bx,bx
    jz retrans_done
;
    push es
    mov es,bx
    SignalWait
    mov ds:tcp_wait,0
    pop es
    jmp retrans_done

retrans_first:
    mov ds:tcp_retries,0

retrans_do:
    or ds:tcp_pending,FLAG_RESENT OR FLAG_RETRY
    and ds:tcp_pending,NOT FLAG_DELAY_ACK
    call SetResendTimeout
;
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].retransmit_tab

retrans_done:
    pop di
    pop cx
    pop es
    ret
Retransmit      Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CheckSeq
;
;       Purpose:        Check if an SEQ is acceptable
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckSeq    Proc near
    mov eax,es:[di].tcp_seq
    Reverse
    mov edx,eax
;
    or cx,cx
    jz check_seq_no_data
;
    mov ax,ds:tcp_buffer_size
    sub ax,ds:tcp_receive_count
    jz check_seq_bad
;
    movzx eax,ax
    add eax,ds:tcp_rcv_next
    cmp edx,eax
    jg check_seq_test2
;
    cmp edx,ds:tcp_rcv_next
    jge check_seq_ok

check_seq_test2:
    movzx ecx,cx
    add edx,ecx
    dec edx
;
    mov ax,ds:tcp_buffer_size
    sub ax,ds:tcp_receive_count
    movzx eax,ax
    add eax,ds:tcp_rcv_next
    cmp edx,eax
    jg check_seq_bad
;
    cmp edx,ds:tcp_rcv_next
    jg check_seq_ok
    jmp check_seq_bad

check_seq_no_data:
    mov ax,ds:tcp_buffer_size
    sub ax,ds:tcp_receive_count
    jz check_seq_both_zero
;
    movzx eax,ax
    add eax,ds:tcp_rcv_next
    cmp edx,eax
    jg check_seq_bad
;
    cmp edx,ds:tcp_rcv_next
    jge check_seq_ok
    jmp check_seq_bad

check_seq_both_zero:
    mov eax,es:[di].tcp_seq
    Reverse
    cmp eax,ds:tcp_rcv_next
    je check_seq_ok

check_seq_bad:
    mov al,es:[di].tcp_flags
    test al,RST
    jnz check_seq_fail
;
    or ds:tcp_pending,FLAG_ACK

check_seq_fail:
    stc
    ret

check_seq_ok:
    clc
    ret
CheckSeq    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CheckRst
;
;       Purpose:        Check for RST
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckRst    Proc near
    mov al,es:[di].tcp_flags
    test al,RST
    clc
    jz check_rst_done
;
    or ds:tcp_pending,FLAG_DELETE_NET
    mov bx,ds:tcp_owner
    Signal
;
    mov bx,ds:tcp_writer
    or bx,bx
    jz check_rst_no_writer
;
    Signal

check_rst_no_writer:
    mov bx,ds:tcp_wait  
    or bx,bx
    jz check_rst_ok
;
    push es
    mov es,bx
    SignalWait
    mov ds:tcp_wait,0
    pop es

check_rst_ok:
    stc

check_rst_done:
    ret
CheckRst    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CheckSyn
;
;       Purpose:        Check for SYN
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CheckSyn    Proc near
    mov al,es:[di].tcp_flags
    test al,SYN
    clc
    jz check_syn_done
;
    or ds:tcp_pending,FLAG_DELETE_NET
    mov bx,ds:tcp_owner
    Signal
    stc

check_syn_done:
    ret
CheckSyn    Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           InitConnection
;
;       Purpose:        Init connection
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

InitConnection  Proc near
    test ds:tcp_pending,FLAG_WAIT
    jz init_con_nowait
;
    and ds:tcp_pending,NOT FLAG_WAIT
    mov bx,ds:tcp_owner
    Signal

init_con_nowait:
    movzx eax,ds:tcp_mtu
    add eax,eax
    mov edx,eax
    cmp edx,4380
    ja iw_max_ok
;
    mov edx,4380    

iw_max_ok:
    add eax,eax
    cmp eax,edx
    jb iw_min_ok
;
    mov eax,edx    

iw_min_ok:
    mov ds:tcp_cwnd,eax
    mov ds:tcp_ssthresh,10000h
    mov ds:tcp_dup_acks,0
;
    mov eax,es:[di].tcp_seq
    Reverse
    mov ds:tcp_send_wl1,eax
    mov eax,es:[di].tcp_ack
    Reverse
    mov ds:tcp_send_wl2,eax
;
    mov ax,es:[di].tcp_window
    xchg al,ah
    mov ds:tcp_send_wnd,ax
    mov ds:tcp_send_max_wnd,ax
    ret
InitConnection  Endp

        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           NewAck
;
;       Purpose:        Handle new ACK
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NewAck  Proc near
    mov ax,es:[di].tcp_window
    xchg al,ah
    mov ds:tcp_send_wnd,ax
    cmp ax,ds:tcp_send_max_wnd
    jb new_ack_not_max_wnd
    mov ds:tcp_send_max_wnd,ax
new_ack_not_max_wnd:
    mov eax,es:[di].tcp_seq
    Reverse
    mov ds:tcp_send_wl1,eax
    mov eax,es:[di].tcp_ack
    Reverse
    mov ds:tcp_send_wl2,eax
;
    xor ax,ax
    xchg ax,ds:tcp_dup_acks
    cmp ax,3
    jb new_ack_congestion
;
    mov eax,ds:tcp_cwnd
    mov ds:tcp_ssthresh,eax
    jmp new_ack_done

new_ack_congestion:
    mov eax,ds:tcp_cwnd
    cmp eax,ds:tcp_ssthresh
    jbe new_ack_slow_start
;
    mov eax,es:[di].tcp_ack
    Reverse
    sub eax,ds:tcp_send_una
    jl new_ack_done
;       
    mul eax
    div ds:tcp_cwnd
    add ds:tcp_cwnd,eax
    jmp new_ack_done

new_ack_slow_start:
    movzx edx,ds:tcp_mtu
    add eax,edx
    mov ds:tcp_cwnd,eax

new_ack_done:
    ret
NewAck  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           DuplicateAck
;
;       Purpose:        Handle duplicate ACK
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DuplicateAck    Proc near
    mov ax,ds:tcp_dup_acks
    inc ax
    mov ds:tcp_dup_acks,ax
    cmp ax,3
    jb dupl_ack_congestion
    jne dupl_ack_not3

dupl_ack3:
    mov eax,ds:tcp_cwnd
    shr eax,1
    movzx edx,ds:tcp_mtu
    add edx,edx
    cmp eax,edx
    ja dupl_ack3_set_thresh
    mov eax,edx
dupl_ack3_set_thresh:
    mov ds:tcp_ssthresh,eax
    add eax,edx
    movzx edx,ds:tcp_mtu
    add eax,edx
    mov ds:tcp_cwnd,eax
    call Retransmit
    jmp dupl_ack_done

dupl_ack_not3:
    movzx eax,ds:tcp_mtu
    add ds:tcp_cwnd,eax
    jmp dupl_ack_done

dupl_ack_congestion:
    mov dx,es:[di].tcp_window
    xchg dl,dh
    movzx edx,dx
;
    mov eax,ds:tcp_cwnd
    cmp eax,edx
    jb dupl_ack_min_ok
    mov eax,edx
dupl_ack_min_ok:
    movzx edx,ds:tcp_mtu
    add edx,edx
    shr eax,1
    cmp eax,edx
    ja upd_thres_size_ok
    mov eax,edx
upd_thres_size_ok:
    mov ds:tcp_ssthresh,eax

dupl_ack_done:
    ret
DuplicateAck    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           UpdateSendWnd
;
;       Purpose:        Update send window
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

UpdateSendWnd   Proc near
    mov eax,es:[di].tcp_ack
    Reverse
    cmp eax,ds:tcp_send_next
    jg update_send_wnd_fail

update_send_wnd_ok:
    cmp eax,ds:tcp_send_una
    jle update_send_wnd_old
;
    mov eax,es:[di].tcp_seq
    Reverse
    cmp eax,ds:tcp_send_wl1
    jg update_send_wnd_new
    jne update_send_wnd_old
;
    mov eax,es:[di].tcp_ack
    Reverse
    cmp eax,ds:tcp_send_wl2
    jl update_send_wnd_old

update_send_wnd_new:
    call NewAck
    call SetResendTimeout
;
    mov eax,es:[di].tcp_ack
    Reverse
    mov ds:tcp_send_una,eax
    clc
    jmp update_send_wnd_done

update_send_wnd_old:
    mov ax,es:[di].tcp_window
    xchg al,ah
    cmp ax,ds:tcp_send_wnd
    jne update_send_wnd_new
;
    mov eax,ds:tcp_send_una
    cmp eax,ds:tcp_send_next
    je update_send_wnd_empty
;
    call DuplicateAck
    clc
    jmp update_send_wnd_done

update_send_wnd_empty:
    mov ds:tcp_dup_acks,0
    clc
    jmp update_send_wnd_done

update_send_wnd_fail:
    or ds:tcp_pending,FLAG_ACK
    stc

update_send_wnd_done:
    ret
UpdateSendWnd   Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           UpdateReceiveWnd
;
;       Purpose:        Update receive window
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

UpdateReceiveWnd    Proc near
    mov ax,ds:tcp_buffer_size
    mov dx,ax
    sub ax,ds:tcp_receive_count
    sub ax,ds:tcp_rcv_wnd
    shr dx,1
    cmp ax,dx
    jb update_rec_wnd_done
;
    cmp ax,ds:tcp_mtu
    jb update_rec_wnd_done
;
    mov ds:tcp_rcv_wnd,ax
    or ds:tcp_pending,FLAG_ACK
    
update_rec_wnd_done:
    ret
UpdateReceiveWnd    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           InsertReordered
;
;       Purpose:        Insert reordered data
;
;       Parameters:         DS          Connection
;                       EAX         Sequence number
;                       CX          Size of data
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

InsertReordered Proc near
    push esi
    push edi
;
    movzx esi,cx
    mov edi,eax
;
    mov bx,OFFSET tcp_reorder_arr
    mov cx,ds:tcp_reorder_count
    or cx,cx
    jz insert_reorder_do

insert_reorder_loop:
    mov edx,ds:[bx].reorder_seq
    cmp eax,edx
    jl insert_reorder_do
;
    add edx,ds:[bx].reorder_size
    cmp eax,edx
    jg insert_reorder_next
;
    add eax,esi
    cmp eax,edx
    jle insert_reorder_done
;
    mov eax,esi
    add eax,edi
    sub eax,ds:[bx].reorder_seq
    mov ds:[bx].reorder_size,eax
    jmp insert_reorder_check_merge

insert_reorder_next:
    add bx,8
    loop insert_reorder_loop

insert_reorder_do:
    mov dx,ds:tcp_reorder_count
    cmp dx,REORDER_ENTRIES
    jne insert_reorder_not_full
;
    sub cx,1
    jc insert_reorder_done
;
    dec ds:tcp_reorder_count

insert_reorder_not_full:
    inc ds:tcp_reorder_count
    mov dx,cx
    shl dx,3
    add bx,dx
    push cx
;
    or cx,cx
    jz insert_reorder_add

insert_reorder_move_fwd:
    mov edx,ds:[bx-8]
    mov ds:[bx],edx
    mov edx,ds:[bx-4]
    mov ds:[bx+4],edx
    sub bx,8
    loop insert_reorder_move_fwd

insert_reorder_add:
    pop cx
    inc cx
    mov ds:[bx].reorder_seq,edi
    mov ds:[bx].reorder_size,esi

insert_reorder_check_merge:
    cmp cx,1
    jbe insert_reorder_done
;
    mov eax,ds:[bx].reorder_seq
    add eax,ds:[bx].reorder_size
    cmp eax,ds:[bx+8].reorder_seq
    jl insert_reorder_done
;
    mov eax,ds:[bx+8].reorder_seq
    add eax,ds:[bx+8].reorder_size
    sub eax,ds:[bx].reorder_seq
    cmp eax,ds:[bx].reorder_size
    jb insert_reorder_size_ok
;
    mov ds:[bx].reorder_size,eax

insert_reorder_size_ok:
    dec cx
    dec ds:tcp_reorder_count
;
    or cx,cx
    jz insert_reorder_done

    push bx
    push cx
insert_reorder_move_back:
    add bx,8
    mov eax,ds:[bx+8]
    mov ds:[bx],eax
    mov eax,ds:[bx+12]
    mov ds:[bx+4],eax
    loop insert_reorder_move_back
;
    pop cx
    pop bx
    jmp insert_reorder_check_merge

insert_reorder_done:
    pop edi
    pop esi
    ret
InsertReordered Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ProcessData
;
;       Purpose:        Process received data
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ProcessData     Proc near;
    mov al,es:[di].tcp_flags
    test al,FIN
    clc
    jz process_data_no_fin
;
    or ds:tcp_pending, FLAG_REC_FIN
    mov eax,es:[di].tcp_seq
    Reverse
    movzx ecx,cx
    add eax,ecx
    mov ds:tcp_fin_seq,eax

process_data_no_fin:
    or cx,cx
    jnz process_data_available
;
    test ds:tcp_pending, FLAG_REC_FIN
    jnz process_data_check_fin
;
    mov al,es:[di].tcp_flags
    test al,PSH
    jz process_data_done
;
    or ds:tcp_pending,FLAG_REC_PUSH
    jmp process_data_check_fin

process_data_available:
    mov fs,ds:tcp_receive_buffer
    mov bx,ds:tcp_receive_tail
    mov eax,es:[di].tcp_seq
    Reverse
    sub eax,ds:tcp_rcv_next
    jg process_data_in_future
;
    neg ax
    add si,ax
    sub cx,ax
    jc process_data_done
;
    mov dx,ds:tcp_buffer_size
    mov ax,dx
    sub ax,ds:tcp_receive_count
    cmp cx,ax
    jbe process_data_do
    mov cx,ax
    jmp process_data_do

process_data_in_future:
    or ds:tcp_pending,FLAG_ACK
    add bx,ax
    cmp bx,ds:tcp_buffer_size
    jc process_data_future_nowrap
;
    sub bx,ds:tcp_buffer_size

process_data_future_nowrap:
    mov dx,ax
    mov ax,ds:tcp_buffer_size
    sub ax,dx
    sub ax,ds:tcp_receive_count
    cmp cx,ax
    jbe process_data_do
    mov cx,ax
    
process_data_do:
    push cx
    push bx
;
    mov eax,es:[di].tcp_seq
    Reverse
    cmp eax,ds:tcp_rcv_next
    jg process_data_reorder
;
    mov eax,ds:tcp_rcv_next

process_data_reorder:
    call InsertReordered
    pop bx
    pop cx
;
    movzx esi,si
    call CopyToBuffer

process_data_moved:
    mov eax,ds:tcp_reorder_arr.reorder_seq
    cmp eax,ds:tcp_rcv_next
    jg process_data_empty
;
    add eax,ds:tcp_reorder_arr.reorder_size
    sub eax,ds:tcp_rcv_next
    add ds:tcp_rcv_next,eax
    mov bx,ds:tcp_receive_tail
    add bx,ax
    cmp bx,ds:tcp_buffer_size
    jc process_data_new_tail_ok
;
    sub bx,ds:tcp_buffer_size

process_data_new_tail_ok:
    mov ds:tcp_receive_tail,bx
    add ds:tcp_receive_count,ax
    sub ds:tcp_rcv_wnd,ax
;
    call UpdateReceiveWnd
    test ds:tcp_pending,FLAG_DELAY_ACK
    jnz process_data_delay_ack_ok
    
    or ds:tcp_pending,FLAG_DELAY_ACK
    mov ds:tcp_ack_timeout,4

process_data_delay_ack_ok:
    mov cx,ds:tcp_reorder_count
    sub cx,1
    mov ds:tcp_reorder_count,cx
    jz process_data_empty
;
    mov bx,OFFSET tcp_reorder_arr

process_data_reorder_remove_loop:
    mov eax,ds:[bx+8]
    mov ds:[bx],eax
    mov eax,ds:[bx+12]
    mov ds:[bx+4],eax
    loop process_data_reorder_remove_loop

process_data_empty:
    mov al,es:[di].tcp_flags
    test al,PSH
    jz process_data_check_fin
;
    or ds:tcp_pending,FLAG_REC_PUSH

process_data_check_fin:
    test ds:tcp_pending, FLAG_REC_FIN
    jz process_data_wake
;
    mov eax,ds:tcp_rcv_next
    cmp eax,ds:tcp_fin_seq
    jl process_data_wake
;
    mov eax,ds:tcp_fin_seq
    inc eax
    mov ds:tcp_rcv_next,eax
    or ds:tcp_pending, FLAG_DELAY_ACK OR FLAG_CLOSED

process_data_wake:
    mov bx,ds:tcp_owner
    Signal
;
    mov bx,ds:tcp_wait  
    or bx,bx
    jz process_data_done
;
    push es
    mov es,bx
    SignalWait
    mov ds:tcp_wait,0
    pop es

process_data_done:
    ret
ProcessData     Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveListen
;
;       Purpose:        Received data in LISTEN state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveListen   Proc near
    mov eax,es:[di].tcp_seq
    Reverse
    inc eax
    mov ds:tcp_rcv_next,eax
;
    mov eax,ds:tcp_iss
    mov ds:tcp_send_una,eax
    inc eax
    mov ds:tcp_send_next,eax    
    mov ds:tcp_state,STATE_SYN_RCVD
;
    xor ecx,ecx
    call CreateSegment
    mov es:[di].tcp_flags, SYN OR ACK
    mov eax,ds:tcp_iss
    Reverse
    mov es:[di].tcp_seq,eax
    mov eax,ds:tcp_rcv_next
    Reverse
    mov es:[di].tcp_ack,eax
    call SendSegment
    ret
ReceiveListen   Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveSynSent
;
;       Purpose:        Received data in SYN-SENT state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveSynSent  Proc near
    mov dl,es:[di].tcp_flags
    test dl,ACK
    jz receive_syn_sent_noack
;
    mov eax,es:[di].tcp_ack
    Reverse
    cmp eax,ds:tcp_iss
    jle receive_syn_sent_reset
;
    cmp eax,ds:tcp_send_next
    jg receive_syn_sent_reset
;
    mov dl,es:[di].tcp_flags
    test dl,RST
    jz receive_syn_sent_norst
;
    or ds:tcp_pending,FLAG_DELETE_NET
    mov bx,ds:tcp_owner
    Signal
    jmp receive_syn_sent_done

receive_syn_sent_noack:
    test dl,RST
    jnz receive_syn_sent_done

receive_syn_sent_norst:
    test dl,SYN
    jz receive_syn_sent_done
;
    mov eax,es:[di].tcp_seq
    Reverse
    inc eax
    mov ds:tcp_rcv_next,eax
;
    test dl,ACK
    jz receive_syn_sent_answer
;
    mov eax,es:[di].tcp_ack
    Reverse
    mov ds:tcp_send_una,eax

receive_syn_sent_answer:
    mov eax,ds:tcp_send_una
    cmp eax,ds:tcp_iss
    jg receive_syn_sent_ok
;
    mov ds:tcp_state, STATE_SYN_RCVD
    xor ecx,ecx
    call CreateSegment
    mov es:[di].tcp_flags, SYN OR ACK
    mov eax,ds:tcp_iss
    Reverse
    mov es:[di].tcp_seq,eax
    mov eax,ds:tcp_rcv_next
    Reverse
    mov es:[di].tcp_ack,eax
    call SendSegment
    jmp receive_syn_sent_done

receive_syn_sent_ok:
    mov ds:tcp_state, STATE_ESTAB
    or ds:tcp_pending, FLAG_DELAY_ACK
    mov ds:tcp_ack_timeout,4
    call InitConnection
    call SendAck
    jmp receive_syn_sent_done

receive_syn_sent_reset:
    mov al,es:[di].tcp_flags
    test al,RST
    jnz receive_syn_sent_done
;
    xor ecx,ecx
    push es:[di].tcp_ack
    call CreateSegment
    mov es:[di].tcp_flags, RST
    pop es:[di].tcp_seq
    call SendSegment

receive_syn_sent_done:
    ret
ReceiveSynSent  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveSynRcvd
;
;       Purpose:        Received data in SYN-RCVD state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveSynRcvd  Proc near
    call CheckSeq
    jc receive_syn_rcvd_done
;
    call CheckRst
    jc receive_syn_rcvd_done
;
    call CheckSyn
    jc receive_syn_rcvd_done
;
    test es:[di].tcp_flags, ACK
    jz receive_syn_rcvd_done
;
    mov eax,es:[di].tcp_ack
    Reverse
    cmp eax,ds:tcp_send_una
    jl receive_syn_rcvd_reset
;
    cmp eax,ds:tcp_send_next
    jle receive_syn_rcvd_ack_ok

receive_syn_rcvd_reset:
    xor ecx,ecx
    push es:[di].tcp_ack
    call CreateSegment
    mov es:[di].tcp_flags, RST
    pop es:[di].tcp_seq
    call SendSegment
    jmp receive_syn_rcvd_done

receive_syn_rcvd_ack_ok:
    mov ds:tcp_state,STATE_ESTAB
    call InitConnection
    call UpdateSendWnd
    jc receive_syn_rcvd_done
;
    mov al,es:[di].tcp_flags
    test al,FIN
    clc
    jz receive_syn_rcvd_done
;
    or ds:tcp_pending, FLAG_REC_FIN OR FLAG_ACK OR FLAG_CLOSED
    mov eax,es:[di].tcp_seq
    Reverse
    cmp eax,ds:tcp_rcv_next
    jne receive_syn_rcvd_done
;
    inc ds:tcp_rcv_next
    mov ds:tcp_state,STATE_CLOSE_WAIT

receive_syn_rcvd_done:
    ret
ReceiveSynRcvd  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveEstab
;
;       Purpose:        Received data in ESTABLISHED state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveEstab    Proc near
    call CheckSeq
    jc receive_estab_done
;
    call CheckRst
    jc receive_estab_done
;
    test es:[di].tcp_flags, SYN
    jz receive_estab_normal
;
    test es:[di].tcp_flags, ACK
    jz receive_estab_done
;
    and ds:tcp_pending,NOT FLAG_ACK
    call SendAck
    jmp receive_estab_done

receive_estab_normal:
    test es:[di].tcp_flags, ACK
    jz receive_estab_done
;
    call UpdateSendWnd
    jc receive_estab_done
;
    call ProcessData
;
    test ds:tcp_pending, FLAG_CLOSED
    jz receive_estab_done
;
    mov ds:tcp_state,STATE_CLOSE_WAIT
    
receive_estab_done:
    ret
ReceiveEstab    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveFinWait1
;
;       Purpose:        Received data in FIN-WAIT1 state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveFinWait1 Proc near
    call CheckSeq
    jc receive_fin_wait1_done
;
    call CheckRst
    jc receive_fin_wait1_done
;
    call CheckSyn
    jc receive_fin_wait1_done
;
    test es:[di].tcp_flags, ACK
    jz receive_fin_wait1_done
;
    call UpdateSendWnd
    jc receive_fin_wait1_done
;
    call ProcessData
;
    test ds:tcp_pending, FLAG_CLOSED
    jz receive_fin_wait1_done
;
    mov al,ds:tcp_state
    cmp al,STATE_FIN_WAIT1
    je receive_fin_wait1_not_acked
;
    mov ds:tcp_state,STATE_TIME_WAIT
    mov ds:tcp_delete_timeout,240 * 10
    jmp receive_fin_wait1_done

receive_fin_wait1_not_acked:
    mov ds:tcp_state,STATE_CLOSING
    mov ds:tcp_delete_timeout,240 * 10

receive_fin_wait1_done:
    ret
ReceiveFinWait1 Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveFinWait2
;
;       Purpose:        Received data in FIN-WAIT2 state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveFinWait2 Proc near
    call CheckSeq
    jc receive_fin_wait2_done
;
    call CheckRst
    jc receive_fin_wait2_done
;
    call CheckSyn
    jc receive_fin_wait2_done
;
    test es:[di].tcp_flags, ACK
    jz receive_fin_wait2_done
;
    call UpdateSendWnd
    jc receive_fin_wait2_done
;
    call ProcessData
;
    test ds:tcp_pending, FLAG_CLOSED
    jz receive_fin_wait1_done
;
    mov ds:tcp_state,STATE_TIME_WAIT
    mov ds:tcp_delete_timeout,240 * 10

receive_fin_wait2_done:
    ret
ReceiveFinWait2 Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveCloseWait
;
;       Purpose:        Received data in CLOSE-WAIT state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveCloseWait    Proc near
    call CheckSeq
    jc receive_close_wait_done
;
    call CheckRst
    jc receive_close_wait_done
;
    call CheckSyn
    jc receive_close_wait_done
;
    test es:[di].tcp_flags, ACK
    jz receive_close_wait_done
;
    call UpdateSendWnd

receive_close_wait_done:
    ret
ReceiveCloseWait    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveClosing
;
;       Purpose:        Received data in CLOSING state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveClosing  Proc near
    call CheckSeq
    jc receive_closing_done
;
    call CheckRst
    jc receive_closing_done
;
    call CheckSyn
    jc receive_closing_done
;
    test es:[di].tcp_flags, ACK
    jz receive_closing_done
;
    call UpdateSendWnd
    jc receive_closing_done

receive_closing_done:
    ret
ReceiveClosing  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveLastAck
;
;       Purpose:        Received data in LAST-ACK state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveLastAck  Proc near
    call CheckSeq
    jc receive_last_ack_done
;
    call CheckRst
    jc receive_last_ack_done
;
    call CheckSyn
    jc receive_last_ack_done
;
    test es:[di].tcp_flags, ACK
    jz receive_last_ack_done
;
    mov eax,es:[di].tcp_ack
    Reverse
    cmp eax,ds:tcp_send_next
    je receive_last_ack_delete
;
    xor ecx,ecx
    call CreateSegment
    mov es:[di].tcp_flags, FIN OR ACK
    mov eax,ds:tcp_send_next
    Reverse
    mov es:[di].tcp_seq,eax
    mov eax,ds:tcp_rcv_next
    Reverse
    mov es:[di].tcp_ack,eax
    call SendSegment
    jmp receive_last_ack_done

receive_last_ack_delete:
    or ds:tcp_pending, FLAG_DELETE_NET
    mov bx,ds:tcp_owner
    Signal

receive_last_ack_done:
    ret
ReceiveLastAck  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveTimeWait
;
;       Purpose:        Received data in TIME-WAIT state
;
;       Parameters:         DS          Connection
;                       CX          Size of data
;                       EDX         Source IP address
;                       ES:SI   TCP data
;                       ES:DI   TCP header
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveTimeWait Proc near
    call CheckSeq
    jc receive_time_wait_done
;
    call CheckRst
    jc receive_time_wait_done
;
    call CheckSyn
    jc receive_time_wait_done
;
    test es:[di].tcp_flags, ACK
    jz receive_time_wait_done

receive_time_wait_done:
    ret
ReceiveTimeWait Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ProcessOptions
;
;       Purpose:        Process IP & TCP options
;
;       Parameters:         DS          Connection
;                       CX          Size of data & header
;                       EDX         Source IP address
;                       ES:SI   IP options
;                       ES:DI   TCP header
;
;       Returns:        ES:ESI  TCP data
;                       CX          Size of data
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ProcessOptions  Proc near
    movzx dx,es:[di].tcp_header_len
    shr dx,2
    sub dx,SIZE tcp_header
    or dx,dx
    jz process_options_done
;
    mov si,di
    add si,SIZE tcp_header

process_options_next:
    sub dx,1
    jz process_options_done
;
    lods byte ptr es:[si]
    or al,al
    jz process_options_done
;
    cmp al,1
    jz process_options_next
;
    cmp al,2
    je process_mtu
;
    jmp process_options_adv

process_mtu:
    mov al,es:[si]
    cmp al,4
    jne process_options_adv
;       
    inc si
    sub dx,3
    jc process_options_done
;
    lods word ptr es:[si]
    xchg al,ah
    cmp ax,ds:tcp_mtu
    ja process_options_ignore_mtu
;
    mov ds:tcp_mtu,ax

process_options_ignore_mtu:
    or dx,dx
    jz process_options_done
    jmp process_options_next

process_options_adv:
    sub dx,1
    jz process_options_done
    lods byte ptr es:[si]
    movzx ax,al
    sub al,2
    add si,ax
    sub dx,ax
    ja process_options_next

process_options_done:
    movzx ax,es:[di].tcp_header_len
    shr ax,2
    sub cx,ax
    mov si,di
    add si,ax
    ret
ProcessOptions  Endp
        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReceiveChecksum
;
;       Purpose:        Check receive checksum
;
;       Parameters:         AX          Size of options
;                       BX          Id
;                       CX          Size of data
;                       EDX         Source IP address
;                       DS:SI   Options
;                       ES:DI   Data
;
;       Returns:        NC          checksum ok
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveChecksum Proc near
    push dx
    push si
    push di
;
    mov dx,cx
    xchg dl,dh
    add dx,600h
    adc dx,0
    adc dx,0
    sub si,8
    lodsw
    add dx,ax
    lodsw
    adc dx,ax
    lodsw
    adc dx,ax
    lodsw
    adc dx,ax
    mov ax,dx
    adc ax,0
    adc ax,0
    mov si,di
    call CalcChecksum
    not ax
    or al,ah
    clc
    jz receive_checksum_done
    stc

receive_checksum_done:
    pop di
    pop si
    pop dx
    ret
ReceiveChecksum Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           Receive
;
;       Purpose:        IP callback
;
;       Parameters:         AX          Size of options
;                       BX          Id
;                       CX          Size of data
;                       EDX         Source IP address
;                       DS:SI   Options
;                       ES:DI   Data
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReceiveTab:
rt00 DW OFFSET ReceiveSynSent
rt01 DW OFFSET ReceiveSynRcvd
rt02 DW OFFSET ReceiveEstab
rt03 DW OFFSET ReceiveFinWait1
rt04 DW OFFSET ReceiveFinWait2
rt05 DW OFFSET ReceiveCloseWait
rt06 DW OFFSET ReceiveLastAck
rt07 DW OFFSET ReceiveClosing
rt08 DW OFFSET ReceiveTimeWait

Receive Proc far
    call ReceiveChecksum
    jc receive_free
;   
    push di
    mov ax,es:[di].tcp_dest
    xchg al,ah
    mov si,ax
    mov ax,es:[di].tcp_source
    xchg al,ah
    mov di,ax
    call FindConnection
    pop di
    jnc receive_connection
;
    call FindListen
    jnc receive_listen
;
    call FindWildConnection
    jc receive_no_connection
;
    mov al,es:[di].tcp_flags
    test al,SYN
    jnz receive_wild_syn

receive_leave_no_connection:
    LeaveSection ds:tcp_section
    jmp receive_no_connection

receive_wild_syn:
    mov ax,es:[di].tcp_source
    xchg al,ah
    mov ds:tcp_remote_port,ax
    jmp receive_connection
    
receive_listen:
    mov al,es:[di].tcp_flags
    test al,RST
    jnz receive_free
;
    test al,ACK
    jnz receive_no_connection
;
    test al,SYN
    jz receive_free
;
    push ds
    push ecx
    push di
    mov ax,es:[di].tcp_source
    xchg al,ah
    mov di,ax
    mov eax,120
    mov ecx,ds:tcp_listen_buffer_size
    call CreateConnection
    pop di
    pop ecx
;
    push es
    call ProcessOptions
    call ReceiveListen
    pop es
    LeaveSection ds:tcp_section
;
    mov bx,ds
    pop ds
;
    push es
    mov es,bx
    EnterSection ds:tcp_listen_section
    mov ax,ds:tcp_listen_list
    mov es:tcp_listen_link,ax
    mov ds:tcp_listen_list,es
    LeaveSection ds:tcp_listen_section
    pop es
;
    mov bx,ds:tcp_listen_wait   
    or bx,bx
    jz receive_free
;
    push es
    mov es,bx
    SignalWait
    mov ds:tcp_listen_wait,0
    pop es
    jmp receive_free

receive_connection:
    push es
    call ProcessOptions
    and ds:tcp_pending,NOT FLAG_RETRY
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].ReceiveTab
    pop es
    mov ax,ds:tcp_pending
    test ax,FLAG_ACK
    jz receive_no_ack
;
    and ax,NOT FLAG_ACK
    test ax,FLAG_DELAY_ACK
    jnz receive_delay_ack_ok
;       
    mov ds:tcp_ack_timeout,4
    or ax,FLAG_DELAY_ACK

receive_delay_ack_ok:
    mov ds:tcp_pending,ax
    jmp receive_leave

receive_no_ack:
    call SendData

receive_leave:
    mov bx,ds:tcp_writer
    or bx,bx
    jz receive_no_writer
    Signal

receive_no_writer:    
    LeaveSection ds:tcp_section
    jmp receive_free

no_options      DB 0

receive_no_connection:
    mov ax,es
    mov ds,ax
    mov si,di
;
    mov al,ds:[si].tcp_flags
    test al,RST
    jnz receive_free
;
    test al,SYN
    jnz receive_free
;
    push ds
    push cx
    push si
    mov al,6
    mov ah,60
    mov ecx,SIZE tcp_header
    mov si,cs
    mov ds,si       
    mov esi,OFFSET no_options
    CreateIpHeader
    pop si
    pop cx
    pop ds
    jc receive_rst_done
;       
    mov ax,ds:[si].tcp_dest
    mov es:[di].tcp_source,ax
    mov ax,ds:[si].tcp_source
    mov es:[di].tcp_dest,ax
    mov es:[di].tcp_seq,0
    mov es:[di].tcp_ack,0
    mov es:[di].tcp_header_len,50h
    mov es:[di].tcp_window,0
    mov es:[di].tcp_urgent,0
;
    mov al,ds:[si].tcp_flags
    test al,ACK
    jz receive_rst_noack

receive_rst_ack:
    mov eax,ds:[si].tcp_ack
    mov es:[di].tcp_seq,eax
    mov es:[di].tcp_flags,RST
    jmp receive_rst_do

receive_rst_noack:
    mov eax,ds:[si].tcp_seq
    Reverse
    movzx ecx,cx
    add eax,ecx
    Reverse
    mov es:[di].tcp_ack,eax
    mov es:[di].tcp_flags,RST OR ACK

receive_rst_do:
    push edx
    pop bx
    pop ax
    add ax,bx
    GetIpAddress
    push edx
    pop bx
    adc ax,bx
    pop bx
    adc ax,bx
    adc ax,600h
    adc ax,0
    adc ax,0
    mov cx,SIZE tcp_header
    xchg cl,ch
    add ax,cx
    adc ax,0
    adc ax,0
    xchg cl,ch
    mov es:[di].tcp_checksum,0
    call CalcChecksum
    not ax
    mov es:[di].tcp_checksum,ax
    SendIp

receive_rst_done:
    mov ax,ds
    mov es,ax

receive_free:
    xor ax,ax
    mov ds,ax
    FreeMem
    retf32
Receive Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CreateTcpListen
;
;       Purpose:        Create a TCP listen handle
;
;       Parameters:         AX      max connections
;           ECX         buffer size
;                       SI              local port
;
;   Returns:    BX      listen handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

create_tcp_listen_name  DB 'Create TCP listen',0

create_tcp_listen       Proc far
    push ds
    push es
    push eax
    push cx
    push dx
;
    call CreateListen
    mov dx,ds
;
    mov ax,TCP_LISTEN_HANDLE
    mov cx,SIZE listen_handle_seg
    AllocateHandle
    mov [ebx].listen_handle_sel,dx
    mov [ebx].hh_sign,TCP_LISTEN_HANDLE
    mov bx,[ebx].hh_handle
;       
    pop dx
    pop cx
    pop eax
    pop es
    pop ds
    retf32
create_tcp_listen   Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           GetTcpListen
;
;       Purpose:        Get a connection from a listen
;
;       Parameters:         BX      listen handle
;
;   Returns:    AX      connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

get_tcp_listen_name     DB 'Get TCP listen',0

get_tcp_listen  Proc far
    push ds
    push es
    push ebx
    push cx
    push dx
;
    mov ax,TCP_LISTEN_HANDLE
    DerefHandle
    jc get_listen_done
;    
    mov ax,[ebx].listen_handle_sel
    mov ds,ax
    EnterSection ds:tcp_listen_section
    mov dx,ds:tcp_listen_list
    or dx,dx
    jz get_listen_leave
;
    mov es,dx
    mov bx,es:tcp_listen_link
    mov ds:tcp_listen_list,bx

get_listen_leave:
    LeaveSection ds:tcp_listen_section          
    or dx,dx
    stc
    jz get_listen_done
;
    mov ax,TCP_SOCKET_HANDLE
    mov cx,SIZE tcp_handle_seg
    AllocateHandle
    mov [ebx].tcp_handle_sel,es
    mov [ebx].hh_sign,TCP_SOCKET_HANDLE
    mov ax,[ebx].hh_handle
    clc

get_listen_done:
    pop dx
    pop cx
    pop ebx
    pop es
    pop ds  
    retf32
get_tcp_listen  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CloseTcpListen
;
;       Purpose:        Close listen
;
;       Parameters:         BX          Listen handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

close_tcp_listen_name DB 'Close TCP Listen',0

close_tcp_listen    Proc far
    push ds
    push es
    pushad
;
    mov ax,TCP_LISTEN_HANDLE
    DerefHandle
    jc close_tcp_listen_done
;    
    mov ax,[ebx].listen_handle_sel
    or ax,ax
    stc
    jz close_tcp_listen_done
;
    mov ds,ax
    call DeleteListen
    clc

close_tcp_listen_done:
    popad
    pop es
    pop ds
    retf32
close_tcp_listen    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           WaitForTcpConnection
;
;       Purpose:        Wait for a connection
;
;       Parameters:         SI          local port
;                       EAX         timeout
;                       BX          connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

wait_for_tcp_connection_name    DB 'Wait For TCP Connection',0

wait_for_tcp_connection Proc far
    push ds
    push es
    pushad
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc wait_tcp_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz wait_tcp_done
;
    push ebx
    mov ds,ax
    EnterSection ds:tcp_section
    cmp ds:tcp_state,STATE_ESTAB
    jae wait_tcp_ok
;
    xor edx,edx
    mov ecx,100
    div ecx
    mov ds:tcp_user_timeout,ax
    ClearSignal
    or ds:tcp_pending,FLAG_WAIT

wait_tcp_retry: 
    GetThread
    mov ds:tcp_owner,ax
    LeaveSection ds:tcp_section
;
    WaitForSignal
    mov ds:tcp_owner,0
    EnterSection ds:tcp_section
    cmp ds:tcp_state,STATE_ESTAB
    jae wait_tcp_ok
;
    mov ax,ds:tcp_user_timeout
    or ax,ax
    jnz wait_tcp_retry
    jmp wait_tcp_fail

wait_tcp_ok:
    LeaveSection ds:tcp_section
    pop ebx
    clc
    jmp wait_tcp_done

wait_tcp_fail:
    mov ds:tcp_delete_timeout,240 * 10
    mov ds:tcp_owner,0
    LeaveSection ds:tcp_section
    pop ebx
    FreeHandle
    stc

wait_tcp_done:
    popad
    pop es
    pop ds  
    retf32
wait_for_tcp_connection Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           OpenTcpConnection
;
;       Purpose:        Open a tcp connection
;
;       Parameters:         EAX         Timeout in milliseconds for connection
;                       ECX         buffer size
;                       EDX         ip address
;                       SI          local port (or 0 for random port)
;                       DI          remote port (or 0 to accept any port)
;
;       Returns:        NC          ok
;                       BX          connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

open_tcp_connection_name    DB 'Open TCP Connection',0

open_tcp_connection     Proc far
    push ds
    push es
    push eax
    push ecx
    push edx
    push esi
    push edi
    push ebp
;
    mov ebp,eax
    or si,si
    jz open_tcp_dyn
;
    call FindConnection
    jc open_tcp_create
;
    LeaveSection ds:tcp_section
    stc
    jmp open_tcp_done

open_tcp_dyn:
    call AllocatePort
    jc open_tcp_done

open_tcp_create:
    call CreateConnection
    mov eax,ds:tcp_iss
    mov ds:tcp_send_una,eax
    inc eax
    mov ds:tcp_send_next,eax
    mov ds:tcp_state,STATE_SYN_SENT
    mov ds:tcp_syn_timeout,50
;       
    ClearSignal
    GetThread
    mov ds:tcp_owner,ax
    mov eax,ebp
    xor edx,edx
    mov ecx,100
    div ecx
    mov ds:tcp_user_timeout,ax
    or ds:tcp_pending,FLAG_WAIT
    LeaveSection ds:tcp_section
;
    or di,di
    jz open_tcp_handle
;
    xor ecx,ecx
    call CreateSegment
    jc open_tcp_arp_fail
;       
    mov es:[di].tcp_flags, SYN
    mov eax,ds:tcp_iss
    Reverse
    mov es:[di].tcp_seq,eax
    call SendSegment
;
    WaitForSignal
    mov ds:tcp_owner,0
    EnterSection ds:tcp_section
    cmp ds:tcp_state,STATE_ESTAB
    jne open_tcp_fail
    LeaveSection ds:tcp_section

open_tcp_handle:
    mov ds:tcp_owner,0
    mov dx,ds
    mov ax,TCP_SOCKET_HANDLE
    mov cx,SIZE tcp_handle_seg
    AllocateHandle
    mov [ebx].tcp_handle_sel,dx
    mov [ebx].hh_sign,TCP_SOCKET_HANDLE
    mov bx,[ebx].hh_handle
    clc
    jmp open_tcp_done

open_tcp_fail:
    LeaveSection ds:tcp_section

open_tcp_arp_fail:
    mov ax,SEG data
    mov es,ax
    RequestSpinlock es:ConnSpinlock
;    
    or ds:tcp_pending,FLAG_DELETE_NET
    or ds:tcp_pending,FLAG_DELETE_USER
    xor ax,ax
    mov ds,ax
;
    ReleaseSpinlock es:ConnSpinlock    
    stc

open_tcp_done:
    pop ebp
    pop edi
    pop esi
    pop edx
    pop ecx
    pop eax
    pop es
    pop ds
    retf32
open_tcp_connection     Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CloseDelete
;
;       Purpose:        Delete close
;
;       Parameters:         DS          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CloseDelete     Proc near
    or ds:tcp_pending,FLAG_DELETE_NET
    ret
CloseDelete     Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CloseNormal
;
;       Purpose:        Normal close
;
;       Parameters:         DS          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CloseNormal     Proc near
    mov ds:tcp_state,STATE_FIN_WAIT1
    or ds:tcp_pending,FLAG_CLOSING
    call SendData
    ret
CloseNormal     Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CloseCloseWait
;
;       Purpose:        Close in CLOSE-WAIT state
;
;       Parameters:         DS          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CloseCloseWait  Proc near
    mov ds:tcp_delete_timeout,240 * 10
    mov ds:tcp_state,STATE_LAST_ACK
    or ds:tcp_pending,FLAG_CLOSING
    call SendData
    ret
CloseCloseWait  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           CloseTcpConnection
;
;       Purpose:        Close connection
;
;       Parameters:         BX          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

close_tcp_connection_name DB 'Close TCP Connection',0

close_tab:
cl0     DW OFFSET CloseDelete
cl1 DW OFFSET CloseNormal
cl2 DW OFFSET CloseNormal
cl3     DW OFFSET IgnoreDummy
cl4     DW OFFSET IgnoreDummy
cl5 DW OFFSET CloseCloseWait
cl6 DW OFFSET IgnoreDummy
cl7 DW OFFSET IgnoreDummy
cl8 DW OFFSET IgnoreDummy

close_tcp_connection    Proc far
    push ds
    push es
    pushad
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc close_tcp_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz close_tcp_done
;
    mov ds,ax
    EnterSection ds:tcp_section
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].close_tab
    LeaveSection ds:tcp_section
;
    mov bx,ds:tcp_writer
    or bx,bx
    jz close_tcp_no_writer
;
    Signal

close_tcp_no_writer:
    mov bx,ds:tcp_owner
    or bx,bx
    jz close_tcp_owner_ok
;
    Signal

close_tcp_owner_ok:
    mov bx,ds:tcp_wait  
    or bx,bx
    clc
    jz close_tcp_done
;
    mov es,bx
    SignalWait
    mov ds:tcp_wait,0
    clc

close_tcp_done:
    popad
    pop es
    pop ds
    retf32
close_tcp_connection    Endp



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           Delete_socket_handle
;
;           DESCRIPTION:    Delete socket handle (called from handle module)
;
;           PARAMETERS:         BX              TCP CONNECTION HANDLE
;                           
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

delete_socket_handle    Proc far
    push ds
    push es
    push ax
    push dx
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc delete_socket_handle_done
;
    push [ebx].tcp_handle_sel
    FreeHandle
    pop ds
;    
    or ax,ax
    stc
    jz delete_socket_handle_done
;    
    mov ds,ax
    EnterSection ds:tcp_section
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].close_tab
    LeaveSection ds:tcp_section
    clc

delete_socket_handle_done:
    pop dx
    pop ax
    pop es
    pop ds
    retf32
delete_socket_handle    Endp



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           Delete_listen_handle
;
;           DESCRIPTION:    Delete listen handle (called from handle module)
;
;           PARAMETERS:         BX              tcp listen handle
;                           
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

delete_listen_handle    Proc far
    push ds
    push es
    push ax
    push dx
;
    mov ax,TCP_LISTEN_HANDLE
    DerefHandle
    jc delete_listen_handle_done
;
    push [ebx].tcp_handle_sel
    FreeHandle
    pop ds
;    
    or ax,ax
    stc
    jz delete_listen_handle_done
;    
    mov ds,ax
    EnterSection ds:tcp_listen_section
    call DeleteListen
    clc

delete_listen_handle_done:
    pop dx
    pop ax
    pop es
    pop ds
    retf32
delete_listen_handle    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           DeleteTcpConnection
;
;       Purpose:        Delete connection handle
;
;       Parameters:         BX          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

delete_tcp_connection_name DB 'Delete TCP Connection',0

delete_tcp_connection   Proc far
    ApiSaveEax
    ApiSaveEcx
    ApiSaveEdx
    ApiSaveEsi
    ApiSaveEdi

    push ds
    push es
    push ax
    push ebx
;
    mov ax,SEG data
    mov es,ax
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc delete_tcp_done
;    
    xor ax,ax
    xchg ax,[ebx].tcp_handle_sel
    or ax,ax
    jz delete_tcp_handle
;
    RequestSpinlock es:ConnSpinlock    
    mov ds,ax
    test ds:tcp_pending,FLAG_UNLINKED
    jz delete_tcp_mark
;    
    ReleaseSpinlockNoSti es:ConnSpinlock
    EnterSection ds:tcp_section
    sti
;
    call DeleteConnection
    jmp delete_tcp_handle

delete_tcp_mark:
    or ds:tcp_pending,FLAG_DELETE_USER
    xor ax,ax
    mov ds,ax
    ReleaseSpinlock es:ConnSpinlock

delete_tcp_handle:
    FreeHandle
    clc

delete_tcp_done:
    pop ebx
    pop ax
    pop es
    pop ds

    ApiCheckEdi
    ApiCheckEsi
    ApiCheckEdx
    ApiCheckEcx
    ApiCheckEax
    retf32
delete_tcp_connection   Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           IsTcpConnectionIdle
;
;       Purpose:        Check if connection is idle
;
;       Parameters:         BX          Connection handle
;
;   Returns:    NC      Connection is idle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

is_tcp_connection_idle_name DB 'Is TCP Connection Idle?',0

is_tcp_connection_idle  Proc far
    ApiSaveEax
    ApiSaveEcx
    ApiSaveEdx
    ApiSaveEsi
    ApiSaveEdi

    push ds
    push eax
    push ebx
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc is_tcp_idle_ok
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    jz is_tcp_idle_ok
;
    mov ds,ax
;
    mov ax,ds:tcp_receive_count
    or ax,ax
    jnz is_tcp_idle_fail
;       
    mov ax,ds:tcp_send_count
    or ax,ax
    jnz is_tcp_idle_fail
;
    mov eax,ds:tcp_send_next
    cmp eax,ds:tcp_send_una
    jnz is_tcp_idle_fail

is_tcp_idle_ok:
    clc
    jmp is_tcp_idle_done

is_tcp_idle_fail:
    stc

is_tcp_idle_done:       
    pop ebx
    pop eax
    pop ds

    ApiCheckEdi
    ApiCheckEsi
    ApiCheckEdx
    ApiCheckEcx
    ApiCheckEax
    retf32
is_tcp_connection_idle  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           IsTcpConnectionClosed
;
;       Purpose:        Check if connection is closed by remote site
;
;       Parameters:         BX          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

is_tcp_connection_closed_name DB 'Is TCP Connection Closed?',0

is_tcp_connection_closed    Proc far
    ApiSaveEax
    ApiSaveEcx
    ApiSaveEdx
    ApiSaveEsi
    ApiSaveEdi

    push ds
    push ax
    push ebx
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc is_tcp_closed_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    jz is_tcp_closed_fail
;
    mov ds,ax
;
    mov ax,ds:tcp_receive_count
    or ax,ax
    jnz is_tcp_closed_ok
;       
    mov al,ds:tcp_state
    cmp al,STATE_ESTAB
    ja is_tcp_closed_fail
;
    mov ax,ds:tcp_pending
    test ax,FLAG_DELETE_NET OR FLAG_CLOSED
    jnz is_tcp_closed_fail

is_tcp_closed_ok:
    clc
    jmp is_tcp_closed_done

is_tcp_closed_fail:
    stc

is_tcp_closed_done:
    pop ebx
    pop ax
    pop ds

    ApiCheckEdi
    ApiCheckEsi
    ApiCheckEdx
    ApiCheckEcx
    ApiCheckEax
    retf32
is_tcp_connection_closed    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           GetRemoteTcpConnectionIP
;
;       Purpose:        Get remote IP of connection
;
;       Parameters:         BX          Connection handle
;
;   Returns:    EAX     IP
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

get_remote_tcp_connection_ip_name DB 'Get Remote TCP Connection IP',0

get_remote_tcp_connection_ip    Proc far
    ApiSaveEcx
    ApiSaveEdx
    ApiSaveEsi
    ApiSaveEdi

    push ds
    push ebx
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc get_rem_ip_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    jz get_rem_ip_fail
;
    mov ds,ax
    mov eax,ds:tcp_remote_ip
    clc
    jmp get_rem_ip_done

get_rem_ip_fail:
    stc

get_rem_ip_done:
    pop ebx
    pop ds

    ApiCheckEdi
    ApiCheckEsi
    ApiCheckEdx
    ApiCheckEcx
    retf32
get_remote_tcp_connection_ip    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           GetRemoteTcpConnectionPort
;
;       Purpose:        Get remote port of connection
;
;       Parameters:         BX          Connection handle
;
;   Returns:    AX      port
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

get_remote_tcp_connection_port_name DB 'Get Remote TCP Connection Port',0

get_remote_tcp_connection_port  Proc far
    ApiSaveEcx
    ApiSaveEdx
    ApiSaveEsi
    ApiSaveEdi

    push ds
    push ebx
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc get_rem_port_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    jz get_rem_port_fail
;
    mov ds,ax
    mov ax,ds:tcp_remote_port
    clc
    jmp get_rem_port_done

get_rem_port_fail:
    stc

get_rem_port_done:
    pop ebx
    pop ds

    ApiCheckEdi
    ApiCheckEsi
    ApiCheckEdx
    ApiCheckEcx
    retf32
get_remote_tcp_connection_port  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           GetLocalTcpConnectionPort
;
;       Purpose:        Get local port of connection
;
;       Parameters:         BX          Connection handle
;
;   Returns:    AX      port
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

get_local_tcp_connection_port_name DB 'Get Local TCP Connection Port',0

get_local_tcp_connection_port   Proc far
    ApiSaveEcx
    ApiSaveEdx
    ApiSaveEsi
    ApiSaveEdi

    push ds
    push ebx
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc get_local_port_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    jz get_local_port_fail
;
    mov ds,ax
    mov ax,ds:tcp_port
    clc
    jmp get_local_port_done

get_local_port_fail:
    stc

get_local_port_done:
    pop ebx
    pop ds

    ApiCheckEdi
    ApiCheckEsi
    ApiCheckEdx
    ApiCheckEcx
    retf32
get_local_tcp_connection_port   Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           AbortDelete
;
;       Purpose:        Delete abort
;
;       Parameters:         DS          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

AbortDelete     Proc near
    mov ds:tcp_delete_timeout,240 * 10
    ret
AbortDelete     Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           AbortReset
;
;       Purpose:        Abort connection (reset & delete)
;
;       Parameters:         DS          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

AbortReset      Proc near
    xor ecx,ecx
    call CreateSegment
    mov es:[di].tcp_flags, RST
    mov eax,ds:tcp_send_next
    Reverse
    mov es:[di].tcp_seq,eax
    call SendSegment
    mov ds:tcp_delete_timeout,240 * 10
    ret
AbortReset      Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           AbortTcpConnection
;
;       Purpose:        Abort connection
;
;       Parameters:         BX          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

abort_tcp_connection_name DB 'Abort TCP Connection',0

abort_tab:
ab0     DW OFFSET AbortDelete
ab1 DW OFFSET AbortReset
ab2 DW OFFSET AbortReset
ab3     DW OFFSET AbortReset
ab4     DW OFFSET AbortReset
ab5 DW OFFSET AbortReset
ab6 DW OFFSET AbortDelete
ab7 DW OFFSET AbortDelete
ab8 DW OFFSET AbortDelete

abort_tcp_connection    Proc far
    push ds
    push es
    pushad
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc abort_tcp_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz abort_tcp_done
;
    mov ds,ax
    EnterSection ds:tcp_section
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].abort_tab
    LeaveSection ds:tcp_section
    pop bx

abort_tcp_done:
    popad
    pop es
    pop ds
    retf32
abort_tcp_connection    Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           Failed
;
;       Purpose:        Failed
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Failed  Proc near
    stc
    ret
Failed  Endp



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           StartWaitForConnection
;
;           DESCRIPTION:    Start a wait for connection
;
;           PARAMETERS:         ES      Wait object
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

start_wait_for_connection       PROC far
    push ds
    push ax
    push ebx
;
    mov bx,es:tw_handle
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc start_wait_for_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    jz start_wait_for_done
;
    mov ds,ax
    mov ds:tcp_wait,es
    mov ax,ds:tcp_receive_count
    or ax,ax
    jnz start_wait_signal
;
    mov ax,ds:tcp_pending
    test ax,FLAG_DELETE_NET
    jnz start_wait_signal
;    
    mov al,ds:tcp_state
    cmp al,STATE_ESTAB
    jbe start_wait_for_done

start_wait_signal:
    mov ds:tcp_wait,0
    SignalWait

start_wait_for_done:
    pop ebx
    pop ax
    pop ds
    retf32
start_wait_for_connection Endp
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           StopWaitForConnection
;
;           DESCRIPTION:    Stop a wait for connection
;
;           PARAMETERS:         ES      Wait object
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

stop_wait_for_connection    PROC far
    push ds
    push ax
    push ebx
;
    mov bx,es:tw_handle
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc stop_wait_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    jz stop_wait_done
;
    mov ds,ax
    mov ds:tcp_wait,0

stop_wait_done:
    pop ebx
    pop ax
    pop ds
    retf32
stop_wait_for_connection Endp


    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           ClearConnection
;
;           DESCRIPTION:    Clear tcp connection
;
;           PARAMETERS:         ES      Wait object
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

clear_connection    PROC far
    retf32
clear_connection Endp


    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           IsConnectionIdle
;
;           DESCRIPTION:    Check if connection is idle
;
;           PARAMETERS:         ES      Wait object
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

is_connection_idle      PROC far
    push ds
    push ax
    push ebx
;
    mov bx,es:tw_handle
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc is_idle_done
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz is_idle_done
;
    mov ds,ax
    mov ax,ds:tcp_pending
    test ax,FLAG_DELETE_NET
    stc
    jnz is_idle_done
;
    mov ax,ds:tcp_receive_count
    or ax,ax
    clc
    je is_idle_done
;
    stc

is_idle_done:
    pop ebx
    pop ax
    pop ds
    retf32
is_connection_idle Endp
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           AddWaitForTcpConnection
;
;           DESCRIPTION:    Add a wait for TCP connection
;
;           PARAMETERS:         AX      Connection handle
;               BX      Wait handle
;               ECX     Signalled ID
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

add_wait_for_tcp_connection_name    DB 'Add Wait For TCP Connection',0

add_wait_tab:
aw0 DD OFFSET start_wait_for_connection,    SEG code
aw1 DD OFFSET stop_wait_for_connection,     SEG code
aw2 DD OFFSET clear_connection,             SEG code
aw3 DD OFFSET is_connection_idle,           SEG code

add_wait_for_tcp_connection     PROC far
    push ds
    push es
    push eax
    push edi
;
    push ax
    mov ax,cs
    mov es,ax
    mov ax,SIZE tcp_wait_header - SIZE wait_obj_header
    mov edi,OFFSET add_wait_tab
    AddWait
    pop ax
    jc add_wait_done
;
    mov es:tw_handle,ax

add_wait_done:
    pop edi
    pop eax
    pop es
    pop ds
    retf32
add_wait_for_tcp_connection     ENDP



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           StartWaitForListen
;
;           DESCRIPTION:    Start a wait for listen
;
;           PARAMETERS:         ES      Wait object
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

start_wait_for_listen   PROC far
    push ds
    push ax
    push ebx
;
    mov bx,es:tw_handle
    mov ax,TCP_LISTEN_HANDLE
    DerefHandle
    jc start_wait_for_listen_done
;    
    mov ax,[ebx].listen_handle_sel
    or ax,ax
    jz start_wait_for_listen_done
;
    mov ds,ax
    mov ds:tcp_listen_wait,es
;
    mov ax,ds:tcp_listen_list
    or ax,ax
    jz start_wait_for_listen_done
;    
    mov ds:tcp_listen_wait,0
    SignalWait

start_wait_for_listen_done:
    pop ebx
    pop ax
    pop ds
    retf32
start_wait_for_listen Endp
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           StopWaitForListen
;
;           DESCRIPTION:    Stop a wait for listen
;
;           PARAMETERS:         ES      Wait object
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

stop_wait_for_listen    PROC far
    push ds
    push ax
    push ebx
;
    mov bx,es:tw_handle
    mov ax,TCP_LISTEN_HANDLE
    DerefHandle
    jc stop_wait_listen_done
;    
    mov ax,[ebx].listen_handle_sel
    or ax,ax
    jz stop_wait_listen_done
;
    mov ds,ax
    mov ds:tcp_listen_wait,0

stop_wait_listen_done:
    pop ebx
    pop ax
    pop ds
    retf32
stop_wait_for_listen Endp


    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           ClearListen
;
;           DESCRIPTION:    Clear tcp listen
;
;           PARAMETERS:         ES      Wait object
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

clear_listen    PROC far
    retf32
clear_listen Endp


    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           IsListenIdle
;
;           DESCRIPTION:    Check if listen is idle
;
;           PARAMETERS:         ES      Wait object
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

is_listen_idle  PROC far
    push ds
    push ax
    push ebx
;
    mov bx,es:tw_handle
    mov ax,TCP_LISTEN_HANDLE
    DerefHandle
    jc is_listen_idle_done
;    
    mov ax,[ebx].listen_handle_sel
    or ax,ax
    stc
    jz is_listen_idle_done
;
    mov ds,ax
    mov ax,ds:tcp_listen_list
    or ax,ax
    clc
    jne is_listen_idle_done
;
    stc

is_listen_idle_done:
    pop ebx
    pop ax
    pop ds
    retf32
is_listen_idle Endp
    
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       
;
;           NAME:           AddWaitForTcpListen
;
;           DESCRIPTION:    Add a wait for TCP listen
;
;           PARAMETERS:         AX      Listen handle
;               BX      Wait handle
;               ECX     Signalled ID
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

add_wait_for_tcp_listen_name    DB 'Add Wait For TCP Listen',0

add_wait_listen_tab:
al0 DD OFFSET start_wait_for_listen,        SEG code
al1 DD OFFSET stop_wait_for_listen,         SEG code
al2 DD OFFSET clear_listen,                 SEG code
al3 DD OFFSET is_listen_idle,               SEG code

add_wait_for_tcp_listen PROC far
    push ds
    push es
    push eax
    push edi
;
    push ax
    mov ax,cs
    mov es,ax
    mov ax,SIZE tcp_wait_header - SIZE wait_obj_header
    mov edi,OFFSET add_wait_listen_tab
    AddWait
    pop ax
    jc add_wait_listen_done
;
    mov es:tw_handle,ax

add_wait_listen_done:
    pop edi
    pop eax
    pop es
    pop ds
    retf32
add_wait_for_tcp_listen ENDP


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReadNormal
;
;       Purpose:        Read connection
;
;       Parameters:         EAX             timeout in ms for receive
;                       BX              connection handle
;                       (E)CX       wanted number of bytes
;                       ES:(E)DI    data buffer
;
;       Returns:        NC              ok
;                       (E)AX       size of received data
;                       CY              connection closed
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

update_receive  Proc near
    call UpdateReceiveWnd
    test ds:tcp_pending,FLAG_ACK OR FLAG_DELAY_ACK
    jz update_rec_done
;
    and ds:tcp_pending,NOT FLAG_ACK
    call SendAck

update_rec_done:
    ret
update_receive  Endp

ReadNormal      Proc near
    mov fs,ds:tcp_receive_buffer
    xor ebp,ebp

read_tcp_loop:
    or ecx,ecx
    jz read_tcp_ok

read_tcp_retry:
    test ds:tcp_pending,FLAG_DELETE_NET
    jnz read_tcp_fail
;
    mov edx,ecx
    movzx eax,ds:tcp_receive_count
    cmp ecx,eax
    jb read_tcp_size_ok
;
    mov ecx,eax

read_tcp_size_ok:
    add ebp,ecx
    sub ds:tcp_receive_count,cx
    mov bx,ds:tcp_receive_head
    call CopyFromBuffer
    mov ds:tcp_receive_head,bx
;
    xchg ecx,edx
    sub ecx,edx
    jz read_tcp_ok    
;
    test ds:tcp_pending, FLAG_REC_PUSH
    jz read_tcp_wait
;
    and ds:tcp_pending, NOT FLAG_REC_PUSH
    or eax,eax
    jnz read_tcp_ok

read_tcp_wait:
    test ds:tcp_pending, FLAG_CLOSED
    jnz read_tcp_ok
;
    push ecx
    push edi
    call update_receive
    ClearSignal
    GetThread
    mov ds:tcp_owner,ax
    LeaveSection ds:tcp_section
    WaitForSignal
    mov ds:tcp_owner,0
    pop edi
    pop ecx
    EnterSection ds:tcp_section
    jmp read_tcp_retry

read_tcp_fail:
    stc
    jmp read_tcp_done

read_tcp_ok:
    call update_receive
    clc

read_tcp_done:
    mov eax,ebp
    ret
ReadNormal      Endp
        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           ReadTcpConnection
;
;       Purpose:        Read connection
;
;       Parameters:         EAX             timeout in ms for receive
;                       BX              connection handle
;                       (E)CX       wanted number of bytes
;                       ES:(E)DI    data buffer
;
;       Returns:        NC              ok
;                       (E)AX       size of received data
;                       CY              connection closed
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

read_tcp_connection_name DB 'Read TCP Connection',0

read_tab:
rd0     DW OFFSET Failed
rd1 DW OFFSET Failed
rd2 DW OFFSET ReadNormal
rd3     DW OFFSET ReadNormal
rd4     DW OFFSET ReadNormal
rd5 DW OFFSET ReadNormal
rd6 DW OFFSET Failed
rd7 DW OFFSET Failed
rd8 DW OFFSET Failed

read_tcp_connection16   Proc far
    push ds
    push es
    push fs
    push ebx
    push ecx
    push edx
    push esi
    push edi
    push ebp
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc read_tcp_done16
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz read_tcp_done16
;
    mov ds,ax
    movzx ecx,cx
    movzx edi,di
    EnterSection ds:tcp_section
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].read_tab
    pushf
    LeaveSection ds:tcp_section
    popf

read_tcp_done16:
    pop ebp
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
    pop fs
    pop es
    pop ds
    retf32
read_tcp_connection16   Endp

read_tcp_connection32   Proc far
    push ds
    push es
    push fs
    push ebx
    push ecx
    push edx
    push esi
    push edi
    push ebp
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc read_tcp_done32
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz read_tcp_done32
;
    mov ds,ax
    EnterSection ds:tcp_section
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].read_tab
    pushf
    LeaveSection ds:tcp_section
    popf

read_tcp_done32:
    pop ebp
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
    pop fs
    pop es
    pop ds
    retf32
read_tcp_connection32   Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           WriteNormal
;
;       Purpose:        Write connection
;
;       Parameters:         BX              connection handle
;                       (E)CX       number of bytes to write
;                       ES:(E)DI    data buffer
;
;       Returns:        NC              ok
;                       CY              connection closed
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

WriteNormal     Proc near
    mov fs,ds:tcp_send_buffer
    mov esi,edi

write_tcp_retry:
    test ds:tcp_pending,FLAG_DELETE_NET OR FLAG_CLOSED
    jnz write_tcp_fail
;
    or ecx,ecx
    jz write_tcp_ok
;       
    mov dx,ds:tcp_buffer_size
    sub dx,ds:tcp_send_count
    movzx edx,dx
;
    mov eax,ds:tcp_send_next
    sub eax,ds:tcp_send_una
;
    sub edx,eax
    jc write_tcp_full
;
    mov eax,ecx
    cmp ecx,edx
    jc write_tcp_size_ok
;       
    mov ecx,edx

write_tcp_size_ok:      
    or ecx,ecx
    jz write_tcp_full
;
    add ds:tcp_send_count,cx
    mov bx,ds:tcp_send_tail
    call CopyToBuffer
    mov ds:tcp_send_tail,bx
;    
    xchg eax,ecx
    sub ecx,eax
    jmp write_tcp_retry

write_tcp_full:
    or ds:tcp_pending,FLAG_SEND_PUSH
    push eax
    push edi
    call SendData
    pop edi
    pop ecx
;
    ClearSignal
    GetThread
    mov ds:tcp_writer,ax
    LeaveSection ds:tcp_section
    WaitForSignal
    EnterSection ds:tcp_section
    mov ds:tcp_writer,0
    jmp write_tcp_retry

write_tcp_fail:
    stc
    jmp write_tcp_done

write_tcp_ok:
    mov ax,ds:tcp_send_count
    cmp ax,600h
    jc write_tcp_delay
;       
    call SendData
    jmp write_tcp_delay_done
    
write_tcp_delay:
    call SetSendTimeout

write_tcp_delay_done:
    clc

write_tcp_done:
    ret
WriteNormal     Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           WriteTcpConnection
;
;       Purpose:        Write connection
;
;       Parameters:         BX              connection handle
;                       (E)CX       number of bytes to write
;                       ES:(E)DI    data buffer
;
;       Returns:        NC              ok
;                       CY              connection closed
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

write_tcp_connection_name       DB 'Write TCP Connection',0

write_tab:
wr0     DW OFFSET Failed
wr1 DW OFFSET Failed
wr2 DW OFFSET WriteNormal
wr3     DW OFFSET Failed
wr4     DW OFFSET Failed
wr5 DW OFFSET WriteNormal
wr6 DW OFFSET Failed
wr7 DW OFFSET Failed
wr8 DW OFFSET Failed

write_tcp_connection16  Proc far
    push ds
    push es
    push fs
    pushad
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc write_tcp_done16
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz write_tcp_done16
;
    mov ds,ax
    movzx ecx,cx
    movzx edi,di
    mov ds,bx
    EnterSection ds:tcp_section
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].write_tab
    pushf
    LeaveSection ds:tcp_section
    popf

write_tcp_done16:
    popad
    pop fs
    pop es
    pop ds
    retf32
write_tcp_connection16  Endp

write_tcp_connection32  Proc far
    push ds
    push es
    push fs
    pushad
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc write_tcp_done32
;    
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz write_tcp_done32
;
    mov ds,ax
    EnterSection ds:tcp_section
    movzx bx,ds:tcp_state
    add bx,bx
    call word ptr cs:[bx].write_tab
    pushf
    LeaveSection ds:tcp_section
    popf

write_tcp_done32:
    popad
    pop fs
    pop es
    pop ds
    retf32
write_tcp_connection32  Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           PushTcpConnection
;
;       Purpose:        Push (commit) data connection
;
;       Parameters:         BX          Connection handle
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

push_tcp_connection_name DB 'Push TCP Connection',0

push_tcp_connection     Proc far
    push ds
    push es
    pushad
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc push_tcp_done
;
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz push_tcp_done
;
    mov ds,ax
    EnterSection ds:tcp_section
    test ds:tcp_pending,FLAG_SEND_PUSH
    jnz push_send_done
;       
    mov ds:tcp_push_timeout,5
    or ds:tcp_pending,FLAG_SEND_PUSH
    call SendData

push_send_done:
    LeaveSection ds:tcp_section

push_tcp_done:
    popad
    pop es
    pop ds
    retf32
push_tcp_connection     Endp


        
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;       Name:           PollTcpConnection
;
;       Purpose:        Poll connection
;
;       Parameters:         BX          Connection handle
;
;   Returns:    EAX     Number of bytes in receive buffer
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

poll_tcp_connection_name DB 'Poll TCP Connection',0

poll_tcp_connection     Proc far
    ApiSaveEcx
    ApiSaveEdx
    ApiSaveEsi
    ApiSaveEdi

    push ds
    push ebx
;
    mov ax,TCP_SOCKET_HANDLE
    DerefHandle
    jc poll_tcp_done
;
    mov ax,[ebx].tcp_handle_sel
    or ax,ax
    stc
    jz poll_tcp_done
;
    mov ds,ax
    EnterSection ds:tcp_section
    movzx eax,ds:tcp_receive_count
    LeaveSection ds:tcp_section
    clc

poll_tcp_done:
    pop ebx
    pop ds

    ApiCheckEdi
    ApiCheckEsi
    ApiCheckEdx
    ApiCheckEcx
    retf32
poll_tcp_connection     Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           UpdateConnection
;
;           DESCRIPTION:    Update a connection
;
;       PARAMETERS:     DS      connection
;
;           RETURNS:        
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

UpdateConnection    Proc near
    mov dx,ds:tcp_writer
    or dx,dx
    jz update_send_no_writer
;    
    or ds:tcp_pending,FLAG_SEND_PUSH
    
update_send_no_writer:    
    mov dx,ds:tcp_send_timeout
    or dx,dx
    jz update_send_timeout_done
;
    sub dx,1
    mov ds:tcp_send_timeout,dx
    jnz update_send_timeout_done
;
    or ds:tcp_pending,FLAG_SEND_PUSH
    
update_send_timeout_done:
    test ds:tcp_pending,FLAG_SEND_PUSH
    jz update_con_push_done
;
    mov cx,ds:tcp_send_count
    or cx,cx
    jnz update_con_check_push
;
    and ds:tcp_pending,NOT FLAG_SEND_PUSH
    jmp update_con_push_done

update_con_check_push:
    mov al,ds:tcp_push_timeout
    or al,al
    jz update_con_push_do
    dec al
    mov ds:tcp_push_timeout,al
    jmp update_con_push_done

update_con_push_do:
    call SendData

update_con_push_done:
    test ds:tcp_pending,FLAG_WAIT
    jz update_user_done
;       
    mov ax,ds:tcp_user_timeout
    sub ax,1
    mov ds:tcp_user_timeout,ax
    jnz update_user_done
;
    and ds:tcp_pending,NOT FLAG_WAIT
    mov bx,ds:tcp_owner
    Signal

update_user_done:       
    cmp ds:tcp_state,STATE_SYN_SENT
    jne update_con_syn_ok
;    
    cmp ds:tcp_remote_port,0
    je update_con_syn_ok
;

    mov ax,ds:tcp_syn_timeout
    sub ax,1
    mov ds:tcp_syn_timeout,ax
    or ax,ax
    jnz update_con_syn_ok
;    
    mov ds:tcp_syn_timeout,50
    push es
    push di
;
    xor ecx,ecx
    call CreateSegment
    jc update_con_syn_pop
;       
    mov es:[di].tcp_flags, SYN
    mov eax,ds:tcp_iss
    Reverse
    mov es:[di].tcp_seq,eax
    call SendSegment

update_con_syn_pop:
    pop di
    pop es

update_con_syn_ok:
    test dx,FLAG_DELAY_ACK
    jz update_delay_ack_done
;
    mov al,ds:tcp_ack_timeout
    sub al,1
    mov ds:tcp_ack_timeout,al
    jnz update_delay_ack_done
;
    call SendAck

update_delay_ack_done:
    mov eax,ds:tcp_send_next
    cmp eax,ds:tcp_send_una
    je update_resend_done
    mov ax,ds:tcp_resend_timeout
    sub ax,1
    mov ds:tcp_resend_timeout,ax
    jnz update_resend_done
;
    call Retransmit

update_resend_done:
    mov ax,ds:tcp_send_count
    or ax,ax
    jz update_con_done
;
    call SendData

update_con_done:
    ret
UpdateConnection    Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           tcp_thread
;
;           DESCRIPTION:    supervisor thread
;
;       PARAMETERS:     
;
;           RETURNS:        
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

tcp_thread_name DB 'TCP',0

LogFileName     DB 'z:\tcp.log',0

tcp_thread_pr:
    mov ax,250
    WaitMilliSec

tcp_sleep:
    mov ax,SEG data
    mov ds,ax
    GetThread
    mov ds:TcpThread,ax
    WaitForSignal
    mov ds:TcpThread,0

tcp_active_loop:
    mov ax,ds:ConnectionList
    or ax,ax
    jz tcp_sleep
;
    EnterSection ds:ListSection
    mov ax,ds:ConnectionList
    push ds

tcp_active_next:
    or ax,ax
    jz tcp_active_wait
;
    mov ds,ax
    EnterSection ds:tcp_section
    test ds:tcp_pending,FLAG_DELETE_NET OR FLAG_DELETE_USER
    jz tcp_update
;
    test ds:tcp_pending,FLAG_WAIT
    jz tcp_user_done
;
    and ds:tcp_pending,NOT FLAG_WAIT
    mov bx,ds:tcp_owner
    Signal
    jmp tcp_update

tcp_user_done:
    or ds:tcp_pending,FLAG_UNLINKED
    mov bx,ds
    mov si,ds:tcp_next
    mov ax,SEG data
    mov ds,ax
    xor dx,dx
    mov ax,ds:ConnectionList

tcp_unlink_loop:
    cmp ax,bx
    je tcp_unlink_do
;
    mov dx,ax
    mov ds,ax
    mov ax,ds:tcp_next
    jmp tcp_unlink_loop

tcp_unlink_do:
    or dx,dx
    jz tcp_unlink_head
;
    mov ds:tcp_next,si
    jmp tcp_delete_do

tcp_unlink_head:
    mov ds:ConnectionList,si

tcp_delete_do:
    mov ax,SEG data
    mov ds,ax
    dec ds:ConnectionCount
    call CheckConnectionList    
;   
    push si
    mov ds,bx
;       
    test ds:tcp_pending,FLAG_DELETE_USER
    jnz tcp_delete_conn_del
;
    LeaveSection ds:tcp_section
    jmp tcp_delete_conn_done

tcp_delete_conn_del:
    call DeleteConnection

tcp_delete_conn_done:
    pop ax
    jmp tcp_active_next

tcp_update:
    call UpdateConnection

tcp_leave:
    mov ax,ds:tcp_delete_timeout
    or ax,ax
    jz tcp_delete_timeout_done
;
    sub ax,1
    mov ds:tcp_delete_timeout,ax
    jz tcp_delete_timeout_do
;
    GetSystemTime
    rcr edx,1
    rcr eax,1
    rcr edx,1
    rcr eax,1
    rcr edx,1
    rcr eax,1
    cmp eax,ds:tcp_send_next
    jl tcp_delete_timeout_done
    
tcp_delete_timeout_do:
    or ds:tcp_pending,FLAG_DELETE_NET
    mov bx,ds:tcp_owner
    Signal
;
    mov bx,ds:tcp_writer
    or bx,bx
    jz tcp_delete_no_writer
;
    Signal

tcp_delete_no_writer:
    mov bx,ds:tcp_wait  
    or bx,bx
    jz tcp_delete_timeout_done
;
    push es
    mov es,bx
    SignalWait
    mov ds:tcp_wait,0
    pop es

tcp_delete_timeout_done:
    mov ax,ds:tcp_next
    LeaveSection ds:tcp_section
    jmp tcp_active_next

tcp_active_wait:
    pop ds
    LeaveSection ds:ListSection
    mov ax,100
    WaitMilliSec
    jmp tcp_active_loop

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;       NAME:           UpdateTcpMtu
;
;       DESCRIPTION:    Update Tcp MTU
;
;       PARAMETERS:     EDX     IP address
;                       DI      Remote port
;                       CX      New MTU
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

update_tcp_mtu_name DB 'Update Tcp MTU', 0

update_tcp_mtu    Proc far
    push ds
    pushad
;    
    sub cx,64
    mov ax,SEG data
    mov ds,ax
    EnterSection ds:ListSection
    mov ax,ds:ConnectionList

utmLoop:    
    or ax,ax
    jz utmLeave
;
    mov ds,ax
    cmp edx,ds:tcp_remote_ip
    jne utmNext
;
    cmp di,ds:tcp_remote_port
    jne utmNext
;
    mov ds:tcp_mtu,cx
    lock or ds:tcp_pending,FLAG_SEND_PUSH
    mov ds:tcp_push_timeout,0
    mov ds:tcp_resend_timeout,1

utmNext:    
    mov ax,ds:tcp_next
    jmp utmLoop

utmLeave:
    mov ax,SEG data
    mov ds,ax
    LeaveSection ds:ListSection
;
    popad
    pop ds
    retf32
update_tcp_mtu  Endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;
;           NAME:           init_task_tcp
;
;           DESCRIPTION:    Init tcp driver, tasking part
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    public init_task_tcp

init_task_tcp    PROC near
    mov bx,SEG data
    mov es,bx
    mov es:ConnectionList,0
    mov es:ConnectionCount,0
    mov es:ListenList,0
    mov es:Handle,0
    mov es:LastPort,545
    mov ax,es
    mov ds,ax
    InitSection ds:ListSection
    InitSpinlock ds:ConnSpinlock
;       
    mov cx,1F00h
    mov di,OFFSET PortMap
    mov al,0FFh
    rep stosb
;
    mov ax,cs
    mov ds,ax
    mov es,ax
;
    mov edi,OFFSET delete_socket_handle
    mov ax,TCP_SOCKET_HANDLE
    RegisterHandle
;
    mov edi,OFFSET delete_listen_handle
    mov ax,TCP_SOCKET_HANDLE
    RegisterHandle
;
    mov esi,OFFSET update_tcp_mtu
    mov edi,OFFSET update_tcp_mtu_name
    xor cl,cl
    mov ax,update_tcp_mtu_nr
    RegisterOsGate
;
    mov esi,OFFSET open_tcp_connection
    mov edi,OFFSET open_tcp_connection_name
    xor dx,dx
    mov ax,open_tcp_connection_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET create_tcp_listen
    mov edi,OFFSET create_tcp_listen_name
    xor dx,dx
    mov ax,create_tcp_listen_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET get_tcp_listen
    mov edi,OFFSET get_tcp_listen_name
    xor dx,dx
    mov ax,get_tcp_listen_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET close_tcp_listen
    mov edi,OFFSET close_tcp_listen_name
    xor dx,dx
    mov ax,close_tcp_listen_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET wait_for_tcp_connection
    mov edi,OFFSET wait_for_tcp_connection_name
    xor dx,dx
    mov ax,wait_for_tcp_connection_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET close_tcp_connection
    mov edi,OFFSET close_tcp_connection_name
    xor dx,dx
    mov ax,close_tcp_connection_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET delete_tcp_connection
    mov edi,OFFSET delete_tcp_connection_name
    xor dx,dx
    mov ax,delete_tcp_connection_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET is_tcp_connection_closed
    mov edi,OFFSET is_tcp_connection_closed_name
    xor dx,dx
    mov ax,is_tcp_connection_closed_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET is_tcp_connection_idle
    mov edi,OFFSET is_tcp_connection_idle_name
    xor dx,dx
    mov ax,is_tcp_connection_idle_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET get_remote_tcp_connection_ip
    mov edi,OFFSET get_remote_tcp_connection_ip_name
    xor dx,dx
    mov ax,get_remote_tcp_connection_ip_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET get_remote_tcp_connection_port
    mov edi,OFFSET get_remote_tcp_connection_port_name
    xor dx,dx
    mov ax,get_remote_tcp_connection_port_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET get_local_tcp_connection_port
    mov edi,OFFSET get_local_tcp_connection_port_name
    xor dx,dx
    mov ax,get_local_tcp_connection_port_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET abort_tcp_connection
    mov edi,OFFSET abort_tcp_connection_name
    xor dx,dx
    mov ax,abort_tcp_connection_nr
    RegisterBimodalUserGate
;
    mov ebx,OFFSET read_tcp_connection16
    mov esi,OFFSET read_tcp_connection32
    mov edi,OFFSET read_tcp_connection_name
    mov dx,virt_es_in
    mov ax,read_tcp_connection_nr
    RegisterUserGate
;
    mov ebx,OFFSET write_tcp_connection16
    mov esi,OFFSET write_tcp_connection32
    mov edi,OFFSET write_tcp_connection_name
    mov dx,virt_es_in
    mov ax,write_tcp_connection_nr
    RegisterUserGate
;
    mov esi,OFFSET push_tcp_connection
    mov edi,OFFSET push_tcp_connection_name
    xor dx,dx
    mov ax,push_tcp_connection_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET poll_tcp_connection
    mov edi,OFFSET poll_tcp_connection_name
    xor dx,dx
    mov ax,poll_tcp_connection_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET add_wait_for_tcp_connection
    mov edi,OFFSET add_wait_for_tcp_connection_name
    xor dx,dx
    mov ax,add_wait_for_tcp_connection_nr
    RegisterBimodalUserGate
;
    mov esi,OFFSET add_wait_for_tcp_listen
    mov edi,OFFSET add_wait_for_tcp_listen_name
    xor dx,dx
    mov ax,add_wait_for_tcp_listen_nr
    RegisterBimodalUserGate
;
    mov al,6
    mov edi,OFFSET Receive
    HookIp
;
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov si,OFFSET tcp_thread_pr
    mov di,OFFSET tcp_thread_name
    mov ax,3
    mov cx,stack0_size
    CreateThread
;
    ret
init_task_tcp    ENDP

code    ENDS

    END