Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1248 → Rev 1249

/kernel/branches/net/kernel.asm
56,13 → 56,13
 
include 'macros.inc'
 
$Revision: 1025 $
$Revision$
 
 
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"
/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/IPv4.inc
3,7 → 3,7
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; IP.INC ;;
;; IPv4.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
rb 2 ; to match ethernet header size ; TODO: fix this hack
.Data: ; Ip header begins here (we will need the IP header to re-construct the complete packet)
ends
 
99,10 → 99,9
 
;-----------------------------------------------------------------
;
; IP_Handler:
; IPv4_Handler:
;
; Called by eth_handler,
; will check if IP Packet isnt damaged
; Will check if IP Packet isnt damaged
; and call appropriate handler. (TCP/UDP/ICMP/..)
;
; It will also re-construct fragmented packets
119,21 → 118,28
IPv4_handler:
 
DEBUGF 1,"IP_Handler - start\n"
mov cx , [edx + IPv4_Packet.HeaderChecksum]
xchg ch , cl ; Get the checksum in intel format
mov word [edx + IPv4_Packet.HeaderChecksum], 0 ; Clear checksum field to recalculating checksum
push edx ebx
 
movzx eax, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field
and eax, 0x0000000F ;
shl eax, 2 ;
; 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
 
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
; 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
 
; 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
183,10 → 189,14
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
385,14 → 395,21
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
493,12 → 510,12
; dx = fragment id
; di = protocol
;
; OUT: eax points to buffer start
; ebx is size of complete buffer
; edi = pointer to start of data (-1 on error)
; OUT: eax = pointer to buffer start
; ebx = pointer to device struct (needed for sending procedure)
; ecx = unchanged (packet size of embedded data)
; edx = pointer to device struct (needed for sending procedure)
; edx = size of complete buffer
; esi = pointer to sending procedure
; edi = pointer to start of data (-1 on error)
;
;-----------------------------------------------------------------
 
550,7 → 567,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
571,14 → 588,18
pop ecx
mov [edi + IPv4_Packet.DestinationAddress], 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
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
add edi, IPv4_Packet.DataOrOptional
 
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", edx
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", ebx
 
ret
 
585,7 → 606,7
 
.not_found:
DEBUGF 1,"Create IPv4 Packet - ARP entry not found!\n"
; TODO: QUEUE!
; TODO: QUEUE the packet to resend later!
.exit:
add esp, 16
.exit_:
/kernel/branches/net/network/ethernet.inc
80,14 → 80,9
mov ecx, (1+MAX_ETH_DEVICES)
rep stosd
 
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
init_queue ETH_IN_QUEUE
init_queue ETH_OUT_QUEUE
 
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
 
 
104,7 → 99,7
;---------------------------------------------------------
 
align 4
ETH_Add_Device:
ETH_add_device:
 
DEBUGF 1,"ETH_Add_Device: %x ", ebx
 
122,7 → 117,6
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
 
167,7 → 161,7
;--------------------------------
 
align 4
ETH_Remove_Device:
ETH_remove_device:
 
cmp [ETH_RUNNING], 0
je .error
212,12 → 206,21
;-------------------------------------------------------------
 
align 4
ETH_Receiver:
DEBUGF 1,"ETH_Receiver \n"
ETH_receiver:
DEBUGF 1,"ETH_Receiver: "
 
add_to_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, .gohome
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
 
.gohome:
.fail:
DEBUGF 1,"ETH_IN_QUEUE is full!\n"
add esp, 4
call kernel_free
add esp, 4
ret
 
 
238,8 → 241,19
align 4
ETH_handler:
 
get_from_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, .gohome
get_from_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.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
262,13 → 276,13
add esp, 4
 
.gohome:
ret ; return 1. to get more from queue / 2. to caller
ret ; return to get more from queue / to caller
 
 
 
;-----------------------------------------------------------------
;
; ETH_Sender:
; ETH_sender:
;
; This function sends an ethernet packet to the correct driver.
;
280,35 → 294,66
;-----------------------------------------------------------------
 
align 4
ETH_Sender:
DEBUGF 1,"ETH_Sender \n"
ETH_sender:
DEBUGF 1,"ETH_Sender: queuing for device: %x, %u bytes\n", [esp], [esp + 4]
 
add_to_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, .gohome
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
 
.gohome:
.fail:
DEBUGF 1,"ETH_OUT_QUEUE is full!\n"
add esp, 4
call kernel_free
add esp, 4
ret
 
 
 
;-----------------------------------------------------------------
;
; ETH_send_queued:
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
 
align 4
ETH_send_queued:
 
get_from_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, .gohome
get_from_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, eth_queue_entry.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
 
DEBUGF 1,"ETH_Sender - device: %u\n", edi
jmp [ebx+ETH_DEVICE.transmit] ; we will return to get_from_queue macro after transmitting packet
 
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
362,7 → 407,7
;---------------------------------------------------------------------------
 
align 4
ETH_create_Packet:
ETH_create_packet:
 
DEBUGF 1,"Creating Ethernet Packet (size=%u): \n", ecx
 
394,7 → 439,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/icmp.inc
133,8 → 133,8
;
; ICMP_Handler:
;
; Called by IP_handler,
; this procedure will send reply's to ICMP echo's etc ;;; TODO: update this to work with fragmented packets too!
; 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!
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
181,33 → 181,31
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 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
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
 
; Recalculate ICMP CheckSum
; mov esi, [esp] ; Find length of IP Packet
movzx eax, word[esi + IPv4_Packet.TotalLength] ;
movzx eax, word[esi + IPv4_Packet.TotalLength] ; Find length of IP Packet
xchg ah , al ;
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
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
mov word [edx + ICMP_Packet.Checksum], ax
 
jmp ETH_Sender ; Send the reply
jmp ETH_sender ; Send the reply
 
 
 
222,20 → 220,14
.try_more:
mov ax , [edx + ICMP_Packet.Identifier]
.next_socket:
mov esi, [esi + SOCKET.NextPtr]
mov esi, [esi + SOCKET_head.NextPtr]
or esi, esi
jz .dump
cmp [esi + SOCKET.Type], IP_PROTO_ICMP
cmp [esi + SOCKET_head.Type], IP_PROTO_ICMP
jne .next_socket
cmp [esi + SOCKET.LocalPort], ax
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + ICMP_SOCKET.Identifier], 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
243,60 → 235,25
 
DEBUGF 1,"Found valid ICMP packet for socket %x\n", esi
 
lea ebx, [esi + SOCKET.lock]
lea ebx, [esi + SOCKET_head.lock]
call wait_mutex
 
