Subversion Repositories Kolibri OS

Compare Revisions

Ignore whitespace Rev 906 → Rev 907

/kernel/trunk/network/eth_drv/drivers/rtl8169.inc
524,7 → 524,7
; Also adjust PCI latency timer to a reasonable value, 32.
proc adjust_pci_device
 
DEBUGF 1,"K : adjust_pci_device\n"
; DEBUGF 1,"K : adjust_pci_device\n"
 
stdcall pci_read_config_word,PCI_COMMAND
mov bx,ax
531,13 → 531,13
or bx,PCI_COMMAND_MASTER or PCI_COMMAND_IO
cmp ax,bx
je @f
DEBUGF 1,"K : adjust_pci_device: The PCI BIOS has not enabled this device!\nK : Updating PCI command %x->%x. pci_bus %x pci_device_fn %x\n",ax,bx,[pci_bus]:2,[pci_dev]:2
; DEBUGF 1,"K : adjust_pci_device: The PCI BIOS has not enabled this device!\nK : Updating PCI command %x->%x. pci_bus %x pci_device_fn %x\n",ax,bx,[pci_bus]:2,[pci_dev]:2
stdcall pci_write_config_word,PCI_COMMAND,ebx
@@:
stdcall pci_read_config_byte,PCI_LATENCY_TIMER
cmp al,32
jae @f
DEBUGF 1,"K : adjust_pci_device: PCI latency timer (CFLT) is unreasonably low at %d.\nK : Setting to 32 clocks.\n",al
; DEBUGF 1,"K : adjust_pci_device: PCI latency timer (CFLT) is unreasonably low at %d.\nK : Setting to 32 clocks.\n",al
stdcall pci_write_config_byte,PCI_LATENCY_TIMER,32
@@:
ret
559,7 → 559,7
stdcall pci_read_config_dword,eax
or eax,eax
jz .not64
DEBUGF 1,"K : pci_bar_start: Unhandled 64bit BAR\n"
; DEBUGF 1,"K : pci_bar_start: Unhandled 64bit BAR\n"
add esp,4
or eax,-1
ret
572,7 → 572,7
 
proc rtl8169_init_board
 
DEBUGF 1,"K : rtl8169_init_board\n"
; DEBUGF 1,"K : rtl8169_init_board\n"
 
call adjust_pci_device
 
592,7 → 592,7
; identify config method
RTL_R32 RTL8169_REG_TxConfig
and eax,0x7c800000
DEBUGF 1,"K : rtl8169_init_board: TxConfig & 0x7c800000 = 0x%x\n",eax
; DEBUGF 1,"K : rtl8169_init_board: TxConfig & 0x7c800000 = 0x%x\n",eax
mov esi,mac_info-8
@@: add esi,8
mov ecx,eax
625,9 → 625,9
jmp .match
@@:
; if unknown chip, assume array element #0, original RTL-8169 in this case
DEBUGF 1,"K : rtl8169_init_board: PCI device: unknown chip version, assuming RTL-8169\n"
; DEBUGF 1,"K : rtl8169_init_board: PCI device: unknown chip version, assuming RTL-8169\n"
RTL_R32 RTL8169_REG_TxConfig
DEBUGF 1,"K : rtl8169_init_board: PCI device: TxConfig = 0x%x\n",eax
; DEBUGF 1,"K : rtl8169_init_board: PCI device: TxConfig = 0x%x\n",eax
 
mov [rtl8169_tpc.chipset],0
 
642,7 → 642,7
 
proc rtl8169_hw_PHY_config
 
DEBUGF 1,"K : rtl8169_hw_PHY_config: priv.mcfg=%d, priv.pcfg=%d\n",[rtl8169_tpc.mcfg],[rtl8169_tpc.pcfg]
; DEBUGF 1,"K : rtl8169_hw_PHY_config: priv.mcfg=%d, priv.pcfg=%d\n",[rtl8169_tpc.mcfg],[rtl8169_tpc.pcfg]
 
; DBG_PRINT("priv->mcfg=%d, priv->pcfg=%d\n", tpc->mcfg, tpc->pcfg);
 
705,7 → 705,7
jmp .exit
.not_2_or_3:
; DBG_PRINT("tpc->mcfg=%d. Discard hw PHY config.\n", tpc->mcfg);
DEBUGF 1,"K : tpc.mcfg=%d, discard hw PHY config\n",[rtl8169_tpc.mcfg]
; DEBUGF 1,"K : tpc.mcfg=%d, discard hw PHY config\n",[rtl8169_tpc.mcfg]
.exit:
ret
endp
716,7 → 716,7
 
proc RTL8169_WRITE_GMII_REG,RegAddr:byte,value:dword
 
;;; DEBUGF 1,"K : RTL8169_WRITE_GMII_REG: 0x%x 0x%x\n",[RegAddr]:2,[value]
;;; DEBUGF 1,"K : RTL8169_WRITE_GMII_REG: 0x%x 0x%x\n",[RegAddr]:2,[value]
 
movzx eax,[RegAddr]
shl eax,16
738,7 → 738,7
 
proc RTL8169_READ_GMII_REG,RegAddr:byte
 
;;; DEBUGF 1,"K : RTL8169_READ_GMII_REG: 0x%x\n",[RegAddr]:2
;;; DEBUGF 1,"K : RTL8169_READ_GMII_REG: 0x%x\n",[RegAddr]:2
 
push ecx
movzx eax,[RegAddr]
767,7 → 767,7
 
proc rtl8169_set_rx_mode
 
DEBUGF 1,"K : rtl8169_set_rx_mode\n"
; DEBUGF 1,"K : rtl8169_set_rx_mode\n"
 
; IFF_ALLMULTI
; Too many to filter perfectly -- accept all multicasts
785,7 → 785,7
 
proc rtl8169_init_ring
 
DEBUGF 1,"K : rtl8169_init_ring\n"
; DEBUGF 1,"K : rtl8169_init_ring\n"
 
xor eax,eax
mov [rtl8169_tpc.cur_rx],eax
834,7 → 834,7
 
proc rtl8169_hw_start
 
DEBUGF 1,"K : rtl8169_hw_start\n"
; DEBUGF 1,"K : rtl8169_hw_start\n"
 
; Soft reset the chip
RTL_W8 RTL8169_REG_ChipCmd,RTL8169_CMD_Reset
883,10 → 883,10
push eax ; shurf 28.09.2008
mov eax, [rtl8169_tpc.TxDescArray] ; shurf 28.09.2008
sub eax, OS_BASE ; shurf 28.09.2008
RTL_W32 RTL8169_REG_TxDescStartAddr,eax ;[rtl8169_tpc.TxDescArray] ; shurf 28.09.2008
RTL_W32 RTL8169_REG_TxDescStartAddr,eax ;[rtl8169_tpc.TxDescArray] ; shurf 28.09.2008
mov eax, [rtl8169_tpc.RxDescArray] ; shurf 28.09.2008
sub eax, OS_BASE ; shurf 28.09.2008
RTL_W32 RTL8169_REG_RxDescStartAddr,eax ;[rtl8169_tpc.RxDescArray] ; shurf 28.09.2008
RTL_W32 RTL8169_REG_RxDescStartAddr,eax ;[rtl8169_tpc.RxDescArray] ; shurf 28.09.2008
pop eax ; shurf 28.09.2008
RTL_W8 RTL8169_REG_Cfg9346,RTL8169_CFG_9346_Lock
stdcall udelay,10
920,7 → 920,7
;***************************************************************************
proc rtl8169_probe
 
DEBUGF 1,"K : rtl8169_probe: 0x%x : 0x%x 0x%x\n",[io_addr]:8,[pci_bus]:2,[pci_dev]:2
; DEBUGF 1,"K : rtl8169_probe: 0x%x : 0x%x 0x%x\n",[io_addr]:8,[pci_bus]:2,[pci_dev]:2
 
call rtl8169_init_board
 
935,7 → 935,7
inc ebx
loop @b
 
DEBUGF 1,"K : rtl8169_probe: MAC = %x-%x-%x-%x-%x-%x\n",[node_addr+0]:2,[node_addr+1]:2,[node_addr+2]:2,[node_addr+3]:2,[node_addr+4]:2,[node_addr+5]:2
; DEBUGF 1,"K : rtl8169_probe: MAC = %x-%x-%x-%x-%x-%x\n",[node_addr+0]:2,[node_addr+1]:2,[node_addr+2]:2,[node_addr+3]:2,[node_addr+4]:2,[node_addr+5]:2
 
; Config PHY
stdcall rtl8169_hw_PHY_config
995,7 → 995,7
;***************************************************************************
proc rtl8169_reset
 
DEBUGF 1,"K : rtl8169_reset: 0x%x : 0x%x 0x%x\n",[io_addr]:8,[pci_bus]:2,[pci_dev]:2
; DEBUGF 1,"K : rtl8169_reset: 0x%x : 0x%x 0x%x\n",[io_addr]:8,[pci_bus]:2,[pci_dev]:2
 
mov [rtl8169_tpc.TxDescArrays],rtl8169_tx_ring
; Tx Desscriptor needs 256 bytes alignment
1040,7 → 1040,7
;***************************************************************************
proc rtl8169_transmit
 
DEBUGF 1,"K : rtl8169_transmit\n" ;: 0x%x : 0x%x 0x%x 0x%x 0x%x\n",[io_addr]:8,edi,bx,ecx,esi
; DEBUGF 1,"K : rtl8169_transmit\n" ;: 0x%x : 0x%x 0x%x 0x%x 0x%x\n",[io_addr]:8,edi,bx,ecx,esi
 
push ecx edx esi
mov eax,MAX_ETH_FRAME_SIZE
1094,7 → 1094,7
add eax,[rtl8169_tpc.TxDescArray]
xchg eax,ebx
mov [ebx + rtl8169_TxDesc.buf_addr],eax
sub [ebx + rtl8169_TxDesc.buf_addr],OS_BASE ; shurf 28.09.2008
sub [ebx + rtl8169_TxDesc.buf_addr],OS_BASE ; shurf 28.09.2008
 
mov eax,ecx
cmp eax,ETH_ZLEN
1118,7 → 1118,7
jnz @f
stdcall udelay,10
loop @b
DEBUGF 1,"K : rtl8169_transmit: TX Time Out\n"
; DEBUGF 1,"K : rtl8169_transmit: TX Time Out\n"
@@:
 
ret
1176,7 → 1176,7
add eax,-4
mov [eth_rx_data_len],ax
 
DEBUGF 1,"K : rtl8169_poll: data length = %u\n",ax
; DEBUGF 1,"K : rtl8169_poll: data length = %u\n",ax
 
push eax
mov ecx,eax
1198,10 → 1198,10
@@: mov [ebx + rtl8169_RxDesc.status],eax
 
mov [ebx + rtl8169_RxDesc.buf_addr],edx
sub [ebx + rtl8169_RxDesc.buf_addr],OS_BASE ; shurf 28.09.2008
sub [ebx + rtl8169_RxDesc.buf_addr],OS_BASE ; shurf 28.09.2008
jmp @f
.else:
DEBUGF 1,"K : rtl8169_poll: Rx Error\n"
; DEBUGF 1,"K : rtl8169_poll: Rx Error\n"
; FIXME: shouldn't I reset the status on an error
@@:
inc [rtl8169_tpc.cur_rx]
/kernel/trunk/network/eth_drv/ethernet.inc
204,7 → 204,7
 
dd 0x006610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; nVidia Corporation nForce2 Ethernet Controller
dd 0x01c310de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested
dd 0x00D610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested
dd 0x00D610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested
dd 0x008610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested
dd 0x008c10de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested
dd 0x00e610de, forcedeth_probe, forcedeth_reset, forcedeth_poll, forcedeth_transmit, forcedeth_cable ; not tested
353,6 → 353,9
; All registers may be destroyed
;
;***************************************************************************
uglobal
ether_IP_handler_cnt dd ?
endg
ether_IP_handler:
mov eax, EMPTY_QUEUE
call dequeue
376,6 → 379,9
cld
rep movsd
 
; inc [ether_IP_handler_cnt]
; DEBUGF 1, "K : ether_IP_handler (%u)\n", [ether_IP_handler_cnt]
 
; And finally, place the buffer in the IPRX queue
pop ebx
mov eax, IPIN_QUEUE
462,16 → 468,18
cmp ax, ETHER_ARP
je .is_arp ; It is ARP
 
DEBUGF 1,"K : eth_rx - dumped (%u)\n", ax
inc [dumped_rx_count]
jmp .exit ; If not IP or ARP, ignore
 
.is_ip:
DEBUGF 1,"K : eth_rx - IP packet\n"
; DEBUGF 1,"K : eth_rx - IP packet\n"
inc dword [ip_rx_count]
call ether_IP_handler
jmp .exit
 
.is_arp:
DEBUGF 1,"K : eth_rx - ARP packet\n"
; DEBUGF 1,"K : eth_rx - ARP packet\n"
; At this point, the packet is still in the Ether_buffer
call arp_handler
 
/kernel/trunk/network/ip.inc
16,22 → 16,22
 
 
; IP underlying protocols numbers
PROTOCOL_ICMP equ 1
PROTOCOL_TCP equ 6
PROTOCOL_UDP equ 17
PROTOCOL_ICMP equ 1
PROTOCOL_TCP equ 6
PROTOCOL_UDP equ 17
 
struc IP_PACKET
{ .VersionAndIHL db ? ;+00 - Version[0-3 bits] and IHL(header length)[4-7 bits]
.TypeOfService db ? ;+01
.TotalLength dw ? ;+02
.Identification dw ? ;+04
.FlagsAndFragmentOffset dw ? ;+06 - Flags[0-2] and FragmentOffset[3-15]
.TimeToLive db ? ;+08
.Protocol db ? ;+09
.HeaderChecksum dw ? ;+10
.SourceAddress dd ? ;+12
.DestinationAddress dd ? ;+16
.DataOrOptional dd ? ;+20
{ .VersionAndIHL db ? ;+00 - Version[0-3 bits] and IHL(header length)[4-7 bits]
.TypeOfService db ? ;+01
.TotalLength dw ? ;+02
.Identification dw ? ;+04
.FlagsAndFragmentOffset dw ? ;+06 - Flags[0-2] and FragmentOffset[3-15]
.TimeToLive db ? ;+08
.Protocol db ? ;+09
.HeaderChecksum dw ? ;+10
.SourceAddress dd ? ;+12
.DestinationAddress dd ? ;+16
.DataOrOptional dd ? ;+20
}
 
virtual at 0
83,10 → 83,14
and reg, 0x0000000F
; IHL keeps number of octets, so we need to << 2 'reg'
shl reg, 2
shl reg, 2
}
 
 
include "tcp.inc"
include "udp.inc"
include "icmp.inc"
 
;***************************************************************************
; Function
; ip_rx
104,7 → 108,7
mov eax, IPIN_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .exit ; Exit if no buffer available
je .exit ; Exit if no buffer available
 
mov [buffer_number], eax ;save buffer number
 
114,12 → 118,14
 
mov ebx, eax ; ebx=pointer to IP_PACKET
 
