Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1249 → Rev 1248

/kernel/branches/net/network/ethernet.inc
80,9 → 80,14
mov ecx, (1+MAX_ETH_DEVICES)
rep stosd
 
init_queue ETH_IN_QUEUE
init_queue ETH_OUT_QUEUE
mov dword [ETH_IN_QUEUE], ETH_QUEUE_SIZE
mov dword [ETH_IN_QUEUE+4], ETH_IN_QUEUE + queue.data
mov dword [ETH_IN_QUEUE+8], ETH_IN_QUEUE + queue.data
 
mov dword [ETH_OUT_QUEUE], ETH_QUEUE_SIZE
mov dword [ETH_OUT_QUEUE+4], ETH_OUT_QUEUE + queue.data
mov dword [ETH_OUT_QUEUE+8], ETH_OUT_QUEUE + queue.data
 
ret
 
 
99,7 → 104,7
;---------------------------------------------------------
 
align 4
ETH_add_device:
ETH_Add_Device:
 
DEBUGF 1,"ETH_Add_Device: %x ", ebx
 
117,6 → 122,7
mov ecx, MAX_ETH_DEVICES ; We need to check whole list because a device may be removed without re-organizing list
mov edi, ETH_DRV_LIST
 
cld
repne scasd ; See if device is already in the list
jz .error
 
161,7 → 167,7
;--------------------------------
 
align 4
ETH_remove_device:
ETH_Remove_Device:
 
cmp [ETH_RUNNING], 0
je .error
206,21 → 212,12
;-------------------------------------------------------------
 
align 4
ETH_receiver:
DEBUGF 1,"ETH_Receiver: "
ETH_Receiver:
DEBUGF 1,"ETH_Receiver \n"
 
push ebx
mov esi, esp
add_to_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.size, .fail
DEBUGF 1,"Queued packet successfully\n"
add esp, 4*3
ret
add_to_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, .gohome
 
.fail:
DEBUGF 1,"ETH_IN_QUEUE is full!\n"
add esp, 4
call kernel_free
add esp, 4
.gohome:
ret
 
 
241,19 → 238,8
align 4
ETH_handler:
 
get_from_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.size, .gohome
get_from_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, .gohome
 
push ETH_handler
 
lodsd
mov ebx, eax
lodsd
mov ecx, eax
lodsd
xchg eax, ecx
push ecx
push eax
 
DEBUGF 1,"ETH_Handler - size: %u\n", ecx
cmp ecx, 60 ; check packet length
jl .dump
276,13 → 262,13
add esp, 4
 
.gohome:
ret ; return to get more from queue / to caller
ret ; return 1. to get more from queue / 2. to caller
 
 
 
;-----------------------------------------------------------------
;
; ETH_sender:
; ETH_Sender:
;
; This function sends an ethernet packet to the correct driver.
;
294,66 → 280,35
;-----------------------------------------------------------------
 
align 4
ETH_sender:
DEBUGF 1,"ETH_Sender: queuing for device: %x, %u bytes\n", [esp], [esp + 4]
ETH_Sender:
DEBUGF 1,"ETH_Sender \n"
 
push ebx
mov esi, esp
add_to_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.size, .fail
DEBUGF 1,"Queued packet successfully\n"
add esp, 3*4
ret
add_to_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, .gohome
 
.fail:
DEBUGF 1,"ETH_OUT_QUEUE is full!\n"
add esp, 4
call kernel_free
add esp, 4
.gohome:
ret
 
 
 
;-----------------------------------------------------------------
;
; ETH_send_queued:
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
 
align 4
ETH_send_queued:
 
get_from_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.size, .gohome
get_from_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, .gohome
 
push ETH_send_queued
 
lodsd
mov ebx, eax
 
sub esp, 8
mov edi, esp
movsd
movsd
 
DEBUGF 1,"dequeued packet for device %x\n", ebx
 
call ETH_struc2dev ; convert struct ptr to device num (this way we know if driver is still mounted)
cmp edi, -1
je .fail
 
jmp [ebx+ETH_DEVICE.transmit] ; we will return to get_from_queue macro after transmitting packet
DEBUGF 1,"ETH_Sender - device: %u\n", edi
 
jmp [ebx+ETH_DEVICE.transmit]
 
.fail:
call kernel_free
add esp, 4 ; pop (balance stack)
DEBUGF 1,"ETH_Sender - fail\n"
 
.gohome:
ret
 
 
;---------------------------------------------------------------------------
;
; ETH_struc2dev
407,7 → 362,7
;---------------------------------------------------------------------------
 
align 4
ETH_create_packet:
ETH_create_Packet:
 
DEBUGF 1,"Creating Ethernet Packet (size=%u): \n", ecx
 
439,7 → 394,7
lea eax, [edi - ETH_FRAME.Data] ; Set eax to buffer start
mov edx, ecx ; Set ebx to complete buffer size
pop ecx
mov esi, ETH_sender
mov esi, ETH_Sender
 
xor ebx, ebx ;;;; TODO: Fixme
mov ebx, [ETH_DRV_LIST + ebx]
/kernel/branches/net/network/IPv4.inc
3,7 → 3,7
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; IPv4.INC ;;
;; IP.INC ;;
;; ;;
;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;;
52,7 → 52,7
.PrevPtr dd ? ; Pointer to previous fragment entry (-1 for first packet)
.NextPtr dd ? ; Pointer to next fragment entry (-1 for last packet)
.Owner dd ? ; Pointer to structure of driver
rb 2 ; to match ethernet header size ; TODO: fix this hack
rb 2 ; to match ethernet header size
.Data: ; Ip header begins here (we will need the IP header to re-construct the complete packet)
ends
 
99,9 → 99,10
 
;-----------------------------------------------------------------
;
; IPv4_Handler:
; IP_Handler:
;
; Will check if IP Packet isnt damaged
; Called by eth_handler,
; will check if IP Packet isnt damaged
; and call appropriate handler. (TCP/UDP/ICMP/..)
;
; It will also re-construct fragmented packets
118,28 → 119,21
IPv4_handler:
 
DEBUGF 1,"IP_Handler - start\n"
mov cx , [edx + IPv4_Packet.HeaderChecksum]
xchg ch , cl ; Get the checksum in intel format
 
push edx ebx
mov word [edx + IPv4_Packet.HeaderChecksum], 0 ; Clear checksum field to recalculating checksum
 
; save checksum, and clear it in original packet
mov di , [edx + IPv4_Packet.HeaderChecksum]
DEBUGF 1,"checksum: %x\n",di
mov word [edx + IPv4_Packet.HeaderChecksum], 0
movzx eax, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field
and eax, 0x0000000F ;
shl eax, 2 ;
 
; Re-calculate checksum
movzx ecx, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field
and ecx, 0x0000000F ;
shl cx , 2 ;
mov esi, edx
xor edx, edx
call checksum_1
call checksum_2
push edx
stdcall checksum_jb, edx, eax ; buf_ptr, buf_size
pop edx
cmp cx , ax
jnz .dump ; if CHECKSUM isn't valid then dump Packet
 
; now compare the two..
cmp dx, di
pop ebx edx
jne .dump ; if checksum isn't valid then dump packet
 
mov eax, [edx + IPv4_Packet.DestinationAddress]
mov edi, BROADCAST
mov ecx, MAX_IP+1
189,14 → 183,10
add eax, edx
push eax
mov al , [edx + IPv4_Packet.Protocol]
;----------------------- experimental
mov esi, [edx + IPv4_Packet.SourceAddress]
mov edi, [edx + IPv4_Packet.DestinationAddress]
;-----------------------
pop edx ; Offset to data (tcp/udp/icmp/.. Packet)
 
cmp al , IP_PROTO_TCP
je TCP_handler
; je TCP_handler
 
cmp al , IP_PROTO_UDP
je UDP_handler
395,21 → 385,14
movzx eax, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field
and ax, 0x000F ;
shl ax, 2 ;
 
sub ecx, eax
 
 
sub ecx, eax ;
add eax, edx
push eax
mov al , [edx + IPv4_Packet.Protocol]
;----------------------- experimental
mov esi, [edx + IPv4_Packet.SourceAddress]
mov edi, [edx + IPv4_Packet.DestinationAddress]
;-----------------------
pop edx ; Offset to data (tcp/udp/icmp/.. Packet)
 
cmp al , IP_PROTO_TCP
je TCP_handler
; je TCP_handler
 
cmp al , IP_PROTO_UDP
je UDP_handler
510,12 → 493,12
; dx = fragment id
; di = protocol
;
; OUT: eax = pointer to buffer start
; ebx = pointer to device struct (needed for sending procedure)
; OUT: eax points to buffer start
; ebx is size of complete buffer
; edi = pointer to start of data (-1 on error)
; ecx = unchanged (packet size of embedded data)
; edx = size of complete buffer
; edx = pointer to device struct (needed for sending procedure)
; esi = pointer to sending procedure
; edi = pointer to start of data (-1 on error)
;
;-----------------------------------------------------------------
 
567,7 → 550,7
mov ecx, [esp+18] ;; 18 or 22 ??
add ecx, IPv4_Packet.DataOrOptional
mov di , ETHER_IPv4
call ETH_create_packet ; TODO: figure out a way to make this work with other protocols too
call ETH_create_Packet ; TODO: figure out a way to make this work with other protocols too
add esp, 6
cmp edi, -1
je .exit
588,18 → 571,14
pop ecx
mov [edi + IPv4_Packet.DestinationAddress], ecx
 
push eax ebx edx
; calculate checksum
xor edx, edx
mov esi, edi
mov ecx, IPv4_Packet.DataOrOptional
call checksum_1
call checksum_2
mov [edi + IPv4_Packet.HeaderChecksum], dx
pop edx ebx eax ecx
push eax
stdcall checksum_jb, edi, IPv4_Packet.DataOrOptional ; buf_ptr, buf_size
xchg al, ah
mov [edi + IPv4_Packet.HeaderChecksum], ax
pop eax ecx
add edi, IPv4_Packet.DataOrOptional
 
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", ebx
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", edx
 
ret
 
606,7 → 585,7
 
.not_found:
DEBUGF 1,"Create IPv4 Packet - ARP entry not found!\n"
; TODO: QUEUE the packet to resend later!
; TODO: QUEUE!
.exit:
add esp, 16
.exit_:
/kernel/branches/net/network/socket.inc
5,6 → 5,7
;; ;;
;; SOCKET.INC ;;
;; ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; based on code by mike.dld ;;
;; ;;
15,7 → 16,8
 
$Revision$
 
struct SOCKET_head
align 4
struct SOCKET
.PrevPtr dd ? ; pointer to previous socket in list
.NextPtr dd ? ; pointer to next socket in list
.Number dd ? ; socket number (unique within single process)
23,34 → 25,19
.Domain dd ? ; INET/UNIX/..
.Type dd ? ; RAW/UDP/TCP/...
.Protocol dd ? ; ICMP/IPv4/ARP/
.lock dd ? ; lock mutex
.end:
ends
 
struct IPv4_SOCKET
.LocalIP dd ?
.RemoteIP dd ?
.SequenceNumber dd ?
 
; todo: add options (for func 8 and 9)
 
.end:
ends
 
struct TCP_SOCKET
 