; Now, copy data to socket. We have socket address in esi.
; Now, assign data to socket. We have socket address in esi.
; We have ICMP Packet in edx
; number of bytes in ecx
 
; 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
mov eax, esi
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, 8 ; pop (balance stack)
add esp, 4 ; pop (balance stack)
 
ret
 
351,7 → 308,7
DEBUGF 1,"ICMP_Handler_fragments - end\n"
 
call kernel_free
add esp, 8 ; pop (balance stack)
add esp, 4 ; pop (balance stack)
ret
 
;-----------------------------------------------------------------
397,11 → 354,14
mov [edi + ICMP_Packet.Identifier], ax
mov [edi + ICMP_Packet.Checksum], 0
 
stdcall checksum_jb, edi , ecx
xchg al, ah
mov [edi + ICMP_Packet.Checksum], ax
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
 
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 ?
.w_ptr dd ?
.r_ptr dd ?
.size dd ? ; number of queued packets in thsi queue
.w_ptr dd ? ; current writing pointer in queue
.r_ptr dd ? ; current reading pointer
.data:
ends
 
struct queue_entry
struct eth_queue_entry
.owner dd ?
.data_ptr dd ?
.data_size dd ?
28,75 → 28,84
.size:
ends
 
struct tcp_in_queue_entry
.data_ptr dd ?
.data_size dd ?
.offset dd ?
.size:
ends
 