; DEBUGF 1, "K : ip_rx - proto: %u\n", [ebx + IP_PACKET.Protocol]:1
 
; Validate the IP checksum
mov dx, word[ebx + IP_PACKET.HeaderChecksum]
xchg dh,dl ; Get the checksum in intel format
xchg dh,dl ; Get the checksum in intel format
mov [ebx + IP_PACKET.HeaderChecksum], word 0 ; clear checksum field - need to when
; recalculating checksum
mov [ebx + IP_PACKET.HeaderChecksum], 0 ; clear checksum field - need to when
; recalculating checksum
; this needs two data pointers and two size #.
; 2nd pointer can be of length 0
 
127,33 → 133,52
stdcall checksum_jb, ebx, ecx ;buf_ptr, buf_size
cmp dx, ax
 
; DEBUGF 1, "K : ip_rx - checksums: %x - %x\n", dx, ax
 
jnz .dump.1 ;if CHECKSUM isn't valid then dump packet
mov edx, ebx ; EDX (IP-BUFFER POINTER) WILL BE USED FOR *_rx HANDLERS BELOW!!!
jnz .dump ;if CHECKSUM isn't valid then dump packet
 
; DEBUGF 1, "K : ip_rx - dest: %x - %x\n", [ebx + IP_PACKET.DestinationAddress], [stack_ip]
 
; Validate the IP address, if it isn't broadcast
mov eax, [stack_ip]
cmp dword[ebx + IP_PACKET.DestinationAddress], eax
je @f
je @f
 
; If the IP address is 255.255.255.255, accept it
; - it is a broadcast packet, which we need for dhcp
cmp dword[ebx + IP_PACKET.DestinationAddress], 0xffffffff
jne .dump
 
mov eax, [ebx + IP_PACKET.DestinationAddress]
cmp eax, 0xffffffff
;je @f
;mov ecx, [stack_ip]
;and eax, [subnet_mask]
;and ecx, [subnet_mask]
;cmp eax, ecx
;jne .dump.2
;mov eax, [ebx + IP_PACKET.DestinationAddress]
;or eax, [subnet_mask]
;cmp eax, 0xffffffff
jne .dump.2
 
@@:
mov al, [ebx + IP_PACKET.VersionAndIHL]
and al, 0x0f ;get IHL(header length)
cmp al, 0x05 ;if IHL!= 5*4(20 bytes)
jnz .dump ;then dump it
; DEBUGF 1, "K : ip_rx - ihl: %x - 05\n", al
jnz .dump.3 ;then dump it
 
cmp byte[ebx + IP_PACKET.TimeToLive], byte 0
je .dump ;if TTL==0 then dump it
; DEBUGF 1, "K : ip_rx - ttl: %x - 00\n", [ebx + IP_PACKET.TimeToLive]:2
 
mov ax, word[ebx + IP_PACKET.FlagsAndFragmentOffset]
and ax, 0xFFBF ;get flags
cmp ax, 0 ;if some flags was set then we dump this packet
jnz .dump ;the flags should be used for fragmented packets
cmp [ebx + IP_PACKET.TimeToLive], 0
je .dump.4 ;if TTL==0 then dump it
 
mov ax, [ebx + IP_PACKET.FlagsAndFragmentOffset]
and ax, 0xFFBF ;get flags
; DEBUGF 1, "K : ip_rx - flags: %x - 0000\n", ax
cmp ax, 0 ;if some flags was set then we dump this packet
jnz .dump.5 ;the flags should be used for fragmented packets
 
; Check the protocol, and call the appropriate handler
; Each handler will re-use or free the queue buffer as appropriate
 
161,7 → 186,7
 
cmp al , PROTOCOL_TCP
jne .not_tcp
DEBUGF 1,"K : ip_rx - TCP packet\n"
; DEBUGF 1,"K : ip_rx - TCP packet\n"
mov eax, dword[buffer_number]
call tcp_rx
jmp .exit
169,16 → 194,16
.not_tcp:
cmp al, PROTOCOL_UDP
jne .not_udp
DEBUGF 1,"K : ip_rx - UDP packet\n"
; DEBUGF 1,"K : ip_rx - UDP packet\n"
mov eax, dword[buffer_number]
call udp_rx
jmp .exit
 
.not_udp:
cmp al , PROTOCOL_ICMP
jne .dump ;protocol ain't supported
cmp al, PROTOCOL_ICMP
jne .dump.6 ;protocol ain't supported
 
DEBUGF 1,"K : ip_rx - ICMP packet\n"
; DEBUGF 1,"K : ip_rx - ICMP packet\n"
;GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx
mov eax, dword[buffer_number]
stdcall icmp_rx,eax,ebx,ecx ;buffer_number,IPPacketBase,IPHeaderLength
185,13 → 210,32
jmp .exit
 
 
.dump:
; No protocol handler available, so
; silently dump the packet, freeing up the queue buffer
.dump.1:
DEBUGF 1, "K : ip_rx - dumped (checksum: 0x%x-0x%x)\n", dx, ax
jmp .dump.x
 
inc dword [dumped_rx_count]
.dump.2:
DEBUGF 1, "K : ip_rx - dumped (ip: %u.%u.%u.%u)\n", [ebx + IP_PACKET.DestinationAddress + 0]:1, [ebx + IP_PACKET.DestinationAddress + 1]:1, [ebx + IP_PACKET.DestinationAddress + 2]:1, [ebx + IP_PACKET.DestinationAddress + 3]:1
jmp .dump.x
 
mov eax, dword[buffer_number]
.dump.3:
DEBUGF 1, "K : ip_rx - dumped (ihl: %u)\n", al
jmp .dump.x
 
.dump.4:
DEBUGF 1, "K : ip_rx - dumped (ihl: %u)\n", [ebx + IP_PACKET.TimeToLive]
jmp .dump.x
 
.dump.5:
DEBUGF 1, "K : ip_rx - dumped (flags: 0x%x)\n", ax
jmp .dump.x
 
.dump.6:
DEBUGF 1, "K : ip_rx - dumped (proto: %u)\n", [ebx + IP_PACKET.Protocol]:1
 
.dump.x:
inc dword[dumped_rx_count]
mov eax, [buffer_number]
call freeBuff
 
.exit:
/kernel/trunk/network/queue.inc
43,18 → 43,19
; all other registers preserved
; This always works, so no error returned
;***************************************************************************
uglobal
freeBuff_cnt dd ?
endg
freeBuff:
; inc [freeBuff_cnt]
; DEBUGF 1, "K : freeBuff (%u)\n", [freeBuff_cnt]
push ebx
push ecx
mov ebx, EMPTY_QUEUE
shl ebx, 1
add ebx, queues
mov ebx, queues + EMPTY_QUEUE * 2
cli ; Ensure that another process does not interfer
movzx ecx, word [ebx]
mov cx, [ebx]
mov [ebx], ax
shl eax, 1
add eax, queueList
mov [eax], cx
mov [queueList + eax * 2], cx
sti
pop ecx
pop ebx
78,7 → 79,7
add ebx, queues
movzx ecx, word [ebx]
cmp cx, NO_BUFFER
je qs_exit
je qs_exit
 
qs_001:
inc eax
86,7 → 87,7
add ecx, queueList
movzx ecx, word [ecx]
cmp cx, NO_BUFFER
je qs_exit
je qs_exit
jmp qs_001
 
qs_exit:
105,15 → 106,20
; all other registers preserved
; This always works, so no error returned
;***************************************************************************
uglobal
queue_cnt dd ?
endg
queue:
; inc [queue_cnt]
; DEBUGF 1, "K : queue (%u)\n", [queue_cnt]
push ebx
shl ebx, 1
add ebx, queueList ; eax now holds address of queue entry
add ebx, queueList ; eax now holds address of queue entry
mov [ebx], word NO_BUFFER ; This buffer will be the last
 
cli
shl eax, 1
add eax, queues ; eax now holds address of queue
add eax, queues ; eax now holds address of queue
movzx ebx, word [eax]
 