.LocalPort dw ? ; In INET byte order
.RemotePort dw ? ; In INET byte order
 
.backlog dw ? ; Backlog
.LocalIP dd ? ; local IP address
.RemoteIP dd ? ; remote IP address
.LocalPort dw ? ; local port (In INET byte order)
.RemotePort dw ? ; remote port (IN INET byte order
.OrigRemoteIP dd ? ; original remote IP address (used to reset to LISTEN state)
.OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state)
.rxDataCount dd ? ; rx data count
.TCBState dd ? ; TCB state
.TCBTimer dd ? ; TCB timer (seconds)
.ISS dd ? ; initial send sequence
.IRS dd ? ; initial receive sequence
.SND_UNA dd ? ; sequence number of unack'ed sent Packets
.SND_NXT dd ? ; next send sequence number to use
.SND_NXT dd ? ; bext send sequence number to use
.SND_WND dd ? ; send window
.RCV_NXT dd ? ; next receive sequence number to use
.RCV_WND dd ? ; receive window
57,40 → 44,17
.SEG_LEN dd ? ; segment length
.SEG_WND dd ? ; segment window
.wndsizeTimer dd ? ; window size timer
 
.flags db ? ; packet flags
 
.end:
.lock dd ? ; lock mutex
.backlog dw ? ; Backlog
.rxData: ; receive data buffer here
ends
 
struct UDP_SOCKET
MAX_backlog equ 20
 
.LocalPort dw ? ; In INET byte order
.RemotePort dw ? ; In INET byte order
; socket buffers
SOCKETBUFFSIZE equ 4096 ; state + config + buffer.
SOCKETHEADERSIZE equ SOCKET.rxData ; thus 4096 - SOCKETHEADERSIZE bytes data
 
.end:
ends
 
struct ICMP_SOCKET
 
.Identifier dw ? ;
 
.end:
 
ends
 
struct IPC_SOCKET
 
.ConnectedTo dd ? ; Socket number of other socket this one is connected to
 
.end:
 
ends
 
MAX_backlog equ 20 ; backlog for stream sockets
SOCKETBUFFSIZE equ 4096 ; in bytes
SOCKET_QUEUE_SIZE equ 10 ; maximum number ofincoming packets queued for 1 socket
 
uglobal
net_sockets rd 2
last_UDP_port dw ? ; These values give the number of the last used ephemeral port
146,10 → 110,6
jz socket_send ; 6
dec bl
jz socket_recv ; 7
dec bl
; jz socket_get_opt ; 8
dec bl
; jz socket_set_opt ; 9
 
s_error:
mov dword [esp+32],-1
179,9 → 139,9
or eax, eax
jz s_error
 
mov [eax + SOCKET_head.Domain], ecx
mov [eax + SOCKET_head.Type], edx
mov [eax + SOCKET_head.Protocol], esi
mov [eax + SOCKET.Domain], ecx
mov [eax + SOCKET.Type], edx
mov [eax + SOCKET.Protocol], esi
 
stdcall net_socket_addr_to_num, eax
DEBUGF 1,", socketnumber: %u\n", eax
193,10 → 153,6
 
 
 
 
 
 
 
;-----------------------------------------------
;
; SOCKET_bind
220,28 → 176,14
jl s_error
 
cmp word [edx], AF_INET4
je .af_inet4
jne s_error
 
cmp word [edx], AF_UNIX
je .af_unix
 
jmp s_error
 
.af_unix:
 
; TODO: write code here
 
 
mov dword [esp+32],0
ret
 
.af_inet4:
 
cmp esi, 6
jl s_error
 
mov ecx, [eax + SOCKET_head.Type]
 
mov ecx, [eax + SOCKET.Type]
mov bx, word [edx + 2]
DEBUGF 1,"local port: %x ",bx
test bx, bx
260,14 → 202,13
 
.got_port:
DEBUGF 1,"using port: %x ",bx
mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
mov word [eax + SOCKET.LocalPort], bx
 
mov ebx, dword [edx + 4]
mov dword [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP], ebx
mov dword [eax + SOCKET.LocalIP], ebx
 
DEBUGF 1,"local ip: %u.%u.%u.%u\n",\
[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 0]:1,[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 1]:1,\
[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 2]:1,[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 3]:1
[eax + SOCKET.LocalIP]:1,[eax + SOCKET.LocalIP + 1]:1,[eax + SOCKET.LocalIP + 2]:1,[eax + SOCKET.LocalIP + 3]:1
 
mov dword [esp+32],0
ret
308,13 → 249,13
cmp esi, 8
jl s_error
 
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
cmp [eax + SOCKET.Type], IP_PROTO_UDP
je .udp
 
cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
je .icmp
 
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
cmp [eax + SOCKET.Type], IP_PROTO_TCP
je .tcp
 
jmp s_error
322,11 → 263,11
.udp:
 
mov bx , word [edx + 2]
mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx
mov word [eax + SOCKET.RemotePort], bx
DEBUGF 1,"remote port: %x ",bx
 
mov ebx, dword [edx + 4]
mov dword [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx
mov dword [eax + SOCKET.RemoteIP], ebx
DEBUGF 1,"remote ip: %u.%u.%u.%u\n",[edx+4]:1,[edx+5]:1,[edx+6]:1,[edx+7]:1
 
mov dword [esp+32],0
334,7 → 275,6
 
.icmp:
 
; TODO: write code here
 
ret
 
447,7 → 387,7
mov dx , 20
.ok:
 
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], dx
mov [eax + SOCKET.backlog], dx
 
; TODO: insert code for active connections like TCP
 
480,21 → 420,7
jz s_error
mov esi, eax
 
cmp word [esi + SOCKET_head.Domain], AF_INET4
je .af_inet4
 
jmp s_error
 
.af_inet4:
 
cmp [esi + SOCKET_head.Type], IP_PROTO_TCP
je .tcp
 
jmp s_error
 
.tcp:
 
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0
cmp [esi + SOCKET.backlog], 0
jz s_error
 
call net_socket_alloc
502,21 → 428,19
jz s_error
mov edi, eax
 