macro add_to_queue ptr, size, returnaddr {
struct tcp_out_queue_entry
.data_ptr dd ?
.data_size dd ?
.ttl dd ?
.retries dd ?
.owner dd ?
.sendproc dd ?
.ack_num dd ?
.size:
ends
 
cmp dword [ptr + queue.size], size ; Check if queue isnt full
jge .fail
struct socket_queue_entry
.data_ptr dd ?
.data_size dd ?
.offset dd ?
.size:
ends
 
DEBUGF 1,"Queuing packet for device %x\n",ebx
macro add_to_queue ptr, size, entry_size, failaddr {
 
inc dword [ptr + queue.size]
cmp [ptr + queue.size], size ; Check if queue isnt full
jge failaddr
 
mov edi, dword [ptr + queue.w_ptr] ; Current write pointer (FIFO!)
inc [ptr + queue.size]
 
mov eax, ebx
stosd
pop eax
stosd
pop eax
stosd
mov edi, [ptr + queue.w_ptr] ; Current write pointer (FIFO!)
mov ecx, entry_size/4 ; Write the queue entry
rep movsd ;
 
cmp edi, size*queue_entry.size+ptr+queue.data ; entry size
lea ecx, [size*entry_size+ptr+queue.data]
cmp edi, ecx ; entry size
jl .no_wrap
 
sub edi, size*queue_entry.size
sub edi, size*entry_size
 
.no_wrap:
mov dword [ptr + queue.w_ptr], edi
jmp returnaddr
mov [ptr + queue.w_ptr], edi
 
.fail:
DEBUGF 1,"queuing failed\n"
 
call kernel_free
add esp, 4
ret
 
}
 
 
macro get_from_queue ptr, size, returnaddr {
 
.start_of_code:
cmp dword [ptr + queue.size], 0 ; any packets queued?
je returnaddr
macro get_from_queue ptr, size, entry_size, failaddr {
 
DEBUGF 1,"Dequeuing packet"
cmp [ptr + queue.size], 0 ; any packets queued?
je failaddr
 
dec dword [ptr + queue.size]
dec [ptr + queue.size]
 
push dword .start_of_code ; return address for call's
 
mov esi, [ptr + queue.r_ptr]
lodsd
mov ebx, eax
lodsd
mov ecx, eax
lodsd
push eax
push ecx
xchg eax, ecx
push esi
 
DEBUGF 1," for device %x\n", ebx
add esi, entry_size
 
cmp esi, size*queue_entry.size+ptr+queue.data ; entry size
lea ecx, [size*entry_size+ptr+queue.data]
cmp esi, ecx ; entry size
jl .no_wrap
 
sub esi, size*queue_entry.size
sub esi, size*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/socket.inc
5,7 → 5,6
;; ;;
;; SOCKET.INC ;;
;; ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; based on code by mike.dld ;;
;; ;;
16,8 → 15,7
 
$Revision$
 
align 4
struct SOCKET
struct SOCKET_head
.PrevPtr dd ? ; pointer to previous socket in list
.NextPtr dd ? ; pointer to next socket in list
.Number dd ? ; socket number (unique within single process)
25,19 → 23,34
.Domain dd ? ; INET/UNIX/..
.Type dd ? ; RAW/UDP/TCP/...
.Protocol dd ? ; ICMP/IPv4/ARP/
.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
.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
.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 ? ; bext send sequence number to use
.SND_NXT dd ? ; next send sequence number to use
.SND_WND dd ? ; send window
.RCV_NXT dd ? ; next receive sequence number to use
.RCV_WND dd ? ; receive window
44,17 → 57,40
.SEG_LEN dd ? ; segment length
.SEG_WND dd ? ; segment window
.wndsizeTimer dd ? ; window size timer
.lock dd ? ; lock mutex
.backlog dw ? ; Backlog
.rxData: ; receive data buffer here
 
.flags db ? ; packet flags
 
.end:
ends
 
MAX_backlog equ 20
struct UDP_SOCKET
 
; socket buffers
SOCKETBUFFSIZE equ 4096 ; state + config + buffer.
SOCKETHEADERSIZE equ SOCKET.rxData ; thus 4096 - SOCKETHEADERSIZE bytes data
.LocalPort dw ? ; In INET byte order
.RemotePort dw ? ; In INET byte order
 
.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
110,6 → 146,10
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
139,9 → 179,9
or eax, eax
jz s_error
 
mov [eax + SOCKET.Domain], ecx
mov [eax + SOCKET.Type], edx
mov [eax + SOCKET.Protocol], esi
mov [eax + SOCKET_head.Domain], ecx
mov [eax + SOCKET_head.Type], edx
mov [eax + SOCKET_head.Protocol], esi
 
stdcall net_socket_addr_to_num, eax
DEBUGF 1,", socketnumber: %u\n", eax
153,6 → 193,10
 
 
 
 
 
 
 
;-----------------------------------------------
;
; SOCKET_bind
176,14 → 220,28
jl s_error
 
cmp word [edx], AF_INET4
jne s_error
je .af_inet4
 
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.Type]
mov ecx, [eax + SOCKET_head.Type]
 
mov bx, word [edx + 2]
DEBUGF 1,"local port: %x ",bx
test bx, bx
202,13 → 260,14
 
.got_port:
DEBUGF 1,"using port: %x ",bx
mov word [eax + SOCKET.LocalPort], bx
mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
 
mov ebx, dword [edx + 4]
mov dword [eax + SOCKET.LocalIP], ebx
mov dword [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP], ebx
 
DEBUGF 1,"local ip: %u.%u.%u.%u\n",\
[eax + SOCKET.LocalIP]:1,[eax + SOCKET.LocalIP + 1]:1,[eax + SOCKET.LocalIP + 2]:1,[eax + SOCKET.LocalIP + 3]:1
[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
 
mov dword [esp+32],0
ret
249,13 → 308,13
cmp esi, 8
jl s_error
 
cmp [eax + SOCKET.Type], IP_PROTO_UDP
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
je .udp
 
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP
je .icmp
 
cmp [eax + SOCKET.Type], IP_PROTO_TCP
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
je .tcp
 
jmp s_error
263,11 → 322,11
.udp:
 
mov bx , word [edx + 2]
mov word [eax + SOCKET.RemotePort], bx
mov word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx
DEBUGF 1,"remote port: %x ",bx
 
mov ebx, dword [edx + 4]
mov dword [eax + SOCKET.RemoteIP], ebx
mov dword [eax + SOCKET_head.end + IPv4_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
275,6 → 334,7
 
.icmp:
 
; TODO: write code here
 
ret
 
387,7 → 447,7
mov dx , 20
.ok:
 
mov [eax + SOCKET.backlog], dx
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], dx
 
; TODO: insert code for active connections like TCP
 
420,7 → 480,21
jz s_error
mov esi, eax
 
cmp [esi + SOCKET.backlog], 0
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
jz s_error
 
call net_socket_alloc
428,19 → 502,21
jz s_error
mov edi, eax
 
dec [esi + SOCKET.backlog]
dec [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog]
 
mov ecx, (SOCKET.rxData+3)/4
mov ecx, (SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end+3)/4
push esi edi
rep movsd
pop edi esi
 
mov [edi + SOCKET.backlog], 0
mov [edi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], 0
 
; TODO: fill in structure in ecx
 
mov [esi + SOCKET.RemoteIP], 0
mov [esi + SOCKET.RemotePort], 0
mov [esi + SOCKET_head.end + IPv4_SOCKET.RemoteIP], 0
mov [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], 0
 
stdcall net_socket_addr_to_num, eax
stdcall net_socket_addr_to_num, edi
mov [esp+32], eax
 
ret
465,14 → 541,16
or eax, eax
jz s_error
 
cmp [eax + SOCKET_head.Domain], AF_INET4
jne s_error
 
cmp [eax + SOCKET.Type], IP_PROTO_UDP
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
je .udp
 
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
cmp [eax + SOCKET_head.Type], IP_PROTO_ICMP
je .icmp
 
cmp [eax + SOCKET.Type], IP_PROTO_TCP
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
je .tcp
 
jmp s_error
479,12 → 557,7
 
.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
 
600,8 → 673,8
;
;
; IN: socket number in ecx
; addr in edx
; addrlen in esi
; addr to buffer in edx
; length of buffer in esi
; flags in edi
; OUT: eax is number of bytes copied, -1 on error
;
609,71 → 682,47
align 4
socket_recv:
 
DEBUGF 1,"Socket_receive: socknum: %u sockaddr: %x, length: %u, flags: %x\n",ecx,edx,esi,edi
DEBUGF 1,"Socket_receive: socknum: %u bufferaddress: %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,"real socket address:%x\n", eax
DEBUGF 1,"Socket pointer: %x\n", eax
 
mov dword[esp+32], -1
get_from_queue (eax + 2048), SOCKET_QUEUE_SIZE, 4*3, s_error
 
mov edi, edx
mov ecx, [esi + socket_queue_entry.data_size]
 
lea ebx, [eax + SOCKET.lock]
call wait_mutex
DEBUGF 1,"Got %u bytes of data\n", ecx
 
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)
cmp ecx, edx
jle .large_enough
DEBUGF 1,"Buffer too small...\n"
jmp s_error
.large_enough:
 
cmp ecx, esi ; if buffer size is larger then the bytes of data, copy all data
jle .copy_all_bytes
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
 
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
mov dword[esp+32+4], ecx ; return number of bytes copied
 
call .start_copy ; copy to the application
shr ecx, 1
jnc .nb
movsb
.nb: shr ecx, 1
jnc .nw
movsw
.nw: rep movsd
 
mov dword[esp+32], edx
call kernel_free
 
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
695,87 → 744,100
or eax, eax
jz s_error
 
cmp word [eax + SOCKET.Domain], AF_INET4
cmp word [eax + SOCKET_head.Domain], AF_INET4
je .af_inet4
 
jmp s_error
 
;---------
.af_inet4:
DEBUGF 1,"Socket type:%u\n", [eax + SOCKET_head.Type]:4
 
DEBUGF 1,"Socket type:%u\n", [eax + SOCKET.Type]:4
cmp [eax + SOCKET_head.Type], IP_PROTO_TCP
je .tcp
 
cmp [eax + SOCKET.Type], IP_PROTO_UDP
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
je .udp
 
cmp [eax + SOCKET.Type], IP_PROTO_ICMP
je .icmp
cmp [eax + SOCKET_head.Type], SOCK_RAW
je .raw
 
cmp [eax + SOCKET.Type], IP_PROTO_TCP
je .tcp
 
jmp s_error
;--------
 
.udp:
 
DEBUGF 1,"type: UDP, "
 
cmp [eax + SOCKET.LocalPort],0
jne .port_ok
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort],0
jne @f
 
push esi
mov ecx, [eax + SOCKET.Type]
mov ecx, [eax + SOCKET_head.Type]
call socket_find_port
test bx, bx
pop esi
je s_error
mov [eax + SOCKET.LocalPort], bx
mov [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_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_create_packet
call UDP_socket_send
 
mov [esp+32], eax
ret
 
.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'
.tcp:
 
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
 
cmp [eax + SOCKET_head.Protocol], IP_PROTO_ICMP
je .raw_icmp
 
jmp s_error
;--------
 
 
.raw_ip:
 
mov [esp+32], eax
ret
 
.tcp:
 
.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)
812,15 → 874,15
mov esi, net_sockets
 
.next_socket:
mov esi, [esi + SOCKET.NextPtr]
mov esi, [esi + SOCKET_head.NextPtr]
or esi, esi
jz .port_ok
 
cmp [esi + SOCKET.Type], ecx
cmp [esi + SOCKET_head.Type], ecx
jne .next_socket
 
rol bx, 8
cmp [esi + SOCKET.LocalPort], bx
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
rol bx, 8 ; this doesnt change the zero flag, does it ?
jne .next_socket
 
852,14 → 914,14
mov esi, net_sockets
 
.next_socket:
mov esi, [esi + SOCKET.NextPtr]
mov esi, [esi + SOCKET_head.NextPtr]
or esi, esi
jz .port_ok
 
cmp [esi + SOCKET.Type], ecx
cmp [esi + SOCKET_head.Type], ecx
jne .next_socket
 
cmp [esi + SOCKET.LocalPort], bx
cmp [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
jne .next_socket
 
xor ebx, ebx
868,20 → 930,19
ret
 
 
 
;-----------------------------------------------
;
; SOCKET_internal_receiver
;
; Checks if any socket wants the received data
; If so, update the socket
; Updates a socket with received data
;
; 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
; Note: the mutex must already be set !
;
; IN: eax = socket ptr
; ecx = size
; esi = pointer to buffer
; edi = offset
;
; OUT: xxx
;
;-----------------------------------------------
888,39 → 949,20
align 4
socket_internal_receiver:
 
DEBUGF 1,"internal socket receiver\n"
DEBUGF 1,"Internal socket receiver: buffer %x, offset: %x\n", esi, edi
 
lea ebx, [eax + SOCKET.lock]
call wait_mutex
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
 
mov [eax + SOCKET.RemotePort], dx ; update remote port number
mov [eax + SOCKET.RemoteIP], edi
mov [eax + SOCKET_head.lock], 0
 
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.PID] ; get socket owner PID
mov edx, [eax + SOCKET_head.PID] ; get socket owner PID
mov ecx, 1
mov esi, TASK_DATA + TASKDATA.pid
 
939,14 → 981,16
mov [check_idle_semaphore], 200
ret
 
.dump:
mov [eax + SOCKET.lock], 0
.full:
DEBUGF 1,"Socket %x is full!\n",eax
mov [eax + SOCKET_head.lock], 0
call kernel_free
add esp, 8
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).
963,6 → 1007,7
; zero-initialize allocated memory
push eax
mov edi, eax
 