cmp bx, NO_BUFFER
155,18 → 161,23
; all other registers preserved
;
;***************************************************************************
uglobal
dequeue_cnt dd ?
endg
dequeue:
push ebx
shl eax, 1
add eax, queues ; eax now holds address of queue
add eax, queues ; eax now holds address of queue
mov ebx, eax
cli
movzx eax, word [eax]
cmp ax, NO_BUFFER
je dq_exit
je dq_exit
; inc [dequeue_cnt]
; DEBUGF 1, "K : dequeue (%u)\n", [dequeue_cnt]
push eax
shl eax, 1
add eax, queueList ; eax now holds address of queue entry
add eax, queueList ; eax now holds address of queue entry
mov ax, [eax]
mov [ebx], ax
pop eax
/kernel/trunk/network/socket.inc
77,21 → 77,21
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 72| Retransmit queue # NOW WINDOW SIZE TIMER INTEL format|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
; 76| RX offset from
; 76| RX Data |
; 76| RX Data Buffer |
; +-+-+-.......... -+
 
 
; so, define struct
struc SOCKET
{ .Status dd ? ;+00 - Status ( of this buffer )
{
.Status dd ? ;+00 - Status ( of this buffer )
.PID dd ? ;+04 - Application Process ID
.LocalIP dd ? ;+08 - Local IP Address
.LocalIP dd ? ;+08 - Local IP Address
.LocalPort dw ? ;+12 - Local Port
.UnusedL dw ? ;+14 - may be removed in future
.RemoteIP dd ? ;+16 - Remote IP Address
.RemotePort dw ? ;+20 - Remote Port
.UnusedR dw ? ;+22 - may be removed in future
.OrigRemoteIP dd ?
.OrigRemotePort dw ?
.rxDataCount dd ? ;+24 - Rx Data Count
.TCBState dd ? ;+28 - TCB STATE
.TCBTimer dd ? ;+32 - TCB Timer (seconds)
105,6 → 105,8
.SEG_LEN dd ? ;+64 - Segment length
.SEG_WND dd ? ;+68 - Segment window
.wndsizeTimer dd ? ;+72 - Retransmit queue # NOW WINDOW SIZE TIMER
.PrevPtr dd ?
.NextPtr dd ?
.rxData dd ? ;+76 - receive data buffer here
}
 
113,21 → 115,128
end virtual
 
; simple macro calcing real memory address of SOCKET struct by socket's
macro Index2RealAddr reg
{
shl reg, 12
add reg, sockets
}
;macro Index2RealAddr reg
;{
; shl reg, 12
; add reg, sockets
;}
 
;Constants
; current socket statuses
SOCK_EMPTY equ 0 ; socket not in use
SOCK_OPEN equ 1 ; open issued, but no data sent
SOCK_EMPTY = 0 ; socket not in use
SOCK_OPEN = 1 ; open issued, but no data sent
 
; TCP opening modes
SOCKET_PASSIVE equ 0
SOCKET_ACTIVE equ 1
 
proc net_socket_alloc stdcall uses ebx ecx edx edi
stdcall kernel_alloc, SOCKETBUFFSIZE
DEBUGF 1, "K : net_socket_alloc (0x%x)\n", eax
or eax, eax
jz .exit
 
push eax
mov edi, eax
mov ecx, SOCKETBUFFSIZE / 4
cld
xor eax, eax
rep stosd
pop eax
 
mov ebx, net_sockets
push [ebx + SOCKET.NextPtr]
mov [ebx + SOCKET.NextPtr], eax
mov [eax + SOCKET.PrevPtr], ebx
pop ebx
mov [eax + SOCKET.NextPtr], ebx
or ebx, ebx
jz @f
mov [ebx + SOCKET.PrevPtr], eax
 
@@: mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx
 
.exit:
ret
endp
 
proc net_socket_free stdcall uses ebx ecx edx, sock:DWORD
mov eax, [sock]
DEBUGF 1, "K : net_socket_free (0x%x)\n", eax
or eax, eax
jz .error
 
mov ebx, net_sockets
mov ecx, [TASK_BASE]
mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .error
cmp ebx, eax
jne .next_socket
;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket
 
mov ebx, [eax + SOCKET.NextPtr]
mov eax, [eax + SOCKET.PrevPtr]
mov [eax + SOCKET.NextPtr], ebx
or ebx, ebx
jz @f
mov [ebx + SOCKET.PrevPtr], eax
 
@@: stdcall kernel_free, [sock]
ret
 
.error:
DEBUGF 1, "K : failed\n"
ret
endp
 
proc net_socket_num_to_addr stdcall uses ebx ecx, x:DWORD
; FIXME: do real transform
mov eax, [x]
mov ebx, net_sockets
mov ecx, [TASK_BASE]
mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .error
cmp ebx, eax
jne .next_socket
;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket
ret
 
.error:
xor eax, eax
ret
endp
 
proc net_socket_addr_to_num stdcall uses ebx ecx, x:DWORD
; FIXME: do real transform
mov eax, [x]
mov ebx, net_sockets
mov ecx, [TASK_BASE]
mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .error
cmp ebx, eax
jne .next_socket
;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket
ret
 
.error:
xor eax, eax
ret
endp
 
;***************************************************************************
; Function
; is_localport_unused
140,55 → 249,30
; On return, eax = 1 for free, 0 for in use
;
;***************************************************************************
is_localport_unused:
mov al, bh
mov ah, bl
mov bx, ax
proc is_localport_unused stdcall
 
mov edx, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
mov eax, 0 ; Assume the return value is 'in use'
xchg bl, bh
 
ilu1:
sub edx, SOCKETBUFFSIZE
cmp [edx + sockets + SOCKET.LocalPort], bx
loopnz ilu1 ; Return back if the socket is occupied
xor eax, eax ; Assume the return value is 'free'
inc al
mov edx, net_sockets
 
jz ilu_exit
inc eax ; return port not in use
.next_socket:
mov edx, [edx + SOCKET.NextPtr]
or edx, edx
jz .exit
cmp [edx + SOCKET.LocalPort], bx
jne .next_socket ; Return back if the port is not occupied
 
ilu_exit:
ret
dec al ; return 'in use'
 
.exit:
ret
endp
 
 
;***************************************************************************
; Function
; get_free_socket
;
; Description
;
;***************************************************************************
get_free_socket:
push ecx
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
 
gfs1:
sub eax, SOCKETBUFFSIZE
cmp [eax + sockets + SOCKET.Status], dword SOCK_EMPTY
loopnz gfs1 ; Return back if the socket is occupied
mov eax, ecx
pop ecx
jz gfs_exit
mov eax, 0xFFFFFFFF
 
gfs_exit:
ret
 
 
;***************************************************************************
; Function
; socket_open
;
; Description
199,38 → 283,35
; return socket # in eax, -1 if none available
;
;***************************************************************************
socket_open:
call get_free_socket
proc socket_open stdcall
call net_socket_alloc
or eax, eax
jz .error
 
cmp eax, 0xFFFFFFFF
jz so_exit
DEBUGF 1, "K : socket_open (0x%x)\n", eax
 
; ax holds the socket number that is free. Get real address
push eax
Index2RealAddr eax
push eax
 
mov [eax + SOCKET.Status], dword SOCK_OPEN
mov [eax + SOCKET.Status], SOCK_OPEN
xchg bh, bl
mov [eax + SOCKET.LocalPort], bx
xchg ch, cl
mov [eax + SOCKET.RemotePort], cx
mov ebx, [stack_ip]
mov [eax + SOCKET.LocalIP], ebx
mov [eax + SOCKET.RemoteIP], edx
 
xchg bh, bl
mov [eax + SOCKET.LocalPort], bx
xchg ch, cl
mov [eax + SOCKET.RemotePort], cx
;pop eax ; Get the socket number back, so we can return it
stdcall net_socket_addr_to_num
ret
 
mov ebx, [stack_ip]
mov [eax + SOCKET.LocalIP], ebx
mov [eax + SOCKET.RemoteIP], edx
mov [eax + SOCKET.rxDataCount], dword 0 ; recieved data count
.error:
DEBUGF 1, "K : socket_open (fail)\n"
or eax, -1
ret
endp
 
mov esi, [TASK_BASE]
mov ebx, [esi+TASKDATA.pid]
mov [eax + SOCKET.PID], ebx ; save the process ID
pop eax ; Get the socket number back, so we can return it
 
so_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_open_tcp
245,94 → 326,110
; return socket # in eax, -1 if none available
;
;***************************************************************************
socket_open_tcp:
call get_free_socket
proc socket_open_tcp stdcall
local sockAddr dd ?
 
cmp eax, 0xFFFFFFFF
jz so_exit
cmp esi, SOCKET_PASSIVE
jne .skip_port_check
 
; ax holds the socket number that is free. Get real address
push eax
Index2RealAddr eax
push ebx
mov eax, ebx
xchg al, ah
mov ebx, net_sockets
 
mov [sktAddr], eax
mov [eax], dword SOCK_OPEN
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .last_socket
cmp [ebx + SOCKET.TCBState], TCB_LISTEN
jne .next_socket
cmp [ebx + SOCKET.LocalPort], ax
jne .next_socket
 
; TODO - check this works!
mov [eax + SOCKET.wndsizeTimer], dword 0 ; Reset the window timer.
xchg al, ah
DEBUGF 1, "K : error: port %u is listened by 0x%x\n", ax, ebx
pop ebx
jmp .error
 
xchg bh, bl
mov [eax + SOCKET.LocalPort], bx
; mov [eax + 12], byte bh ; Local port ( LS 16 bits )
; mov [eax + 13], byte bl ; Local port ( LS 16 bits )
.last_socket:
pop ebx
 
xchg ch, cl
mov [eax + SOCKET.RemotePort], cx
; mov [eax + 20], ch ; Remote Port ( LS 16 bits )
; mov [eax + 21], cl ; Remote Port ( LS 16 bits )
.skip_port_check:
call net_socket_alloc
or eax, eax
jz .error
 
mov ebx, [stack_ip]
mov [eax + SOCKET.LocalIP], ebx
mov [eax + SOCKET.RemoteIP], edx
mov [eax + SOCKET.rxDataCount], dword 0
DEBUGF 1, "K : socket_open_tcp (0x%x)\n", eax
 
; Now fill in TCB state
mov ebx, TCB_LISTEN
cmp esi, SOCKET_PASSIVE
jz sot_001
mov ebx, TCB_SYN_SENT
mov [sockAddr], eax
 
sot_001:
mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB
; TODO - check this works!
;xxx: already 0 (intialized by net_socket_alloc)
;mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer.
 
mov esi, [TASK_BASE]
mov ecx, [esi+TASKDATA.pid]
mov [eax + SOCKET.PID], ecx ; save the process ID
xchg bh, bl
mov [eax + SOCKET.LocalPort], bx
xchg ch, cl
mov [eax + SOCKET.RemotePort], cx
mov [eax + SOCKET.OrigRemotePort], cx
mov ebx, [stack_ip]
mov [eax + SOCKET.LocalIP], ebx
mov [eax + SOCKET.RemoteIP], edx
mov [eax + SOCKET.OrigRemoteIP], edx
 
cmp ebx, TCB_LISTEN
je sot_done
mov ebx, TCB_LISTEN
cmp esi, SOCKET_PASSIVE
je @f
mov ebx, TCB_SYN_SENT
@@: mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB
 
; Now, if we are in active mode, then we have to send a SYN to the specified remote port
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je sot_done
cmp ebx, TCB_LISTEN
je .exit
 
push eax
; Now, if we are in active mode, then we have to send a SYN to the specified remote port
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .exit
 
mov bl, 0x02 ; SYN
mov ecx, 0
push eax
 
call buildTCPPacket
mov bl, TH_SYN
xor ecx, ecx
stdcall build_tcp_packet, [sockAddr]
 
mov eax, NET1OUT_QUEUE
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
mov eax, IPIN_QUEUE
 
mov edx, [stack_ip]
mov ecx, [sktAddr ]
mov ecx, [ecx + 16]
cmp edx, ecx
jne sot_notlocal
mov eax, IPIN_QUEUE
.not_local:
; Send it.
pop ebx
call queue
 
sot_notlocal:
; Send it.
pop ebx
call queue
mov esi, [sockAddr]
 
mov esi, [sktAddr]
; increment SND.NXT in socket
add esi, SOCKET.SND_NXT
call inc_inet_esi
 
; increment SND.NXT in socket
add esi, 48
call inc_inet_esi
.exit:
mov ebx, [sockAddr]
mov [ebx + SOCKET.Status], SOCK_OPEN
;pop eax ; Get the socket number back, so we can return it
stdcall net_socket_addr_to_num, ebx
ret
 
sot_done:
pop eax ; Get the socket number back, so we can return it
.error:
DEBUGF 1, "K : socket_open_tcp (fail)\n"
or eax, -1
ret
endp
 
sot_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_close
342,26 → 439,33
; returns 0 for ok, -1 for socket not open (fail)
;
;***************************************************************************
socket_close:
mov eax, 0xFFFFFFFF ; assume this operation will fail..
cmp ebx, NUM_SOCKETS
jae sc_exit
Index2RealAddr ebx
cmp [ebx + SOCKET.Status], dword SOCK_EMPTY
jz sc_exit
proc socket_close stdcall
DEBUGF 1, "K : socket_close (0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
or eax, eax
jz .error
 
; Clear the socket varaibles
xor eax, eax
mov edi, ebx
mov ecx, SOCKETHEADERSIZE
cld
rep stosb
cmp [eax + SOCKET.Status], dword SOCK_EMPTY
jz .error
 
sc_exit:
ret
; Clear the socket varaibles
stdcall net_socket_free, eax
; mov edi, eax
; xor eax, eax
; mov ecx, SOCKETHEADERSIZE
; cld
; rep stosb
 
xor eax, eax
ret
 
.error:
DEBUGF 1, "K : socket_close (fail)\n"
or eax, -1
ret
endp
 
 
;***************************************************************************
; Function
; socket_close_tcp
371,112 → 475,120
; returns 0 for ok, -1 for socket not open (fail)
;
;***************************************************************************
socket_close_tcp:
; first, remove any resend entries
pusha
proc socket_close_tcp stdcall
local sockAddr dd ?
DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx
; first, remove any resend entries
pusha
 
mov esi, resendQ
mov ecx, 0
mov esi, resendQ
mov ecx, 0
 
sct001:
cmp ecx, NUMRESENDENTRIES
je sct003 ; None left
cmp [esi], bl
je sct002 ; found one
inc ecx
add esi, 4
jmp sct001
.next_resendq:
cmp ecx, NUMRESENDENTRIES
je .last_resendq ; None left
;cmp [esi], bl ; XTODO: bl -> ebx
cmp [esi + 4], ebx
je @f ; found one
inc ecx
add esi, 8
jmp .next_resendq
 
sct002:
;@@: mov byte[esi], 0xff ; XTODO: 0xff -> 0
@@: mov dword[esi + 4], 0
inc ecx
add esi, 8
jmp .next_resendq
 
mov [esi], byte 0xFF
jmp sct001
.last_resendq:
popa
 
sct003:
popa
stdcall net_socket_num_to_addr, ebx
or eax, eax
jz .error
 
Index2RealAddr ebx
mov [sktAddr], ebx
mov eax, 0xFFFFFFFF ; assume this operation will fail..
cmp [ebx + SOCKET.Status], dword SOCK_EMPTY
jz sct_exit
mov ebx, eax
mov [sockAddr], eax
cmp [ebx + SOCKET.Status], SOCK_EMPTY
je .error
 
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stl_exit
cmp [ebx + SOCKET.TCBState], TCB_LISTEN ;xxx
je .destroy_tcb ;xxx
cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT ;xxx
je .destroy_tcb ;xxx
 
push eax
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .error
 
mov bl, 0x11 ; FIN + ACK
mov ecx, 0
mov esi, 0
push eax
 
call buildTCPPacket
;xxx mov bl, TH_FIN + TH_ACK
mov bl, TH_FIN ;xxx
xor ecx, ecx
xor esi, esi
stdcall build_tcp_packet, [sockAddr]
 
mov ebx, [sktAddr]
mov ebx, [sockAddr]
; increament SND.NXT in socket
lea esi, [ebx + SOCKET.SND_NXT]
call inc_inet_esi
 
; increament SND.NXT in socket
mov esi, 48
add esi, ebx
call inc_inet_esi
; Get the socket state
mov eax, [ebx + SOCKET.TCBState]
;xxx cmp eax, TCB_LISTEN
;xxx je .destroy_tcb
;xxx cmp eax, TCB_SYN_SENT
;xxx je .destroy_tcb
cmp eax, TCB_SYN_RECEIVED
je .fin_wait_1
cmp eax, TCB_ESTABLISHED
je .fin_wait_1
 
; assume CLOSE WAIT
; Send a fin, then enter last-ack state
; TODO: check if it's really a TCB_CLOSE_WAIT
mov [ebx + SOCKET.TCBState], TCB_LAST_ACK
jmp .send
 
; Get the socket state
mov eax, [ebx + SOCKET.TCBState]
cmp eax, TCB_LISTEN
je destroyTCB
cmp eax, TCB_SYN_SENT
je destroyTCB
cmp eax, TCB_SYN_RECEIVED
je sct_finwait1
cmp eax, TCB_ESTABLISHED
je sct_finwait1
.fin_wait_1:
; Send a fin, then enter finwait2 state
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1
 
; assume CLOSE WAIT
; Send a fin, then enter last-ack state
mov eax, TCB_LAST_ACK
mov [ebx + SOCKET.TCBState], eax
xor eax, eax
jmp sct_send
.send:
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
mov eax, IPIN_QUEUE
 
sct_finwait1:
; Send a fin, then enter finwait2 state
mov eax, TCB_FIN_WAIT_1
mov [ebx + SOCKET.TCBState], eax
xor eax, eax
.not_local:
; Send it.
pop ebx
call queue
jmp .exit
 
sct_send:
mov eax, NET1OUT_QUEUE
.destroy_tcb:
;xxx pop eax
 
mov edx, [stack_ip]
mov ecx, [sktAddr ]
mov ecx, [ecx + 16]
cmp edx, ecx
jne sct_notlocal
mov eax, IPIN_QUEUE
; Clear the socket variables
;xxx stdcall net_socket_free, [sockAddr]
stdcall net_socket_free, ebx
 
sct_notlocal:
; Send it.
pop ebx
call queue
jmp sct_exit
.exit:
xor eax, eax
ret
 
destroyTCB:
pop eax
; Clear the socket varaibles
xor eax, eax
mov edi, ebx
mov ecx, SOCKETHEADERSIZE
cld
rep stosb
.error:
DEBUGF 1, "K : socket_close_tcp (fail)\n"
or eax, -1
ret
endp
 
sct_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_poll
486,12 → 598,20
; returns count in eax.
;
;***************************************************************************
socket_poll:
Index2RealAddr ebx
mov eax, [ebx + SOCKET.rxDataCount]
proc socket_poll stdcall
; DEBUGF 1, "socket_poll(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
or eax, eax
jz .error
 
ret
mov eax, [eax + SOCKET.rxDataCount]
ret
 
.error:
;or eax, -1
xor eax, eax
ret
endp
 
 
;***************************************************************************
503,14 → 623,27
; returns TCB state in eax.
;
;***************************************************************************
socket_status:
Index2RealAddr ebx
mov eax, [ebx + SOCKET.TCBState]
proc socket_status stdcall
;; DEBUGF 1, "socket_status(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
or eax, eax
jz .error
 
ret
mov eax, [eax + SOCKET.TCBState]
ret
 
.error:
;or eax, -1
xor eax, eax
ret
endp
 
; Index2RealAddr ebx
; mov eax, [ebx + SOCKET.TCBState]
;
; ret
 
 
;***************************************************************************
; Function
; socket_read
520,35 → 653,40
; returns # of bytes remaining in eax, data in bl
;
;***************************************************************************
socket_read:
Index2RealAddr ebx
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes
mov ecx, 1
test eax, eax
jz sr2
proc socket_read stdcall
; DEBUGF 1, "socket_read(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
or eax, eax
jz .error
 
dec eax
mov esi, ebx ; esi is address of socket
mov [ebx + SOCKET.rxDataCount], eax ; store new count
;movzx ebx, byte [ebx + SOCKET.rxData] ; get the byte
movzx ebx, byte [ebx + SOCKETHEADERSIZE] ; get the byte
add esi, SOCKETHEADERSIZE
mov edi, esi
inc esi
mov ebx, eax
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes
test eax, eax
jz .error
 
mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4
cld
rep movsd
xor ecx, ecx
dec eax
mov esi, ebx ; esi is address of socket
mov [ebx + SOCKET.rxDataCount], eax ; store new count
;movzx ebx, byte[ebx + SOCKET.rxData] ; get the byte
movzx ebx, byte[ebx + SOCKETHEADERSIZE] ; get the byte
add esi, SOCKETHEADERSIZE
mov edi, esi
inc esi
 
sr1:
jmp sor_exit
mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4
lea edi, [ebx + SOCKETHEADERSIZE]
lea esi, [edi + 1]
cld
rep movsd
 
sr2:
xor bl, bl
ret
 
sor_exit:
ret
.error:
;or eax, -1
xor eax, eax
xor ebx, ebx
ret
endp
 
 
;***************************************************************************
562,63 → 700,71
; returns # of bytes copied in eax
;
;***************************************************************************
socket_read_packet:
Index2RealAddr ebx ; get real socket address
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes
test eax, eax ; if count of bytes is zero..
jz .exit ; exit function (eax will be zero)
proc socket_read_packet stdcall
; DEBUGF 1, "socket_read_packet(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx ; get real socket address
or eax, eax
jz .error
 
test edx, edx ; if buffer size is zero, copy all data
jz .copyallbytes
cmp edx, eax ; if buffer size is larger then the bytes of data, copy all data
jge .copyallbytes
mov ebx, eax
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes
test eax, eax ; if count of bytes is zero..
jz .exit ; exit function (eax will be zero)
 
sub eax, edx ; store new count (data bytes in buffer - bytes we're about to copy)
mov [ebx + SOCKET.rxDataCount], eax ;
push eax
mov eax, edx ; number of bytes we want to copy must be in eax
call .startcopy ; copy to the application
test edx, edx ; if buffer size is zero, copy all data
jz .copy_all_bytes
cmp edx, eax ; if buffer size is larger then the bytes of data, copy all data
jge .copy_all_bytes
 
mov esi, ebx ; now we're going to copy the remaining bytes to the beginning
add esi, SOCKETHEADERSIZE ; we dont need to copy the header
mov edi, esi ; edi is where we're going to copy to
add esi, edx ; esi is from where we copy
pop ecx ; count of bytes we have left
push ecx ; push it again so we can re-use it later
shr ecx, 2 ; divide eax by 4
cld
rep movsd ; copy all full dwords
pop ecx
and ecx, 3
rep movsb ; copy remaining bytes
sub eax, edx ; store new count (data bytes in buffer - bytes we're about to copy)
mov [ebx + SOCKET.rxDataCount], eax ;
push eax
mov eax, edx ; number of bytes we want to copy must be in eax
call .start_copy ; copy to the application
 
ret ; at last, exit
mov esi, ebx ; now we're going to copy the remaining bytes to the beginning
add esi, SOCKETHEADERSIZE ; we dont need to copy the header
mov edi, esi ; edi is where we're going to copy to
add esi, edx ; esi is from where we copy
pop ecx ; count of bytes we have left
push ecx ; push it again so we can re-use it later
shr ecx, 2 ; divide eax by 4
cld
rep movsd ; copy all full dwords
pop ecx
and ecx, 3
rep movsb ; copy remaining bytes
 
.copyallbytes:
xor esi, esi
mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero)
.exit:
ret ; at last, exit
 
.startcopy:
mov edi, ecx ;
; add edi, std_application_base_address ; get data pointer to buffer in application
.error:
;or eax, -1
xor eax, eax
ret
 
mov esi, ebx ;
add esi, SOCKETHEADERSIZE ; we dont need to copy the header
mov ecx, eax ; eax is count of bytes
push ecx
shr ecx, 2 ; divide eax by 4
cld ; copy all full dwords
rep movsd ;
pop ecx
and ecx, 3
rep movsb ; copy the rest bytes
.copy_all_bytes:
xor esi, esi
mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero)
call .start_copy
ret
 
.exit:
ret ; exit, or go back to shift remaining bytes if any
.start_copy:
mov edi, ecx
mov esi, ebx
add esi, SOCKETHEADERSIZE ; we dont need to copy the header
mov ecx, eax ; eax is count of bytes
push ecx
shr ecx, 2 ; divide eax by 4
cld ; copy all full dwords
rep movsd
pop ecx
and ecx, 3
rep movsb ; copy the rest bytes
retn ; exit, or go back to shift remaining bytes if any
endp
 
 
 
 
;***************************************************************************
; Function
; socket_write
631,170 → 777,163
; could not queue IP packet )
;
;***************************************************************************
socket_write:
Index2RealAddr ebx
proc socket_write stdcall
; DEBUGF 1, "socket_write(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx ; get real socket address
or eax, eax
jz .error
 