dec [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
dec [esi + SOCKET.backlog]
 
mov ecx, (SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end+3)/4
push esi edi
mov ecx, (SOCKET.rxData+3)/4
rep movsd
pop edi esi
 
mov [edi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0
mov [edi + SOCKET.backlog], 0
 
; TODO: fill in structure in ecx
 
mov [esi + SOCKET_head.end + IPv4_SOCKET.RemoteIP], 0
mov [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], 0
mov [esi + SOCKET.RemoteIP], 0
mov [esi + SOCKET.RemotePort], 0
 
stdcall net_socket_addr_to_num, edi
stdcall net_socket_addr_to_num, eax
mov [esp+32], eax
 
ret
541,16 → 465,14
or eax, eax
jz s_error
 
cmp [eax + SOCKET_head.Domain], AF_INET4
jne s_error
 
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
cmp [eax + SOCKET.Type], IP_PROTO_UDP
je .udp
 
cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
je .icmp
 
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
cmp [eax + SOCKET.Type], IP_PROTO_TCP
je .tcp
 
jmp s_error
557,7 → 479,12
 
.udp:
 
lea ebx, [eax + SOCKET.lock]
call wait_mutex
; TODO: mark the socket for deletion, using the mutex
 
stdcall net_socket_free, eax
 
mov dword [esp+32],0
ret
 
673,8 → 600,8
;
;
; IN: socket number in ecx
; addr to buffer in edx
; length of buffer in esi
; addr in edx
; addrlen in esi
; flags in edi
; OUT: eax is number of bytes copied, -1 on error
;
682,47 → 609,71
align 4
socket_recv:
 
DEBUGF 1,"Socket_receive: socknum: %u bufferaddress: %x, length: %u, flags: %x\n",ecx,edx,esi,edi
DEBUGF 1,"Socket_receive: socknum: %u sockaddr: %x, length: %u, flags: %x\n",ecx,edx,esi,edi
 
stdcall net_socket_num_to_addr, ecx ; get real socket address
or eax, eax
jz s_error
 
DEBUGF 1,"Socket pointer: %x\n", eax
DEBUGF 1,"real socket address:%x\n", eax
 
get_from_queue (eax + 2048), SOCKET_QUEUE_SIZE, 4*3, s_error
mov dword[esp+32], -1
 
mov edi, edx
mov ecx, [esi + socket_queue_entry.data_size]
 
DEBUGF 1,"Got %u bytes of data\n", ecx
lea ebx, [eax + SOCKET.lock]
call wait_mutex
 
cmp ecx, edx
jle .large_enough
DEBUGF 1,"Buffer too small...\n"
jmp s_error
.large_enough:
mov ecx, [eax + SOCKET.rxDataCount] ; get count of bytes
DEBUGF 1,"bytes in socket:%u\n", ecx
test ecx, ecx ; if count of bytes is zero..
jz .exit ; exit function (eax will be zero)
 
push [esi + socket_queue_entry.data_ptr]
mov esi, [esi + socket_queue_entry.offset]
add esi, [esp]
DEBUGF 1,"Source buffer: %x, real addr: %x\n", [esp], esi
cmp ecx, esi ; if buffer size is larger then the bytes of data, copy all data
jle .copy_all_bytes
 
mov dword[esp+32+4], ecx ; return number of bytes copied
sub ecx, esi ; store new count (data bytes in buffer - bytes we're about to copy)
mov [eax + SOCKET.rxDataCount], ecx ;
push ecx
mov edx, esi
 
shr ecx, 1
jnc .nb
movsb
.nb: shr ecx, 1
jnc .nw
movsw
.nw: rep movsd
call .start_copy ; copy to the application
 
call kernel_free
mov dword[esp+32], edx
 
lea edi, [eax + SOCKET.rxData] ; Now shift the remaining bytes to start of buffer
lea esi, [edi + edx]
mov ecx, [esp]
shr ecx, 2 ; divide eax by 4
rep movsd ; copy all full dwords
pop ecx
and ecx, 3
rep movsb ; copy remaining bytes
 
.exit:
mov [eax + SOCKET.lock], 0
ret
 
.copy_all_bytes:
mov dword[esp+32], ecx
mov [eax + SOCKET.rxDataCount], 0 ; store new count (zero)
push dword .exit ; this code results in same as commented out code
 
.start_copy:
DEBUGF 1,"copying %u bytes\n",ecx
 
lea esi, [eax + SOCKET.rxData]
push ecx
shr ecx, 2 ; divide eax by 4
rep movsd
pop ecx
and ecx, 3
rep movsb ; copy the rest bytes
 
ret ; exit, or go back to shift remaining bytes if any
 
 
 
;-----------------------------------------------
;
; SOCKET_send
744,100 → 695,87
or eax, eax
jz s_error
 
cmp word [eax + SOCKET_head.Domain], AF_INET4
cmp word [eax + SOCKET.Domain], AF_INET4
je .af_inet4
 
jmp s_error
 
;---------
.af_inet4:
DEBUGF 1,"Socket type:%u\n", [eax + SOCKET_head.Type]:4
 
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
je .tcp
DEBUGF 1,"Socket type:%u\n", [eax + SOCKET.Type]:4
 
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
cmp [eax + SOCKET.Type], IP_PROTO_UDP
je .udp
 
cmp [eax + SOCKET_head.Type], SOCK_RAW
je .raw
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
je .icmp
 
cmp [eax + SOCKET.Type], IP_PROTO_TCP
je .tcp
 
jmp s_error
;--------
 
.udp:
 
DEBUGF 1,"type: UDP, "
 
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort],0
jne @f
cmp [eax + SOCKET.LocalPort],0
jne .port_ok
 
push esi
mov ecx, [eax + SOCKET_head.Type]
mov ecx, [eax + SOCKET.Type]
call socket_find_port
test bx, bx
pop esi
je s_error
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
mov [eax + SOCKET.LocalPort], bx
 
@@:
.port_ok:
 
mov ecx, esi
mov esi, edx
mov edx, dword [eax + SOCKET.LocalPort] ; load local port and remote port at once
DEBUGF 1,"local port: %x, remote port: %x\n",[eax + SOCKET.LocalPort]:4, [eax + SOCKET.RemotePort]:4
mov ebx, [eax + SOCKET.LocalIP]
mov eax, [eax + SOCKET.RemoteIP]
 
call UDP_socket_send
call UDP_create_packet
 
mov [esp+32], eax
ret
 
.tcp:
.icmp:
; note: for ICMP sockets the SOCKET.LocalPort is used as the 'Identifier' value for ICMP packets
; the application must add the header to the data, the kernel will fill in 'identifier' and 'checksum'
 
sub ecx, ICMP_Packet.Data
mov esi, edx
push ax
call IPv4_get_frgmnt_num
mov dx, ax
pop ax
shl edx, 16
mov dh , [esi + ICMP_Packet.Type]
mov dl , [esi + ICMP_Packet.Code]
mov di , [esi + ICMP_Packet.Identifier]
; mov [eax + SOCKET.LocalPort], di ; Set localport to the identifier number, so we can receive reply's
shl edi, 16
mov di , [esi + ICMP_Packet.SequenceNumber]
add esi, ICMP_Packet.Data
mov ebx, [eax + SOCKET.LocalIP]
mov eax, [eax + SOCKET.RemoteIP]
call ICMP_create_packet
 
mov [esp+32], eax
ret
 
;--------
.raw:
cmp [eax + SOCKET_head.Protocol], IP_PROTO_IP
je .raw_ip
.tcp:
 
cmp [eax + SOCKET_head.Protocol], IP_PROTO_ICMP
je .raw_icmp
 
jmp s_error
;--------
 
 
.raw_ip:
 
mov [esp+32], eax
ret
 
 
.raw_icmp:
 
; sub ecx, ICMP_Packet.Data
; mov esi, edx
; push ax
; call IPv4_get_frgmnt_num
; mov dx, ax
; pop ax
; shl edx, 16
; mov dh , [esi + ICMP_Packet.Type]
; mov dl , [esi + ICMP_Packet.Code]
; mov di , [esi + ICMP_Packet.Identifier]
; mov [eax + SOCKET.LocalPort], di ; Set localport to the identifier number, so we can receive reply's
; shl edi, 16
; mov di , [esi + ICMP_Packet.SequenceNumber]
; add esi, ICMP_Packet.Data
; mov ebx, [eax + SOCKET.LocalIP]
; mov eax, [eax + SOCKET.RemoteIP]
; call ICMP_create_packet
 
mov [esp+32], eax
ret
 
 
 
;-----------------------------------------------
;
; SOCKET_find_free_port (local port)
874,15 → 812,15
mov esi, net_sockets
 
.next_socket:
mov esi, [esi + SOCKET_head.NextPtr]
mov esi, [esi + SOCKET.NextPtr]
or esi, esi
jz .port_ok
 
cmp [esi + SOCKET_head.Type], ecx
cmp [esi + SOCKET.Type], ecx
jne .next_socket
 
rol bx, 8
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
cmp [esi + SOCKET.LocalPort], bx
rol bx, 8 ; this doesnt change the zero flag, does it ?
jne .next_socket
 
914,14 → 852,14
mov esi, net_sockets
 
.next_socket:
mov esi, [esi + SOCKET_head.NextPtr]
mov esi, [esi + SOCKET.NextPtr]
or esi, esi
jz .port_ok
 
cmp [esi + SOCKET_head.Type], ecx
cmp [esi + SOCKET.Type], ecx
jne .next_socket
 
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
cmp [esi + SOCKET.LocalPort], bx
jne .next_socket
 
xor ebx, ebx
930,19 → 868,20
ret
 
 
 
;-----------------------------------------------
;
; SOCKET_internal_receiver
;
; Updates a socket with received data
; Checks if any socket wants the received data
; If so, update the socket
;
; Note: the mutex must already be set !
; IN: eax = socket number
; ecx = number of bytes
; esi = pointer to beginning of data
; dx = Remote port (in INET byte order)
; edi = IP address of sender
;
; IN: eax = socket ptr
; ecx = size
; esi = pointer to buffer
; edi = offset
;
; OUT: xxx
;
;-----------------------------------------------
949,20 → 888,39
align 4
socket_internal_receiver:
 
DEBUGF 1,"Internal socket receiver: buffer %x, offset: %x\n", esi, edi
DEBUGF 1,"internal socket receiver\n"
 
push edi ; offset
push ecx ; size
push esi ; data_ptr
mov esi, esp
add_to_queue (eax + 2048), SOCKET_QUEUE_SIZE, 3*4, .full
DEBUGF 1,"Queued packet successfully\n"
add esp, 4*3
lea ebx, [eax + SOCKET.lock]
call wait_mutex
 
mov [eax + SOCKET_head.lock], 0
mov [eax + SOCKET.RemotePort], dx ; update remote port number
mov [eax + SOCKET.RemoteIP], edi
 
mov edx, [eax + SOCKET.rxDataCount] ; get # of bytes already in buffer
DEBUGF 1,"bytes already in socket: %u ", edx
 
lea edi, [ecx + edx] ; check for buffer overflow
cmp edi, SOCKETBUFFSIZE - SOCKETHEADERSIZE ;
jg .dump ;
 
lea edi, [eax + SOCKET.rxData + edx]
add [eax + SOCKET.rxDataCount], ecx ; increment the count of bytes in buffer
DEBUGF 1,"adding %u bytes\n", ecx
 
; copy the data across
push cx
shr ecx, 2
rep movsd
pop cx
and cx, 3
rep movsb
 
DEBUGF 1,"socket updated\n"
 
mov [eax + SOCKET.lock], 0
 
; flag an event to the application
mov edx, [eax + SOCKET_head.PID] ; get socket owner PID
mov edx, [eax + SOCKET.PID] ; get socket owner PID
mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid
 
981,16 → 939,14
mov [check_idle_semaphore], 200
ret
 
.full:
DEBUGF 1,"Socket %x is full!\n",eax
mov [eax + SOCKET_head.lock], 0
call kernel_free
add esp, 8
.dump:
mov [eax + SOCKET.lock], 0
ret
 
 
 
 
 
; Allocate memory for socket data and put new socket into the list
; Newly created socket is initialized with calling PID and number and
; put into beginning of list (which is a fastest way).
1007,7 → 963,6
; zero-initialize allocated memory
push eax
mov edi, eax
 
mov ecx, SOCKETBUFFSIZE / 4
; cld
xor eax, eax
1014,23 → 969,21
rep stosd
pop eax
 
init_queue (eax + 2048)
 
; add socket to the list by changing pointers
mov ebx, net_sockets
push [ebx + SOCKET_head.NextPtr]
mov [ebx + SOCKET_head.NextPtr], eax
mov [eax + SOCKET_head.PrevPtr], ebx
push [ebx + SOCKET.NextPtr]
mov [ebx + SOCKET.NextPtr], eax
mov [eax + SOCKET.PrevPtr], ebx
pop ebx
mov [eax + SOCKET_head.NextPtr], ebx
mov [eax + SOCKET.NextPtr], ebx
or ebx, ebx
jz @f
mov [ebx + SOCKET_head.PrevPtr], eax
mov [ebx + SOCKET.PrevPtr], eax
 
@@: ; set socket owner PID to the one of calling process
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET_head.PID], ebx
mov [eax + SOCKET.PID], ebx
 
; find first free socket number and use it
;mov edx, ebx
1039,10 → 992,10
.next_socket_number:
inc ecx
.next_socket:
mov ebx, [ebx + SOCKET_head.NextPtr]
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .last_socket_number
cmp [ebx + SOCKET_head.Number], ecx
cmp [ebx + SOCKET.Number], ecx
jne .next_socket
;cmp [ebx + SOCKET.PID], edx
;jne .next_socket
1050,7 → 1003,7
jmp .next_socket_number
 
.last_socket_number:
mov [eax + SOCKET_head.Number], ecx
mov [eax + SOCKET.Number], ecx
 
.exit:
ret
1072,7 → 1025,7
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET_head.NextPtr]
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .error
cmp ebx, eax
1082,16 → 1035,13
 
; okay, we found the correct one
; remove it from the list first, changing pointers
mov ebx, [eax + SOCKET_head.NextPtr]
mov eax, [eax + SOCKET_head.PrevPtr]
mov [eax + SOCKET_head.NextPtr], ebx
mov ebx, [eax + SOCKET.NextPtr]
mov eax, [eax + SOCKET.PrevPtr]
mov [eax + SOCKET.NextPtr], ebx
or ebx, ebx
jz @f
mov [ebx + SOCKET_head.PrevPtr], eax
mov [ebx + SOCKET.PrevPtr], eax
 
lea ebx, [eax + SOCKET_head.lock]
call wait_mutex
 
@@: ; and finally free the memory structure used
stdcall kernel_free, [sockAddr]
ret
1120,10 → 1070,10
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET_head.NextPtr]
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .error
cmp [ebx + SOCKET_head.Number], eax
cmp [ebx + SOCKET.Number], eax
jne .next_socket
;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket
1156,7 → 1106,7
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET_head.NextPtr]
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .error
cmp ebx, eax
1165,7 → 1115,7
;jne .next_socket
 
; okay, we found the correct one
mov eax, [ebx + SOCKET_head.Number]
mov eax, [ebx + SOCKET.Number]
ret
 
.error:
/kernel/branches/net/network/udp.inc
75,34 → 75,8
UDP_handler:
 
DEBUGF 1,"UDP_Handler\n"
; First validate, checksum:
; TODO: First validate the header & checksum!
 
DEBUGF 1,"Real UDP checksum: %x\n", [edx + UDP_Packet.Checksum]:4
mov [edx + UDP_Packet.Checksum], 0
 
pusha
 
rol cx, 8
push cx
rol cx, 8
push word IP_PROTO_UDP shl 8
push edi
push esi
 
mov esi, edx
xor edx, edx
call checksum_1
; Checksum for pseudoheader
mov ecx, 12
mov esi, esp
call checksum_1
add esp, 12
call checksum_2
 
popa
 
 
 