mov ecx, SOCKETBUFFSIZE / 4
; cld
xor eax, eax
969,21 → 1014,23
rep stosd
pop eax
 
init_queue (eax + 2048)
 
; add socket to the list by changing pointers
mov ebx, net_sockets
push [ebx + SOCKET.NextPtr]
mov [ebx + SOCKET.NextPtr], eax
mov [eax + SOCKET.PrevPtr], ebx
push [ebx + SOCKET_head.NextPtr]
mov [ebx + SOCKET_head.NextPtr], eax
mov [eax + SOCKET_head.PrevPtr], ebx
pop ebx
mov [eax + SOCKET.NextPtr], ebx
mov [eax + SOCKET_head.NextPtr], ebx
or ebx, ebx
jz @f
mov [ebx + SOCKET.PrevPtr], eax
mov [ebx + SOCKET_head.PrevPtr], eax
 
@@: ; set socket owner PID to the one of calling process
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx
mov [eax + SOCKET_head.PID], ebx
 
; find first free socket number and use it
;mov edx, ebx
992,10 → 1039,10
.next_socket_number:
inc ecx
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx
jz .last_socket_number
cmp [ebx + SOCKET.Number], ecx
cmp [ebx + SOCKET_head.Number], ecx
jne .next_socket
;cmp [ebx + SOCKET.PID], edx
;jne .next_socket
1003,7 → 1050,7
jmp .next_socket_number
 
.last_socket_number:
mov [eax + SOCKET.Number], ecx
mov [eax + SOCKET_head.Number], ecx
 
.exit:
ret
1025,7 → 1072,7
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx
jz .error
cmp ebx, eax
1035,13 → 1082,16
 
; okay, we found the correct one
; remove it from the list first, changing pointers
mov ebx, [eax + SOCKET.NextPtr]
mov eax, [eax + SOCKET.PrevPtr]
mov [eax + SOCKET.NextPtr], ebx
mov ebx, [eax + SOCKET_head.NextPtr]
mov eax, [eax + SOCKET_head.PrevPtr]
mov [eax + SOCKET_head.NextPtr], ebx
or ebx, ebx
jz @f
mov [ebx + SOCKET.PrevPtr], eax
mov [ebx + SOCKET_head.PrevPtr], eax
 
lea ebx, [eax + SOCKET_head.lock]
call wait_mutex
 
@@: ; and finally free the memory structure used
stdcall kernel_free, [sockAddr]
ret
1070,10 → 1120,10
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx
jz .error
cmp [ebx + SOCKET.Number], eax
cmp [ebx + SOCKET_head.Number], eax
jne .next_socket
;cmp [ebx + SOCKET.PID], ecx
;jne .next_socket
1106,7 → 1156,7
;mov ecx, [TASK_BASE]
;mov ecx, [ecx + TASKDATA.pid]
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx
jz .error
cmp ebx, eax
1115,7 → 1165,7
;jne .next_socket
 
; okay, we found the correct one
mov eax, [ebx + SOCKET.Number]
mov eax, [ebx + SOCKET_head.Number]
ret
 
.error:
/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,6 → 86,7
call IPv4_init
call ARP_init
call UDP_init
call TCP_init
call ICMP_init
call socket_init
 
115,20 → 116,20
cmp [ETH_RUNNING], 0
je .exit
 
call ETH_handler ; handle all queued ethernet packets
call ETH_send_queued
 
; Test for 10ms tick, call tcp timer
; Test for 10ms tick
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, call 1s timer functions
; Test for 1 second event
mov al, 0x0 ;second
out 0x70, al
in al, 0x71
139,7 → 140,7
 
call ARP_decrease_entry_ttls
call IPv4_decrease_fragment_ttls
; call tcp_tcb_handler
call TCP_decrease_socket_ttls
 
.exit:
ret
146,41 → 147,77
 
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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
 
 
;-----------------------------------------------------------------
;
; 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
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
 
shr ecx, 1
pushf
.loop:
lodsw ;eax=word[esi],esi=esi+2
xchg ah,al ;cause must be a net byte-order
add ebx, eax
lodsw
xchg al, ah
add edx, eax
loop .loop
 
mov eax, ebx
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
shr eax, 16
add ax, bx
not ax
add edx, eax
 
not dx
jnz .not_zero
dec dx
.not_zero:
xchg dl, dh
 
DEBUGF 1,"Checksum: %x\n",dx
 
ret
endp
 
 
 
250,7 → 287,15
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,7 → 18,6
$Revision$
 
 
; TCP TCB states
TCB_LISTEN equ 1
TCB_SYN_SENT equ 2
TCB_SYN_RECEIVED equ 3
31,20 → 30,21
TCB_TIMED_WAIT equ 10
TCB_CLOSED equ 11
 