mov eax, 0xFFFFFFFF
; If the socket is invalid, return with an error code
cmp [ebx], dword SOCK_EMPTY
je sw_exit
mov ebx, eax
 
; If the socket is invalid, return with an error code
cmp [ebx + SOCKET.Status], SOCK_EMPTY
je .error
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je sw_exit
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .error
 
; Save the queue entry number
push eax
; Save the queue entry number
push eax
 
; save the pointers to the data buffer & size
push edx
push ecx
; save the pointers to the data buffer & size
push edx
push ecx
 
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
mov edx, eax
mov edx, eax
 
; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
 
; Fill in the IP header ( some data is in the socket descriptor)
mov eax, [ebx + 8]
mov [edx + 12], eax ; source IP
mov eax, [ebx + 16]
mov [edx + 16], eax ; Destination IP
; Fill in the IP header (some data is in the socket descriptor)
mov eax, [ebx + SOCKET.LocalIP]
mov [edx + IP_PACKET.SourceAddress], eax
mov eax, [ebx + SOCKET.RemoteIP]
mov [edx + IP_PACKET.DestinationAddress], eax
 
mov al, 0x45
mov [edx], al ; Version, IHL
xor al, al
mov [edx + 1], al ; Type of service
mov [edx + IP_PACKET.VersionAndIHL], 0x45
mov [edx + IP_PACKET.TypeOfService], 0
 
pop eax ; Get the UDP data length
push eax
pop eax ; Get the UDP data length
push eax
 
add eax, 20 + 8 ; add IP header and UDP header lengths
mov [edx + 2], ah
mov [edx + 3], al
xor al, al
mov [edx + 4], al
mov [edx + 5], al
mov al, 0x40
mov [edx + 6], al
xor al, al
mov [edx + 7], al
mov al, 0x20
mov [edx + 8], al
mov al, 17
mov [edx + 9], al
add eax, 20 + 8 ; add IP header and UDP header lengths
xchg al, ah
mov [edx + IP_PACKET.TotalLength], ax
xor eax, eax
mov [edx + IP_PACKET.Identification], ax
mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
mov [edx + IP_PACKET.TimeToLive], 0x20
mov [edx + IP_PACKET.Protocol], PROTOCOL_UDP
 
; Checksum left unfilled
xor ax, ax
mov [edx + 10], ax
; Checksum left unfilled
mov [edx + IP_PACKET.HeaderChecksum], ax
 
; Fill in the UDP header ( some data is in the socket descriptor)
mov ax, [ebx + 12]
mov [edx + 20], ax
; Fill in the UDP header (some data is in the socket descriptor)
mov ax, [ebx + SOCKET.LocalPort]
mov [edx + 20 + UDP_PACKET.SourcePort], ax
 
mov ax, [ebx + 20]
mov [edx + 20 + 2], ax
mov ax, [ebx + SOCKET.RemotePort]
mov [edx + 20 + UDP_PACKET.DestinationPort], ax
 
pop eax
push eax
pop eax
push eax
 
add eax, 8
mov [edx + 20 + 4], ah
mov [edx + 20 + 5], al
add eax, 8
xchg al, ah
mov [edx + 20 + UDP_PACKET.Length], ax
 
; Checksum left unfilled
xor ax, ax
mov [edx + 20 + 6], ax
; Checksum left unfilled
xor eax, eax
mov [edx + 20 + UDP_PACKET.Checksum], ax
 
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
pop eax ; get callers ptr to data to send
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
pop eax ; get callers ptr to data to send
 
; Get the address of the callers data
mov edi, [TASK_BASE]
add edi, TASKDATA.mem_start
add eax, [edi]
mov esi, eax
; Get the address of the callers data
mov edi, [TASK_BASE]
add edi, TASKDATA.mem_start
add eax, [edi]
mov esi, eax
 
mov edi, edx
add edi, 28
cld
rep movsb ; copy the data across
mov edi, edx
add edi, 28
cld
rep movsb ; copy the data across
 
; we have edx as IPbuffer ptr.
; Fill in the UDP checksum
; First, fill in pseudoheader
mov eax, [edx + 12]
mov [pseudoHeader], eax
mov eax, [edx + 16]
mov [pseudoHeader+4], eax
mov ax, 0x1100 ; 0 + protocol
mov [pseudoHeader+8], ax
add ebx, 8
mov eax, ebx
mov [pseudoHeader+10], ah
mov [pseudoHeader+11], al
; we have edx as IPbuffer ptr.
; Fill in the UDP checksum
; First, fill in pseudoheader
mov eax, [edx + IP_PACKET.SourceAddress]
mov [pseudoHeader], eax
mov eax, [edx + IP_PACKET.DestinationAddress]
mov [pseudoHeader + 4], eax
mov word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0 ; 0 + protocol
add ebx, 8
mov eax, ebx
xchg al, ah
mov [pseudoHeader + 10], ax
 
mov eax, pseudoHeader
mov [checkAdd1], eax
mov [checkSize1], word 12
mov eax, edx
add eax, 20
mov [checkAdd2], eax
mov eax, ebx
mov [checkSize2], ax ; was eax!! mjh 8/7/02
mov eax, pseudoHeader
mov [checkAdd1], eax
mov [checkSize1], word 12
mov eax, edx
add eax, 20
mov [checkAdd2], eax
mov eax, ebx
mov [checkSize2], ax ; was eax!! mjh 8/7/02
 
call checksum
call checksum
 
; store it in the UDP checksum ( in the correct order! )
mov ax, [checkResult]
; store it in the UDP checksum ( in the correct order! )
mov ax, [checkResult]
 
; If the UDP checksum computes to 0, we must make it 0xffff
; (0 is reserved for 'not used')
cmp ax, 0
jne sw_001
mov ax, 0xffff
; If the UDP checksum computes to 0, we must make it 0xffff
; (0 is reserved for 'not used')
test ax, ax
jnz @f
mov ax, 0xffff
 
sw_001:
mov [edx + 20 + 6], ah
mov [edx + 20 + 7], al
@@: xchg al, ah
mov [edx + 20 + UDP_PACKET.Checksum], ax
 
; Fill in the IP header checksum
GET_IHL ecx,edx ; get IP-Header length
stdcall checksum_jb,edx,ecx ; buf_ptr, buf_size
; Fill in the IP header checksum
GET_IHL ecx,edx ; get IP-Header length
stdcall checksum_jb,edx,ecx ; buf_ptr, buf_size
xchg al, ah
mov [edx + IP_PACKET.HeaderChecksum], ax
 
mov [edx + 10], ah
mov [edx + 11], al
; Check destination IP address.
; If it is the local host IP, route it back to IP_RX
 
; Check destination IP address.
; If it is the local host IP, route it back to IP_RX
pop ebx
 
pop ebx
mov eax, NET1OUT_QUEUE
mov eax, NET1OUT_QUEUE
mov ecx, [edx + SOCKET.RemoteIP]
mov edx, [stack_ip]
cmp edx, ecx
jne .not_local
mov eax, IPIN_QUEUE
 
mov ecx, [ edx + 16]
mov edx, [stack_ip]
cmp edx, ecx
jne sw_notlocal
mov eax, IPIN_QUEUE
.not_local:
; Send it.
call queue
 
sw_notlocal:
; Send it.
call queue
xor eax, eax
ret
 
xor eax, eax
.error:
or eax, -1
ret
endp
 
sw_exit:
ret
 
 
 
;***************************************************************************
; Function
; socket_write_tcp
807,128 → 946,131
; could not queue IP packet )
;
;***************************************************************************
socket_write_tcp:
Index2RealAddr ebx
proc socket_write_tcp stdcall
local sockAddr dd ?
 
mov [sktAddr], ebx
; DEBUGF 1, "socket_write_tcp(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
or eax, eax
jz .error
 
mov eax, 0xFFFFFFFF
; If the socket is invalid, return with an error code
cmp [ebx], dword SOCK_EMPTY
je swt_exit
mov ebx, eax
mov [sockAddr], ebx
 
; If the sockets window timer is nonzero, do not queue packet
; TODO - done
cmp [ebx + SOCKET.wndsizeTimer], dword 0
jne swt_exit
; If the socket is invalid, return with an error code
cmp [ebx + SOCKET.Status], SOCK_EMPTY
je .error
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je swt_exit
; If the sockets window timer is nonzero, do not queue packet
; TODO - done
cmp [ebx + SOCKET.wndsizeTimer], 0
jne .error
 
push eax
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .error
 
mov bl, 0x10 ; ACK
push eax
 
; Get the address of the callers data
mov edi, [TASK_BASE]
add edi, TASKDATA.mem_start
add edx, [edi]
mov esi, edx
; Get the address of the callers data
mov edi, [TASK_BASE]
add edi, TASKDATA.mem_start
add edx, [edi]
mov esi, edx
 
pop eax
push eax
pop eax
push eax
 
push ecx
call buildTCPPacket
pop ecx
push ecx
mov bl, TH_ACK
stdcall build_tcp_packet, [sockAddr]
pop ecx
 
; Check destination IP address.
; If it is the local host IP, route it back to IP_RX
; Check destination IP address.
; If it is the local host IP, route it back to IP_RX
 
pop ebx
push ecx
mov eax, NET1OUT_QUEUE
pop ebx
push ecx
 
mov edx, [stack_ip]
mov ecx, [sktAddr ]
mov ecx, [ecx + 16]
cmp edx, ecx
jne swt_notlocal
mov eax, IPIN_QUEUE
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
mov eax, IPIN_QUEUE
 
swt_notlocal:
pop ecx
.not_local:
pop ecx
push ebx ; save ipbuffer number
 
push ebx ; save ipbuffer number
call queue
 
call queue
mov esi, [sockAddr]
 
mov esi, [sktAddr]
; increament SND.NXT in socket
; Amount to increment by is in ecx
add esi, SOCKET.SND_NXT
call add_inet_esi
 
; increament SND.NXT in socket
; Amount to increment by is in ecx
add esi, 48
call add_inet_esi
pop ebx
 
pop ebx
; Copy the IP buffer to a resend queue
; If there isn't one, dont worry about it for now
mov esi, resendQ
mov ecx, 0
 
; Copy the IP buffer to a resend queue
; If there isn't one, dont worry about it for now
mov esi, resendQ
mov ecx, 0
.next_resendq:
cmp ecx, NUMRESENDENTRIES
je .exit ; None found
;cmp byte[esi], 0xff ; XTODO: 0xff -> 0
cmp dword[esi + 4], 0
je @f ; found one
inc ecx
add esi, 8
jmp .next_resendq
 
swt003:
cmp ecx, NUMRESENDENTRIES
je swt001 ; None found
cmp [esi], byte 0xFF
je swt002 ; found one
inc ecx
add esi, 4
jmp swt003
@@: push ebx
 
swt002:
push ebx
; OK, we have a buffer descriptor ptr in esi.
; resend entry # in ecx
; Populate it
; socket #
; retries count
; retry time
; fill IP buffer associated with this descriptor
 
; OK, we have a buffer descriptor ptr in esi.
; resend entry # in ecx
; Populate it
; socket #
; retries count
; retry time
; fill IP buffer associated with this descriptor
stdcall net_socket_addr_to_num, [sockAddr]
;mov [esi], al ; XTODO: al -> eax
mov [esi + 4], eax
mov byte[esi + 1], TCP_RETRIES
mov word[esi + 2], TCP_TIMEOUT
 
mov eax, [sktAddr]
sub eax, sockets
shr eax, 12 ; get skt #
mov [esi], al
mov [esi + 1], byte TCP_RETRIES
mov [esi + 2], word TCP_TIMEOUT
inc ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
mov edi, resendBuffer - IPBUFFSIZE
 
inc ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
mov edi, resendBuffer - IPBUFFSIZE
swt002a:
add edi, IPBUFFSIZE
loop swt002a
@@: add edi, IPBUFFSIZE
loop @b
 
; we have dest buffer location in edi
pop eax
; convert source buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
mov esi, eax
; we have dest buffer location in edi
pop eax
; convert source buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
mov esi, eax
 
; do copy
mov ecx, IPBUFFSIZE
cld
rep movsb
; do copy
mov ecx, IPBUFFSIZE
cld
rep movsb
 