; Look for a socket where
; IP Packet UDP Destination Port = local Port
; IP Packet SA = Remote IP
111,14 → 85,14
.try_more:
mov bx , [edx + UDP_Packet.DestinationPort] ; get the local port from the IP Packet's UDP header
.next_socket:
mov eax, [eax + SOCKET_head.NextPtr]
mov eax, [eax + SOCKET.NextPtr]
or eax, eax
jz .dump
cmp [eax + SOCKET_head.Domain], AF_INET4
cmp [eax + SOCKET.Domain], AF_INET4
jne .next_socket
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
cmp [eax + SOCKET.Type], IP_PROTO_UDP
jne .next_socket
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
cmp [eax + SOCKET.LocalPort], bx
jne .next_socket
 
DEBUGF 1,"found socket with matching domain, type and localport\n"
127,12 → 101,12
; 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 [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], 0xffffffff
cmp [eax + SOCKET.RemoteIP], 0xffffffff
je .ok1
 
mov ebx, [esp]
mov ebx, [ebx + ETH_FRAME.Data + IPv4_Packet.SourceAddress] ; get the Source address from the IP Packet FIXME
cmp [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx
cmp [eax + SOCKET.RemoteIP], ebx
jne .try_more ; Quit if the source IP is not valid, check for more sockets with this IP/PORT combination
 
 
141,10 → 115,10
 
mov bx, [edx + UDP_Packet.SourcePort] ; Remote port must be 0, or equal to sourceport of packet
 
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], 0
cmp [eax + SOCKET.RemotePort], 0
je .ok2
 
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx
cmp [eax + SOCKET.RemotePort], bx
jne .dump
 
.ok2:
156,21 → 130,10
sub cx , UDP_Packet.Data
mov dx , bx
 
call socket_internal_receiver
 
lea ebx, [eax + SOCKET_head.lock]
call wait_mutex
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], dx ; update remote port number
mov [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], edi
inc [UDP_PACKETS_RX]
 
pop edi
add esp, 4
 
sub esi, edi
xchg esi, edi
jmp socket_internal_receiver
 
 
.dump:
DEBUGF 1,"Dumping UDP packet\n"
call kernel_free
183,93 → 146,69
 
;-----------------------------------------------------------------
;
; UDP_socket_send
; Note: UDP works only on top of IP protocol :)
;
; IN: eax = socket pointer
; ecx = number of bytes to send
; esi = pointer to data
; IN: eax = dest ip
; ebx = source ip
; ecx = data length
; edx = remote port shl 16 + local port (both in INET order)
; esi = data offset
;
;-----------------------------------------------------------------
 
align 4
UDP_socket_send:
UDP_create_packet:
 
mov edx, dword [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort] ; load local port and remote port at once
DEBUGF 1,"local port: %x, remote port: %x\n",\
[eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort]:4,\
[eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort]:4
mov ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
 
DEBUGF 1,"Create UDP Packet (size=%u)\n",ecx
 
mov di , IP_PROTO_UDP
push edx esi
 
sub esp, 8 ; reserve some place in stack for later
 
; Create the pseudoheader in stack,
; (now that we still have all the variables that are needed.)
push dword IP_PROTO_UDP shl 8
push eax
push ebx
 
add ecx, UDP_Packet.Data
mov di , IP_PROTO_UDP
 
; TODO: fill in: dx = fragment id
; dx = fragment id
 
push edx esi
call IPv4_create_packet ; TODO: figure out a way to choose between IPv4 and IPv6
cmp edi, -1
je .fail
 
mov [esp + 8 + 12], eax ; pointer to buffer start
mov [esp + 8 + 12 + 4], edx ; buffer size
mov byte[edi + UDP_Packet.Length], ch
mov byte[edi + UDP_Packet.Length+1], cl
sub ecx , UDP_Packet.Data
 
rol cx, 8
mov [edi + UDP_Packet.Length], cx
mov [esp + 8 + 10], cx
ror cx, 8
 
pop esi
push edi ecx
sub ecx, UDP_Packet.Data
push edi
add edi, UDP_Packet.Data
push cx
shr ecx, 2
rep movsd
mov ecx, [esp]
pop cx
and cx , 3
rep movsb
pop ecx edi
pop edi
 
pop dword [edi + UDP_Packet.SourcePort] ; fill in both portnumbers
mov [edi + UDP_Packet.Checksum], 0 ; set it to zero, to calculate checksum
pop ecx
mov dword [edi + UDP_Packet.SourcePort], ecx ; notice: we write both port's at once
 
; Checksum for UDP header + data
xor edx, edx
mov esi, edi
call checksum_1
; Checksum for pseudoheader
mov ecx, 12
mov esi, esp
call checksum_1
add esp, 12 ; remove the pseudoheader from stack
; Now create the final checksum and store it in UDP header
call checksum_2
mov [edi + UDP_Packet.Checksum], dx
mov [edi + UDP_Packet.Checksum], 0
 
; TODO: calculate checksum using Pseudo-header (However, using a 0 as checksum shouldnt generate any errors :)
 
inc [UDP_PACKETS_TX]
 
push edx eax ; TODO: make this work on other protocols besides ethernet
DEBUGF 1,"Sending UDP Packet to device %x\n", ebx ;
jmp ETH_sender ;
jmp ETH_Sender ;
 
.exit:
ret
 
.fail:
; todo: queue the packet
add esp, 8+12+8
add esp, 8
ret
 
 
 
 
;---------------------------------------------------------------------------
;
; UDP_API
/kernel/branches/net/network/ARP.inc
221,7 → 221,7
mov ecx, 60 ; minimum packet size
mov edx, edi ;;;
mov di , ETHER_ARP
call ETH_create_packet
call ETH_create_Packet
cmp edi, -1
je .exit
 
248,7 → 248,7
DEBUGF 1,"ARP Packet for device %x created successfully\n", ebx
 
push edx ecx
jmp ETH_sender
jmp ETH_Sender
 
.exit:
add esp, 8
555,7 → 555,7
 
DEBUGF 1,"ARP_Handler - Sending reply \n"
 
jmp ETH_sender ; And send it!
jmp ETH_Sender ; And send it!
 
.exit:
call kernel_free
/kernel/branches/net/network/icmp.inc
133,8 → 133,8
;
; ICMP_Handler:
;
; this procedure will send reply's to ICMP echo's
; and insert packets into sockets when needed ;;; TODO: update this to work with fragmented packets too!
; Called by IP_handler,
; this procedure will send reply's to ICMP echo's etc ;;; TODO: update this to work with fragmented packets too!
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
181,31 → 181,33
mov dword [esi + ETH_FRAME.Data + IPv4_Packet.SourceAddress], ecx
 
; Recalculate ip header checksum
; mov esi, [esp]
add esi, ETH_FRAME.Data ; Point esi to start of IP Packet
movzx ecx, byte [esi + IPv4_Packet.VersionAndIHL] ; Calculate IP Header length by using IHL field
and ecx, 0x0000000F ;
shl cx , 2
push ebx edx ecx esi
xor edx, edx
call checksum_1
call checksum_2
pop esi
mov word [esi + IPv4_Packet.HeaderChecksum], dx ; Store it in the IP Packet header
movzx eax, byte [esi + IPv4_Packet.VersionAndIHL] ; Calculate IP Header length by using IHL field
and eax, 0x0000000F ;
shl eax, 2 ;
push ebx edx esi
stdcall checksum_jb, esi, eax ; calculate the checksum
pop esi edx ebx
xchg al, ah ; convert to intel byte order
; mov esi, [esp]
mov word [esi + IPv4_Packet.HeaderChecksum], ax ; Store it in the IP Packet header
 
; Recalculate ICMP CheckSum
movzx eax, word[esi + IPv4_Packet.TotalLength] ; Find length of IP Packet
; mov esi, [esp] ; Find length of IP Packet
movzx eax, word[esi + IPv4_Packet.TotalLength] ;
xchg ah , al ;
sub eax, [esp] ; Now we know the length of ICMP data in eax
mov ecx, eax
mov esi, [esp + 4]
xor edx, edx
call checksum_1
call checksum_2
mov ax , dx
pop ecx edx ebx
movzx edi, byte [esi + IPv4_Packet.VersionAndIHL] ; Calculate IP Header length by using IHL field
and edi, 0x0000000F ;
shl edi, 2 ;
sub ax , di ; Now we know the length of ICMP data in eax
push ebx edx
stdcall checksum_jb,edx,eax ; Calculate the checksum of icmp data
pop edx ebx
xchg al, ah ; Convert to intel byte order
mov word [edx + ICMP_Packet.Checksum], ax
 
jmp ETH_sender ; Send the reply
jmp ETH_Sender ; Send the reply
 
 
 
220,14 → 222,20
.try_more:
mov ax , [edx + ICMP_Packet.Identifier]
.next_socket:
mov esi, [esi + SOCKET_head.NextPtr]
mov esi, [esi + SOCKET.NextPtr]
or esi, esi
jz .dump
cmp [esi + SOCKET_head.Type], IP_PROTO_ICMP
cmp [esi + SOCKET.Type], IP_PROTO_ICMP
jne .next_socket
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + ICMP_SOCKET.Identifier], ax
cmp [esi + SOCKET.LocalPort], ax
jne .next_socket
 
cmp [esi + SOCKET.rxDataCount],0 ; get # of bytes already in buffer
jnz .dump ; only one packet at a time may be in the buffer!
 
cmp ecx, SOCKETBUFFSIZE - SOCKETHEADERSIZE; TODO: fix this problem !
jg .dump
 
call IPv4_dest_to_dev
cmp edi,-1
je .dump
235,25 → 243,60
 
DEBUGF 1,"Found valid ICMP packet for socket %x\n", esi
 
lea ebx, [esi + SOCKET_head.lock]
lea ebx, [esi + SOCKET.lock]
call wait_mutex
 
; Now, assign data to socket. We have socket address in esi.
; Now, copy data to socket. We have socket address in esi.
; We have ICMP Packet in edx
; number of bytes in ecx
 
mov eax, esi
; note: we do not strip the header!
 
DEBUGF 1,"bytes: %u\n", ecx
 
mov [esi + SOCKET.rxDataCount], ecx
 
lea edi, [esi + SOCKETHEADERSIZE]
push esi
push ecx
mov esi, edx
shr ecx, 2
rep movsd ; copy the data across
pop ecx
and ecx, 3
rep movsb
pop esi
add esp, 4
sub edx, esi
mov edi, edx
jmp socket_internal_receiver
 
DEBUGF 1,"ICMP socket updated\n"
 
mov [esi + SOCKET.lock], 0
 
; flag an event to the application
mov eax, [esi + SOCKET.PID] ; get socket owner PID
mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid
 
.next_pid:
cmp [esi], eax
je .found_pid
inc ecx
add esi, 0x20
cmp ecx, [TASK_COUNT]
jbe .next_pid
 
jmp .dump
 
.found_pid:
shl ecx, 8
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
 
mov [check_idle_semaphore], 200
 
.dump:
DEBUGF 1,"ICMP_Handler - dumping\n"
 
call kernel_free
add esp, 4 ; pop (balance stack)
add esp, 8 ; pop (balance stack)
 
ret
 
308,7 → 351,7
DEBUGF 1,"ICMP_Handler_fragments - end\n"
 
call kernel_free
add esp, 4 ; pop (balance stack)
add esp, 8 ; pop (balance stack)
ret
 
;-----------------------------------------------------------------
354,14 → 397,11
mov [edi + ICMP_Packet.Identifier], ax
mov [edi + ICMP_Packet.Checksum], 0
 