TH_FIN equ 0x01
TH_SYN equ 0x02
TH_RST equ 0x04
TH_PUSH equ 0x08
TH_ACK equ 0x10
TH_URG equ 0x20
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
 
TWOMSL equ 10 ; # of secs to wait before closing socket
 
TCP_RETRIES equ 5 ; Number of times to resend a Packet
TCP_TIMEOUT equ 10 ; resend if not replied to in x hs
TCP_TIMEOUT equ 10 ; resend if not replied to in 1/100 s
 
TCP_QUEUE_SIZE equ 16
 
 
struct TCP_Packet
.SourcePort dw ?
.DestinationPort dw ?
65,14 → 65,55
TCP_PACKETS_TX rd MAX_IP
TCP_PACKETS_RX rd MAX_IP
 
TCP_IN_QUEUE rd 3*TCP_QUEUE_SIZE+3
TCP_OUT_QUEUE rd 3*TCP_QUEUE_SIZE+3
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
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
92,58 → 133,55
mov ecx, 2*MAX_IP
rep stosd
 
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
init_queue TCP_IN_QUEUE
init_queue TCP_OUT_QUEUE
 
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_tcb_handler
; TCP_decrease_socket_ttls
;
; Handles sockets in the timewait state, closing them
; when the TCB timer expires
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
 
align 4
tcp_tcb_handler:
TCP_decrease_socket_ttls:
; scan through all the sockets, decrementing active timers
 
mov ebx, net_sockets
 
cmp [ebx + SOCKET.NextPtr], 0
cmp [ebx + SOCKET_head.NextPtr], 0
je .exit
DEBUGF 1, "K : sockets:\n"
 
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
mov ebx, [ebx + SOCKET_head.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.TCBTimer], 0
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer], 0
jne .decrement_tcb
cmp [ebx + SOCKET.wndsizeTimer], 0
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_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.TCBTimer]
dec [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer]
jnz .next_socket
 
cmp [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT
jne .next_socket
 
push [ebx + SOCKET.PrevPtr]
push [ebx + SOCKET_head.PrevPtr]
stdcall net_socket_free, ebx
pop ebx
jmp .next_socket
150,7 → 188,7
 
.decrement_wnd:
; TODO - prove it works!
dec [ebx + SOCKET.wndsizeTimer]
dec [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer]
jmp .next_socket
 
.exit:
157,120 → 195,124
ret
 
 
;***************************************************************************
; Function
; tcp_tx_handler
 
;-----------------------------------------------------------------
;
; Description
; Handles queued TCP data
; This is a kernel function, called by stack_handler
; TCP_send_queued:
;
;***************************************************************************
; 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_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
TCP_send_queued:
 
mov esi, resendQ
mov ecx, 0
cmp [TCP_OUT_QUEUE], 0
je .exit
 
.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
mov eax, TCP_QUEUE_SIZE
mov ecx, [TCP_OUT_QUEUE]
mov esi, TCP_OUT_QUEUE+4
 
@@: ; 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
.loop:
cmp [esi + tcp_out_queue_entry.data_ptr], 0
jnz .found_one
add esi, tcp_out_queue_entry.size
loop .loop
.exit:
ret
 
@@:
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
.found_one:
dec [esi + tcp_out_queue_entry.ttl]
jz .send_it
.find_next:
dec eax
jz .exit
jmp .loop
 
; retries now 0, so delete from queue
xchg [esi + 4], ebx
.send_it:
push eax ecx esi
 
@@: ; resend Packet
pushad
push [esi + tcp_out_queue_entry.data_size]
push [esi + tcp_out_queue_entry.data_ptr]
mov ebx, [esi + tcp_out_queue_entry.owner]
 
; mov eax, EMPTY_QUEUE
; call dequeue
; cmp ax, NO_BUFFER
jne .tth004z
call [esi + tcp_out_queue_entry.sendproc]
 
; TODO - try again in 10ms.
test ebx, ebx
jnz @f
mov [esi + 4], ebx
pop esi ecx eax
 
@@: ; Mark it to expire in 10ms - 1 tick
mov byte[esi + 1], 1
mov word[esi + 2], 1
jmp .tth005
dec [esi + tcp_out_queue_entry.retries]
jz .remove_it
mov [esi + tcp_out_queue_entry.ttl], TCP_TIMEOUT
jmp .find_next
 
.tth004z:
; we have a buffer # in ax
; push eax ecx
; mov ecx, IPBUFFSIZE
; mul ecx
; add eax, IPbuffs
.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
 
; 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
 
; copy data across
push edi
cld
rep movsb
pop edi
;-----------------------------------------------------------------
;
; 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: /
;
;-----------------------------------------------------------------
 
; queue Packet
; mov eax, NET1OUT_QUEUE
; mov edx, [IP_LIST]
; cmp edx, [edi + IP_Packet.DestinationAddress]
; jne .not_local
; mov eax, IPIN_QUEUE
align 4
TCP_add_to_queue:
 
.not_local:
pop ebx
; call queue
cmp [TCP_OUT_QUEUE], TCP_QUEUE_SIZE
jge .full
 
.tth005:
popad
mov ecx, TCP_QUEUE_SIZE
mov eax, TCP_OUT_QUEUE+4
 
inc ecx
add esi, 8
jmp .next_resendq
.loop:
cmp [eax + tcp_out_queue_entry.data_ptr], 0
je .found_it
add eax, tcp_out_queue_entry.size
loop .loop
 
.exit:
.full: ; silently discard the packet
call kernel_free
add esp, 4
 
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.
285,136 → 327,104
;
;-----------------------------------------------------------------
 
TCP_Handler :
align 4
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
; IP Packet TCP Source Port = remote Port
; IP Packet SA = Remote IP OR = 0
; IP Packet TCP Source Port = remote Port OR = 0
 
mov ebx, net_sockets
 
.next_socket.1:
mov ebx, [ebx + SOCKET.NextPtr]
.socket_loop:
mov ebx, [ebx + SOCKET_head.NextPtr]
or ebx, ebx
jz .next_socket.1.exit
jz .dump
 
; DEBUGF 1, "K : tcp_rx - 1.dport: %x - %x\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
mov ax, [edx + TCP_Packet.DestinationPort]
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], ax
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 eax, [ebx + SOCKET_head.end + IPv4_SOCKET.RemoteIP]
cmp eax, esi
je @f
test eax, eax
jne .socket_loop
@@:
 
; DEBUGF 1, "K : tcp_rx - 1.addr: %x - %x\n", [edx + IP_Packet.SourceAddress], [ebx + SOCKET.RemoteIP]
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
 
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
.change_state:
 