swt001:
xor eax, eax
.exit:
xor eax, eax
ret
 
swt_exit:
ret
 
.error:
or eax, -1
ret
endp
/kernel/trunk/network/stack.inc
37,7 → 37,7
 
uglobal
StackCounters:
dumped_rx_count: dd 0
dumped_rx_count dd 0
arp_tx_count: dd 0
arp_rx_count: dd 0
ip_rx_count: dd 0
46,9 → 46,9
 
; socket buffers
SOCKETBUFFSIZE equ 4096 ; state + config + buffer.
SOCKETHEADERSIZE equ 76 ; thus 4096 - SOCKETHEADERSIZE bytes data
SOCKETHEADERSIZE equ 76+8+8 ; thus 4096 - SOCKETHEADERSIZE bytes data
 
NUM_SOCKETS equ 16 ; Number of open sockets supported. Was 20
;NUM_SOCKETS equ 16 ; Number of open sockets supported. Was 20
 
; IPBUFF status values
BUFF_EMPTY equ 0
59,6 → 59,7
NUM_IPBUFFERS equ 20 ; buffers allocated for TX/RX
 
NUMQUEUES equ 4
 
EMPTY_QUEUE equ 0
IPIN_QUEUE equ 1
IPOUT_QUEUE equ 2
94,7 → 95,7
; TODO :: empty memory area
 
; Address of selected socket
sktAddr equ stack_data + 32
;sktAddr equ stack_data + 32
; Parameter to checksum routine - data ptr
checkAdd1 equ stack_data + 36
; Parameter to checksum routine - 2nd data ptr
110,8 → 111,8
pseudoHeader equ stack_data + 50
 
; receive and transmit IP buffer allocation
sockets equ stack_data + 62
Next_free2 equ sockets + (SOCKETBUFFSIZE * NUM_SOCKETS)
;sockets equ stack_data + 62
Next_free2 equ stack_data + 62;Next_free2 equ sockets + (SOCKETBUFFSIZE * NUM_SOCKETS)
; 1560 byte buffer for rx / tx ethernet packets
Ether_buffer equ Next_free2
Next_free3 equ Ether_buffer + 1518
128,9 → 129,15
 
 
;resendQ equ 0x770000
resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP
;resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP ; XTODO: validate size
resendBuffer equ resendQ + ( 8 * NUMRESENDENTRIES ) ; for TCP
 
 
uglobal
net_sockets_mutex dd 0
net_sockets rd 2
endg
 
; simple macro for memory set operation
macro _memset_dw adr,value,amount
{
151,9 → 158,6
include "queue.inc"
include "eth_drv/ethernet.inc"
include "ip.inc"
include "icmp.inc"
include "tcp.inc"
include "udp.inc"
include "socket.inc"
 
;***************************************************************************
171,7 → 175,8
stack_init:
; Init two address spaces with default values
_memset_dw stack_data_start, 0, 0x20000/4
_memset_dw resendQ, 0xFFFFFFFF, NUMRESENDENTRIES
;_memset_dw resendQ, 0xFFFFFFFF, NUMRESENDENTRIES ; XTODO: validate size
_memset_dw resendQ, 0xFFFFFFFF, NUMRESENDENTRIES * 2
 
; Queries initialization
call queueInit
931,13 → 936,11
pop edx
 
push eax ; save address of IP data
 
; Get the address of the callers data
mov edi,[TASK_BASE]
add edi,TASKDATA.mem_start
add edx,[edi]
mov edi, edx
 
pop eax
 
mov ecx, 1500 ; should get the actual number of bytes to write
/kernel/trunk/network/tcp.inc
15,6 → 15,7
;; v0.6 : Added reset handling in the established state ;;
;; Added a timer per socket to allow delays when ;;
;; rx window gets below 1KB ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
21,23 → 22,30
 
 
; TCP TCB states
TCB_LISTEN equ 1
TCB_SYN_SENT equ 2
TCB_SYN_RECEIVED equ 3
TCB_ESTABLISHED equ 4
TCB_FIN_WAIT_1 equ 5
TCB_FIN_WAIT_2 equ 6
TCB_CLOSE_WAIT equ 7
TCB_CLOSING equ 8
TCB_LAST_ACK equ 9
TCB_TIME_WAIT equ 10
TCB_CLOSED equ 11
TCB_LISTEN equ 1
TCB_SYN_SENT equ 2
TCB_SYN_RECEIVED equ 3
TCB_ESTABLISHED equ 4
TCB_FIN_WAIT_1 equ 5
TCB_FIN_WAIT_2 equ 6
TCB_CLOSE_WAIT equ 7
TCB_CLOSING equ 8
TCB_LAST_ACK equ 9
TCB_TIMED_WAIT equ 10
TCB_CLOSED equ 11
 
TWOMSL equ 10 ; # of secs to wait before closing socket
TH_FIN = 0x01
TH_SYN = 0x02
TH_RST = 0x04
TH_PUSH = 0x08
TH_ACK = 0x10
TH_URG = 0x20
 
TCP_RETRIES equ 5 ; Number of times to resend a packet
TCP_TIMEOUT equ 10 ; resend if not replied to in x hs
TWOMSL equ 10 ; # of secs to wait before closing socket
 
TCP_RETRIES equ 5 ; Number of times to resend a packet
TCP_TIMEOUT equ 10 ; resend if not replied to in x hs
 
;*******************************************************************
; Interface
;
73,18 → 81,18
 
 
struc TCP_PACKET
{ .SourcePort dw ? ;+00
{ .SourcePort dw ? ;+00
.DestinationPort dw ? ;+02
.SequenceNumber dd ? ;+04
.AckNumber dd ? ;+08
.DataOffset db ? ;+12 - DataOffset[0-3 bits] and Reserved[4-7]
.Flags db ? ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
.Window dw ? ;+14
.Checksum dw ? ;+16
.AckNumber dd ? ;+08
.DataOffset db ? ;+12 - DataOffset[0-3 bits] and Reserved[4-7]
.Flags db ? ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
.Window dw ? ;+14
.Checksum dw ? ;+16
.UrgentPointer dw ? ;+18
.Options rb 3 ;+20
.Padding db ? ;+23
.Data db ? ;+24
.Options rb 3 ;+20
.Padding db ? ;+23
.Data db ? ;+24
}
 
virtual at 0
102,64 → 110,52
; when the TCB timer expires
;
;***************************************************************************
tcp_tcb_handler:
; scan through all the sockets, decrementing active timers
 
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
proc tcp_tcb_handler stdcall uses ebx
; scan through all the sockets, decrementing active timers
 
tth1:
sub eax, SOCKETBUFFSIZE
cmp [eax + sockets + 32], dword 0
jne tth2
mov ebx, net_sockets
 
tth1a:
cmp [eax + sockets + 72], dword 0
jne tth4
cmp [ebx + SOCKET.NextPtr], 0
je .exit
DEBUGF 1, "K : sockets:\n"
 
loop tth1
ret
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .exit
 
tth2:
; decrement it, delete socket if TCB timer = 0 & socket in timewait state
pusha
dec dword [eax + sockets + 32]
cmp [eax + sockets + 32], dword 0
jne tth3
DEBUGF 1, "K : %x: %x-%x-%x-%u\n", ebx, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState]
 
cmp [eax + sockets + 28], dword TCB_TIME_WAIT
jne tth3
cmp [ebx + SOCKET.TCBTimer], 0
jne .decrement_tcb
cmp [ebx + SOCKET.wndsizeTimer], 0
jne .decrement_wnd
jmp .next_socket
 
; OK, delete socket
mov edi, eax
add edi, sockets
.decrement_tcb:
; decrement it, delete socket if TCB timer = 0 & socket in timewait state
dec [ebx + SOCKET.TCBTimer]
jnz .next_socket
 
xor eax, eax
mov ecx, SOCKETHEADERSIZE
cld
rep stosb
cmp [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
jne .next_socket
 
tth3:
popa
push [ebx + SOCKET.PrevPtr]
stdcall net_socket_free, ebx
pop ebx
jmp .next_socket
 
jmp tth1a
.decrement_wnd:
; TODO - prove it works!
dec [ebx + SOCKET.wndsizeTimer]
jmp .next_socket
 
loop tth1
ret
.exit:
ret
endp
 
; TODO - prove it works!
tth4:
dec dword [eax + sockets + 72]
loop tth1
ret
 
 
 
 
tth_exit:
ret
 
 
;***************************************************************************
; Function
; tcp_tx_handler
169,124 → 165,112
; This is a kernel function, called by stack_handler
;
;***************************************************************************
tcp_tx_handler:
 
proc tcp_tx_handler stdcall
; decrement all resend buffers timers. If they
; expire, queue them for sending, and restart the timer.
; If the retries counter reach 0, delete the entry
 
mov esi, resendQ
mov ecx, 0
mov esi, resendQ
mov ecx, 0
 
tth001:
cmp ecx, NUMRESENDENTRIES
je tth003 ; None left
cmp [esi], byte 0xFF
jne tth002 ; found one
inc ecx
add esi, 4
jmp tth001
.next_resendq:
cmp ecx, NUMRESENDENTRIES
je .exit ; None left
;cmp [esi], byte 0xFF ; XTODO: 0xff -> 0
cmp dword[esi + 4], 0
jne @f ; found one
inc ecx
add esi, 8
jmp .next_resendq
 
tth002:
; we have one. decrement it's timer by 1
dec word [esi+2]
mov ax, [esi+2]
cmp ax, 0
je tth002a
inc ecx
add esi, 4
jmp tth001 ; Timer not zero, so move on
@@: ; we have one. decrement it's timer by 1
dec word[esi + 2]
jz @f
inc ecx
add esi, 8
jmp .next_resendq ; Timer not zero, so move on
 
tth002a:
mov bl, 0xff
; restart timer, and decrement retries
; After the first resend, back of on next, by a factor of 5
mov [esi+2], word TCP_TIMEOUT * 5
dec byte [esi+1]
mov al, [esi+1]
cmp al, 0
jne tth004
@@:
;mov bl, 0xff ; XTODO: bl -> ebx, 0xff -> 0
xor ebx, ebx
; restart timer, and decrement retries
; After the first resend, back of on next, by a factor of 5
mov [esi + 2], word TCP_TIMEOUT * 5
dec byte[esi + 1]
jnz @f
 
; retries now 0, so delete from queue
xchg [esi], bl
tth004:
; retries now 0, so delete from queue
;xchg [esi], bl ; XTODO: bl -> ebx
xchg [esi + 4], ebx
 
; resend packet
pusha
@@: ; resend packet
pushad
 
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
jne tth004z
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
jne .tth004z
 
; TODO - try again in 10ms.
cmp bl, 0xff
jne tth004za
mov [esi], bl
; TODO - try again in 10ms.
;cmp bl, 0xff ; XTODO: 0xff -> 0
test ebx, ebx
jnz @f
;mov [esi], bl ; XTODO: bl -> ebx
mov [esi + 4], ebx
 
tth004za:
; Mark it to expire in 10ms - 1 tick
mov [esi+1], byte 1
mov [esi+2], word 1
jmp tth005
@@: ; Mark it to expire in 10ms - 1 tick
mov byte[esi + 1], 1
mov word[esi + 2], 1
jmp .tth005
 
tth004z:
; we have a buffer # in ax
.tth004z:
; we have a buffer # in ax
push eax ecx
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
push eax
push ecx
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
; we have the buffer address in eax
mov edi, eax
pop ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
mov esi, resendBuffer
@@: add esi, IPBUFFSIZE
loop @b
 
; we have the buffer address in eax
mov edi, eax
pop ecx
; get resend data address
inc ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
mov esi, resendBuffer - IPBUFFSIZE
tth004a:
add esi, IPBUFFSIZE
loop tth004a
; we have resend buffer location in esi
mov ecx, IPBUFFSIZE
 
; we have resend buffer location in esi
mov ecx, IPBUFFSIZE
; copy data across
push edi
cld
rep movsb
pop edi
 
; copy data across
cld
rep movsb
; queue packet
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
cmp edx, [edi + IP_PACKET.DestinationAddress]
jne .not_local
mov eax, IPIN_QUEUE
 
; queue packet
.not_local:
pop ebx
call queue
 
.tth005:
popad
 
inc ecx
add esi, 8
jmp .next_resendq
 
mov eax, NET1OUT_QUEUE
.exit:
ret
endp
 
mov edx, [stack_ip]
mov ecx, [ edi + 16 ]
cmp edx, ecx
jne tth004b
mov eax, IPIN_QUEUE
 
tth004b:
pop ebx
 
call queue
 
 
tth005:
popa
 
inc ecx
add esi, 4
jmp tth001
 
tth003:
ret
 
 
 
 
;***************************************************************************
; Function
; tcp_rx
299,127 → 283,167
; Free up (or re-use) IP buffer when finished
;
;***************************************************************************
tcp_rx:
; The process is as follows.
; Look for a socket with matching remote IP, remote port, local port
; if not found, then
; look for remote IP + local port match ( where sockets remote port = 0)
; if not found, then
; look for a socket where local socket port == IP packets remote port
; where sockets remote port, remote IP = 0
; discard if not found
; Call sockets tcbStateMachine, with pointer to packet.
; the state machine will not delete the packet, so do that here.
 
push eax
proc tcp_rx stdcall uses ebx
; The process is as follows.
; Look for a socket with matching remote IP, remote port, local port
; if not found, then
; look for remote IP + local port match ( where sockets remote port = 0)
; if not found, then
; look for a socket where local socket port == IP packets remote port
; where sockets remote port, remote IP = 0
; discard if not found
; Call sockets tcbStateMachine, with pointer to packet.
; the state machine will not delete the packet, so do that here.
 
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; IP Packet SA = Remote IP
; IP Packet TCP Source Port = remote Port
push eax
 
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
ss1:
sub eax, SOCKETBUFFSIZE
movzx ebx, word [edx + 22] ; get the dest. port from the TCP hdr
cmp [eax + sockets + 12], bx ; compare with socket's local port
jnz nxttst1 ; different - try next socket
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; IP Packet SA = Remote IP
; IP Packet TCP Source Port = remote Port
 
movzx ebx, word [edx + 20] ; get the source port from the TCP hdr
cmp [eax + sockets + 20], bx ; compare with socket's remote port
jnz nxttst1 ; different - try next socket
mov ebx, net_sockets
 
.next_socket.1:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .next_socket.1.exit
 
mov ebx, [edx + 12] ; get the source IP Addr from the IP hdr
cmp [eax + sockets + 16], ebx ; compare with socket's remote IP
jnz nxttst1 ; different - try next socket
cmp [ebx + SOCKET.Status], SOCK_OPEN
jne .next_socket.1
 
; We have a complete match - use this socket
jmp tcprx_001
; DEBUGF 1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
 
nxttst1:
loop ss1 ; Return back if no match
mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get the dest. port from the TCP hdr
cmp [ebx + SOCKET.LocalPort], ax ; get the dest. port from the TCP hdr
jne .next_socket.1 ; different - try next socket
 
; If we got here, there was no match
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; IP Packet SA = Remote IP
; socket remote Port = 0
; DEBUGF 1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
 
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
mov eax, [edx + IP_PACKET.SourceAddress] ; get the source IP Addr from the IP hdr
cmp [ebx + SOCKET.RemoteIP], eax ; compare with socket's remote IP
jne .next_socket.1 ; different - try next socket
 
ss2:
sub eax, SOCKETBUFFSIZE
; DEBUGF 1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4
 
movzx ebx, word [edx + 22] ; get the dest. port from the TCP hdr
cmp [eax + sockets + 12], bx ; compare with socket's local port
jnz nxttst2 ; different - try next socket
mov ax, [edx + 20 + TCP_PACKET.SourcePort] ; get the source port from the TCP hdr
cmp [ebx + SOCKET.RemotePort], ax ; compare with socket's remote port
jne .next_socket.1 ; different - try next socket
 
mov ebx, [edx + 12] ; get the source IP Addr from the IP hdr
cmp [eax + sockets + 16], ebx ; compare with socket's remote IP
jnz nxttst2 ; different - try next socket
; We have a complete match - use this socket
jmp .change_state
 
mov ebx, 0
cmp [eax + sockets + 20], bx ; only match a remote socket of 0
jnz nxttst2 ; different - try next socket
.next_socket.1.exit:
 
; We have a complete match - use this socket
jmp tcprx_001
; If we got here, there was no match
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; IP Packet SA = Remote IP
; socket remote Port = 0
 
nxttst2:
loop ss2 ; Return back if no match
mov ebx, net_sockets
 
; If we got here, there was no match
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; socket Remote IP = 0
; socket remote Port = 0
.next_socket.2:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .next_socket.2.exit
 
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
cmp [ebx + SOCKET.Status], SOCK_OPEN
jne .next_socket.2
 
ss3:
sub eax, SOCKETBUFFSIZE
; DEBUGF 1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
 
movzx ebx, word [edx + 22] ; get destination port from the TCP hdr
cmp [eax + sockets + 12], bx ; compare with socket's local port
jnz nxttst3 ; different - try next socket
mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get the dest. port from the TCP hdr
cmp [ebx + SOCKET.LocalPort], ax ; compare with socket's local port
jne .next_socket.2 ; different - try next socket
 
mov ebx, 0
cmp [eax + sockets + 20], bx ; only match a remote socket of 0
jnz nxttst3 ; different - try next socket
; DEBUGF 1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP]
 
mov ebx, 0
cmp [eax + sockets + 16], ebx ; only match a socket remote IP of 0
jnz nxttst3 ; different - try next socket
mov eax, [edx + IP_PACKET.SourceAddress] ; get the source IP Addr from the IP hdr
cmp [ebx + SOCKET.RemoteIP], eax ; compare with socket's remote IP
jne .next_socket.2 ; different - try next socket
 
; We have a complete match - use this socket
jmp tcprx_001
; DEBUGF 1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
 
nxttst3:
loop ss3 ; Return back if no match
cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0
jne .next_socket.2 ; different - try next socket
 
; If we got here, we need to reject the packet
inc dword [dumped_rx_count]
jmp tcprx_exit
; We have a complete match - use this socket
jmp .change_state
 
tcprx_001:
; We have a valid socket/TCB, so call the TCB State Machine for that skt.
; socket is pointed to by [eax + sockets]
; IP packet is pointed to by [edx]
; IP buffer number is on stack ( it will be popped at the end)
call tcpStateMachine
.next_socket.2.exit:
 
tcprx_exit:
pop eax
call freeBuff
; If we got here, there was no match
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; socket Remote IP = 0
; socket remote Port = 0
 
ret
mov ebx, net_sockets
 
.next_socket.3:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .next_socket.3.exit
 
cmp [ebx + SOCKET.Status], SOCK_OPEN
jne .next_socket.3
 
; DEBUGF 1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
 
mov ax, [edx + 20 + TCP_PACKET.DestinationPort] ; get destination port from the TCP hdr
cmp [ebx + SOCKET.LocalPort], ax ; compare with socket's local port
jne .next_socket.3 ; different - try next socket
 
; DEBUGF 1, "K : tcp_rx - 3.addr: 00000000 - %x\n", [ebx + SOCKET.RemoteIP]
 
cmp [ebx + SOCKET.RemoteIP], 0 ; only match a socket remote IP of 0
jne .next_socket.3 ; different - try next socket
 
; DEBUGF 1, "K : tcp_rx - 3.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
 
cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0
jne .next_socket.3 ; different - try next socket
 
; We have a complete match - use this socket
jmp .change_state
 
.next_socket.3.exit:
 
; If we got here, we need to reject the packet
 
DEBUGF 1, "K : tcp_rx - dumped\n"
DEBUGF 1, "K : --------: %x-%x-%x (flags: %x)\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [edx + IP_PACKET.SourceAddress], [edx + 20 + TCP_PACKET.SourcePort]:4, [edx + 20 + TCP_PACKET.Flags]:2
; mov ebx, net_sockets
;
; .next_socket.4:
; mov ebx, [ebx + SOCKET.NextPtr]
; or ebx, ebx
; jz .next_socket.4.exit
; DEBUGF 1, "K : %x: %x-%x-%x-%u\n", ebx, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState]
; jne .next_socket.4
;
; .next_socket.4.exit:
inc [dumped_rx_count]
jmp .exit
 