push eax ebx ecx edx
mov esi, edi
xor edx, edx
call checksum_1
call checksum_2
mov [edi + ICMP_Packet.Checksum], dx
pop edx ecx ebx eax esi
stdcall checksum_jb, edi , ecx
xchg al, ah
mov [edi + ICMP_Packet.Checksum], ax
 
pop esi
sub ecx, ICMP_Packet.Data
add edi, ICMP_Packet.Data
push cx
/kernel/branches/net/network/queue.inc
15,13 → 15,13
$Revision$
 
struct queue
.size dd ? ; number of queued packets in thsi queue
.w_ptr dd ? ; current writing pointer in queue
.r_ptr dd ? ; current reading pointer
.size dd ?
.w_ptr dd ?
.r_ptr dd ?
.data:
ends
 
struct eth_queue_entry
struct queue_entry
.owner dd ?
.data_ptr dd ?
.data_size dd ?
28,84 → 28,75
.size:
ends
 
struct tcp_in_queue_entry
.data_ptr dd ?
.data_size dd ?
.offset dd ?
.size:
ends
 
struct tcp_out_queue_entry
.data_ptr dd ?
.data_size dd ?
.ttl dd ?
.retries dd ?
.owner dd ?
.sendproc dd ?
.ack_num dd ?
.size:
ends
macro add_to_queue ptr, size, returnaddr {
 
struct socket_queue_entry
.data_ptr dd ?
.data_size dd ?
.offset dd ?
.size:
ends
cmp dword [ptr + queue.size], size ; Check if queue isnt full
jge .fail
 
macro add_to_queue ptr, size, entry_size, failaddr {
DEBUGF 1,"Queuing packet for device %x\n",ebx
 
cmp [ptr + queue.size], size ; Check if queue isnt full
jge failaddr
inc dword [ptr + queue.size]
 
inc [ptr + queue.size]
mov edi, dword [ptr + queue.w_ptr] ; Current write pointer (FIFO!)
 
mov edi, [ptr + queue.w_ptr] ; Current write pointer (FIFO!)
mov ecx, entry_size/4 ; Write the queue entry
rep movsd ;
mov eax, ebx
stosd
pop eax
stosd
pop eax
stosd
 
lea ecx, [size*entry_size+ptr+queue.data]
cmp edi, ecx ; entry size
cmp edi, size*queue_entry.size+ptr+queue.data ; entry size
jl .no_wrap
 
sub edi, size*entry_size
sub edi, size*queue_entry.size
 
.no_wrap:
mov [ptr + queue.w_ptr], edi
mov dword [ptr + queue.w_ptr], edi
jmp returnaddr
 
.fail:
DEBUGF 1,"queuing failed\n"
 
call kernel_free
add esp, 4
ret
 
}
 
 
macro get_from_queue ptr, size, returnaddr {
 
macro get_from_queue ptr, size, entry_size, failaddr {
.start_of_code:
cmp dword [ptr + queue.size], 0 ; any packets queued?
je returnaddr
 
cmp [ptr + queue.size], 0 ; any packets queued?
je failaddr
DEBUGF 1,"Dequeuing packet"
 
dec [ptr + queue.size]
dec dword [ptr + queue.size]
 
push dword .start_of_code ; return address for call's
 
mov esi, [ptr + queue.r_ptr]
push esi
lodsd
mov ebx, eax
lodsd
mov ecx, eax
lodsd
push eax
push ecx
xchg eax, ecx
 
add esi, entry_size
DEBUGF 1," for device %x\n", ebx
 
lea ecx, [size*entry_size+ptr+queue.data]
cmp esi, ecx ; entry size
cmp esi, size*queue_entry.size+ptr+queue.data ; entry size
jl .no_wrap
 
sub esi, size*entry_size
sub esi, size*queue_entry.size
 
.no_wrap:
mov dword [ptr + queue.r_ptr], esi
 
pop esi
 
}
 
macro init_queue queue_ptr {
 
mov [queue_ptr + queue.size] , 0
lea esi, [queue_ptr + queue.data]
mov [queue_ptr + queue.w_ptr], esi
mov [queue_ptr + queue.r_ptr], esi
}
/kernel/branches/net/network/stack.inc
33,7 → 33,7
ETHER_ARP equ 0x0608
 
;AF_UNSPEC equ 0
AF_UNIX equ 1
;AF_UNIX equ 1
AF_INET4 equ 2
;AF_AX25 equ 3
;AF_IPX equ 4
64,7 → 64,7
include "IPv4.inc"
include "ethernet.inc"
include "socket.inc"
include "tcp.inc"
;include "tcp.inc"
include "udp.inc"
include "icmp.inc"
 
86,7 → 86,6
call IPv4_init
call ARP_init
call UDP_init
call TCP_init
call ICMP_init
call socket_init
 
116,20 → 115,20
cmp [ETH_RUNNING], 0
je .exit
 
; Test for 10ms tick
call ETH_handler ; handle all queued ethernet packets
call ETH_send_queued
 
; Test for 10ms tick, call tcp timer
mov eax, [timer_ticks]
cmp eax, [last_1hsTick]
je .exit
 
mov [last_1hsTick], eax
; call tcp_tx_handler
 
call ETH_handler ; handle all queued ethernet packets
call ETH_send_queued
call TCP_send_queued
 
.sec_tick:
 
; Test for 1 second event
; Test for 1 second event, call 1s timer functions
mov al, 0x0 ;second
out 0x70, al
in al, 0x71
140,7 → 139,7
 
call ARP_decrease_entry_ttls
call IPv4_decrease_fragment_ttls
call TCP_decrease_socket_ttls
; call tcp_tcb_handler
 
.exit:
ret
147,77 → 146,41
 
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Checksum [by Johnny_B]
;; IN:
;; buf_ptr=POINTER to buffer
;; buf_size=SIZE of buffer
;; OUT:
;; AX=16-bit checksum
;; Saves all used registers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
proc checksum_jb stdcall uses ebx esi ecx,\
buf_ptr:DWORD, buf_size:DWORD
 
xor eax, eax
xor ebx, ebx ;accumulator
mov esi, dword[buf_ptr]
mov ecx, dword[buf_size]
shr ecx, 1 ; ecx=ecx/2
jnc @f ; if CF==0 then size is even number
mov bh, byte[esi + ecx*2]
@@:
cld
 
;-----------------------------------------------------------------
;
; checksum_1
;
; This is the first of two functions needed to calculate the TCP checksum.
;
; IN: edx = start offeset for semi-checksum
; esi = pointer to data
; ecx = data size
; OUT: edx = semi-checksum
;
;-----------------------------------------------------------------
 
align 4
checksum_1:
 
xor eax, eax
shr ecx, 1
pushf
.loop:
lodsw
xchg al, ah
add edx, eax
lodsw ;eax=word[esi],esi=esi+2
xchg ah,al ;cause must be a net byte-order
add ebx, eax
loop .loop
 
popf
jnc .end
 
lodsb
shl ax, 8
add edx, eax
 
.end:
 
ret
 
 
 
;-----------------------------------------------------------------
;
; checksum_2
;
; This function calculates the final ip/tcp/udp checksum for you
;
; IN: edx = semi-checksum
; OUT: dx = checksum (in INET byte order)
;
;-----------------------------------------------------------------
 
align 4
checksum_2:
 
mov ecx, edx
shr ecx, 16
and edx, 0xffff
add edx, ecx
mov eax, edx
mov eax, ebx
shr eax, 16
add edx, eax
add ax, bx
not ax
 
not dx
jnz .not_zero
dec dx
.not_zero:
xchg dl, dh
 
DEBUGF 1,"Checksum: %x\n",dx
 
ret
endp
 
 
 
287,15 → 250,7
jmp .return
 
@@:
dec bl ; 4 = Get driver pointer
jnz @f
 
; ..;
 
 
@@:
; ... ; 5 Get driver name
 
.doesnt_exist:
DEBUGF 1,"sys_network: invalid device/function specified!\n"
mov eax, -1
/kernel/branches/net/network/tcp.inc
18,6 → 18,7
$Revision$
 
 
; TCP TCB states
TCB_LISTEN equ 1
TCB_SYN_SENT equ 2
TCB_SYN_RECEIVED equ 3
30,21 → 31,20
TCB_TIMED_WAIT equ 10
TCB_CLOSED equ 11
 
TH_FIN equ 1 shl 0
TH_SYN equ 1 shl 1
TH_RST equ 1 shl 2
TH_PUSH equ 1 shl 3
TH_ACK equ 1 shl 4
TH_URG equ 1 shl 5
TH_FIN equ 0x01
TH_SYN equ 0x02
TH_RST equ 0x04
TH_PUSH equ 0x08
TH_ACK equ 0x10
TH_URG equ 0x20
 
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 1/100 s
TCP_TIMEOUT equ 10 ; resend if not replied to in x hs
 
TCP_QUEUE_SIZE equ 16
 
 
struct TCP_Packet
.SourcePort dw ?
.DestinationPort dw ?
65,55 → 65,14
TCP_PACKETS_TX rd MAX_IP
TCP_PACKETS_RX rd MAX_IP
 
TCP_IN_QUEUE rd (tcp_in_queue_entry.size*TCP_QUEUE_SIZE+queue.data)/4
TCP_OUT_QUEUE dd ?
rd (tcp_out_queue_entry.size*TCP_QUEUE_SIZE)/4
TCP_IN_QUEUE rd 3*TCP_QUEUE_SIZE+3
TCP_OUT_QUEUE rd 3*TCP_QUEUE_SIZE+3
endg
 
align 4
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
 
endg
 
 
macro inc_INET reg {
 
inc byte [reg + 0]
adc byte [reg + 1], 0
adc byte [reg + 2], 0
adc byte [reg + 3], 0
 
}
 
 
macro add_INET reg {
 
rol ecx, 16
adc byte [reg + 0], ch
adc byte [reg + 1], cl
rol ecx, 16
adc byte [reg + 2], ch
adc byte [reg + 3], cl
 
}
 
 
 
 
;-----------------------------------------------------------------
;
; TCP_init
133,55 → 92,58
mov ecx, 2*MAX_IP
rep stosd
 
init_queue TCP_IN_QUEUE
init_queue TCP_OUT_QUEUE
mov dword [TCP_IN_QUEUE], TCP_QUEUE_SIZE
mov dword [TCP_IN_QUEUE+4], TCP_IN_QUEUE + queue.data
mov dword [TCP_IN_QUEUE+8], TCP_IN_QUEUE + queue.data
 
mov dword [TCP_OUT_QUEUE], TCP_QUEUE_SIZE
mov dword [TCP_OUT_QUEUE+4], TCP_OUT_QUEUE + queue.data
mov dword [TCP_OUT_QUEUE+8], TCP_OUT_QUEUE + queue.data
 
ret
 
 
;-----------------------------------------------------------------
;
; TCP_decrease_socket_ttls
; tcp_tcb_handler
;
; IN: /
; OUT: /
; Handles sockets in the timewait state, closing them
; when the TCB timer expires
;
;-----------------------------------------------------------------
 
align 4
TCP_decrease_socket_ttls:
tcp_tcb_handler:
; scan through all the sockets, decrementing active timers
 
mov ebx, net_sockets
 
cmp [ebx + SOCKET_head.NextPtr], 0
cmp [ebx + SOCKET.NextPtr], 0
je .exit
DEBUGF 1, "K : sockets:\n"
 
.next_socket:
mov ebx, [ebx + SOCKET_head.NextPtr]
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .exit
 
cmp [ebx + SOCKET_head.Type], IP_PROTO_TCP
jne .next_socket
 
; DEBUGF 1, "K : %x-%x: %x-%x-%x-%u\n", [ebx + SOCKET.PID]:2, [ebx + SOCKET.Number]:2, [ebx + SOCKET.LocalPort]:4, [ebx + SOCKET.RemoteIP], [ebx + SOCKET.RemotePort]:4, [ebx + SOCKET.TCBState]
 
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer], 0
cmp [ebx + SOCKET.TCBTimer], 0
jne .decrement_tcb
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0
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
dec [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer]
dec [ebx + SOCKET.TCBTimer]
jnz .next_socket
 
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT
cmp [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
jne .next_socket
 
push [ebx + SOCKET_head.PrevPtr]
push [ebx + SOCKET.PrevPtr]
stdcall net_socket_free, ebx
pop ebx
jmp .next_socket
188,7 → 150,7
 
.decrement_wnd:
; TODO - prove it works!
dec [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer]
dec [ebx + SOCKET.wndsizeTimer]
jmp .next_socket
 
.exit:
195,124 → 157,120
ret
 
 
 
;-----------------------------------------------------------------
;***************************************************************************
; Function
; tcp_tx_handler
;
; TCP_send_queued:
; Description
; Handles queued TCP data
; This is a kernel function, called by stack_handler
;
; Decreases 'ttl' of tcp packets queued.
; if 'ttl' reaches 0, resend the packet and decrease 'retries'
; if 'retries' reaches zero, remove the queued packet
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
;***************************************************************************
 
align 4
TCP_send_queued:
tcp_tx_handler:
; 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
 
cmp [TCP_OUT_QUEUE], 0
je .exit
mov esi, resendQ
mov ecx, 0
 
mov eax, TCP_QUEUE_SIZE
mov ecx, [TCP_OUT_QUEUE]
mov esi, TCP_OUT_QUEUE+4
.next_resendq:
; cmp ecx, NUMRESENDENTRIES
je .exit ; None left
cmp dword[esi + 4], 0
jne @f ; found one
inc ecx
add esi, 8
jmp .next_resendq
 
.loop:
cmp [esi + tcp_out_queue_entry.data_ptr], 0
jnz .found_one
add esi, tcp_out_queue_entry.size
loop .loop
.exit:
ret
@@: ; 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
 
.found_one:
dec [esi + tcp_out_queue_entry.ttl]
jz .send_it
.find_next:
dec eax
jz .exit
jmp .loop
@@:
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
 
.send_it:
push eax ecx esi
; retries now 0, so delete from queue
xchg [esi + 4], ebx
 
push [esi + tcp_out_queue_entry.data_size]
push [esi + tcp_out_queue_entry.data_ptr]
mov ebx, [esi + tcp_out_queue_entry.owner]
@@: ; resend Packet
pushad
 
call [esi + tcp_out_queue_entry.sendproc]
; mov eax, EMPTY_QUEUE
; call dequeue
; cmp ax, NO_BUFFER
jne .tth004z
 
pop esi ecx eax
; TODO - try again in 10ms.
test ebx, ebx
jnz @f
mov [esi + 4], ebx
 
dec [esi + tcp_out_queue_entry.retries]
jz .remove_it
mov [esi + tcp_out_queue_entry.ttl], TCP_TIMEOUT
jmp .find_next
@@: ; Mark it to expire in 10ms - 1 tick
mov byte[esi + 1], 1
mov word[esi + 2], 1
jmp .tth005
 
.remove_it:
push [esi + tcp_out_queue_entry.data_ptr]
mov [esi + tcp_out_queue_entry.data_ptr], 0
dec [TCP_OUT_QUEUE]
call kernel_free
jmp .find_next
.tth004z:
; we have a buffer # in ax
; push eax 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 resend buffer location in esi
; mov ecx, IPBUFFSIZE
 
;-----------------------------------------------------------------
;
; TCP_add_to_queue:
;
; Queue a TCP packet for sending
;
; IN: [esp] pointer to buffer
; [esp + 4] size of buffer
; ebx = driver struct
; esi = sender proc
; edx = acknum
; OUT: /
;
;-----------------------------------------------------------------
; copy data across
push edi
cld
rep movsb
pop edi
 
align 4
TCP_add_to_queue:
; queue Packet
; mov eax, NET1OUT_QUEUE
; mov edx, [IP_LIST]
; cmp edx, [edi + IP_Packet.DestinationAddress]
; jne .not_local
; mov eax, IPIN_QUEUE
 
cmp [TCP_OUT_QUEUE], TCP_QUEUE_SIZE
jge .full
.not_local:
pop ebx
; call queue
 
mov ecx, TCP_QUEUE_SIZE
mov eax, TCP_OUT_QUEUE+4
.tth005:
popad
 
.loop:
cmp [eax + tcp_out_queue_entry.data_ptr], 0
je .found_it
add eax, tcp_out_queue_entry.size
loop .loop
inc ecx
add esi, 8
jmp .next_resendq
 
.full: ; silently discard the packet
call kernel_free
add esp, 4
 
.exit:
ret
 
.found_it: ; eax point to empty queue entry
 
pop [eax + tcp_out_queue_entry.data_ptr]
pop [eax + tcp_out_queue_entry.data_size]
mov [eax + tcp_out_queue_entry.ttl], 1 ; send immediately
mov [eax + tcp_out_queue_entry.retries], TCP_RETRIES
mov [eax + tcp_out_queue_entry.owner], ebx
mov [eax + tcp_out_queue_entry.sendproc], esi
mov [eax + tcp_out_queue_entry.ack_num], edx
 
 
ret
 
 
;-----------------------------------------------------------------
;
; TCP_handler:
; TCP_Handler:
;
; Called by IPv4_handler,
; this procedure will inject the tcp data diagrams in the application sockets.
327,104 → 285,136
;
;-----------------------------------------------------------------
 
align 4
TCP_handler :
TCP_Handler :
 
 
DEBUGF 1,"TCP_Handler\n"
 
jmp .exit ;;;;
 
; Look for a socket where
; IP Packet TCP Destination Port = local Port
; IP Packet SA = Remote IP OR = 0
; IP Packet TCP Source Port = remote Port OR = 0
; IP Packet SA = Remote IP
; IP Packet TCP Source Port = remote Port
 
mov ebx, net_sockets
 
.socket_loop:
mov ebx, [ebx + SOCKET_head.NextPtr]
.next_socket.1:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .dump
jz .next_socket.1.exit
 
mov ax, [edx + TCP_Packet.DestinationPort]
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax
jne .socket_loop
; DEBUGF 1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
 
mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
cmp eax, esi
je @f
test eax, eax
jne .socket_loop
@@:
mov ax, [edx + 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
 
mov ax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
cmp [edx + TCP_Packet.SourcePort] , ax
je .change_state
test ax, ax
jne .socket_loop
; DEBUGF 1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_Packet.SourceAddress], [ebx + SOCKET.RemoteIP]
 
.change_state:
mov eax, esi ;[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
 
push ebx
lea ebx, [ebx + SOCKET_head.lock]
call wait_mutex
pop ebx
; DEBUGF 1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_Packet.SourcePort]:4, [ebx + SOCKET.RemotePort]:4
 
;----------------------------------
; ebx is pointer to socket
; ecx is size of tcp packet
; edx is pointer to tcp packet
mov ax, [edx + 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
 
; as a Packet has been received, update the TCB timer
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer], TWOMSL
; We have a complete match - use this socket
jmp .change_state
 
; If the received Packet has an ACK bit set, remove any Packets in the resend queue that this received Packet acknowledges
test [edx + TCP_Packet.Flags], TH_ACK
jz .call_handler ; No ACK, so no data yet
.next_socket.1.exit:
 
mov eax, [edx + TCP_Packet.SequenceNumber] ; Calculate sequencenumber in eax
bswap eax ;
add eax, ecx ;
; 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
 
cmp [TCP_OUT_QUEUE], 0
je .call_handler
mov ebx, net_sockets
 
push ecx
mov ecx, TCP_QUEUE_SIZE
mov esi, TCP_OUT_QUEUE+4
.next_socket.2:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .next_socket.2.exit
 
.loop:
cmp [esi + tcp_out_queue_entry.data_ptr], 0
jne .maybe_next
cmp [esi + tcp_out_queue_entry.ack_num], eax
jg .maybe_next
; DEBUGF 1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
 
push [esi + tcp_out_queue_entry.data_ptr]
mov [esi + tcp_out_queue_entry.data_ptr], 0
dec [TCP_OUT_QUEUE]
call kernel_free
mov ax, [edx + 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
 
.maybe_next:
add esi, tcp_out_queue_entry.size
loop .loop
pop ecx
; DEBUGF 1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_Packet.SourceAddress], [ebx + SOCKET.RemoteIP]
 
.call_handler:
; Call handler for given TCB state
mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState]
cmp eax, TCB_LISTEN
jb .exit
cmp eax, TCB_CLOSED
ja .exit
; mov eax, esi ;[edx + IP_Packet.SourceAddress] ; get the source IP Addr from the IP hdr
cmp [ebx + SOCKET.RemoteIP], esi ; compare with socket's remote IP
jne .next_socket.2 ; different - try next socket
 
shl eax, 2
add eax, TCBStateHandler - 4
; DEBUGF 1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
 
push .exit
jmp eax
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 .change_state
 
.next_socket.2.exit:
 
; 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
 
mov ebx, net_sockets
 
.next_socket.3:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .next_socket.3.exit
 
; DEBUGF 1, "K : tcp_rx - 3.dport: %x - %x\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
 
mov ax, [edx + 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
 
; 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:
mov [ebx + SOCKET_head.lock], 0
 
.dump:
DEBUGF 1,"Dumping TCP packet\n"
call kernel_free
add esp, 4 ; pop (balance stack)
 
434,223 → 424,370
 
;-----------------------------------------------------------------
;
; TCP_socket_send
; IN: eax = dest ip
; ebx = source ip
; ecx = data length
; edx = remote port shl 16 + local port
; esi = data offset
;
; IN: eax = socket pointer
; ecx = number of bytes to send
; esi = pointer to data
;
;-----------------------------------------------------------------
 
align 4
TCP_socket_send:
TCP_create_Packet:
 
DEBUGF 1,"Creating TCP Packet\n"
DEBUGF 1,"Create TCP Packet\n"
;***************************************************************************
; Function
; buildTCPPacket
;
; Description
; builds an IP Packet with TCP data fully populated for transmission
; You may destroy any and all registers
; TCP control flags specified in bl
; This TCB is in [sktAddr]
; User data pointed to by esi
; Data length in ecx
; Transmit buffer number in eax
;
;***************************************************************************
 
mov di , IP_PROTO_TCP
push ecx ; Save data length
 
; Create an IPv4 Packet of the correct size
push eax
mov ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
add ecx, UDP_Packet.Data
mov di , IP_PROTO_UDP
 
; meanwhile, create the pseudoheader in stack,
; (now that we still have all the variables that are needed.)
push cx
push di
; dx = fragment id
 
call IPv4_create_Packet ; TODO: figure out a way to choose between IPv4 and IPv6
cmp edi, -1
je .exit
 
mov [edi + TCP_Packet.Flags], bl ; TCP flags
 
; mov ebx, [sockAddr];---------------------------------------------------------- eof
 
; 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 + SOCKET.LocalIP]
; mov [edx + IP_Packet.SourceAddress], eax
mov eax, [ebx + SOCKET.RemoteIP]
; mov [edx + IP_Packet.DestinationAddress], eax
 
; mov [edx + IP_Packet.VersionAndIHL], 0x45
; mov [edx + IP_Packet.TypeOfService], 0
 
pop eax ; Get the TCP data length
push eax
push ebx
 
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
 
push ecx esi eax ; save some variables for later
add ecx, TCP_Packet.Data
call IPv4_create_packet
cmp edi, -1
je .fail
; Checksum left unfilled
; mov [edx + IP_Packet.HeaderChecksum], 0
 
pop esi
; 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
 
; Now add the TCP header to the IPv4 packet
mov ax, [ebx + SOCKET.RemotePort]
mov [edx + 20 + TCP_Packet.DestinationPort], ax ; desitination Port
 
push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
pop [edi + TCP_Packet.SequenceNumber]
; Checksum left unfilled
mov [edx + 20 + TCP_Packet.Checksum], 0
 
push dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
pop dword [edi + TCP_Packet.SourcePort]
; sequence number
mov eax, [ebx + SOCKET.SND_NXT]
mov [edx + 20 + TCP_Packet.SequenceNumber], eax
 
; ack number
mov eax, [ebx + SOCKET.RCV_NXT]
mov [edx + 20 + TCP_Packet.AckNumber], eax
 
push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
pop [edi + TCP_Packet.AckNumber]
; window ( 0x2000 is default ).I could accept 4KB, fa0, ( skt buffer size)
; 768 bytes seems better
mov [edx + 20 + TCP_Packet.Window], 0x0003
 
mov al, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.flags]
mov [edi + TCP_Packet.Flags], al
; Urgent pointer (0)
mov [edx + 20 + TCP_Packet.UrgentPointer], 0
 