; DEBUGF 1, "K : tcp_rx - 1.sport: %x - %x\n", [edx + 20 + TCP_Packet.SourcePort]:4, [ebx + SOCKET.RemotePort]:4
push ebx
lea ebx, [ebx + SOCKET_head.lock]
call wait_mutex
pop ebx
 
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
;----------------------------------
; ebx is pointer to socket
; ecx is size of tcp packet
; edx is pointer to tcp packet
 
; We have a complete match - use this socket
jmp .change_state
; as a Packet has been received, update the TCB timer
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBTimer], TWOMSL
 
.next_socket.1.exit:
; 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
 
; 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
mov eax, [edx + TCP_Packet.SequenceNumber] ; Calculate sequencenumber in eax
bswap eax ;
add eax, ecx ;
 
mov ebx, net_sockets
cmp [TCP_OUT_QUEUE], 0
je .call_handler
 
.next_socket.2:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .next_socket.2.exit
push ecx
mov ecx, TCP_QUEUE_SIZE
mov esi, TCP_OUT_QUEUE+4
 
; DEBUGF 1, "K : tcp_rx - 2.dport: %x - %x\n", [edx + 20 + TCP_Packet.DestinationPort]:4, [ebx + SOCKET.LocalPort]:4
.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
 
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
push [esi + tcp_out_queue_entry.data_ptr]
mov [esi + tcp_out_queue_entry.data_ptr], 0
dec [TCP_OUT_QUEUE]
call kernel_free
 
; DEBUGF 1, "K : tcp_rx - 2.addr: %x - %x\n", [edx + IP_Packet.SourceAddress], [ebx + SOCKET.RemoteIP]
.maybe_next:
add esi, tcp_out_queue_entry.size
loop .loop
pop ecx
 
; 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
.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
 
; DEBUGF 1, "K : tcp_rx - 2.sport: 0000 - %x\n", [ebx + SOCKET.RemotePort]:4
shl eax, 2
add eax, TCBStateHandler - 4
 
cmp [ebx + SOCKET.RemotePort], 0 ; only match a remote socket of 0
jne .next_socket.2 ; different - try next socket
push .exit
jmp eax
 
; 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)
 
424,370 → 434,223
 
;-----------------------------------------------------------------
;
; IN: eax = dest ip
; ebx = source ip
; ecx = data length
; edx = remote port shl 16 + local port
; esi = data offset
; TCP_socket_send
;
; IN: eax = socket pointer
; ecx = number of bytes to send
; esi = pointer to data
;
;-----------------------------------------------------------------
 
TCP_create_Packet:
align 4
TCP_socket_send:
 
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
;
;***************************************************************************
DEBUGF 1,"Creating TCP Packet\n"
 
push ecx ; Save data length
mov di , IP_PROTO_TCP
 
add ecx, UDP_Packet.Data
mov di , IP_PROTO_UDP
; 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]
 
; 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
; meanwhile, create the pseudoheader in stack,
; (now that we still have all the variables that are needed.)
push cx
push di
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
 
; Checksum left unfilled
; mov [edx + IP_Packet.HeaderChecksum], 0
push ecx esi eax ; save some variables for later
add ecx, TCP_Packet.Data
call IPv4_create_packet
cmp edi, -1
je .fail
 
; 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
pop esi
 
mov ax, [ebx + SOCKET.RemotePort]
mov [edx + 20 + TCP_Packet.DestinationPort], ax ; desitination Port
; Now add the TCP header to the IPv4 packet
 
; Checksum left unfilled
mov [edx + 20 + TCP_Packet.Checksum], 0
push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
pop [edi + TCP_Packet.SequenceNumber]
 
; sequence number
mov eax, [ebx + SOCKET.SND_NXT]
mov [edx + 20 + TCP_Packet.SequenceNumber], eax
push dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
pop dword [edi + TCP_Packet.SourcePort]
 
; ack number
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 [edx + 20 + TCP_Packet.Window], 0x0003
push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
pop [edi + TCP_Packet.AckNumber]
 
; Urgent pointer (0)
mov [edx + 20 + TCP_Packet.UrgentPointer], 0
mov al, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.flags]
mov [edi + TCP_Packet.Flags], al
 
; data offset ( 0x50 )
mov [edx + 20 + TCP_Packet.DataOffset], 0x50
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
 
pop ecx ; count of bytes to send
mov ebx, ecx ; need the length later
; Copy the data
mov esi, [esp]
mov ecx, [esp+4]
add edi, TCP_Packet.Data
 
cmp ebx, 0
jz @f
shr ecx, 1
jnc .nb
movsb
.nb: shr ecx, 1
jnc .nw
movsw
.nw: rep movsd
 
mov edi, edx
add edi, 40
cld
rep movsb ; copy the data across
; 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
 
@@: ; 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
; 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
 
; 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)
 
.fail:
add esp, 12+4
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
;-----------------------------------------------------------------
;
; Description
; TCP state machine
; This is a kernel function, called by tcp_rx
; TCP_send_ack
;
; IP buffer address given in edx
; Socket/TCB address in ebx
; IN: eax = socket pointer
; bl = flags
;
; The IP buffer will be released by the caller
;***************************************************************************
;-----------------------------------------------------------------
 
proc tcpStateMachine stdcall, sockAddr:DWORD
; as a Packet has been received, update the TCB timer
mov [ebx + SOCKET.TCBTimer], TWOMSL
align 4
TCP_send_ack:
 
; 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
DEBUGF 1,"Creating TCP ACK\n"
 
; get skt number in eax
stdcall net_socket_addr_to_num, ebx
mov di , IP_PROTO_TCP
mov cx , TCP_Packet.Data
 
; The ack number is in [edx + 28], inet format
; skt in eax
push bx eax
 
mov esi, resendQ
xor ecx, ecx
; 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]
 
.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
call IPv4_create_packet
cmp edi, -1
je .fail
 
@@: ; Can we delete this buffer?
; Fill in the TCP header
pop esi
 
; If yes, goto @@. No, goto .next_resendq
; Get Packet data address
push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
pop [edi + TCP_Packet.SequenceNumber]
 
push ecx
; Now get buffer location, and copy buffer across. argh! more copying,,
; imul edi, ecx, IPBUFFSIZE
; add edi, resendBuffer
push dword [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort]
pop dword [edi + TCP_Packet.SourcePort]
 
; 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
push [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
pop [edi + TCP_Packet.AckNumber]
 
; get recievd ack #, in intel format
mov ebx, [edx + 20 + TCP_Packet.AckNumber]
bswap ebx
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
 
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 eax edx
 
inc ecx
add esi, 8
jmp .next_resendq
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]
 