.change_state:
 
; We have a valid socket/TCB, so call the TCB State Machine for that skt.
; socket is pointed to by ebx
; IP packet is pointed to by edx
; IP buffer number is on stack ( it will be popped at the end)
 
stdcall tcpStateMachine, ebx
 
.exit:
pop eax
call freeBuff
ret
endp
 
 
;***************************************************************************
; Function
; buildTCPPacket
434,216 → 458,166
; Transmit buffer number in eax
;
;***************************************************************************
buildTCPPacket:
push ecx ; Save data length
 
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
proc build_tcp_packet stdcall, sockAddr:DWORD
push ecx ; Save data length
 
mov edx, eax
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
add eax, IPbuffs
 
mov [edx + 33], bl ; TCP flags
mov edx, eax
 
mov ebx, [sktAddr]
mov [edx + 20 + TCP_PACKET.Flags], bl ; TCP flags
 
; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
mov ebx, [sockAddr]
 
; Fill in the IP header ( some data is in the socket descriptor)
mov eax, [ebx + 8]
mov [edx + 12], eax ; source IP
mov eax, [ebx + 16]
mov [edx + 16], eax ; Destination IP
; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
 
mov al, 0x45
mov [edx], al ; Version, IHL
xor al, al
mov [edx + 1], al ; Type of service
; Fill in the IP header ( some data is in the socket descriptor)
mov eax, [ebx + SOCKET.LocalIP]
mov [edx + IP_PACKET.SourceAddress], eax
mov eax, [ebx + SOCKET.RemoteIP]
mov [edx + IP_PACKET.DestinationAddress], eax
 
pop eax ; Get the TCP data length
push eax
mov [edx + IP_PACKET.VersionAndIHL], 0x45
mov [edx + IP_PACKET.TypeOfService], 0
 
add eax, 20 + 20 ; add IP header and TCP header lengths
mov [edx + 2], ah
mov [edx + 3], al
xor al, al
mov [edx + 4], al
mov [edx + 5], al
mov al, 0x40
mov [edx + 6], al
xor al, al
mov [edx + 7], al
mov al, 0x20
mov [edx + 8], al
mov al, 6 ; TCP protocol
mov [edx + 9], al
pop eax ; Get the TCP data length
push eax
 
; Checksum left unfilled
xor ax, ax
mov [edx + 10], ax
add eax, 20 + 20 ; add IP header and TCP header lengths
rol ax, 8
mov [edx + IP_PACKET.TotalLength], ax
mov [edx + IP_PACKET.Identification], 0
mov [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
mov [edx + IP_PACKET.TimeToLive], 0x20
mov [edx + IP_PACKET.Protocol], PROTOCOL_TCP
 
; Fill in the TCP header ( some data is in the socket descriptor)
mov ax, [ebx + 12]
mov [edx + 20], ax ; Local Port
; Checksum left unfilled
mov [edx + IP_PACKET.HeaderChecksum], 0
 
mov ax, [ebx + 20]
mov [edx + 20 + 2], ax ; desitination Port
; Fill in the TCP header (some data is in the socket descriptor)
mov ax, [ebx + SOCKET.LocalPort]
mov [edx + 20 + TCP_PACKET.SourcePort], ax ; Local Port
 
; Checksum left unfilled
xor ax, ax
mov [edx + 20 + 16], ax
mov ax, [ebx + SOCKET.RemotePort]
mov [edx + 20 + TCP_PACKET.DestinationPort], ax ; desitination Port
 
; sequence number
mov eax, [ebx + 48]
mov [edx + 20 + 4], eax
; Checksum left unfilled
mov [edx + 20 + TCP_PACKET.Checksum], 0
 
; ack number
mov eax, [ebx + 56]
mov [edx + 20 + 8], eax
; sequence number
mov eax, [ebx + SOCKET.SND_NXT]
mov [edx + 20 + TCP_PACKET.SequenceNumber], eax
 
; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
; 768 bytes seems better
mov ax, 0x0003
mov [edx + 20 + 14], ax
; ack number
mov eax, [ebx + SOCKET.RCV_NXT]
mov [edx + 20 + TCP_PACKET.AckNumber], eax
 
; Urgent pointer (0)
mov ax, 0
mov [edx + 20 + 18], ax
; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
; 768 bytes seems better
mov [edx + 20 + TCP_PACKET.Window], 0x0003
 
; data offset ( 0x50 )
mov al, 0x50
mov [edx + 20 + 12], al
; Urgent pointer (0)
mov [edx + 20 + TCP_PACKET.UrgentPointer], 0
 
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
; data offset ( 0x50 )
mov [edx + 20 + TCP_PACKET.DataOffset], 0x50
 
cmp ebx, 0
jz btp_001
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
 
mov edi, edx
add edi, 40
cld
rep movsb ; copy the data across
cmp ebx, 0
jz @f
 
btp_001:
; we have edx as IPbuffer ptr.
; Fill in the TCP checksum
; First, fill in pseudoheader
mov eax, [edx + 12]
mov [pseudoHeader], eax
mov eax, [edx + 16]
mov [pseudoHeader+4], eax
mov ax, 0x0600 ; 0 + protocol
mov [pseudoHeader+8], ax
add ebx, 20
mov eax, ebx
mov [pseudoHeader+10], ah
mov [pseudoHeader+11], al
mov edi, edx
add edi, 40
cld
rep movsb ; copy the data across
 
mov eax, pseudoHeader
mov [checkAdd1], eax
mov [checkSize1], word 12
mov eax, edx
add eax, 20
mov [checkAdd2], eax
mov eax, ebx
mov [checkSize2], ax
@@: ; we have edx as IPbuffer ptr.
; Fill in the TCP checksum
; First, fill in pseudoheader
mov eax, [edx + IP_PACKET.SourceAddress]
mov [pseudoHeader], eax
mov eax, [edx + IP_PACKET.DestinationAddress]
mov [pseudoHeader + 4], eax
mov word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0
add ebx, 20
mov [pseudoHeader + 10], bh
mov [pseudoHeader + 11], bl
 
call checksum
mov eax, pseudoHeader
mov [checkAdd1], eax
mov word[checkSize1], 12
mov eax, edx
add eax, 20
mov [checkAdd2], eax
mov eax, ebx
mov [checkSize2], ax
 
; store it in the TCP checksum ( in the correct order! )
mov ax, [checkResult]
call checksum
 
mov [edx + 20 + 16], ah
mov [edx + 20 + 17], al
; store it in the TCP checksum ( in the correct order! )
mov ax, [checkResult]
rol ax, 8
mov [edx + 20 + TCP_PACKET.Checksum], ax
 
; Fill in the IP header checksum
GET_IHL eax,edx ; get IP-Header length
stdcall checksum_jb,edx,eax ; buf_ptr, buf_size
; Fill in the IP header checksum
GET_IHL eax, edx ; get IP-Header length
stdcall checksum_jb, edx, eax ; buf_ptr, buf_size
rol ax, 8
mov [edx + IP_PACKET.HeaderChecksum], ax
 
mov [edx + 10], ah
mov [edx + 11], al
ret
endp
 
ret
 
 
; Increments the 32 bit value pointed to by esi in internet order
inc_inet_esi:
push eax
add esi, 3
mov al, byte[esi]
inc al
mov byte[esi], al
cmp al, 0
jnz iie_exit
dec esi
mov al, byte[esi]
inc al
mov byte[esi], al
cmp al, 0
jnz iie_exit
dec esi
mov al, byte[esi]
inc al
mov byte[esi], al
cmp al, 0
jnz iie_exit
dec esi
mov al, byte[esi]
inc al
mov byte[esi], al
proc inc_inet_esi stdcall
push eax
mov eax, [esi]
bswap eax
inc eax
bswap eax
mov [esi], eax
pop eax
ret
endp
 
iie_exit:
pop eax
ret
 
 
; Increments the 32 bit value pointed to by esi in internet order
; by the value in ecx
add_inet_esi:
push eax
proc add_inet_esi stdcall
push eax
mov eax, [esi]
bswap eax
add eax, ecx
bswap eax
mov [esi], eax
pop eax
ret
endp
 
mov al, [esi]
shl eax, 8
inc esi
mov al, [esi]
shl eax, 8
inc esi
mov al, [esi]
shl eax, 8
inc esi
mov al, [esi]
add eax, ecx
mov [esi], al
dec esi
shr eax, 8
mov [esi], al
dec esi
shr eax, 8
mov [esi], al
dec esi
shr eax, 8
mov [esi], al
pop eax
ret
 
 
iglobal
TCBStateHandler:
dd stateTCB_LISTEN
dd stateTCB_SYN_SENT
dd stateTCB_SYN_RECEIVED
dd stateTCB_ESTABLISHED
dd stateTCB_FIN_WAIT_1
dd stateTCB_FIN_WAIT_2
dd stateTCB_CLOSE_WAIT
dd stateTCB_CLOSING
dd stateTCB_LAST_ACK
dd stateTCB_TIME_WAIT
dd stateTCB_CLOSED
TCBStateHandler dd \
stateTCB_LISTEN, \
stateTCB_SYN_SENT, \
stateTCB_SYN_RECEIVED, \
stateTCB_ESTABLISHED, \
stateTCB_FIN_WAIT_1, \
stateTCB_FIN_WAIT_2, \
stateTCB_CLOSE_WAIT, \
stateTCB_CLOSING, \
stateTCB_LAST_ACK, \
stateTCB_TIME_WAIT, \
stateTCB_CLOSED
endg
 
 
;***************************************************************************
; Function
; tcpStateMachine
653,651 → 627,553
; This is a kernel function, called by tcp_rx
;
; IP buffer address given in edx
; Socket/TCB address in [eax + sockets]
; Socket/TCB address in ebx
;
; The IP buffer will be released by the caller
;***************************************************************************
tcpStateMachine:
mov ebx, sockets
add ebx, eax
mov [sktAddr], ebx
 
; as a packet has been received, update the TCB timer
mov ecx, TWOMSL
mov [ebx + 32], ecx
proc tcpStateMachine stdcall, sockAddr:DWORD
; as a packet has been received, update the TCB timer
mov [ebx + SOCKET.TCBTimer], TWOMSL
 
; If the received packet has an ACK bit set,
; remove any packets in the resend queue that this
; received packet acknowledges
pusha
mov cl, [edx + 33]
and cl, 0x10
cmp cl, 0x10
jne tsm001 ; No ACK, so no data yet
; If the received packet has an ACK bit set,
; remove any packets in the resend queue that this
; received packet acknowledges
pushad
test [edx + 20 + TCP_PACKET.Flags], TH_ACK
jz .call_handler ; No ACK, so no data yet
 
; get skt number in eax
stdcall net_socket_addr_to_num, ebx
 
; get skt number in al
shr eax, 12
; The ack number is in [edx + 28], inet format
; skt in eax
 
; The ack number is in [edx + 28], inet format
; skt in al
mov esi, resendQ
xor ecx, ecx
 
mov esi, resendQ
mov ecx, 0
.next_resendq:
cmp ecx, NUMRESENDENTRIES
je .call_handler ; None left
;cmp [esi], al ; XTODO: al -> eax
cmp [esi + 4], eax
je @f ; found one
inc ecx
add esi, 8
jmp .next_resendq
 
t001:
cmp ecx, NUMRESENDENTRIES
je t003 ; None left
cmp [esi], al
je t002 ; found one
inc ecx
add esi, 4
jmp t001
@@: ; Can we delete this buffer?
 
t002: ; Can we delete this buffer?
; If yes, goto @@. No, goto .next_resendq
; Get packet data address
 
; If yes, goto t004. No, goto t001
; Get packet data address
push ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
imul edi, ecx, IPBUFFSIZE
add edi, resendBuffer
 
push ecx
inc ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
mov edi, resendBuffer - IPBUFFSIZE
t002a:
add edi, IPBUFFSIZE
loop t002a
; we have dest buffer location in edi. incoming packet in edx.
; Get this packets sequence number
; preserve al, ecx, esi, edx
mov ecx, [edi + 20 + TCP_PACKET.SequenceNumber]
bswap ecx
movzx ebx, word[edi + 2]
xchg bl, bh
sub ebx, 40
add ecx, ebx ; ecx is now seq# of last byte +1, intel format
 
; we have dest buffer location in edi. incoming packet in edx.
; Get this packets sequence number
; preserve al, ecx, esi, edx
; get recievd ack #, in intel format
mov ebx, [edx + 20 + TCP_PACKET.AckNumber]
bswap ebx
 
mov cl, [edi + 24]
shl ecx, 8
mov cl, [edi + 25]
shl ecx, 8
mov cl, [edi + 26]
shl ecx, 8
mov cl, [edi + 27]
movzx ebx, byte [edi + 3]
mov bh, [edi + 2]
sub ebx, 40
add ecx, ebx ; ecx is now seq# of last byte +1, intel format
cmp ebx, ecx ; Finally. ecx = rx'ed ack. ebx = last byte in que
; DANGER! need to handle case that we have just
; passed the 2**32, and wrapped round!
pop ecx
jae @f ; if rx > old, delete old
 
; get recievd ack #, in intel format
mov bl, [edx + 28]
shl ebx, 8
mov bl, [edx + 29]
shl ebx, 8
mov bl, [edx + 30]
shl ebx, 8
mov bl, [edx + 31]
inc ecx
add esi, 8
jmp .next_resendq
 
cmp ebx, ecx ; Finally. ecx = rx'ed ack. ebx = last byte in que
; DANGER! need to handle case that we have just
; passed the 2**32, and wrapped round!
pop ecx
;@@: mov byte[esi], 0xff ; XTODO: 0xff -> 0
@@: mov dword[esi + 4], 0
inc ecx
add esi, 8
jmp .next_resendq
 
jae t004 ; if rx > old, delete old
inc ecx
add esi, 4
jmp t001
.call_handler:
popad
 
; Call handler for given TCB state
 
t004:
dec dword [arp_rx_count] ; ************ TEST ONLY!
mov eax, [ebx + SOCKET.TCBState]
cmp eax, TCB_LISTEN
jb .exit
cmp eax, TCB_CLOSED
ja .exit
 
mov [esi], byte 0xFF
inc ecx
add esi, 4
jmp t001
stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr]
 
