/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 |
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 |
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 |
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 |
1201,7 → 1201,7 |
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 |
---|
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 |
---|
87,6 → 87,10 |
} |
include "tcp.inc" |
include "udp.inc" |
include "icmp.inc" |
;*************************************************************************** |
; Function |
; ip_rx |
114,11 → 118,13 |
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 |
mov [ebx + IP_PACKET.HeaderChecksum], word 0 ; clear checksum field - need to when |
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,9 → 133,13 |
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 |
137,22 → 147,37 |
; 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] |
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 ;the flags should be used for fragmented packets |
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,7 → 194,7 |
.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 |
176,9 → 201,9 |
.not_udp: |
cmp al , PROTOCOL_ICMP |
jne .dump ;protocol ain't supported |
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 |
.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 |
.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, dword[buffer_number] |
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 |
105,7 → 106,12 |
; 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 |
155,6 → 161,9 |
; all other registers preserved |
; |
;*************************************************************************** |
uglobal |
dequeue_cnt dd ? |
endg |
dequeue: |
push ebx |
shl eax, 1 |
164,6 → 173,8 |
movzx eax, word [eax] |
cmp ax, NO_BUFFER |
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 |
/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 |
.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,51 → 249,26 |
; 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' |
;*************************************************************************** |
; 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: |
.exit: |
ret |
endp |
;*************************************************************************** |
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 |
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 |
mov [eax + SOCKET.rxDataCount], dword 0 ; recieved data count |
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 |
;pop eax ; Get the socket number back, so we can return it |
stdcall net_socket_addr_to_num |
ret |
so_exit: |
.error: |
DEBUGF 1, "K : socket_open (fail)\n" |
or eax, -1 |
ret |
endp |
;*************************************************************************** |
; 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 |
xchg al, ah |
DEBUGF 1, "K : error: port %u is listened by 0x%x\n", ax, ebx |
pop ebx |
jmp .error |
.last_socket: |
pop ebx |
.skip_port_check: |
call net_socket_alloc |
or eax, eax |
jz .error |
DEBUGF 1, "K : socket_open_tcp (0x%x)\n", eax |
mov [sockAddr], eax |
; TODO - check this works! |
mov [eax + SOCKET.wndsizeTimer], dword 0 ; Reset the window timer. |
;xxx: already 0 (intialized by net_socket_alloc) |
;mov [eax + SOCKET.wndsizeTimer], 0 ; Reset the window timer. |
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 ) |
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 ) |
mov [eax + SOCKET.OrigRemotePort], cx |
mov ebx, [stack_ip] |
mov [eax + SOCKET.LocalIP], ebx |
mov [eax + SOCKET.RemoteIP], edx |
mov [eax + SOCKET.rxDataCount], dword 0 |
mov [eax + SOCKET.OrigRemoteIP], edx |
; Now fill in TCB state |
mov ebx, TCB_LISTEN |
cmp esi, SOCKET_PASSIVE |
jz sot_001 |
je @f |
mov ebx, TCB_SYN_SENT |
@@: mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB |
sot_001: |
mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB |
mov esi, [TASK_BASE] |
mov ecx, [esi+TASKDATA.pid] |
mov [eax + SOCKET.PID], ecx ; save the process ID |
cmp ebx, TCB_LISTEN |
je sot_done |
je .exit |
; 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 |
je .exit |
push eax |
mov bl, 0x02 ; SYN |
mov ecx, 0 |
mov bl, TH_SYN |
xor ecx, ecx |
stdcall build_tcp_packet, [sockAddr] |
call buildTCPPacket |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne sot_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
sot_notlocal: |
.not_local: |
; Send it. |
pop ebx |
call queue |
mov esi, [sktAddr] |
mov esi, [sockAddr] |
; increment SND.NXT in socket |
add esi, 48 |
add esi, SOCKET.SND_NXT |
call inc_inet_esi |
sot_done: |
pop eax ; Get the socket number back, so we can return it |
.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_exit: |
.error: |
DEBUGF 1, "K : socket_open_tcp (fail)\n" |
or eax, -1 |
ret |
endp |
;*************************************************************************** |
; 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 |
cmp [eax + SOCKET.Status], dword SOCK_EMPTY |
jz .error |
; Clear the socket varaibles |
stdcall net_socket_free, eax |
; mov edi, eax |
; xor eax, eax |
; mov ecx, SOCKETHEADERSIZE |
; cld |
; rep stosb |
xor eax, eax |
mov edi, ebx |
mov ecx, SOCKETHEADERSIZE |
cld |
rep stosb |
ret |
sc_exit: |
.error: |
DEBUGF 1, "K : socket_close (fail)\n" |
or eax, -1 |
ret |
endp |
;*************************************************************************** |
; Function |
; socket_close_tcp |
371,7 → 475,9 |
; returns 0 for ok, -1 for socket not open (fail) |
; |
;*************************************************************************** |
socket_close_tcp: |
proc socket_close_tcp stdcall |
local sockAddr dd ? |
DEBUGF 1, "K : socket_close_tcp (0x%x)\n", ebx |
; first, remove any resend entries |
pusha |
378,105 → 484,111 |
mov esi, resendQ |
mov ecx, 0 |
sct001: |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je sct003 ; None left |
cmp [esi], bl |
je sct002 ; found one |
je .last_resendq ; None left |
;cmp [esi], bl ; XTODO: bl -> ebx |
cmp [esi + 4], ebx |
je @f ; found one |
inc ecx |
add esi, 4 |
jmp sct001 |
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 |
sct003: |
.last_resendq: |
popa |
Index2RealAddr ebx |
mov [sktAddr], ebx |
mov eax, 0xFFFFFFFF ; assume this operation will fail.. |
cmp [ebx + SOCKET.Status], dword SOCK_EMPTY |
jz sct_exit |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
mov ebx, eax |
mov [sockAddr], eax |
cmp [ebx + SOCKET.Status], SOCK_EMPTY |
je .error |
cmp [ebx + SOCKET.TCBState], TCB_LISTEN ;xxx |
je .destroy_tcb ;xxx |
cmp [ebx + SOCKET.TCBState], TCB_SYN_SENT ;xxx |
je .destroy_tcb ;xxx |
; Now construct the response, and queue for sending by IP |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je stl_exit |
je .error |
push eax |
mov bl, 0x11 ; FIN + ACK |
mov ecx, 0 |
mov esi, 0 |
;xxx mov bl, TH_FIN + TH_ACK |
mov bl, TH_FIN ;xxx |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
call buildTCPPacket |
mov ebx, [sktAddr] |
mov ebx, [sockAddr] |
; increament SND.NXT in socket |
mov esi, 48 |
add esi, ebx |
lea esi, [ebx + SOCKET.SND_NXT] |
call inc_inet_esi |
; Get the socket state |
mov eax, [ebx + SOCKET.TCBState] |
cmp eax, TCB_LISTEN |
je destroyTCB |
cmp eax, TCB_SYN_SENT |
je destroyTCB |
;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 sct_finwait1 |
je .fin_wait_1 |
cmp eax, TCB_ESTABLISHED |
je sct_finwait1 |
je .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 |
; TODO: check if it's really a TCB_CLOSE_WAIT |
mov [ebx + SOCKET.TCBState], TCB_LAST_ACK |
jmp .send |
sct_finwait1: |
.fin_wait_1: |
; Send a fin, then enter finwait2 state |
mov eax, TCB_FIN_WAIT_1 |
mov [ebx + SOCKET.TCBState], eax |
xor eax, eax |
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1 |
sct_send: |
.send: |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne sct_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
sct_notlocal: |
.not_local: |
; Send it. |
pop ebx |
call queue |
jmp sct_exit |
jmp .exit |
destroyTCB: |
pop eax |
; Clear the socket varaibles |
.destroy_tcb: |
;xxx pop eax |
; Clear the socket variables |
;xxx stdcall net_socket_free, [sockAddr] |
stdcall net_socket_free, ebx |
.exit: |
xor eax, eax |
mov edi, ebx |
mov ecx, SOCKETHEADERSIZE |
cld |
rep stosb |
ret |
sct_exit: |
.error: |
DEBUGF 1, "K : socket_close_tcp (fail)\n" |
or eax, -1 |
ret |
endp |
;*************************************************************************** |
; 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 |
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 |
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,12 → 653,16 |
; returns # of bytes remaining in eax, data in bl |
; |
;*************************************************************************** |
socket_read: |
Index2RealAddr ebx |
proc socket_read stdcall |
; DEBUGF 1, "socket_read(0x%x)\n", ebx |
stdcall net_socket_num_to_addr, ebx |
or eax, eax |
jz .error |
mov ebx, eax |
mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes |
mov ecx, 1 |
test eax, eax |
jz sr2 |
jz .error |
dec eax |
mov esi, ebx ; esi is address of socket |
537,18 → 674,19 |
inc esi |
mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4 |
lea edi, [ebx + SOCKETHEADERSIZE] |
lea esi, [edi + 1] |
cld |
rep movsd |
xor ecx, ecx |
sr1: |
jmp sor_exit |
ret |
sr2: |
xor bl, bl |
sor_exit: |
.error: |
;or eax, -1 |
xor eax, eax |
xor ebx, ebx |
ret |
endp |
;*************************************************************************** |
562,22 → 700,27 |
; returns # of bytes copied in eax |
; |
;*************************************************************************** |
socket_read_packet: |
Index2RealAddr ebx ; get real socket address |
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 |
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) |
test edx, edx ; if buffer size is zero, copy all data |
jz .copyallbytes |
jz .copy_all_bytes |
cmp edx, eax ; if buffer size is larger then the bytes of data, copy all data |
jge .copyallbytes |
jge .copy_all_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 .startcopy ; copy to the application |
call .start_copy ; copy to the application |
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 |
592,33 → 735,36 |
and ecx, 3 |
rep movsb ; copy remaining bytes |
.exit: |
ret ; at last, exit |
.copyallbytes: |
.error: |
;or eax, -1 |
xor eax, eax |
ret |
.copy_all_bytes: |
xor esi, esi |
mov [ebx + SOCKET.rxDataCount], esi ; store new count (zero) |
call .start_copy |
ret |
.startcopy: |
mov edi, ecx ; |
; add edi, std_application_base_address ; get data pointer to buffer in application |
mov esi, ebx ; |
.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 ; |
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 |
.exit: |
ret ; exit, or go back to shift remaining bytes if any |
;*************************************************************************** |
; Function |
; socket_write |
631,19 → 777,22 |
; 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 |
mov ebx, eax |
; If the socket is invalid, return with an error code |
cmp [ebx], dword SOCK_EMPTY |
je sw_exit |
cmp [ebx + SOCKET.Status], SOCK_EMPTY |
je .error |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je sw_exit |
je .error |
; Save the queue entry number |
push eax |
662,55 → 811,46 |
; 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 |
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 |
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 |
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 |
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 |
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 |
add eax, 8 |
mov [edx + 20 + 4], ah |
mov [edx + 20 + 5], al |
xchg al, ah |
mov [edx + 20 + UDP_PACKET.Length], ax |
; Checksum left unfilled |
xor ax, ax |
mov [edx + 20 + 6], ax |
xor eax, eax |
mov [edx + 20 + UDP_PACKET.Checksum], ax |
pop ecx ; count of bytes to send |
mov ebx, ecx ; need the length later |
730,16 → 870,15 |
; we have edx as IPbuffer ptr. |
; Fill in the UDP checksum |
; First, fill in pseudoheader |
mov eax, [edx + 12] |
mov eax, [edx + IP_PACKET.SourceAddress] |
mov [pseudoHeader], eax |
mov eax, [edx + 16] |
mov eax, [edx + IP_PACKET.DestinationAddress] |
mov [pseudoHeader+4], eax |
mov ax, 0x1100 ; 0 + protocol |
mov [pseudoHeader+8], ax |
mov word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0 ; 0 + protocol |
add ebx, 8 |
mov eax, ebx |
mov [pseudoHeader+10], ah |
mov [pseudoHeader+11], al |
xchg al, ah |
mov [pseudoHeader + 10], ax |
mov eax, pseudoHeader |
mov [checkAdd1], eax |
757,44 → 896,44 |
; If the UDP checksum computes to 0, we must make it 0xffff |
; (0 is reserved for 'not used') |
cmp ax, 0 |
jne sw_001 |
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 |
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 |
pop ebx |
mov eax, NET1OUT_QUEUE |
mov ecx, [ edx + 16] |
mov ecx, [edx + SOCKET.RemoteIP] |
mov edx, [stack_ip] |
cmp edx, ecx |
jne sw_notlocal |
jne .not_local |
mov eax, IPIN_QUEUE |
sw_notlocal: |
.not_local: |
; Send it. |
call queue |
xor eax, eax |
ret |
sw_exit: |
.error: |
or eax, -1 |
ret |
endp |
;*************************************************************************** |
; Function |
; socket_write_tcp |
807,30 → 946,33 |
; 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 |
mov ebx, eax |
mov [sockAddr], ebx |
; If the socket is invalid, return with an error code |
cmp [ebx], dword SOCK_EMPTY |
je swt_exit |
cmp [ebx + SOCKET.Status], SOCK_EMPTY |
je .error |
; If the sockets window timer is nonzero, do not queue packet |
; TODO - done |
cmp [ebx + SOCKET.wndsizeTimer], dword 0 |
jne swt_exit |
cmp [ebx + SOCKET.wndsizeTimer], 0 |
jne .error |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je swt_exit |
je .error |
push eax |
mov bl, 0x10 ; ACK |
; Get the address of the callers data |
mov edi, [TASK_BASE] |
add edi, TASKDATA.mem_start |
841,7 → 983,8 |
push eax |
push ecx |
call buildTCPPacket |
mov bl, TH_ACK |
stdcall build_tcp_packet, [sockAddr] |
pop ecx |
; Check destination IP address. |
849,27 → 992,25 |
pop ebx |
push ecx |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [sktAddr ] |
mov ecx, [ecx + 16] |
cmp edx, ecx |
jne swt_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
swt_notlocal: |
.not_local: |
pop ecx |
push ebx ; save ipbuffer number |
call queue |
mov esi, [sktAddr] |
mov esi, [sockAddr] |
; increament SND.NXT in socket |
; Amount to increment by is in ecx |
add esi, 48 |
add esi, SOCKET.SND_NXT |
call add_inet_esi |
pop ebx |
879,17 → 1020,17 |
mov esi, resendQ |
mov ecx, 0 |
swt003: |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je swt001 ; None found |
cmp [esi], byte 0xFF |
je swt002 ; found one |
je .exit ; None found |
;cmp byte[esi], 0xff ; XTODO: 0xff -> 0 |
cmp dword[esi + 4], 0 |
je @f ; found one |
inc ecx |
add esi, 4 |
jmp swt003 |
add esi, 8 |
jmp .next_resendq |
swt002: |
push ebx |
@@: push ebx |
; OK, we have a buffer descriptor ptr in esi. |
; resend entry # in ecx |
899,20 → 1040,19 |
; retry time |
; fill IP buffer associated with this descriptor |
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 |
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 |
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 |
926,9 → 1066,11 |
cld |
rep movsb |
swt001: |
.exit: |
xor eax, eax |
ret |
swt_exit: |
.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$ |
30,9 → 31,16 |
TCB_CLOSE_WAIT equ 7 |
TCB_CLOSING equ 8 |
TCB_LAST_ACK equ 9 |
TCB_TIME_WAIT equ 10 |
TCB_TIMED_WAIT equ 10 |
TCB_CLOSED equ 11 |
TH_FIN = 0x01 |
TH_SYN = 0x02 |
TH_RST = 0x04 |
TH_PUSH = 0x08 |
TH_ACK = 0x10 |
TH_URG = 0x20 |
TWOMSL equ 10 ; # of secs to wait before closing socket |
TCP_RETRIES equ 5 ; Number of times to resend a packet |
102,62 → 110,50 |
; when the TCB timer expires |
; |
;*************************************************************************** |
tcp_tcb_handler: |
proc tcp_tcb_handler stdcall uses ebx |
; scan through all the sockets, decrementing active timers |
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
mov ebx, net_sockets |
tth1: |
sub eax, SOCKETBUFFSIZE |
cmp [eax + sockets + 32], dword 0 |
jne tth2 |
cmp [ebx + SOCKET.NextPtr], 0 |
je .exit |
DEBUGF 1, "K : sockets:\n" |
tth1a: |
cmp [eax + sockets + 72], dword 0 |
jne tth4 |
.next_socket: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .exit |
loop tth1 |
ret |
DEBUGF 1, "K : %x: %x-%x-%x-%u\n", ebx, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState] |
tth2: |
cmp [ebx + SOCKET.TCBTimer], 0 |
jne .decrement_tcb |
cmp [ebx + SOCKET.wndsizeTimer], 0 |
jne .decrement_wnd |
jmp .next_socket |
.decrement_tcb: |
; 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 |
dec [ebx + SOCKET.TCBTimer] |
jnz .next_socket |
cmp [eax + sockets + 28], dword TCB_TIME_WAIT |
jne tth3 |
cmp [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
jne .next_socket |
; OK, delete socket |
mov edi, eax |
add edi, sockets |
push [ebx + SOCKET.PrevPtr] |
stdcall net_socket_free, ebx |
pop ebx |
jmp .next_socket |
xor eax, eax |
mov ecx, SOCKETHEADERSIZE |
cld |
rep stosb |
tth3: |
popa |
jmp tth1a |
loop tth1 |
ret |
.decrement_wnd: |
; TODO - prove it works! |
tth4: |
dec dword [eax + sockets + 72] |
loop tth1 |
ret |
dec [ebx + SOCKET.wndsizeTimer] |
jmp .next_socket |
tth_exit: |
.exit: |
ret |
endp |
;*************************************************************************** |
169,7 → 165,8 |
; 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 |
177,63 → 174,59 |
mov esi, resendQ |
mov ecx, 0 |
tth001: |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je tth003 ; None left |
cmp [esi], byte 0xFF |
jne tth002 ; found one |
je .exit ; None left |
;cmp [esi], byte 0xFF ; XTODO: 0xff -> 0 |
cmp dword[esi + 4], 0 |
jne @f ; found one |
inc ecx |
add esi, 4 |
jmp tth001 |
add esi, 8 |
jmp .next_resendq |
tth002: |
; we have one. decrement it's timer by 1 |
@@: ; we have one. decrement it's timer by 1 |
dec word [esi+2] |
mov ax, [esi+2] |
cmp ax, 0 |
je tth002a |
jz @f |
inc ecx |
add esi, 4 |
jmp tth001 ; Timer not zero, so move on |
add esi, 8 |
jmp .next_resendq ; Timer not zero, so move on |
tth002a: |
mov bl, 0xff |
@@: |
;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] |
mov al, [esi+1] |
cmp al, 0 |
jne tth004 |
jnz @f |
; retries now 0, so delete from queue |
xchg [esi], bl |
tth004: |
;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 |
jne .tth004z |
; TODO - try again in 10ms. |
cmp bl, 0xff |
jne tth004za |
mov [esi], bl |
;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: |
.tth004z: |
; we have a buffer # in ax |
push eax |
push ecx |
push eax ecx |
mov ecx, IPBUFFSIZE |
mul ecx |
add eax, IPbuffs |
241,52 → 234,43 |
; 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 |
mov esi, resendBuffer |
@@: add esi, IPBUFFSIZE |
loop @b |
; we have resend buffer location in esi |
mov ecx, IPBUFFSIZE |
; copy data across |
push edi |
cld |
rep movsb |
pop edi |
; queue packet |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [ edi + 16 ] |
cmp edx, ecx |
jne tth004b |
cmp edx, [edi + IP_PACKET.DestinationAddress] |
jne .not_local |
mov eax, IPIN_QUEUE |
tth004b: |
.not_local: |
pop ebx |
call queue |
.tth005: |
popad |
tth005: |
popa |
inc ecx |
add esi, 4 |
jmp tth001 |
add esi, 8 |
jmp .next_resendq |
tth003: |
.exit: |
ret |
endp |
;*************************************************************************** |
; Function |
; tcp_rx |
299,7 → 283,8 |
; Free up (or re-use) IP buffer when finished |
; |
;*************************************************************************** |
tcp_rx: |
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 |
318,28 → 303,38 |
; IP Packet SA = Remote IP |
; IP Packet TCP Source Port = remote Port |
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 |
mov ebx, net_sockets |
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 |
.next_socket.1: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .next_socket.1.exit |
cmp [ebx + SOCKET.Status], SOCK_OPEN |
jne .next_socket.1 |
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 |
; DEBUGF 1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
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 |
; DEBUGF 1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP] |
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 |
; DEBUGF 1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_PACKET.SourcePort]:4, [ebx + SOCKET.RemotePort]:4 |
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 |
; We have a complete match - use this socket |
jmp tcprx_001 |
jmp .change_state |
nxttst1: |
loop ss1 ; Return back if no match |
.next_socket.1.exit: |
; If we got here, there was no match |
; Look for a socket where |
347,29 → 342,37 |
; IP Packet SA = Remote IP |
; socket remote Port = 0 |
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
mov ebx, net_sockets |
ss2: |
sub eax, SOCKETBUFFSIZE |
.next_socket.2: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .next_socket.2.exit |
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 |
cmp [ebx + SOCKET.Status], SOCK_OPEN |
jne .next_socket.2 |
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 |
; DEBUGF 1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
mov ebx, 0 |
cmp [eax + sockets + 20], bx ; only match a remote socket of 0 |
jnz nxttst2 ; 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 |
; DEBUGF 1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_PACKET.SourceAddress], [ebx + SOCKET.RemoteIP] |
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 |
; DEBUGF 1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4 |
cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0 |
jne .next_socket.2 ; different - try next socket |
; We have a complete match - use this socket |
jmp tcprx_001 |
jmp .change_state |
nxttst2: |
loop ss2 ; Return back if no match |
.next_socket.2.exit: |
; If we got here, there was no match |
; Look for a socket where |
377,49 → 380,70 |
; socket Remote IP = 0 |
; socket remote Port = 0 |
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
mov ebx, net_sockets |
ss3: |
sub eax, SOCKETBUFFSIZE |
.next_socket.3: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .next_socket.3.exit |
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 |
cmp [ebx + SOCKET.Status], SOCK_OPEN |
jne .next_socket.3 |
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 - 3.dport: %x - %x\n", [edx + 20 + TCP_PACKET.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4 |
mov ebx, 0 |
cmp [eax + sockets + 16], ebx ; only match a socket remote IP of 0 |
jnz nxttst3 ; different - try next socket |
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 tcprx_001 |
jmp .change_state |
nxttst3: |
loop ss3 ; Return back if no match |
.next_socket.3.exit: |
; If we got here, we need to reject the packet |
inc dword [dumped_rx_count] |
jmp tcprx_exit |
tcprx_001: |
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 [eax + sockets] |
; IP packet is pointed to by [edx] |
; 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) |
call tcpStateMachine |
tcprx_exit: |
stdcall tcpStateMachine, ebx |
.exit: |
pop eax |
call freeBuff |
ret |
endp |
;*************************************************************************** |
; Function |
; buildTCPPacket |
434,7 → 458,8 |
; Transmit buffer number in eax |
; |
;*************************************************************************** |
buildTCPPacket: |
proc build_tcp_packet stdcall, sockAddr:DWORD |
push ecx ; Save data length |
; convert buffer pointer eax to the absolute address |
444,82 → 469,68 |
mov edx, eax |
mov [edx + 33], bl ; TCP flags |
mov [edx + 20 + TCP_PACKET.Flags], bl ; TCP flags |
mov ebx, [sktAddr] |
mov ebx, [sockAddr] |
; 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 |
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 TCP data length |
push eax |
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 |
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 |
; Checksum left unfilled |
xor ax, ax |
mov [edx + 10], ax |
mov [edx + IP_PACKET.HeaderChecksum], 0 |
; Fill in the TCP header ( some data is in the socket descriptor) |
mov ax, [ebx + 12] |
mov [edx + 20], ax ; Local Port |
mov ax, [ebx + SOCKET.LocalPort] |
mov [edx + 20 + TCP_PACKET.SourcePort], ax ; Local Port |
mov ax, [ebx + 20] |
mov [edx + 20 + 2], ax ; desitination Port |
mov ax, [ebx + SOCKET.RemotePort] |
mov [edx + 20 + TCP_PACKET.DestinationPort], ax ; desitination Port |
; Checksum left unfilled |
xor ax, ax |
mov [edx + 20 + 16], ax |
mov [edx + 20 + TCP_PACKET.Checksum], 0 |
; sequence number |
mov eax, [ebx + 48] |
mov [edx + 20 + 4], eax |
mov eax, [ebx + SOCKET.SND_NXT] |
mov [edx + 20 + TCP_PACKET.SequenceNumber], eax |
; ack number |
mov eax, [ebx + 56] |
mov [edx + 20 + 8], eax |
mov eax, [ebx + SOCKET.RCV_NXT] |
mov [edx + 20 + TCP_PACKET.AckNumber], 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 |
mov [edx + 20 + TCP_PACKET.Window], 0x0003 |
; Urgent pointer (0) |
mov ax, 0 |
mov [edx + 20 + 18], ax |
mov [edx + 20 + TCP_PACKET.UrgentPointer], 0 |
; data offset ( 0x50 ) |
mov al, 0x50 |
mov [edx + 20 + 12], al |
mov [edx + 20 + TCP_PACKET.DataOffset], 0x50 |
pop ecx ; count of bytes to send |
mov ebx, ecx ; need the length later |
cmp ebx, 0 |
jz btp_001 |
jz @f |
mov edi, edx |
add edi, 40 |
526,24 → 537,21 |
cld |
rep movsb ; copy the data across |
btp_001: |
; we have edx as IPbuffer ptr. |
@@: ; we have edx as IPbuffer ptr. |
; Fill in the TCP checksum |
; First, fill in pseudoheader |
mov eax, [edx + 12] |
mov eax, [edx + IP_PACKET.SourceAddress] |
mov [pseudoHeader], eax |
mov eax, [edx + 16] |
mov eax, [edx + IP_PACKET.DestinationAddress] |
mov [pseudoHeader+4], eax |
mov ax, 0x0600 ; 0 + protocol |
mov [pseudoHeader+8], ax |
mov word[pseudoHeader + 8], PROTOCOL_TCP shl 8 + 0 |
add ebx, 20 |
mov eax, ebx |
mov [pseudoHeader+10], ah |
mov [pseudoHeader+11], al |
mov [pseudoHeader + 10], bh |
mov [pseudoHeader + 11], bl |
mov eax, pseudoHeader |
mov [checkAdd1], eax |
mov [checkSize1], word 12 |
mov word[checkSize1], 12 |
mov eax, edx |
add eax, 20 |
mov [checkAdd2], eax |
554,96 → 562,62 |
; store it in the TCP checksum ( in the correct order! ) |
mov ax, [checkResult] |
rol ax, 8 |
mov [edx + 20 + TCP_PACKET.Checksum], ax |
mov [edx + 20 + 16], ah |
mov [edx + 20 + 17], al |
; 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 |
; Increments the 32 bit value pointed to by esi in internet order |
inc_inet_esi: |
proc inc_inet_esi stdcall |
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 |
iie_exit: |
mov eax, [esi] |
bswap eax |
inc eax |
bswap eax |
mov [esi], eax |
pop eax |
ret |
endp |
; Increments the 32 bit value pointed to by esi in internet order |
; by the value in ecx |
add_inet_esi: |
proc add_inet_esi stdcall |
push eax |
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] |
mov eax, [esi] |
bswap eax |
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 |
bswap eax |
mov [esi], eax |
pop eax |
ret |
endp |
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,211 → 627,186 |
; 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 |
proc tcpStateMachine stdcall, sockAddr:DWORD |
; as a packet has been received, update the TCB timer |
mov ecx, TWOMSL |
mov [ebx + 32], ecx |
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 |
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 al |
; skt in eax |
mov esi, resendQ |
mov ecx, 0 |
xor ecx, ecx |
t001: |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je t003 ; None left |
cmp [esi], al |
je t002 ; found one |
je .call_handler ; None left |
;cmp [esi], al ; XTODO: al -> eax |
cmp [esi + 4], eax |
je @f ; found one |
inc ecx |
add esi, 4 |
jmp t001 |
add esi, 8 |
jmp .next_resendq |
t002: ; Can we delete this buffer? |
@@: ; Can we delete this buffer? |
; If yes, goto t004. No, goto t001 |
; If yes, goto @@. No, goto .next_resendq |
; Get packet data address |
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 |
imul edi, ecx, IPBUFFSIZE |
add edi, resendBuffer |
; we have dest buffer location in edi. incoming packet in edx. |
; Get this packets sequence number |
; preserve al, ecx, esi, edx |
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] |
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 |
; 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] |
mov ebx, [edx + 20 + TCP_PACKET.AckNumber] |
bswap ebx |
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 |
jae t004 ; if rx > old, delete old |
inc ecx |
add esi, 4 |
jmp t001 |
add esi, 8 |
jmp .next_resendq |
t004: |
dec dword [arp_rx_count] ; ************ TEST ONLY! |
mov [esi], byte 0xFF |
;@@: mov byte[esi], 0xff ; XTODO: 0xff -> 0 |
@@: mov dword[esi + 4], 0 |
inc ecx |
add esi, 4 |
jmp t001 |
add esi, 8 |
jmp .next_resendq |
t003: |
.call_handler: |
popad |
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 |
dec ebx |
call dword [TCBStateHandler+ebx*4] |
mov eax, [ebx + SOCKET.TCBState] |
cmp eax, TCB_LISTEN |
jb .exit |
cmp eax, TCB_CLOSED |
ja .exit |
tsm_exit: |
stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr] |
.exit: |
ret |
endp |
stateTCB_LISTEN: |
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 |
; Look at control flags |
mov bl, [edx + 33] |
and bl, 0x02 |
cmp bl, 0x02 |
jnz stl_exit |
test [edx + 20 + TCP_PACKET.Flags], TH_SYN |
jz .exit |
; We have a SYN. update the socket with this IP packets details, |
; And send a response |
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 |
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 ebx, [eax + sockets + 36] ; ISS |
mov [eax + sockets + 48], ebx ; SND.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 stl_exit |
je .exit |
push eax |
mov bl, 0x12 ; SYN + ACK |
mov ecx, 0 |
mov esi, 0 |
mov bl, TH_SYN + TH_ACK |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
call buildTCPPacket |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [ sktAddr ] |
mov ecx, [ ecx + 16 ] |
cmp edx, ecx |
jne stl_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
stl_notlocal: |
.not_local: |
; Send it. |
pop ebx |
call queue |
mov esi, [sockAddr] |
mov [esi + SOCKET.TCBState], TCB_SYN_RECEIVED |
mov ebx, TCB_SYN_RECEIVED |
mov esi, [sktAddr] |
mov [esi + 28], ebx |
; increament SND.NXT in socket |
add esi, 48 |
; increment SND.NXT in socket |
add esi, SOCKET.SND_NXT |
call inc_inet_esi |
stl_exit: |
.exit: |
ret |
endp |
stateTCB_SYN_SENT: |
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 |
mov bl, [edx + 33] |
and bl, 0x12 |
cmp bl, 0x12 |
jnz stss_exit |
mov ebx, TCB_ESTABLISHED |
mov esi, [sktAddr] |
mov [esi + 28], ebx |
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 + SOCKET.TCBState], TCB_SYN_RECEIVED |
push TH_SYN + TH_ACK |
jmp .send |
.syn_ack: |
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED |
push TH_ACK |
.send: |
; Store the recv.nxt field |
mov eax, [edx + 24] |
mov eax, [edx + 20 + TCP_PACKET.SequenceNumber] |
; Update our recv.nxt field |
mov esi, [sktAddr] |
add esi, 56 |
mov [esi], eax |
mov [ebx + SOCKET.RCV_NXT], eax |
lea esi, [ebx + SOCKET.RCV_NXT] |
call inc_inet_esi |
; Send an ACK |
865,196 → 814,173 |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je stss_exit |
pop ebx |
je .exit |
push eax |
mov bl, 0x10 ; ACK |
mov ecx, 0 |
mov esi, 0 |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
call buildTCPPacket |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [ sktAddr ] |
mov ecx, [ ecx + 16 ] |
cmp edx, ecx |
jne stss_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
stss_notlocal: |
.not_local: |
; Send it. |
pop ebx |
call queue |
stss_exit: |
.exit: |
ret |
endp |
stateTCB_SYN_RECEIVED: |
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 |
test [edx + 20 + TCP_PACKET.Flags], TH_RST ;xxx |
jz .check_ack ;xxx |
push [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP] |
pop [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort] |
mov [ebx + SOCKET.TCBState], TCB_LISTEN ;xxx |
jmp .exit ;xxx |
.check_ack: ;xxx |
; Look at control flags - expecting an ACK |
mov bl, [edx + 33] |
and bl, 0x10 |
cmp bl, 0x10 |
jnz stsr_exit |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .exit |
mov ebx, TCB_ESTABLISHED |
mov esi, [sktAddr] |
mov [esi + 28], ebx |
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED |
stsr_exit: |
.exit: |
ret |
endp |
stateTCB_ESTABLISHED: |
proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD |
; Here we are expecting data, or a request to close |
; OR both... |
; Did we receive a FIN or RST? |
mov bl, [edx + 33] |
and bl, 0x05 |
cmp bl, 0 |
je ste_chkack |
;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 |
; It was a fin or reset. |
; Remove resend entries from the queue - I dont want to send any more data |
pusha |
pushad |
mov ebx, [sktAddr] |
sub ebx, sockets |
shr ebx, 12 ; get skt # |
; get skt # |
stdcall net_socket_addr_to_num, ebx |
mov esi, resendQ |
mov ecx, 0 |
ste001: |
.next_resendq: |
cmp ecx, NUMRESENDENTRIES |
je ste003 ; None left |
cmp [esi], bl |
je ste002 ; found one |
je .last_resendq ; None left |
;cmp [esi], al ; XTODO: al -> eax |
cmp [esi + 4], eax |
je @f ; found one |
inc ecx |
add esi, 4 |
jmp ste001 |
add esi, 8 |
jmp .next_resendq |
ste002: |
dec dword [arp_rx_count] ; ************ TEST ONLY! |
;@@: 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 ste001 |
.last_resendq: |
popad |
ste003: |
popa |
;xxx ; was it a reset? |
;xxx test [edx + 20 + TCP_PACKET.Flags], TH_RST |
;xxx jz @f |
; was it a reset? |
mov bl, [edx + 33] |
and bl, 0x04 |
cmp bl, 0x04 |
jne ste003a |
;xxx mov [ebx + SOCKET.TCBState], TCB_CLOSED |
;xxx jmp .exit |
mov esi, [sktAddr] |
mov ebx, TCB_CLOSED |
mov [esi + 28], ebx |
jmp ste_exit |
@@: ; Send an ACK to that fin, and enter closewait state |
ste003a: |
; Send an ACK to that fin, and enter closewait state |
mov esi, [sktAddr] |
mov ebx, TCB_CLOSE_WAIT |
mov [esi + 28], ebx |
add esi, 56 |
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 |
ste_chkack: |
.check_ack: |
; Check that we received an ACK |
mov bl, [edx + 33] |
and bl, 0x10 |
cmp bl, 0x10 |
jnz ste_exit |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .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. |
; 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] |
mov cx, [edx + 20 + TCP_PACKET.Window] |
xchg cl, ch |
cmp cx, 1024 |
ja ste004 |
ja @f |
mov ecx, [sktAddr] |
mov [ecx+72], dword 1 |
mov [ebx + SOCKET.wndsizeTimer], 1 |
ste004: |
; OK, here is the deal |
@@: ; 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. |
; recv.nxt is in dword [edx+24], in inext format |
; 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, [sktAddr] |
add ecx, 56 |
cmp [ecx - 56 + 28], dword TCB_CLOSE_WAIT |
mov ecx, [ecx] |
jne stenofin |
mov ecx, [ebx + SOCKET.RCV_NXT] |
cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT |
jne @f |
mov ecx, eax |
stenofin: |
cmp ecx, [edx+24] |
jne ste_ack |
@@: cmp ecx, [edx + 20 + TCP_PACKET.SequenceNumber] |
jne .ack |
; Read the data bytes, store in socket buffer |
xor ecx, ecx |
mov ch, [edx + 2] |
mov cl, [edx + 3] |
movzx ecx, [edx + IP_PACKET.TotalLength] |
xchg cl, ch |
sub ecx, 40 ; Discard 40 bytes of header |
jnz .data ; Read data, if any |
cmp ecx, 0 |
jnz ste_data ; Read data, if any |
; 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 |
cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT |
je .ack |
jmp .exit |
ste_data: |
.data: |
push ecx |
mov esi, [sktAddr] |
add [esi + 24], ecx ; increment the count of bytes in buffer |
add [ebx + SOCKET.rxDataCount], ecx ; increment the count of bytes in buffer |
mov eax, [esi + 4] ; get socket owner PID |
mov eax, [ebx + SOCKET.PID] ; get socket owner PID |
push eax |
mov eax, [esi + 24] ; get # of bytes already in buffer |
mov eax, [ebx + SOCKET.rxDataCount] ; get # of bytes already in buffer |
; point to the location to store the data |
add esi, eax |
sub esi, ecx |
add esi, SOCKETHEADERSIZE |
lea edi, [ebx + eax + SOCKETHEADERSIZE] |
sub edi, ecx |
add edx, 40 ; edx now points to the data |
mov edi, esi |
mov esi, edx |
cld |
1065,79 → 991,75 |
mov ecx,1 |
mov esi,TASK_DATA+TASKDATA.pid |
news: |
.next_pid: |
cmp [esi],eax |
je foundPID1 |
je .found_pid |
inc ecx |
add esi,0x20 |
cmp ecx,[TASK_COUNT] |
jbe news |
jbe .next_pid |
foundPID1: |
.found_pid: |
shl ecx,8 |
or dword [ecx+SLOT_BASE+APPDATA.event_mask],dword 10000000b ; stack event |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event |
pop ecx |
; Update our recv.nxt field |
mov esi, [sktAddr] |
add esi, 56 |
lea esi, [ebx + SOCKET.RCV_NXT] |
call add_inet_esi |
ste_ack: |
.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 |
je .exit |
push eax |
mov bl, 0x10 ; ACK |
mov ecx, 0 |
mov esi, 0 |
mov bl, TH_ACK |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
call buildTCPPacket |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [ sktAddr ] |
mov ecx, [ ecx + 16 ] |
cmp edx, ecx |
jne ste_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
ste_notlocal: |
.not_local: |
; Send it. |
pop ebx |
call queue |
ste_exit: |
.exit: |
ret |
endp |
stateTCB_FIN_WAIT_1: |
proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD |
; 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 |
mov al, [edx + 20 + TCP_PACKET.Flags] |
and al, TH_FIN + TH_ACK |
cmp al, TH_ACK |
jne @f |
; It was an ACK |
mov esi, [sktAddr] |
mov ebx, TCB_FIN_WAIT_2 |
mov [esi + 28], ebx |
jmp stfw1_exit |
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2 |
jmp .exit |
stfw1_001: |
; It must be a fin then |
mov esi, [sktAddr] |
mov ebx, TCB_CLOSING |
mov [esi + 28], ebx |
add esi, 56 |
@@: mov [ebx + SOCKET.TCBState], TCB_CLOSING |
cmp al, TH_FIN |
je @f |
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
@@: lea esi, [ebx + SOCKET.RCV_NXT] |
call inc_inet_esi |
; Send an ACK |
1144,160 → 1066,114 |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je stfw1_exit |
je .exit |
push eax |
mov bl, 0x10 ; ACK |
mov ecx, 0 |
mov esi, 0 |
mov bl, TH_ACK |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
call buildTCPPacket |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [ sktAddr ] |
mov ecx, [ ecx + 16 ] |
cmp edx, ecx |
jne stfw1_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
stfw1_notlocal: |
.not_local: |
; Send it. |
pop ebx |
call queue |
stfw1_exit: |
.exit: |
ret |
endp |
proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD |
test [edx + 20 + TCP_PACKET.Flags], TH_FIN |
jz .exit |
stateTCB_FIN_WAIT_2: |
mov esi, [sktAddr] |
; Get data length |
xor ecx, ecx |
mov ch, [edx+2] |
mov cl, [edx+3] |
sub ecx, 40 |
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 |
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
inc ecx ; FIN is part of the sequence space |
lea esi, [ebx + SOCKET.RCV_NXT] |
call inc_inet_esi |
stfw2001: |
add esi, 56 |
call add_inet_esi |
; Send an ACK |
mov eax, EMPTY_QUEUE |
call dequeue |
cmp ax, NO_BUFFER |
je stfw2_exit |
je .exit |
push eax |
mov bl, 0x10 ; ACK |
mov ecx, 0 |
mov esi, 0 |
mov bl, TH_ACK |
xor ecx, ecx |
xor esi, esi |
stdcall build_tcp_packet, [sockAddr] |
call buildTCPPacket |
mov eax, NET1OUT_QUEUE |
mov edx, [stack_ip] |
mov ecx, [ sktAddr ] |
mov ecx, [ ecx + 16 ] |
cmp edx, ecx |
jne stfw2_notlocal |
mov ecx, [sockAddr] |
cmp edx, [ecx + SOCKET.RemoteIP] |
jne .not_local |
mov eax, IPIN_QUEUE |
stfw2_notlocal: |
.not_local: |
; 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: |
.exit: |
ret |
endp |
stateTCB_CLOSE_WAIT: |
proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD |
; Intentionally left empty |
; socket_close_tcp handles this |
ret |
endp |
stateTCB_CLOSING: |
proc stateTCB_CLOSING stdcall, sockAddr:DWORD |
; 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 |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .exit |
; It was an ACK |
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT |
mov edi, [sktAddr] |
; delete the socket |
xor eax, eax |
mov ecx,SOCKETHEADERSIZE |
cld |
rep stosb |
stc_exit: |
.exit: |
ret |
endp |
stateTCB_LAST_ACK: |
proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD |
; Look at control flags - expecting an ACK |
mov bl, [edx + 33] |
and bl, 0x10 |
cmp bl, 0x10 |
jnz stla_exit |
test [edx + 20 + TCP_PACKET.Flags], TH_ACK |
jz .exit |
mov edi, [sktAddr] |
; delete the socket |
xor eax, eax |
mov ecx,SOCKETHEADERSIZE |
cld |
rep stosb |
stdcall net_socket_free, ebx |
; mov edi, ebx |
; xor eax, eax |
; mov ecx, SOCKETHEADERSIZE |
; cld |
; rep stosb |
stla_exit: |
.exit: |
ret |
endp |
stateTCB_TIME_WAIT: |
proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD |
ret |
endp |
stateTCB_CLOSED: |
proc stateTCB_CLOSED stdcall, sockAddr:DWORD |
ret |
endp |
/kernel/trunk/network/udp.inc |
---|
71,7 → 71,8 |
; Free up (or re-use) IP buffer when finished |
; |
;*************************************************************************** |
udp_rx: |
proc udp_rx stdcall |
push eax |
; First validate the header & checksum. Discard buffer if error |
80,69 → 81,55 |
; IP Packet UDP Destination Port = local Port |
; IP Packet SA = Remote IP |
movzx ebx, word [edx + 22] ; get the local port from |
mov ax, [edx + 20 + UDP_PACKET.DestinationPort] ; get the local port from |
; the IP packet's UDP header |
mov eax, SOCKETBUFFSIZE * NUM_SOCKETS |
mov ecx, NUM_SOCKETS |
fs1: |
sub eax, SOCKETBUFFSIZE |
cmp [eax + sockets + 12], bx ; bx will hold the 'wrong' value, |
mov ebx, net_sockets_mutex |
call wait_mutex |
mov ebx, net_sockets |
.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 |
loopnz fs1 ; Return back if no match |
jz fs_done |
jne .next_socket ; Return back if no match |
; No match, so exit |
jmp udprx_001 |
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 |
cmp [ebx + SOCKET.RemoteIP], 0xffffffff |
je @f |
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 |
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 |
udprx_002: |
; OK - we have a valid UDP packet for this socket. |
@@: ; 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 |
mov ax, [edx + 20 + UDP_PACKET.SourcePort] ; get the UDP source port |
; ( was 69, now new ) |
mov [eax + sockets + 20], bx |
mov [ebx + SOCKET.RemotePort], ax |
; Now, copy data to socket. We have socket address as [eax + sockets]. |
; We have IP packet in edx |
; 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 |
movzx ecx, [edx + IP_PACKET.TotalLength] ; total length of IP packet. Subtract |
xchg cl, ch ; 20 + 8 gives data length |
sub ecx, 28 |
mov ebx, eax |
add ebx, sockets ; ebx = address of actual socket |
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+ 4] ; get socket owner PID |
push eax |
; ecx has count, edx points to data |
mov eax, [ebx + 24] ; get # of bytes already in buffer |
add [ebx + 24], ecx ; increment the count of bytes in buffer |
; point to the location to store the data |
add ebx, eax |
add ebx, SOCKETHEADERSIZE |
; ebx = location for first byte, ecx has count, |
; edx points to data |
add edx, 28 ; edx now points to the data |
mov edi, ebx |
lea edi, [ebx + eax + SOCKETHEADERSIZE] |
mov esi, edx |
cld |
149,25 → 136,28 |
rep movsb ; copy the data across |
; flag an event to the application |
pop eax |
mov eax, [ebx + SOCKET.PID] ; get socket owner PID |
mov ecx,1 |
mov esi,TASK_DATA+TASKDATA.pid |
newsearch: |
.next_pid: |
cmp [esi],eax |
je foundPID |
je .found_pid |
inc ecx |
add esi,0x20 |
cmp ecx,[TASK_COUNT] |
jbe newsearch |
jbe .next_pid |
foundPID: |
jmp .exit |
.found_pid: |
shl ecx,8 |
or dword [ecx+SLOT_BASE+APPDATA.event_mask],dword 10000000b ; stack event |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event |
mov [check_idle_semaphore],200 |
udprx_001: |
.exit: |
pop eax |
call freeBuff ; Discard the packet |
ret |
endp |