@@: mov dword[esi + 4], 0
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
 
.call_handler:
popad
; 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 for given TCB state
.fail:
add esp, 12+4
ret
 
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
 
 
proc stateTCB_LISTEN stdcall, sockAddr:DWORD
align 4
stateTCB_LISTEN:
; In this case, we are expecting a SYN Packet
; For now, if the Packet is a SYN, process it, and send a response
; If not, ignore it
 
; Look at control flags
test [edx + 20 + TCP_Packet.Flags], TH_SYN
test [edx + TCP_Packet.Flags], TH_SYN
jz .exit
 
; We have a SYN. update the socket with this IP Packets details,
; And send a response
 
; mov eax, [edx + IP_Packet.SourceAddress]
; mov [ebx + SOCKET.RemoteIP], eax
; mov ax, [edx + 20 + TCP_Packet.SourcePort]
; mov [ebx + SOCKET.RemotePort], ax
; mov eax, [edx + 20 + TCP_Packet.SequenceNumber]
; mov [ebx + SOCKET.IRS], eax
; mov [ebx + SOCKET.RCV_NXT], eax
; lea esi, [ebx + SOCKET.RCV_NXT]
; call inc_inet_esi ; RCV.NXT
; mov eax, [ebx + SOCKET.ISS]
; mov [ebx + SOCKET.SND_NXT], eax
;
; Now construct the response, and queue for sending by IP
; mov eax, EMPTY_QUEUE
; call dequeue
; cmp ax, NO_BUFFER
; je .exit
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
 
push eax
; Now construct the response
mov bl, TH_SYN + TH_ACK
xor ecx, ecx
xor esi, esi
; stdcall build_tcp_Packet, [sockAddr]
call TCP_send_ack
 
; mov eax, NET1OUT_QUEUE
;;; mov edx, [stack_ip]
mov ecx, [sockAddr]
cmp edx, [ecx + SOCKET.RemoteIP]
jne .not_local
; mov eax, IPIN_QUEUE
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_SYN_RECEIVED
 
.not_local:
; Send it.
pop ebx
;;; call queue
 
mov esi, [sockAddr]
mov [esi + SOCKET.TCBState], TCB_SYN_RECEIVED
 
; increment SND.NXT in socket
add esi, SOCKET.SND_NXT
call inc_inet_esi
lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT]
inc_INET esi
 
.exit:
ret
endp
 
 
proc stateTCB_SYN_SENT stdcall, sockAddr:DWORD
align 4
stateTCB_SYN_SENT:
; We are awaiting an ACK to our SYN, with a SYM
; Look at control flags - expecting an ACK
 
mov al, [edx + 20 + TCP_Packet.Flags]
mov al, [edx + TCP_Packet.Flags]
and al, TH_SYN + TH_ACK
cmp al, TH_SYN + TH_ACK
je .syn_ack
795,139 → 658,89
test al, TH_SYN
jz .exit
 
mov [ebx + SOCKET.TCBState], TCB_SYN_RECEIVED
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_SYN_RECEIVED
push TH_SYN + TH_ACK
jmp .send
 
.syn_ack:
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_ESTABLISHED
push TH_ACK
 
.send:
; Store the recv.nxt field
mov eax, [edx + 20 + TCP_Packet.SequenceNumber]
mov eax, [edx + TCP_Packet.SequenceNumber]
 
; Update our recv.nxt field
mov [ebx + SOCKET.RCV_NXT], eax
lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi
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
 
; Send an ACK
; Now construct the response, and queue for sending by IP
; mov eax, EMPTY_QUEUE
; call dequeue
; cmp ax, NO_BUFFER
pop ebx
je .exit
call TCP_send_ack
 
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
 
 
proc stateTCB_SYN_RECEIVED stdcall, sockAddr:DWORD
 
align 4
stateTCB_SYN_RECEIVED:
; In this case, we are expecting an ACK Packet
; For now, if the Packet is an ACK, process it,
; If not, ignore it
 
test [edx + 20 + TCP_Packet.Flags], TH_RST
test [edx + TCP_Packet.Flags], TH_RST
jz .check_ack
 
push [ebx + SOCKET.OrigRemotePort] [ebx + SOCKET.OrigRemoteIP]
pop [ebx + SOCKET.RemoteIP] [ebx + SOCKET.RemotePort]
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]
 
mov [ebx + SOCKET.TCBState], TCB_LISTEN
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_LISTEN
jmp .exit
 
.check_ack:
; Look at control flags - expecting an ACK
test [edx + 20 + TCP_Packet.Flags], TH_ACK
test [edx + TCP_Packet.Flags], TH_ACK
jz .exit
 
mov [ebx + SOCKET.TCBState], TCB_ESTABLISHED
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_ESTABLISHED
 
.exit:
ret
endp
 
 
proc stateTCB_ESTABLISHED stdcall, sockAddr:DWORD
 
align 4
stateTCB_ESTABLISHED:
; Here we are expecting data, or a request to close
; OR both...
 
; Did we receive a FIN or RST?
test [edx + 20 + TCP_Packet.Flags], TH_FIN
test [edx + 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
pushad
; Send an ACK to that fin, and enter closewait state
 
; 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 + 20 + TCP_Packet.Flags], TH_ACK
test [edx + 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 + 20 + TCP_Packet.Window]
mov cx, [edx + TCP_Packet.Window]
xchg cl, ch
cmp cx, 1024
ja @f
 
mov [ebx + SOCKET.wndsizeTimer], 1
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 1
 
@@: ; OK, here is the deal
; My recv.nct field holds the seq of the expected next rec byte
938,117 → 751,41
; recv.nxt is in dword [edx+24], in inet format
; recv seq is in [sktAddr]+56, in inet format
; just do a comparision
mov ecx, [ebx + SOCKET.RCV_NXT]
cmp [ebx + SOCKET.TCBState], TCB_CLOSE_WAIT
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
jne @f
mov ecx, eax
 