t003:
.exit:
ret
endp
 
tsm001:
popa
 
; Call handler for given TCB state
mov ebx, [eax + sockets+28]
cmp ebx, TCB_LISTEN
jb tsm_exit
cmp ebx, TCB_CLOSED
ja tsm_exit
proc stateTCB_LISTEN stdcall, sockAddr:DWORD
; In this case, we are expecting a SYN packet
; For now, if the packet is a SYN, process it, and send a response
; If not, ignore it
 
dec ebx
call dword [TCBStateHandler+ebx*4]
; Look at control flags
test [edx + 20 + TCP_PACKET.Flags], TH_SYN
jz .exit
 
tsm_exit:
ret
; We have a SYN. update the socket with this IP packets details,
; And send a response
 
mov eax, [edx + IP_PACKET.SourceAddress]
mov [ebx + SOCKET.RemoteIP], eax
mov ax, [edx + 20 + TCP_PACKET.SourcePort]
mov [ebx + SOCKET.RemotePort], ax
mov eax, [edx + 20 + TCP_PACKET.SequenceNumber]
mov [ebx + SOCKET.IRS], eax
mov [ebx + SOCKET.RCV_NXT], eax
lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi ; RCV.NXT
mov eax, [ebx + SOCKET.ISS]
mov [ebx + SOCKET.SND_NXT], eax
 
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .exit
 
stateTCB_LISTEN:
; In this case, we are expecting a SYN packet
; For now, if the packet is a SYN, process it, and send a response
; If not, ignore it
push eax
mov bl, TH_SYN + TH_ACK
xor ecx, ecx
xor esi, esi
stdcall build_tcp_packet, [sockAddr]
 
; Look at control flags
mov bl, [edx + 33]
and bl, 0x02
cmp bl, 0x02
jnz stl_exit
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
mov eax, IPIN_QUEUE
 
; We have a SYN. update the socket with this IP packets details,
; And send a response
.not_local:
; Send it.
pop ebx
call queue
 
mov ebx, [edx + 12] ; IP source address
mov [eax + sockets + 16], ebx
mov bx, [edx + 20] ; IP source port
mov [eax + sockets + 20], bx
mov ebx, [edx + 24] ; IRS
mov [eax + sockets + 40], ebx
mov [eax + sockets + 56], ebx
mov esi, sockets
add esi, eax
add esi, 56
call inc_inet_esi ; RCV.NXT
mov ebx, [eax + sockets + 36] ; ISS
mov [eax + sockets + 48], ebx ; SND.NXT
mov esi, [sockAddr]
mov [esi + SOCKET.TCBState], TCB_SYN_RECEIVED
 
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stl_exit
; increment SND.NXT in socket
add esi, SOCKET.SND_NXT
call inc_inet_esi
 
push eax
mov bl, 0x12 ; SYN + ACK
mov ecx, 0
mov esi, 0
.exit:
ret
endp
 
call buildTCPPacket
 
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne stl_notlocal
mov eax, IPIN_QUEUE
proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD
; We are awaiting an ACK to our SYN, with a SYM
; Look at control flags - expecting an ACK
 
stl_notlocal:
; Send it.
pop ebx
call queue
mov al, [edx + 20 + TCP_PACKET.Flags]
and al, TH_SYN + TH_ACK
cmp al, TH_SYN + TH_ACK
je .syn_ack
 
test al, TH_SYN
jz .exit
 
mov ebx, TCB_SYN_RECEIVED
mov esi, [sktAddr]
mov [esi + 28], ebx
mov [ebx + SOCKET.TCBState], TCB_SYN_RECEIVED
push TH_SYN + TH_ACK
jmp .send
 
; increament SND.NXT in socket
add esi, 48
call inc_inet_esi
.syn_ack:
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED
push TH_ACK
 
stl_exit:
ret
.send:
; Store the recv.nxt field
mov eax, [edx + 20 + TCP_PACKET.SequenceNumber]
 
; Update our recv.nxt field
mov [ebx + SOCKET.RCV_NXT], eax
lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi
 
; Send an ACK
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
pop ebx
je .exit
 
stateTCB_SYN_SENT:
; We are awaiting an ACK to our SYN, with a SYM
; Look at control flags - expecting an ACK
mov bl, [edx + 33]
and bl, 0x12
cmp bl, 0x12
jnz stss_exit
push eax
 
mov ebx, TCB_ESTABLISHED
mov esi, [sktAddr]
mov [esi + 28], ebx
xor ecx, ecx
xor esi, esi
stdcall build_tcp_packet, [sockAddr]
 
; Store the recv.nxt field
mov eax, [edx + 24]
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
mov eax, IPIN_QUEUE
 
; Update our recv.nxt field
mov esi, [sktAddr]
add esi, 56
mov [esi], eax
call inc_inet_esi
.not_local:
; Send it.
pop ebx
call queue
 
; Send an ACK
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stss_exit
.exit:
ret
endp
 
push eax
 
mov bl, 0x10 ; ACK
mov ecx, 0
mov esi, 0
proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD
; In this case, we are expecting an ACK packet
; For now, if the packet is an ACK, process it,
; If not, ignore it
 
call buildTCPPacket
test [edx + 20 + TCP_PACKET.Flags], TH_RST ;xxx
jz .check_ack ;xxx
 
mov eax, NET1OUT_QUEUE
push [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP]
pop [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort]
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne stss_notlocal
mov eax, IPIN_QUEUE
mov [ebx + SOCKET.TCBState], TCB_LISTEN ;xxx
jmp .exit ;xxx
 
stss_notlocal:
; Send it.
pop ebx
call queue
.check_ack: ;xxx
; Look at control flags - expecting an ACK
test [edx + 20 + TCP_PACKET.Flags], TH_ACK
jz .exit
 
stss_exit:
ret
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED
 
.exit:
ret
endp
 
 
stateTCB_SYN_RECEIVED:
; In this case, we are expecting an ACK packet
; For now, if the packet is an ACK, process it,
; If not, ignore it
proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD
; Here we are expecting data, or a request to close
; OR both...
 
; Look at control flags - expecting an ACK
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz stsr_exit
; Did we receive a FIN or RST?
;xxx test [edx + 20 + TCP_PACKET.Flags], TH_FIN + TH_RST
;xxx jz .check_ack
test [edx + 20 + TCP_PACKET.Flags], TH_FIN ;xxx
jz .check_ack ;xxx
 
mov ebx, TCB_ESTABLISHED
mov esi, [sktAddr]
mov [esi + 28], ebx
; It was a fin or reset.
 
stsr_exit:
ret
; Remove resend entries from the queue - I dont want to send any more data
pushad
 
; get skt #
stdcall net_socket_addr_to_num, ebx
 
mov esi, resendQ
mov ecx, 0
 
stateTCB_ESTABLISHED:
; Here we are expecting data, or a request to close
; OR both...
.next_resendq:
cmp ecx, NUMRESENDENTRIES
je .last_resendq ; None left
;cmp [esi], al ; XTODO: al -> eax
cmp [esi + 4], eax
je @f ; found one
inc ecx
add esi, 8
jmp .next_resendq
 
; Did we receive a FIN or RST?
mov bl, [edx + 33]
and bl, 0x05
cmp bl, 0
je ste_chkack
;@@: mov byte[esi], 0xff ; XTODO: 0xff -> 0
@@: mov dword[esi + 4], 0
inc ecx
add esi, 8
jmp .next_resendq
 
; It was a fin or reset.
.last_resendq:
popad
 
; Remove resend entries from the queue - I dont want to send any more data
pusha
;xxx ; was it a reset?
;xxx test [edx + 20 + TCP_PACKET.Flags], TH_RST
;xxx jz @f
 
mov ebx, [sktAddr]
sub ebx, sockets
shr ebx, 12 ; get skt #
;xxx mov [ebx + SOCKET.TCBState], TCB_CLOSED
;xxx jmp .exit
 
mov esi, resendQ
mov ecx, 0
@@: ; Send an ACK to that fin, and enter closewait state
 