mov [edi + TCP_Packet.Window], 0x0005 ; 1280 bytes ;;; TODO: read RFC !
mov [edi + TCP_Packet.UrgentPointer], 0
mov [edi + TCP_Packet.DataOffset], 0x50
mov [edi + TCP_Packet.Checksum], 0
; data offset ( 0x50 )
mov [edx + 20 + TCP_Packet.DataOffset], 0x50
 
; Copy the data
mov esi, [esp]
mov ecx, [esp+4]
add edi, TCP_Packet.Data
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
 
shr ecx, 1
jnc .nb
movsb
.nb: shr ecx, 1
jnc .nw
movsw
.nw: rep movsd
cmp ebx, 0
jz @f
 
; Now, calculate the checksum for pseudoheader
xor edx, edx
mov ecx, 12
mov esi, esp
call checksum_1
add esp, 12 ; remove the pseudoheader from stack
; And that of the data
pop esi
pop ecx
call checksum_1
; Now create the final checksum and store it in TCP header
call checksum_2
mov [edi + TCP_Packet.Checksum], dx
mov edi, edx
add edi, 40
cld
rep movsb ; copy the data across
 
; And now, send it!
DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
mov esi, ETH_sender
mov edx, [edi + TCP_Packet.AckNumber]
jmp TCP_add_to_queue
@@: ; 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
;
; 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
;
; call checksum
 