@@: cmp ecx, [edx + 20 + TCP_Packet.SequenceNumber]
@@: cmp ecx, [edx + 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.TCBState], TCB_CLOSE_WAIT
cmp [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_CLOSE_WAIT
je .ack
jmp .exit
 
.data:
push ebx
add ebx, SOCKET.lock
call wait_mutex
pop ebx
mov esi, [esp + 4]
sub edx, esi
mov edi, edx
call socket_internal_receiver
 
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
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
 
call TCP_send_ack
.exit:
ret
.overflow:
; no place in buffer
; so simply restore stack and exit
pop eax ecx
mov [ebx + SOCKET.lock], 0
ret
endp
 
 
proc stateTCB_FIN_WAIT_1 stdcall, sockAddr:DWORD
 
align 4
stateTCB_FIN_WAIT_1:
; We can either receive an ACK of a fin, or a fin
mov al, [edx + 20 + TCP_Packet.Flags]
mov al, [edx + TCP_Packet.Flags]
and al, TH_FIN + TH_ACK
 
cmp al, TH_ACK
1055,109 → 792,69
jne @f
 
; It was an ACK
mov [ebx + SOCKET.TCBState], TCB_FIN_WAIT_2
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_FIN_WAIT_2
jmp .exit
 
@@: mov [ebx + SOCKET.TCBState], TCB_CLOSING
@@: mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_CLOSING
cmp al, TH_FIN
je @f
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT
 
@@: lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi
 
@@: lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
inc_INET esi
; Send an ACK
; mov eax, EMPTY_QUEUE
; call dequeue
; cmp ax, NO_BUFFER
je .exit
 
push eax
 
mov bl, TH_ACK
xor ecx, ecx
xor esi, esi
; stdcall build_tcp_Packet, [sockAddr]
call TCP_send_ack
 
; 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
 
 
proc stateTCB_FIN_WAIT_2 stdcall, sockAddr:DWORD
test [edx + 20 + TCP_Packet.Flags], TH_FIN
 
align 4
stateTCB_FIN_WAIT_2:
test [edx + TCP_Packet.Flags], TH_FIN
jz .exit
 
; Change state, as we have a fin
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT
 
lea esi, [ebx + SOCKET.RCV_NXT]
call inc_inet_esi
lea esi, [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RCV_NXT]
inc_INET esi
 
; Send an ACK
; mov eax, EMPTY_QUEUE
; call dequeue
;; cmp ax, NO_BUFFER
; je .exit
 
push eax
 
mov bl, TH_ACK
xor ecx, ecx
xor esi, esi
; stdcall build_tcp_Packet, [sockAddr]
call TCP_send_ack
 
; 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
 
 
proc stateTCB_CLOSE_WAIT stdcall, sockAddr:DWORD
 
align 4
stateTCB_CLOSE_WAIT:
; Intentionally left empty
; socket_close_tcp handles this
ret
endp
 
 
proc stateTCB_CLOSING stdcall, sockAddr:DWORD
 
align 4
stateTCB_CLOSING:
; We can either receive an ACK of a fin, or a fin
test [edx + 20 + TCP_Packet.Flags], TH_ACK
test [edx + TCP_Packet.Flags], TH_ACK
jz .exit
 
mov [ebx + SOCKET.TCBState], TCB_TIMED_WAIT
mov [ebx + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.TCBState], TCB_TIMED_WAIT
 
.exit:
ret
endp
 
 
proc stateTCB_LAST_ACK stdcall, sockAddr:DWORD
align 4
stateTCB_LAST_ACK:
; Look at control flags - expecting an ACK
test [edx + 20 + TCP_Packet.Flags], TH_ACK
test [edx + TCP_Packet.Flags], TH_ACK
jz .exit
 
; delete the socket
1165,235 → 862,17
 
.exit:
ret
endp
 
 
proc stateTCB_TIME_WAIT stdcall, sockAddr:DWORD
align 4
stateTCB_TIME_WAIT:
ret
endp
 
 
proc stateTCB_CLOSED stdcall, sockAddr:DWORD
align 4
stateTCB_CLOSED:
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/network/udp.inc
75,8 → 75,34
UDP_handler:
 
DEBUGF 1,"UDP_Handler\n"
; TODO: First validate the header & checksum!
; First validate, 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
85,14 → 111,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.NextPtr]
mov eax, [eax + SOCKET_head.NextPtr]
or eax, eax
jz .dump
cmp [eax + SOCKET.Domain], AF_INET4
cmp [eax + SOCKET_head.Domain], AF_INET4
jne .next_socket
cmp [eax + SOCKET.Type], IP_PROTO_UDP
cmp [eax + SOCKET_head.Type], IP_PROTO_UDP
jne .next_socket
cmp [eax + SOCKET.LocalPort], bx
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
jne .next_socket
 
DEBUGF 1,"found socket with matching domain, type and localport\n"
101,12 → 127,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.RemoteIP], 0xffffffff
cmp [eax + SOCKET_head.end + IPv4_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.RemoteIP], ebx
cmp [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx
jne .try_more ; Quit if the source IP is not valid, check for more sockets with this IP/PORT combination
 
 
115,10 → 141,10
 
mov bx, [edx + UDP_Packet.SourcePort] ; Remote port must be 0, or equal to sourceport of packet
 
cmp [eax + SOCKET.RemotePort], 0
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], 0
je .ok2
 
cmp [eax + SOCKET.RemotePort], bx
cmp [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx
jne .dump
 
.ok2:
130,10 → 156,21
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
146,69 → 183,93
 
;-----------------------------------------------------------------
;
; Note: UDP works only on top of IP protocol :)
; UDP_socket_send
;
; IN: eax = dest ip
; ebx = source ip
; ecx = data length
; edx = remote port shl 16 + local port (both in INET order)
; esi = data offset
; IN: eax = socket pointer
; ecx = number of bytes to send
; esi = pointer to data
;
;-----------------------------------------------------------------
 
UDP_create_packet:
align 4
UDP_socket_send:
 
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
 
push edx esi
mov di , IP_PROTO_UDP
 
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
 
; dx = fragment id
; TODO: fill in: 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 byte[edi + UDP_Packet.Length], ch
mov byte[edi + UDP_Packet.Length+1], cl
sub ecx , UDP_Packet.Data
mov [esp + 8 + 12], eax ; pointer to buffer start
mov [esp + 8 + 12 + 4], edx ; buffer size
 
rol cx, 8
mov [edi + UDP_Packet.Length], cx
mov [esp + 8 + 10], cx
ror cx, 8
 
pop esi
push edi
push edi ecx
sub ecx, UDP_Packet.Data
add edi, UDP_Packet.Data
push cx
shr ecx, 2
rep movsd
pop cx
mov ecx, [esp]
and cx , 3
rep movsb
pop edi
pop ecx edi
 
pop ecx
mov dword [edi + UDP_Packet.SourcePort], ecx ; notice: we write both port's at once
pop dword [edi + UDP_Packet.SourcePort] ; fill in both portnumbers
mov [edi + UDP_Packet.Checksum], 0 ; set it to zero, to calculate checksum
 
mov [edi + UDP_Packet.Checksum], 0
; 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
 
; 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
add esp, 8+12+8
ret
 
 
 
 
;---------------------------------------------------------------------------
;
; UDP_API