ste001:
cmp ecx, NUMRESENDENTRIES
je ste003 ; None left
cmp [esi], bl
je ste002 ; found one
inc ecx
add esi, 4
jmp ste001
mov [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
lea esi, [ebx + SOCKET.RCV_NXT]
mov eax, [esi] ; save original
call inc_inet_esi
;; jmp ste_ack - NO, there may be data
 
ste002:
dec dword [arp_rx_count] ; ************ TEST ONLY!
.check_ack:
; Check that we received an ACK
test [edx + 20 + TCP_PACKET.Flags], TH_ACK
jz .exit
 
mov [esi], byte 0xFF
jmp ste001
; TODO - done, I think!
; First, look at the incoming window. If this is less than or equal to 1024,
; Set the socket window timer to 1. This will stop an additional packets being queued.
; ** I may need to tweak this value, since I do not know how many packets are already queued
mov cx, [edx + 20 + TCP_PACKET.Window]
xchg cl, ch
cmp cx, 1024
ja @f
 
ste003:
popa
mov [ebx + SOCKET.wndsizeTimer], 1
 
; was it a reset?
mov bl, [edx + 33]
and bl, 0x04
cmp bl, 0x04
jne ste003a
@@: ; OK, here is the deal
; My recv.nct field holds the seq of the expected next rec byte
; if the recevied sequence number is not equal to this, do not
; increment the recv.nxt field, do not copy data - just send a
; repeat ack.
 
mov esi, [sktAddr]
mov ebx, TCB_CLOSED
mov [esi + 28], ebx
jmp ste_exit
; recv.nxt is in dword [edx+24], in inet format
; recv seq is in [sktAddr]+56, in inet format
; just do a comparision
mov ecx, [ebx + SOCKET.RCV_NXT]
cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
jne @f
mov ecx, eax
 
ste003a:
; Send an ACK to that fin, and enter closewait state
@@: cmp ecx, [edx + 20 + TCP_PACKET.SequenceNumber]
jne .ack
 
mov esi, [sktAddr]
mov ebx, TCB_CLOSE_WAIT
mov [esi + 28], ebx
add esi, 56
mov eax, [esi] ; save original
call inc_inet_esi
;; jmp ste_ack - NO, there may be data
 
ste_chkack:
; Check that we received an ACK
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz ste_exit
; Read the data bytes, store in socket buffer
movzx ecx, [edx + IP_PACKET.TotalLength]
xchg cl, ch
sub ecx, 40 ; Discard 40 bytes of header
jnz .data ; Read data, if any
 
; If we had received a fin, we need to ACK it.
cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
je .ack
jmp .exit
 
; TODO - done, I think!
; First, look at the incoming window. If this is less than or equal to 1024,
; Set the socket window timer to 1. This will stop an additional packets being
; queued.
; ** I may need to tweak this value, since I do not know how many packets are already queued
mov ch, [edx + 34]
mov cl, [edx + 35]
cmp cx, 1024
ja ste004
.data:
push ecx
 
mov ecx, [sktAddr]
mov [ecx+72], dword 1
add [ebx + SOCKET.rxDataCount], ecx ; increment the count of bytes in buffer
 
ste004:
mov eax, [ebx + SOCKET.PID] ; get socket owner PID
push eax
 
; OK, here is the deal
; My recv.nct field holds the seq of the expected next rec byte
; if the recevied sequence number is not equal to this, do not
; increment the recv.nxt field, do not copy data - just send a
; repeat ack.
mov eax, [ebx + SOCKET.rxDataCount] ; get # of bytes already in buffer
 
; recv.nxt is in dword [edx+24], in inext format
; recv seq is in [sktAddr]+56, in inet format
; just do a comparision
mov ecx, [sktAddr]
add ecx, 56
; point to the location to store the data
lea edi, [ebx + eax + SOCKETHEADERSIZE]
sub edi, ecx
 
cmp [ecx - 56 + 28], dword TCB_CLOSE_WAIT
mov ecx, [ecx]
jne stenofin
mov ecx, eax
add edx, 40 ; edx now points to the data
mov esi, edx
 
stenofin:
cmp ecx, [edx+24]
jne ste_ack
cld
rep movsb ; copy the data across
 
; flag an event to the application
pop eax
mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid
 
; Read the data bytes, store in socket buffer
xor ecx, ecx
mov ch, [edx + 2]
mov cl, [edx + 3]
sub ecx, 40 ; Discard 40 bytes of header
.next_pid:
cmp [esi], eax
je .found_pid
inc ecx
add esi, 0x20
cmp ecx, [TASK_COUNT]
jbe .next_pid
 
cmp ecx, 0
jnz ste_data ; Read data, if any
.found_pid:
shl ecx, 8
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
 
; If we had received a fin, we need to ACK it.
mov esi, [sktAddr]
mov ebx, [esi + 28]
cmp ebx, TCB_CLOSE_WAIT
jz ste_ack
jnz ste_exit
pop ecx
 
ste_data:
push ecx
mov esi, [sktAddr]
; Update our recv.nxt field
lea esi, [ebx + SOCKET.RCV_NXT]
call add_inet_esi
 
add [esi + 24], ecx ; increment the count of bytes in buffer
.ack:
; Send an ACK
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .exit
 
mov eax, [esi + 4] ; get socket owner PID
push eax
push eax
 
mov eax, [esi + 24] ; get # of bytes already in buffer
mov bl, TH_ACK
xor ecx, ecx
xor esi, esi
stdcall build_tcp_packet, [sockAddr]
 
; point to the location to store the data
add esi, eax
sub esi, ecx
add esi, SOCKETHEADERSIZE
mov eax, NET1OUT_QUEUE
 
add edx, 40 ; edx now points to the data
mov edi, esi
mov esi, edx
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
mov eax, IPIN_QUEUE
 
cld
rep movsb ; copy the data across
.not_local:
; Send it.
pop ebx
call queue
 
; flag an event to the application
pop eax
mov ecx,1
mov esi,TASK_DATA+TASKDATA.pid
.exit:
ret
endp
 
news:
cmp [esi],eax
je foundPID1
inc ecx
add esi,0x20
cmp ecx,[TASK_COUNT]
jbe news
 
foundPID1:
shl ecx,8
or dword [ecx+SLOT_BASE+APPDATA.event_mask],dword 10000000b ; stack event
proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD
; We can either receive an ACK of a fin, or a fin
mov al, [edx + 20 + TCP_PACKET.Flags]
and al, TH_FIN + TH_ACK
 
pop ecx
cmp al, TH_ACK
jne @f
 
; Update our recv.nxt field
mov esi, [sktAddr]
add esi, 56
call add_inet_esi
; It was an ACK
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2
jmp .exit
 
ste_ack:
; Send an ACK
; Now construct the response, and queue for sending by IP
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je ste_exit
@@: mov [ebx + SOCKET.TCBState], TCB_CLOSING
cmp al, TH_FIN
je @f
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
 
push eax
@@: lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi
 
mov bl, 0x10 ; ACK
mov ecx, 0
mov esi, 0
; Send an ACK
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .exit
 
call buildTCPPacket
push eax
 
mov eax, NET1OUT_QUEUE
mov bl, TH_ACK
xor ecx, ecx
xor esi, esi
stdcall build_tcp_packet, [sockAddr]
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne ste_notlocal
mov eax, IPIN_QUEUE
ste_notlocal:
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
mov eax, IPIN_QUEUE
 
; Send it.
pop ebx
call queue
.not_local:
; Send it.
pop ebx
call queue
 
ste_exit:
ret
.exit:
ret
endp
 
 
proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD
test [edx + 20 + TCP_PACKET.Flags], TH_FIN
jz .exit
 
stateTCB_FIN_WAIT_1:
; We can either receive an ACK of a fin, or a fin
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz stfw1_001
; Change state, as we have a fin
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
 
; It was an ACK
mov esi, [sktAddr]
mov ebx, TCB_FIN_WAIT_2
mov [esi + 28], ebx
jmp stfw1_exit
lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi
 
stfw1_001:
; It must be a fin then
mov esi, [sktAddr]
mov ebx, TCB_CLOSING
mov [esi + 28], ebx
add esi, 56
call inc_inet_esi
; Send an ACK
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je .exit
 
; Send an ACK
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stfw1_exit
push eax
 
push eax
mov bl, TH_ACK
xor ecx, ecx
xor esi, esi
stdcall build_tcp_packet, [sockAddr]
 
mov bl, 0x10 ; ACK
mov ecx, 0
mov esi, 0
mov eax, NET1OUT_QUEUE
mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
mov eax, IPIN_QUEUE
 
call buildTCPPacket
mov eax, NET1OUT_QUEUE
.not_local:
; Send it.
pop ebx
call queue
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne stfw1_notlocal
mov eax, IPIN_QUEUE
.exit:
ret
endp
 
stfw1_notlocal:
; Send it.
pop ebx
call queue
 
stfw1_exit:
ret
proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD
; Intentionally left empty
; socket_close_tcp handles this
ret
endp
 
 
proc stateTCB_CLOSING stdcall, sockAddr:DWORD
; We can either receive an ACK of a fin, or a fin
test [edx + 20 + TCP_PACKET.Flags], TH_ACK
jz .exit
 
stateTCB_FIN_WAIT_2:
mov esi, [sktAddr]
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
 
; Get data length
xor ecx, ecx
mov ch, [edx+2]
mov cl, [edx+3]
sub ecx, 40
.exit:
ret
endp
 
mov bl, [edx + 33]
and bl, 0x01
cmp bl, 0x01
jne stfw2001
 
; Change state, as we have a fin
mov ebx, TCB_TIME_WAIT
mov [esi + 28], ebx
proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD
; Look at control flags - expecting an ACK
test [edx + 20 + TCP_PACKET.Flags], TH_ACK
jz .exit
 
inc ecx ; FIN is part of the sequence space
; delete the socket
stdcall net_socket_free, ebx
; mov edi, ebx
; xor eax, eax
; mov ecx, SOCKETHEADERSIZE
; cld
; rep stosb
 
stfw2001:
add esi, 56
call add_inet_esi
.exit:
ret
endp
 
; Send an ACK
mov eax, EMPTY_QUEUE
call dequeue
cmp ax, NO_BUFFER
je stfw2_exit
 
push eax
proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD
ret
endp
 
mov bl, 0x10 ; ACK
mov ecx, 0
mov esi, 0
 
call buildTCPPacket
 
mov eax, NET1OUT_QUEUE
 
mov edx, [stack_ip]
mov ecx, [ sktAddr ]
mov ecx, [ ecx + 16 ]
cmp edx, ecx
jne stfw2_notlocal
mov eax, IPIN_QUEUE
 
stfw2_notlocal:
; Send it.
pop ebx
call queue
 
; Only delete the socket if we received the FIN
 
mov edx, [sktAddr]
mov bl, [edx + 33]
and bl, 0x01
cmp bl, 0x01
jne stfw2_exit
 
; mov edi, [sktAddr]
 
; delete the socket. Should really wait for 2MSL
; xor eax, eax
; mov ecx,SOCKETHEADERSIZE
; cld
; rep stosb
 
stfw2_exit:
ret
 
 
 
stateTCB_CLOSE_WAIT:
; Intentionally left empty
; socket_close_tcp handles this
ret
 
 
 
stateTCB_CLOSING:
; We can either receive an ACK of a fin, or a fin
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz stc_exit
 
; It was an ACK
 
mov edi, [sktAddr]
 
; delete the socket
xor eax, eax
mov ecx,SOCKETHEADERSIZE
cld
rep stosb
 
stc_exit:
ret
 
 
 
stateTCB_LAST_ACK:
; Look at control flags - expecting an ACK
mov bl, [edx + 33]
and bl, 0x10
cmp bl, 0x10
jnz stla_exit
 
mov edi, [sktAddr]
 
; delete the socket
xor eax, eax
mov ecx,SOCKETHEADERSIZE
cld
rep stosb
 
stla_exit:
ret
 
 
 
stateTCB_TIME_WAIT:
ret
 
 
 
stateTCB_CLOSED:
ret
proc stateTCB_CLOSED stdcall, sockAddr:DWORD
ret
endp
/kernel/trunk/network/udp.inc
47,11 → 47,11
;
 
struc UDP_PACKET
{ .SourcePort dw ? ;+00
{ .SourcePort dw ? ;+00
.DestinationPort dw ? ;+02
.Length dw ? ;+04 - Length of (UDP Header + Data)
.Checksum dw ? ;+06
.Data db ? ;+08
.Length dw ? ;+04 - Length of (UDP Header + Data)
.Checksum dw ? ;+06
.Data db ? ;+08
}
 
virtual at 0
71,103 → 71,93
; Free up (or re-use) IP buffer when finished
;
;***************************************************************************
udp_rx:
push eax
 
; First validate the header & checksum. Discard buffer if error
proc udp_rx stdcall
push eax
 
; Look for a socket where
; IP Packet UDP Destination Port = local Port
; IP Packet SA = Remote IP
; First validate the header & checksum. Discard buffer if error
 
movzx ebx, word [edx + 22] ; get the local port from
; the IP packet's UDP header
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS
mov ecx, NUM_SOCKETS
; Look for a socket where
; IP Packet UDP Destination Port = local Port
; IP Packet SA = Remote IP
 
fs1:
sub eax, SOCKETBUFFSIZE
cmp [eax + sockets + 12], bx ; bx will hold the 'wrong' value,
; but the comparision is correct
loopnz fs1 ; Return back if no match
jz fs_done
mov ax, [edx + 20 + UDP_PACKET.DestinationPort] ; get the local port from
; the IP packet's UDP header
 
; No match, so exit
jmp udprx_001
mov ebx, net_sockets_mutex
call wait_mutex
mov ebx, net_sockets
 
fs_done:
; For dhcp, we must allow any remote server to respond.
; I will accept the first incoming response to be the one
; I bind to, if the socket is opened with a destination IP address of
; 255.255.255.255
mov ebx, [eax + sockets + 16]
cmp ebx, 0xffffffff
je udprx_002
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .exit ; No match, so exit
cmp [ebx + SOCKET.LocalPort], ax ; ax will hold the 'wrong' value,
; but the comparision is correct
jne .next_socket ; Return back if no match
 
mov ebx, [edx + 12] ; get the Source address from the IP packet
cmp [eax + sockets + 16], ebx
jne udprx_001 ; Quit if the source IP is not valid
; For dhcp, we must allow any remote server to respond.
; I will accept the first incoming response to be the one
; I bind to, if the socket is opened with a destination IP address of
; 255.255.255.255
cmp [ebx + SOCKET.RemoteIP], 0xffffffff
je @f
 
udprx_002:
; OK - we have a valid UDP packet for this socket.
; First, update the sockets remote port number with the incoming msg
; - it will have changed
; from the original ( 69 normally ) to allow further connects
movzx ebx, word [edx + 20] ; get the UDP source port
; ( was 69, now new )
mov [eax + sockets + 20], bx
mov eax, [edx + IP_PACKET.SourceAddress] ; get the Source address from the IP packet
cmp [ebx + SOCKET.RemoteIP], ebx
jne .exit ; Quit if the source IP is not valid
 
; Now, copy data to socket. We have socket address as [eax + sockets].
; We have IP packet in edx
@@: ; OK - we have a valid UDP packet for this socket.
; First, update the sockets remote port number with the incoming msg
; - it will have changed
; from the original ( 69 normally ) to allow further connects
mov ax, [edx + 20 + UDP_PACKET.SourcePort] ; get the UDP source port
; ( was 69, now new )
mov [ebx + SOCKET.RemotePort], ax
 
; get # of bytes in ecx
movzx ecx, byte [edx + 3] ; total length of IP packet. Subtract
mov ch, byte [edx + 2] ; 20 + 8 gives data length
sub ecx, 28
; Now, copy data to socket. We have socket address as [eax + sockets].
; We have IP packet in edx
 
mov ebx, eax
add ebx, sockets ; ebx = address of actual socket
; get # of bytes in ecx
movzx ecx, [edx + IP_PACKET.TotalLength] ; total length of IP packet. Subtract
xchg cl, ch ; 20 + 8 gives data length
sub ecx, 28
 
mov eax, [ebx+ 4] ; get socket owner PID
push eax
mov eax, [ebx + SOCKET.rxDataCount] ; get # of bytes already in buffer
add [ebx + SOCKET.rxDataCount], ecx ; increment the count of bytes in buffer
 
mov eax, [ebx + 24] ; get # of bytes already in buffer
add [ebx + 24], ecx ; increment the count of bytes in buffer
; ecx has count, edx points to data
 
; point to the location to store the data
add ebx, eax
add ebx, SOCKETHEADERSIZE
add edx, 28 ; edx now points to the data
lea edi, [ebx + eax + SOCKETHEADERSIZE]
mov esi, edx
 
; ebx = location for first byte, ecx has count,
; edx points to data
cld
rep movsb ; copy the data across
 
add edx, 28 ; edx now points to the data
mov edi, ebx
mov esi, edx
; flag an event to the application
mov eax, [ebx + SOCKET.PID] ; get socket owner PID
mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid
 
cld
rep movsb ; copy the data across
.next_pid:
cmp [esi], eax
je .found_pid
inc ecx
add esi, 0x20
cmp ecx, [TASK_COUNT]
jbe .next_pid
 
; flag an event to the application
pop eax
mov ecx,1
mov esi,TASK_DATA+TASKDATA.pid
jmp .exit
 
newsearch:
cmp [esi],eax
je foundPID
inc ecx
add esi,0x20
cmp ecx,[TASK_COUNT]
jbe newsearch
.found_pid:
shl ecx, 8
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
 
foundPID:
shl ecx,8
or dword [ecx+SLOT_BASE+APPDATA.event_mask],dword 10000000b ; stack event
mov [check_idle_semaphore], 200
 
mov [check_idle_semaphore],200
 
udprx_001:
pop eax
call freeBuff ; Discard the packet
ret
.exit:
pop eax
call freeBuff ; Discard the packet
ret
endp