.fail:
add esp, 12+4
; 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
; movzx eax, byte [edx + IP_Packet.VersionAndIHL] ; Calculate Header length by using IHL field
; and eax, 0x0000000F ;
; shl eax, 2 ;
;
stdcall checksum_jb, edx, eax ; buf_ptr, buf_size
rol ax, 8
; mov [edx + IP_Packet.HeaderChecksum], ax
 
 
.exit:
 
call kernel_free
add esp, 4 ; pop (balance stack)
 
ret
;endp
 
 
; Increments the 32 bit value pointed to by esi in internet order
proc inc_inet_esi stdcall
; push eax
; mov eax, [esi]
; bswap eax
; inc eax
; bswap eax
; mov [esi], eax
; pop eax
; ret
inc byte[esi+0]
adc byte[esi+1],0
adc byte[esi+2],0
adc byte[esi+3],0
endp
 
 
; Increments the 32 bit value pointed to by esi in internet order
; by the value in ecx
proc add_inet_esi stdcall
push eax
mov eax, [esi]
bswap eax
add eax, ecx
bswap eax
mov [esi], eax
pop eax
ret
endp
 
;-----------------------------------------------------------------
 
iglobal
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
;
; TCP_send_ack
; Description
; TCP state machine
; This is a kernel function, called by tcp_rx
;
; IN: eax = socket pointer
; bl = flags
; IP buffer address given in edx
; Socket/TCB address in ebx
;
;-----------------------------------------------------------------
; The IP buffer will be released by the caller
;***************************************************************************
 
align 4
TCP_send_ack:
proc tcpStateMachine stdcall, sockAddr:DWORD
; as a Packet has been received, update the TCB timer
mov [ebx + SOCKET.TCBTimer], TWOMSL
 
DEBUGF 1,"Creating TCP ACK\n"
; 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
 
mov di , IP_PROTO_TCP
mov cx , TCP_Packet.Data
; get skt number in eax
stdcall net_socket_addr_to_num, ebx
 
push bx eax
; The ack number is in [edx + 28], inet format
; skt in eax
 
; Create an IPv4 Packet of the correct size
mov ebx, [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
mov eax, [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
mov esi, resendQ
xor ecx, ecx
 
call IPv4_create_packet
cmp edi, -1
je .fail
.next_resendq:
; cmp ecx, NUMRESENDENTRIES
je .call_handler ; None left
cmp [esi + 4], eax
je @f ; found one
inc ecx
add esi, 8
jmp .next_resendq
 
; Fill in the TCP header
pop esi
@@: ; Can we delete this buffer?
 
push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
pop [edi + TCP_Packet.SequenceNumber]
; If yes, goto @@. No, goto .next_resendq
; Get Packet data address
 
push dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
pop dword [edi + TCP_Packet.SourcePort]
push ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
; imul edi, ecx, IPBUFFSIZE
; add edi, resendBuffer
 
push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
pop [edi + TCP_Packet.AckNumber]
; 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
 
pop cx
mov [edi + TCP_Packet.Flags], cl
mov [edi + TCP_Packet.Window], 0x0005 ; 1280 bytes
mov [edi + TCP_Packet.UrgentPointer], 0
mov [edi + TCP_Packet.DataOffset], 0x50
; get recievd ack #, in intel format
mov ebx, [edx + 20 + TCP_Packet.AckNumber]
bswap ebx
 
push eax edx
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
 
push word TCP_Packet.Data shl 8
push IP_PROTO_TCP
push [esi + SOCKET_head.end + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
push [esi + SOCKET_head.end + SOCKET_head.end + IPv4_SOCKET.LocalIP]
inc ecx
add esi, 8
jmp .next_resendq
 
; Now, calculate the checksum for pseudoheader
xor edx, edx
mov ecx, 12
mov esi, esp
call checksum_1
add esp, 12 ; remove the pseudoheader from stack
; Now create the final checksum and store it in TCP header
call checksum_2
mov [edi + TCP_Packet.Checksum], dx
@@: mov dword[esi + 4], 0
inc ecx
add esi, 8
jmp .next_resendq
 
; And now, send it!
DEBUGF 1,"Sending TCP Packet to device %x\n", ebx
mov esi, ETH_sender
mov edx, [edi + TCP_Packet.AckNumber]
jmp TCP_add_to_queue
.call_handler:
popad
 
.fail:
add esp, 12+4
ret
; Call handler for given TCB state
 
mov eax, [ebx + SOCKET.TCBState]
cmp eax, TCB_LISTEN
jb .exit
cmp eax, TCB_CLOSED
ja .exit
 
stdcall [TCBStateHandler + (eax - 1) * 4], [sockAddr]
 
.exit:
ret
endp
 
 
align 4
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
test [edx + TCP_Packet.Flags], TH_SYN
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 + SOCKET_head.end + IPv4_SOCKET.RemoteIP], esi ; IP source address
mov ax, [edx + TCP_Packet.SourcePort]
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], ax
mov eax, [edx + TCP_Packet.SequenceNumber]
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.IRS], eax
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax
lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
inc_INET esi ; RCV.NXT
mov eax, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS]
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], eax
; 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
 
; Now construct the response
push eax
mov bl, TH_SYN + TH_ACK
call TCP_send_ack
xor ecx, ecx
xor esi, esi
; stdcall build_tcp_Packet, [sockAddr]
 
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_SYN_RECEIVED
; mov eax, NET1OUT_QUEUE
;;; mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
; mov eax, IPIN_QUEUE
 
.not_local:
; Send it.
pop ebx
;;; call queue
 
mov esi, [sockAddr]
mov [esi + SOCKET.TCBState], TCB_SYN_RECEIVED
 
; increment SND.NXT in socket
lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
inc_INET esi
add esi, SOCKET.SND_NXT
call inc_inet_esi
 
.exit:
ret
endp
 
 
align 4
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 al, [edx + TCP_Packet.Flags]
mov al, [edx + 20 + TCP_Packet.Flags]
and al, TH_SYN + TH_ACK
cmp al, TH_SYN + TH_ACK
je .syn_ack
658,89 → 795,139
test al, TH_SYN
jz .exit
 
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_SYN_RECEIVED
mov [ebx + SOCKET.TCBState], TCB_SYN_RECEIVED
push TH_SYN + TH_ACK
jmp .send
 
.syn_ack:
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_ESTABLISHED
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED
push TH_ACK
 
.send:
; Store the recv.nxt field
mov eax, [edx + TCP_Packet.SequenceNumber]
mov eax, [edx + 20 + TCP_Packet.SequenceNumber]
 
; Update our recv.nxt field
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT], eax
lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
inc_INET esi
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
call TCP_send_ack
je .exit
 
push eax
 
xor ecx, ecx
xor esi, esi
; stdcall build_tcp_Packet, [sockAddr]
 
; mov eax, NET1OUT_QUEUE
;;; mov edx, [stack_ip]
; mov ecx, [sockAddr]
; cmp edx, [ecx + SOCKET.RemoteIP]
; jne .not_local
; mov eax, IPIN_QUEUE
 
.not_local:
; Send it.
pop ebx
;;; call queue
 
.exit:
ret
endp
 
 
 
align 4
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 + TCP_Packet.Flags], TH_RST
test [edx + 20 + TCP_Packet.Flags], TH_RST
jz .check_ack
 
push [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemotePort]
pop [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort]
push [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.OrigRemoteIP]
pop [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
push [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP]
pop [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort]
 
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_LISTEN
mov [ebx + SOCKET.TCBState], TCB_LISTEN
jmp .exit
 
.check_ack:
; Look at control flags - expecting an ACK
test [edx + TCP_Packet.Flags], TH_ACK
test [edx + 20 + TCP_Packet.Flags], TH_ACK
jz .exit
 
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_ESTABLISHED
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED
 
.exit:
ret
endp
 
 
 
align 4
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?
test [edx + TCP_Packet.Flags], TH_FIN
test [edx + 20 + TCP_Packet.Flags], TH_FIN
jz .check_ack
 
; It was a fin or reset.
 
; Remove resend entries from the queue - I dont want to send any more data
; Send an ACK to that fin, and enter closewait state
pushad
 
; get skt #
stdcall net_socket_addr_to_num, ebx
 
mov esi, resendQ
mov ecx, 0
 
.next_resendq:
; cmp ecx, NUMRESENDENTRIES
; je .last_resendq ; None left
; cmp [esi + 4], eax
; je @f ; found one
; inc ecx
; add esi, 8
; jmp .next_resendq
 
@@: mov dword[esi + 4], 0
inc ecx
add esi, 8
jmp .next_resendq
 
.last_resendq:
popad
 
@@: ; Send an ACK to that fin, and enter closewait state
 
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
 
.check_ack:
; Check that we received an ACK
test [edx + TCP_Packet.Flags], TH_ACK
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.
; ** I may need to tweak this value, since I do not know how many Packets are already queued
mov cx, [edx + TCP_Packet.Window]
mov cx, [edx + 20 + TCP_Packet.Window]
xchg cl, ch
cmp cx, 1024
ja @f
 
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
mov [ebx + SOCKET.wndsizeTimer], 1
 
@@: ; OK, here is the deal
; My recv.nct field holds the seq of the expected next rec byte
751,41 → 938,117
; 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_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_CLOSE_WAIT
mov ecx, [ebx + SOCKET.RCV_NXT]
cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
jne @f
mov ecx, eax
 
@@: cmp ecx, [edx + TCP_Packet.SequenceNumber]
@@: cmp ecx, [edx + 20 + TCP_Packet.SequenceNumber]
jne .ack
 
test ecx, ecx
jnz .data
 
; 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
ja .data ; Read data, if any
 
; If we had received a fin, we need to ACK it.
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_CLOSE_WAIT
cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
je .ack
jmp .exit
 
.data:
mov esi, [esp + 4]
sub edx, esi
mov edi, edx
call socket_internal_receiver
push ebx
add ebx, SOCKET.lock
call wait_mutex
pop ebx
 
push ecx
push [ebx + SOCKET.PID] ; get socket owner PID
mov eax, [ebx + SOCKET.rxDataCount]
add eax, ecx
cmp eax, SOCKETBUFFSIZE - SOCKETHEADERSIZE
ja .overflow
 
mov [ebx + SOCKET.rxDataCount], eax ; increment the count of bytes in buffer
 
; point to the location to store the data
lea edi, [ebx + eax + SOCKETHEADERSIZE]
sub edi, ecx
 
add edx, 40 ; edx now points to the data
mov esi, edx
 
cld
rep movsb ; copy the data across
mov [ebx + SOCKET.lock], 0 ; release mutex
 
; flag an event to the application
pop eax
mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid
 
.next_pid:
cmp [esi], eax
je .found_pid
inc ecx
add esi, 0x20
cmp ecx, [TASK_COUNT]
jbe .next_pid
 
.found_pid:
shl ecx, 8
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event
 
pop ecx
 
; Update our recv.nxt field
lea esi, [ebx + SOCKET.RCV_NXT]
call add_inet_esi
 
.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
 
push eax
 
mov bl, TH_ACK
call TCP_send_ack
xor ecx, ecx
xor esi, esi
; stdcall build_tcp_Packet, [sockAddr]
 
; mov eax, NET1OUT_QUEUE
 
;;; mov edx, [stack_ip]
; mov ecx, [sockAddr]
; cmp edx, [ecx + SOCKET.RemoteIP]
; jne .not_local
; mov eax, IPIN_QUEUE
 
.not_local:
; Send it.
pop ebx
;;; call queue
 
.exit:
ret
.overflow:
; no place in buffer
; so simply restore stack and exit
pop eax ecx
mov [ebx + SOCKET.lock], 0
ret
endp
 
 
 
align 4
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 al, [edx + TCP_Packet.Flags]
mov al, [edx + 20 + TCP_Packet.Flags]
and al, TH_FIN + TH_ACK
 
cmp al, TH_ACK
792,69 → 1055,109
jne @f
 
; It was an ACK
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_FIN_WAIT_2
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2
jmp .exit
 
@@: mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_CLOSING
@@: mov [ebx + SOCKET.TCBState], TCB_CLOSING
cmp al, TH_FIN
je @f
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
 
@@: lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
inc_INET esi
@@: lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi
 
; Send an ACK
; mov eax, EMPTY_QUEUE
; call dequeue
; cmp ax, NO_BUFFER
je .exit
 
push eax
 
mov bl, TH_ACK
call TCP_send_ack
xor ecx, ecx
xor esi, esi
; stdcall build_tcp_Packet, [sockAddr]
 
; mov eax, NET1OUT_QUEUE
;;; mov edx, [stack_ip]
; mov ecx, [sockAddr]
; cmp edx, [ecx + SOCKET.RemoteIP]
; jne .not_local
; mov eax, IPIN_QUEUE
 
.not_local:
; Send it.
pop ebx
;;; call queue
 
.exit:
ret
endp
 
 
 
align 4
stateTCB_FIN_WAIT_2:
test [edx + TCP_Packet.Flags], TH_FIN
proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD
test [edx + 20 + TCP_Packet.Flags], TH_FIN
jz .exit
 
; Change state, as we have a fin
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
 
lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
inc_INET esi
lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi
 
; Send an ACK
; mov eax, EMPTY_QUEUE
; call dequeue
;; cmp ax, NO_BUFFER
; je .exit
 
push eax
 
mov bl, TH_ACK
call TCP_send_ack
xor ecx, ecx
xor esi, esi
; stdcall build_tcp_Packet, [sockAddr]
 
; mov eax, NET1OUT_QUEUE
;;; mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
; mov eax, IPIN_QUEUE
 
.not_local:
; Send it.
pop ebx
;;; call queue
 
.exit:
ret
endp
 
 
 
align 4
stateTCB_CLOSE_WAIT:
proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD
; Intentionally left empty
; socket_close_tcp handles this
ret
endp
 
 
 
align 4
stateTCB_CLOSING:
proc stateTCB_CLOSING stdcall, sockAddr:DWORD
; We can either receive an ACK of a fin, or a fin
test [edx + TCP_Packet.Flags], TH_ACK
test [edx + 20 + TCP_Packet.Flags], TH_ACK
jz .exit
 
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
 
.exit:
ret
endp
 
 
align 4
stateTCB_LAST_ACK:
proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD
; Look at control flags - expecting an ACK
test [edx + TCP_Packet.Flags], TH_ACK
test [edx + 20 + TCP_Packet.Flags], TH_ACK
jz .exit
 
; delete the socket
862,17 → 1165,235
 
.exit:
ret
endp
 
 
align 4
stateTCB_TIME_WAIT:
proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD
ret
endp
 
 
align 4
stateTCB_CLOSED:
proc stateTCB_CLOSED stdcall, sockAddr:DWORD
ret
endp
 
 
 
;; [53.7] Send data through STREAM socket
;
; @param EBX is socket number
; @param ECX is application data size (number of bytes to send)
; @param EDX is pointer to application data buffer
; @return 0 (sent successfully) or -1 (error) in EAX
;;
;proc socket_write_tcp stdcall
;local sockAddr dd ?
 
; DEBUGF 1, "socket_write_tcp(0x%x)\n", ebx
stdcall net_socket_num_to_addr, ebx
or eax, eax
jz .error
 
mov ebx, eax
; mov [sockAddr], ebx
 
; If the sockets window timer is nonzero, do not queue Packet
cmp [ebx + SOCKET.wndsizeTimer], 0
jne .error
 
; mov eax, EMPTY_QUEUE
; call dequeue
; cmp ax, NO_BUFFER
; je .error
 
push eax
 
; 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
 
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
 
pop ebx
push ecx
 
; mov eax, NET1OUT_QUEUE
;;; TODO: get device id in edx
xor edx, edx
 
shl edx, 2
mov edx, [IP_LIST+edx]
; mov ecx, [sockAddr]
; cmp edx, [ecx + SOCKET.RemoteIP]
; jne .not_local
; mov eax, IPIN_QUEUE
 
.not_local:
pop ecx
push ebx ; save ipbuffer number
 
;;;; call queue
 
; mov esi, [sockAddr]
 
; increament SND.NXT in socket
; Amount to increment by is in ecx
add esi, SOCKET.SND_NXT
call add_inet_esi
 
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
 
.next_resendq:
; cmp ecx, NUMRESENDENTRIES
je .exit ; None found
cmp dword[esi + 4], 0
je @f ; found one
inc ecx
add esi, 8
jmp .next_resendq
 
@@: 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
 
; stdcall net_socket_addr_to_num, [sockAddr]
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
 
; @@: 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
 
; do copy
; mov ecx, IPBUFFSIZE
; cld
rep movsb
 
.exit:
xor eax, eax
ret
 
.error:
or eax, -1
ret
;endp
 
 
 
;***************************************************************************
; Function
; checksum
;
; Description
; checkAdd1,checkAdd2, checkSize1, checkSize2, checkResult
; Dont break anything; Most registers are used by the caller
; This code is derived from the 'C' source, cksum.c, in the book
; Internetworking with TCP/IP Volume II by D.E. Comer
;
;***************************************************************************
 
 
checksum:
pusha
; mov eax, [checkAdd1]
xor edx, edx ; edx is the accumulative checksum
xor ebx, ebx
; mov cx, [checkSize1]
shr cx, 1
jz cs1_1
 
cs1:
mov bh, [eax]
mov bl, [eax + 1]
 
add eax, 2
add edx, ebx
 
loopw cs1
 
cs1_1:
; and word [checkSize1], 0x01
jz cs_test2
 
mov bh, [eax]
xor bl, bl
 
add edx, ebx
 
cs_test2:
; mov cx, [checkSize2]
cmp cx, 0
jz cs_exit ; Finished if no 2nd buffer
 
; mov eax, [checkAdd2]
 
shr cx, 1
jz cs2_1
 
cs2:
mov bh, [eax]
mov bl, [eax + 1]
 
add eax, 2
add edx, ebx
 
loopw cs2
 
cs2_1:
; and word [checkSize2], 0x01
jz cs_exit
 
mov bh, [eax]
xor bl, bl
 
add edx, ebx
 
cs_exit:
mov ebx, edx
 
shr ebx, 16
and edx, 0xffff
add edx, ebx
mov eax, edx
shr eax, 16
add edx, eax
not dx
 
; mov [checkResult], dx
popa
ret
 
/kernel/branches/net/kernel.asm
56,13 → 56,13
 
include 'macros.inc'
 
$Revision$
$Revision: 1025 $
 
 
USE_COM_IRQ equ 1 ; make irq 3 and irq 4 available for PCI devices
 
; Enabling the next line will enable serial output console
debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used
;debug_com_base equ 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used
 
include "proc32.inc"
include "kglobals.inc"