Deleted double macro in netdrv.inc

Refactoring of ARP code.
Used universal names for protocol handlers.
Moved some pieces of code from procs to macros.
Added IPv4_fragment (currently disabled)
Added ring-buffer functions for sockets 
Updates in TCP code

git-svn-id: svn://kolibrios.org@1529 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr 2010-07-27 18:53:38 +00:00
parent f01c3da0f2
commit fab920c5c8
10 changed files with 1704 additions and 1541 deletions

View File

@ -82,7 +82,7 @@ iglobal
szNetUnRegDev db 'NetUnRegDev',0
szNetPtrToNum db 'NetPtrToNum',0
szEthReceiver db 'EthReceiver',0
szIPv4Handler db 'IPv4Handler',0
szIPv4_input db 'IPv4_input',0
align 16
@ -155,8 +155,8 @@ kernel_export:
dd szNetRegDev , NET_add_device
dd szNetUnRegDev , NET_remove_device
dd szNetPtrToNum , NET_ptr_to_num
dd szEthReceiver , ETH_receiver
dd szIPv4Handler , IPv4_handler
dd szEthReceiver , ETH_input
dd szIPv4_input , IPv4_input
exp_lfb:
dd szLFBAddress , 0

View File

@ -35,22 +35,15 @@
macro set_io addr {
if addr = 0
mov edx, [device.io_addr]
else if addr = LAST_IO
else
add edx, addr - LAST_IO
end if
LAST_IO = addr
}
macro allocate_and_clear dest, size, err {
; We need to allocate at least 8 pages, if we want a continuous memory in ram
@ -83,8 +76,6 @@ macro allocate_and_clear dest, size, err {
}
macro find_io bus, dev, io {
local .check, .inc, .got
@ -126,7 +117,6 @@ macro find_irq bus, dev, irq {
}
macro find_rev bus, dev, rev {
push eax edx ecx
@ -138,8 +128,6 @@ macro find_rev bus, dev, rev {
}
macro make_bus_master bus, dev {
movzx ecx, bus
@ -168,10 +156,7 @@ virtual at edx
end virtual
if used null_op
align 4
null_op:
or eax, -1
@ -180,11 +165,11 @@ null_op:
end if
macro virt_to_dma { ; input is eax
macro GetRealAddr { ; input is eax
push ax
and word[esp], PAGESIZE - 1
call GetPgAddr
and word[esp], PAGESIZE - 1
or ax, word[esp]
inc esp
inc esp
@ -209,7 +194,7 @@ macro NET_DEVICE {
.end:
}
;struc ETH_DEVICE {
macro ETH_DEVICE {
NET_DEVICE
@ -235,16 +220,4 @@ macro SLIP_DEVICE {
.mode dd ?
}
macro GetRealAddr {
push eax
call GetPgAddr
and dword [esp], (PAGESIZE - 1)
or eax, dword [esp]
add esp, 4
}
}

View File

@ -12,34 +12,30 @@
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June- 1991 ;;
;; Version 2, June- 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
ARP_NO_ENTRY equ 0
ARP_VALID_MAPPING equ 1
ARP_AWAITING_RESPONSE equ 2
ARP_RESPONSE_TIMEOUT equ 3
ARP_NO_ENTRY equ 0
ARP_VALID_MAPPING equ 1
ARP_AWAITING_RESPONSE equ 2
ARP_RESPONSE_TIMEOUT equ 3
ARP_REQUEST_TTL equ 31 ; 20 s
ARP_ENTRY_TTL equ 937 ; 600 s
ARP_REQUEST_TTL = 20 ; in seconds
ARP_ENTRY_TTL = 600 ; in seconds
ARP_REQ_OPCODE equ 0x0100 ; request
ARP_REP_OPCODE equ 0x0200 ; reply
ETHER_ARP equ 0x0608
ARP_REQ_OPCODE equ 0x0100 ; request
ARP_REP_OPCODE equ 0x0200 ; reply
ARP_TABLE_SIZE equ 20 ; Size of table
ARP_TABLE_SIZE equ 20 ; Size of table
struct ARP_ENTRY
.IP dd ?
.MAC dp ?
.Status dw ?
.TTL dw ? ; in seconds
.TTL dw ?
.size:
ends
@ -53,29 +49,19 @@ struct ARP_Packet
.SenderIP dd ?
.TargetMAC dp ?
.TargetIP dd ?
.size:
ends
; The TTL field is decremented every second, and is deleted when it
; reaches 0. It is refreshed every time a packet is received
; If the TTL field is 0xFFFF it is a static entry and is never deleted
; The status field can be the following values:
; 0x0000 entry not used
; 0x0001 entry holds a valid mapping
; 0x0002 entry contains an IP address, awaiting ARP response
; 0x0003 No response received to ARP request.
; The last status value is provided to allow the network layer to delete
; a packet that is queued awaiting an ARP response
align 4
uglobal
NumARP dd ?
ARPTable rb ARP_ENTRY.size * ARP_TABLE_SIZE
ARP_table rb ARP_ENTRY.size * ARP_TABLE_SIZE
ARP_PACKETS_TX rd MAX_NET_DEVICES
ARP_PACKETS_RX rd MAX_NET_DEVICES
ARP_PACKETS_TX rd MAX_NET_DEVICES
ARP_PACKETS_RX rd MAX_NET_DEVICES
endg
@ -88,379 +74,81 @@ endg
;
; This function resets all ARP variables
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
align 4
ARP_init:
macro ARP_init {
xor eax, eax
mov [NumARP], eax
mov edi, ARP_PACKETS_TX
mov ecx, 2*MAX_NET_DEVICES
rep stosd
ret
;-----------------------------------------------------------------
;
; ARP_IP_to_MAC
;
; This function resets all ARP variables
;
; IN: eax = IPv4 address
; OUT: eax = -1 on error, else eax = first two bytes of mac
; ( high 16 bits are zero)
; ebx = last four bytes of mac ; TODO: special eax value for 'request send'
;
;-----------------------------------------------------------------
align 4
ARP_IP_to_MAC:
DEBUGF 1,"ARP_IP_to_MAC\n"
; first, check destination IP to see if it is on 'this' network.
; The test is:
; if ( destIP & subnet_mask == stack_ip & subnet_mask )
; destination is local
; else
; destination is remote, so pass to gateway
xor edx, edx ;;; TODO: find device num in edx
mov ebx, [IP_LIST + edx]
and ebx, [SUBNET_LIST + edx]
mov ecx, eax
and ecx, [SUBNET_LIST + edx]
cmp ecx, ebx
je .local
mov eax, [GATEWAY_LIST + edx]
DEBUGF 1,"requested IP is not on subnet, using gateway\n"
.local:
; try to find it on the list
mov ecx, [NumARP]
test ecx, ecx
jz .not_in_list
mov esi, ARPTable + ARP_ENTRY.IP
.scan_loop:
cmp [esi], eax
je .found_it
add esi, ARP_ENTRY.size
loop .scan_loop
.not_in_list:
DEBUGF 1,"IP not found on list, preparing for ARP request\n"
; if not, reserve an entry in list and send an ARP request packet
push eax
pushw ARP_REQUEST_TTL
pushw ARP_AWAITING_RESPONSE
pushd 0
pushw 0
pushd eax
call ARP_add_entry
cmp eax, -1
je .full
; <Some dirty test code>
; This piece of code waits for an ARP reply
mov ebx, eax
pop eax
push ebx
call ARP_create_request
push [timer_ticks]
add dword[esp], 100*ARP_REQUEST_TTL
DEBUGF 1,"Waiting for ARP reply, time: %x, entry:%u\n",[timer_ticks], [esp + 4]
.dirty_loop:
call change_task ; The ARP reply hasnt been received yet, tell the processor to do some other stuff first
mov eax, [esp + 4]
imul eax, ARP_ENTRY.size
add eax, ARPTable
cmp [eax + ARP_ENTRY.Status], ARP_VALID_MAPPING
je .gogogo
mov eax, [esp] ; Check if the reply hasnt timed-out yet
cmp [timer_ticks], eax
jl .dirty_loop
; </Some dirty test code>
or eax, -1
add esp, 8
ret
.found_it:
DEBUGF 1,"found MAC in ARPTable\n"
movzx eax, word [esi+ARP_ENTRY.MAC]
mov ebx, dword[esi+ARP_ENTRY.MAC+2]
ret
.full:
add esp, 4
mov eax, -1
ret
.gogogo:
DEBUGF 1,"got ARP reply, time: %x\n",[timer_ticks]
mov ebx, dword[eax+ARP_ENTRY.MAC+2]
movzx eax, word [eax+ARP_ENTRY.MAC]
add esp, 8
ret
;---------------------------------------------------------------------------
;
; ARP_create_request
;
; IN: ip in eax
;
; OUT: /
;
;---------------------------------------------------------------------------
align 4
ARP_create_request:
DEBUGF 1,"Create ARP Packet\n"
call IPv4_dest_to_dev
push eax ; DestIP
mov eax, [IP_LIST+4*edi] ; senderIP
push eax
mov edi, [NET_DRV_LIST + 4*edi]
lea eax, [edi + ETH_DEVICE.mac]
mov ebx, ETH_BROADCAST
mov ecx, 60 ; minimum packet size
mov edx, edi ;;;
mov di , ETHER_ARP
call ETH_create_packet
jz .exit
mov ecx, eax
mov [edi + ARP_Packet.HardwareType], 0x0100 ;Ethernet
mov [edi + ARP_Packet.ProtocolType], 0x0008 ;IP
mov [edi + ARP_Packet.HardwareSize], 6 ;MAC-addr length
mov [edi + ARP_Packet.ProtocolSize], 4 ;IP-addr length
mov [edi + ARP_Packet.Opcode], ARP_REQ_OPCODE ;Request
add edi, ARP_Packet.SenderMAC ; sendermac
lea esi, [ebx + ETH_DEVICE.mac] ;
movsw ;
movsd ;
pop eax ;
stosd ;
mov eax, -1 ; destmac
stosd ;
stosw ;
pop eax
stosd ;
DEBUGF 1,"ARP Packet for device %x created successfully\n", ebx
push edx ecx
call [ebx + NET_DEVICE.transmit]
ret
.exit:
add esp, 8
DEBUGF 1,"Create ARP Packet - failed\n"
mov eax, -1
ret
}
;---------------------------------------------------------------------------
;
; ARP_decrease_entry_ttls
;
; IN: /
; OUT: /
;
;---------------------------------------------------------------------------
align 4
ARP_decrease_entry_ttls:
macro ARP_decrease_entry_ttls {
local .loop
local .exit
; The TTL field is decremented every second, and is deleted when it reaches 0.
; It is refreshed every time a packet is received.
; If the TTL field is 0xFFFF it is a static entry and is never deleted.
; The status field can be the following values:
; 0x0000 entry not used
; 0x0001 entry holds a valid mapping
; 0x0002 entry contains an IP address, awaiting ARP response
; 0x0003 No response received to ARP request.
; The last status value is provided to allow the network layer to delete
; a packet that is queued awaiting an ARP response
mov ecx, [NumARP]
test ecx, ecx
jz .exit
mov ebx, ARPTable
mov esi, ARP_table
.loop:
cmp [esi + ARP_ENTRY.TTL], 0xffff ; 0xffff = static entry
je .next
.timer_loop:
dec [esi + ARP_ENTRY.TTL]
jz .time_out
cmp [ebx + ARP_ENTRY.TTL], 0xFFFF
je .timer_loop_end ;if TTL==0xFFFF then it's static entry
cmp [ebx + ARP_ENTRY.TTL], 0
jnz .timer_loop_end_with_dec ;if TTL!=0
; Ok, TTL is 0
;if Status==AWAITING_RESPONSE and TTL==0
;then we have to change it to ARP_RESPONSE_TIMEOUT
cmp [ebx + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE
jne @f
mov [ebx + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT
mov [ebx + ARP_ENTRY.TTL], word 0x000A ;10 sec
jmp .timer_loop_end
@@:
;if TTL==0 and Status==VALID_MAPPING, we have to delete it
;if TTL==0 and Status==RESPONSE_TIMEOUT, delete too
mov esi, [NumARP]
sub esi, ecx ;esi=index of entry, will be deleted
push ebx ecx
call ARP_del_entry
pop ecx ebx
jmp .timer_loop_end
.timer_loop_end_with_dec:
dec [ebx + ARP_ENTRY.TTL] ;decrease TTL
.timer_loop_end:
add ebx, ARP_ENTRY.size
loop .timer_loop
.exit:
ret
;-----------------------------------------------------------------
;
; ARP_add_entry (or update)
;
; IN: arp entry in stack: esp .IP
; esp+4 .MAC
; esp+10 .Status
; esp+12 .TTL
; esp+14
;
; OUT: eax = entry #, -1 on error
;
;----------------------------------------------------------------- ; TODO: use a mutex
align 4
ARP_add_entry:
DEBUGF 1,"ARP add entry: "
mov ecx, [NumARP]
test ecx, ecx
jz .add
mov eax, dword[esp + 4 + ARP_ENTRY.MAC]
mov bx , word[esp + 4 + ARP_ENTRY.MAC + 4]
mov esi, ARPTable
.loop:
cmp dword [esi + ARP_ENTRY.MAC], eax
jne .maybe_next
cmp word [esi + ARP_ENTRY.MAC + 4], bx
jne .maybe_next
cmp dword[esi + ARP_ENTRY.TTL], 0xFFFF ; static entry
jne .notstatic
cmp dword[esp + 4 + ARP_ENTRY.TTL], 0xFFFF
jne .error
.notstatic:
mov ebx, [NumARP]
xchg ebx, ecx
sub ecx, ebx
jmp .add
.maybe_next:
.next:
add esi, ARP_ENTRY.size
loop .loop
mov ecx, [NumARP]
cmp ecx, ARP_TABLE_SIZE
jge .error
.add:
push ecx
imul ecx, ARP_ENTRY.size
lea edi, [ecx + ARPTable]
lea esi, [esp + 8]
mov ecx, ARP_ENTRY.size/2
repz movsw
inc [NumARP]
pop eax
DEBUGF 1,"New entry created: %u\n", eax
.exit:
DEBUGF 1,"Exiting\n"
ret ARP_ENTRY.size
.error:
DEBUGF 1,"error! \n"
mov eax, -1
jmp .exit
.time_out:
cmp [esi + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE
jz .response_timeout
;-----------------------------------------------------------------
;
; ARP_del_entry
;
; IN: entry # in esi
; OUT: /
;
;-----------------------------------------------------------------
align 4
ARP_del_entry:
push esi ecx
call ARP_del_entry
pop ecx esi
DEBUGF 1,"ARP del entry %u, total entrys: %u\n", esi, [NumARP]
jmp .next
cmp esi, [NumARP]
jge .error
.response_timeout:
mov [esi + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT
mov [esi + ARP_ENTRY.TTL], 10
imul esi, ARP_ENTRY.size
mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY.size
sub ecx, esi
lea edi, [ARPTable + esi] ;edi=ptr to entry that should be deleted
lea esi, [edi + ARP_ENTRY.size] ;esi=ptr to next entry
shr ecx,1 ;ecx/2 => ARP_ENTRY_SIZE MUST BE EVEN NUMBER!
rep movsw
dec [NumARP] ;decrease arp-entries counter
DEBUGF 1,"ARP entry deleted\n"
.error:
ret
jmp .next
.exit:
}
;-----------------------------------------------------------------
;
; ARP_Handler:
;
; This function handles ARP protocol over ethernet
; (other protocols may follow in the future)
; ARP_input
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
@ -469,13 +157,16 @@ ARP_del_entry:
;
;-----------------------------------------------------------------
align 4
ARP_handler:
ARP_input:
DEBUGF 1,"ARP_Handler - start\n"
cmp ecx, 28
jl .exit
cmp word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE ; Is this a reply packet?
;---------------------
; Handle Reply packets
cmp word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE
jne .maybe_request
DEBUGF 1,"ARP_Handler - it's a reply packet from %u.%u.%u.%u\n",\
@ -486,10 +177,10 @@ ARP_handler:
jz .exit
mov eax, [edx + ARP_Packet.SenderIP]
mov esi, ARPTable+ARP_ENTRY.IP
mov esi, ARP_table
.loop:
cmp [esi], eax
cmp [esi + ARP_ENTRY.IP], eax
je .gotit
add esi, ARP_ENTRY.size
loop .loop
@ -497,10 +188,9 @@ ARP_handler:
jmp .exit
.gotit:
DEBUGF 1,"ARP_Handler - found matching entry\n"
cmp [esi+ARP_ENTRY.Status], 0x0300 ;if it is a static entry, dont touch it
cmp [esi+ARP_ENTRY.TTL], 0xffff ; if it is a static entry, dont touch it
je .exit
DEBUGF 1,"ARP_Handler - updating entry\n"
@ -516,32 +206,29 @@ ARP_handler:
jmp .exit
;------
;-----------------------
; Handle Request packets
.maybe_request:
cmp word [edx + ARP_Packet.Opcode], ARP_REQ_OPCODE ; Is this a request packet?
cmp word [edx + ARP_Packet.Opcode], ARP_REQ_OPCODE
jne .exit
call NET_ptr_to_num
DEBUGF 1,"ARP Request packet through device: %u\n", edi
inc [ARP_PACKETS_RX+4*edi]
cmp edi, -1
jz .exit
DEBUGF 1,"ARP Request packet through device: %u\n", edi
inc [ARP_PACKETS_RX+4*edi]
mov eax, edi
shl eax, 2
add eax, IP_LIST
mov eax, [eax]
mov eax, [IP_LIST+4*edi]
cmp eax, [edx + ARP_Packet.TargetIP] ; Is it looking for my IP address?
jnz .exit
jne .exit ; TODO: instead of quitting, update local entrys with matching IP's ?
push eax
push edi
; OK, it is a request for one of our MAC addresses. Build the frame and send it
; We can reuse the buffer. (faster then using ARP_create_packet)
; OK, it is a request for one of our MAC addresses.
; Build the frame and send it. We can reuse the buffer. (faster then using ARP_create_packet)
cld
lea esi, [edx + ARP_Packet.SenderMAC]
lea edi, [edx + ARP_Packet.TargetMAC]
movsd ; Move Sender Mac to Dest MAC
@ -580,10 +267,269 @@ ARP_handler:
call kernel_free
add esp, 4 ; pop (balance stack)
DEBUGF 1,"ARP_Handler - exiting\n"
DEBUGF 1,"ARP_Handler - exiting\n"
ret
;---------------------------------------------------------------------------
;
; ARP_output_request
;
; IN: ip in eax
; OUT: /
;
;---------------------------------------------------------------------------
align 4
ARP_output_request:
DEBUGF 1,"Create ARP Packet\n"
call IPv4_dest_to_dev
push eax ; DestIP
pushd [IP_LIST+edi] ; SenderIP
mov ebx, [NET_DRV_LIST+edi] ; device ptr
lea eax, [ebx + ETH_DEVICE.mac] ; local device mac
mov edx, ETH_BROADCAST ; broadcast mac
mov ecx, ARP_Packet.size
mov di, ETHER_ARP
call ETH_output
jz .exit
mov ecx, eax
mov [edi + ARP_Packet.HardwareType], 0x0100 ; Ethernet
mov [edi + ARP_Packet.ProtocolType], 0x0008 ; IP
mov [edi + ARP_Packet.HardwareSize], 6 ; MAC-addr length
mov [edi + ARP_Packet.ProtocolSize], 4 ; IP-addr length
mov [edi + ARP_Packet.Opcode], ARP_REQ_OPCODE ; Request
add edi, ARP_Packet.SenderMAC
lea esi, [ebx + ETH_DEVICE.mac] ; SenderMac
movsw ;
movsd ;
pop eax ; SenderIP
stosd ;
mov eax, -1 ; DestMac
stosd ;
stosw ;
pop eax ; DestIP
stosd ;
DEBUGF 1,"ARP Packet for device %x created successfully\n", ebx
push edx ecx
call [ebx + NET_DEVICE.transmit]
ret
.exit:
add esp, 4+4
DEBUGF 1,"Create ARP Packet - failed\n"
sub eax, eax
ret
;-----------------------------------------------------------------
;
; ARP_add_entry (or update)
;
; IN: esi = ptr to entry (can easily be made on the stack)
; OUT: eax = entry #, -1 on error
;
;----------------------------------------------------------------- ; TODO: use a mutex
align 4
ARP_add_entry:
DEBUGF 1,"ARP add entry: "
mov ecx, [NumARP]
test ecx, ecx ; first entry?
jz .add
cmp ecx, ARP_TABLE_SIZE ; list full ?
jge .error
mov eax, dword[esi + ARP_ENTRY.MAC]
mov bx , word[esi + ARP_ENTRY.MAC + 4]
mov edi, ARP_table
.loop:
cmp dword [edi + ARP_ENTRY.MAC], eax ; Check for duplicate MAC's
jne .maybe_next ;
cmp word [edi + ARP_ENTRY.MAC + 4], bx ;
jne .maybe_next ;
cmp dword[edi + ARP_ENTRY.TTL], 0xFFFF ; static entry
jne .notstatic
cmp dword[esi + ARP_ENTRY.TTL], 0xFFFF
jne .error
.notstatic:
neg ecx
add ecx, [NumARP]
jmp .add
.maybe_next:
add esi, ARP_ENTRY.size
loop .loop
mov ecx, [NumARP]
.add:
push ecx
imul ecx, ARP_ENTRY.size
lea edi, [ecx + ARP_table]
mov ecx, ARP_ENTRY.size/2
rep movsw
lea esi, [edi - ARP_ENTRY.size]
inc [NumARP]
pop eax
DEBUGF 1,"New entry created: %u\n", eax
.exit:
DEBUGF 1,"Exiting\n"
ret
.error:
DEBUGF 1,"error! \n"
mov eax, -1
ret
;-----------------------------------------------------------------
;
; ARP_del_entry
;
; IN: esi = ptr to arp entry
; OUT: /
;
;-----------------------------------------------------------------
align 4
ARP_del_entry:
DEBUGF 1,"ARP del entry %x, total entrys: %u\n", esi, [NumARP]
mov ecx, ARP_table + (ARP_TABLE_SIZE - 1) * ARP_ENTRY.size
sub ecx, esi
shr ecx, 1
mov edi, esi
lea esi, [edi + ARP_ENTRY.size]
rep movsw
dec [NumARP]
DEBUGF 1,"ARP entry deleted\n"
ret
;-----------------------------------------------------------------
;
; ARP_IP_to_MAC
;
; This function translates an IP address to a MAC address
;
; IN: eax = IPv4 address
; OUT: eax = -1 on error, -2 means request send
; else, ax = first two bytes of mac (high 16 bits of eax will be 0)
; ebx = last four bytes of mac
;
;-----------------------------------------------------------------
align 4
ARP_IP_to_MAC:
DEBUGF 1,"ARP_IP_to_MAC\n"
cmp eax, 0xffffffff
je .broadcast
; if ((Remote IP & subnet_mask) == (local IP & subnet_mask ))
; destination is on same subnet
; else, destination is remote and must use a gateway
call IPv4_dest_to_dev
mov ebx, [IP_LIST + edi]
and ebx, [SUBNET_LIST + edi]
mov ecx, eax
and ecx, [SUBNET_LIST + edi]
cmp ecx, ebx
je .local
mov eax, [GATEWAY_LIST + edi]
DEBUGF 1,"requested IP is not on subnet, using default gateway\n"
;--------------------------------
; Try to find the IP in ARP_table
.local:
mov ecx, [NumARP]
test ecx, ecx
jz .not_in_list
mov esi, ARP_table + ARP_ENTRY.IP
.scan_loop:
cmp [esi], eax
je .found_it
add esi, ARP_ENTRY.size
loop .scan_loop
.not_in_list:
DEBUGF 1,"IP not found on list, preparing for ARP request\n"
;--------------------
; Send an ARP request
push eax
pushw ARP_REQUEST_TTL
pushw ARP_AWAITING_RESPONSE
pushd 0
pushw 0
pushd eax
mov esi, esp
call ARP_add_entry
add esp, ARP_ENTRY.size
cmp eax, -1
je .full
pop eax
call ARP_output_request
mov eax, -2 ; request send
ret
.found_it:
DEBUGF 1,"found IP in ARPTable\n"
cmp [esi + ARP_ENTRY.Status], 1
jne .invalid
movzx eax, word [esi+ARP_ENTRY.MAC]
mov ebx, dword[esi+ARP_ENTRY.MAC+2]
ret
.invalid:
mov eax, -1
ret
.full:
DEBUGF 1,"ARP table is full!\n"
pop eax
mov eax, -1
ret
.broadcast:
mov eax, 0x0000ffff
mov ebx, 0xffffffff
ret
;-----------------------------------------------------------------
@ -643,7 +589,7 @@ ARP_API:
; edi = pointer to buffer
; ecx = # entry
imul ecx, ARP_ENTRY.size
add ecx, ARPTable
add ecx, ARP_table
mov esi, ecx
mov ecx, ARP_ENTRY.size/2
rep movsw
@ -653,16 +599,15 @@ ARP_API:
.write:
; esi = pointer to buffer
sub esp, ARP_ENTRY.size
mov edi, esp
mov ecx, ARP_ENTRY.size/2
rep movsw
call ARP_add_entry ;out: eax = entry number, -1 on error
ret
.remove:
; ecx = # entry
mov esi, ecx
cmp ecx, [NumARP]
jge .error
imul ecx, ARP_ENTRY.size
lea esi, [ARP_table + ecx]
call ARP_del_entry
ret

View File

@ -53,6 +53,73 @@ struct FRAGMENT_entry ; This structure will replace the ethernet header
.Data: ; Ip header begins here (we will need the IP header to re-construct the complete packet)
ends
macro IPv4_checksum ptr {
; This is the fast procedure to create or check a IP header without options
; To create a new checksum, the checksum field must be set to 0 before computation
; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct
push ebx
xor ebx, ebx
add bl, [ptr+1]
adc bh, [ptr+0]
adc bl, [ptr+3]
adc bh, [ptr+2]
adc bl, [ptr+5]
adc bh, [ptr+4]
adc bl, [ptr+7]
adc bh, [ptr+6]
adc bl, [ptr+9]
adc bh, [ptr+8]
; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation
adc bl, [ptr+13]
adc bh, [ptr+12]
adc bl, [ptr+15]
adc bh, [ptr+14]
adc bl, [ptr+17]
adc bh, [ptr+16]
adc bl, [ptr+19]
adc bh, [ptr+18]
adc ebx, 0
push ecx
mov ecx, ebx
shr ecx, 16
and ebx, 0xffff
add ebx, ecx
mov ecx, ebx
shr ecx, 16
add ebx, ecx
not bx
jnz .not_zero
dec bx
.not_zero:
xchg bl, bh
pop ecx
neg word [ptr+10] ; zero will stay zero so we just get the checksum
add word [ptr+10], bx ; , else we will get (new checksum - old checksum) in the end, wich should be 0 :)
pop ebx
}
align 4
uglobal
@ -74,30 +141,49 @@ endg
;
; This function resets all IP variables
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
align 4
IPv4_init:
macro IPv4_init {
or eax, -1
xor eax, eax
mov edi, IP_LIST
mov ecx, 4*MAX_IP
rep stosd
inc eax
mov edi, FRAGMENT_LIST
mov ecx, FRAGMENT_slot.size*MAX_FRAGMENTS/4 + 2*MAX_IP
rep stosd
ret
}
;-----------------------------------------------------------------
;
; Decrease TimeToLive of all fragment slots
;
;-----------------------------------------------------------------
macro IPv4_decrease_fragment_ttls {
local .loop
mov esi, FRAGMENT_LIST
mov ecx, MAX_FRAGMENTS
.loop:
cmp [esi + FRAGMENT_slot.ttl], 0
je .try_next
dec [esi + FRAGMENT_slot.ttl]
jnz .try_next
DEBUGF 1,"Fragment slot timed-out!\n"
;;; TODO: clear all entry's of timed-out slot
.try_next:
add esi, 4
loop .loop
}
;-----------------------------------------------------------------
;
; IPv4_Handler:
; IPv4_input:
;
; Will check if IP Packet isnt damaged
; and call appropriate handler. (TCP/UDP/ICMP/..)
@ -112,7 +198,7 @@ IPv4_init:
;
;-----------------------------------------------------------------
align 4
IPv4_handler: ; TODO: implement handler for IP options
IPv4_input: ; TODO: implement handler for IP options
; TODO2: add code for raw sockets
DEBUGF 1,"IPv4_Handler, packet from: %u.%u.%u.%u ",\
@ -137,13 +223,8 @@ IPv4_handler: ; TODO: implement handler for IP options
;-------------------------------
; Now, re-calculate the checksum
push edx ebx
mov esi, edx
call IPv4_checksum
pop ebx edx
cmp [edx + IPv4_Packet.HeaderChecksum], 0
jne .dump ; if checksum isn't valid then dump packet
IPv4_checksum edx
jnz .dump ; if checksum isn't valid then dump packet
DEBUGF 1,"IPv4 Checksum is correct\n"
@ -435,10 +516,7 @@ IPv4_handler: ; TODO: implement handler for IP options
; mov esi, edx ; This prints the IP packet to the debug board (usefull when using serial output debug..)
; ;
; @@: ;
; lodsb ;
; DEBUGF 1,"%x ", eax:2 ;
; loop @r ;
; packet_to_debug
jmp .handle_it ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
@ -460,9 +538,6 @@ IPv4_handler: ; TODO: implement handler for IP options
;-----------------------------------------------------------------
;
; find fragment slot
@ -501,70 +576,15 @@ IPv4_find_fragment_slot:
ret
;-----------------------------------------------------------------
;
; Decrease TimeToLive of all fragment slots
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
align 4
IPv4_decrease_fragment_ttls:
mov esi, FRAGMENT_LIST
mov ecx, MAX_FRAGMENTS
.loop:
cmp [esi + FRAGMENT_slot.ttl], 0
je .try_next
dec [esi + FRAGMENT_slot.ttl]
jnz .try_next
DEBUGF 1,"Fragment slot timed-out!\n"
;;; TODO: clear all entry's of timed-out slot
.try_next:
add esi, 4
loop .loop
ret
;------------------------------------------------------------------
;
;
; IN: dword [esp] = pointer to packet to be fragmented
; dword [esp+4] = buffer size
; edx = pointer to IPv4 header in that packet
; ecx = data length
; ebx = device structure
;
; OUT: /
;
;------------------------------------------------------------------
align 4
IPv4_fragment:
;;; TODO: write code here
call kernel_free
add esp, 4
ret
;------------------------------------------------------------------
;
; Create_IPv4_Packet
; IPv4_output
;
; IN: eax = dest ip
; ebx = source ip
; ecx = data length
; dx = fragment id ;;;;
; di = protocol
; dx = fragment id
; di = TTL shl 8 + protocol
;
; OUT: eax = pointer to buffer start
; ebx = pointer to device struct (needed for sending procedure)
@ -574,184 +594,224 @@ IPv4_fragment:
;
;------------------------------------------------------------------
align 4
IPv4_create_packet:
IPv4_output:
DEBUGF 1,"Create IPv4 Packet (size=%u)\n", ecx
DEBUGF 1,"IPv4_create_packet: size=%u\n", ecx
cmp ecx, 65500 ; Max IPv4 packet size
jg .exit_
test ebx, ebx ; if source ip = 0
jnz .ip_ok ; and local ip is valid
; use local ip instead
cmp [IP_LIST],0xffffffff ;
je .ip_ok ; TODO: find solution to send broadcast
; on device other then device 0
mov ebx, [IP_LIST] ;
;
.ip_ok: ;
cmp ecx, 65500 ; Max IPv4 packet size
jg .too_large
push ecx eax ebx dx di
cmp eax, -1
je .broadcast ; If it is broadcast, just send
call ARP_IP_to_MAC
test eax, 0xffff0000 ; error bits
jnz .arp_error
push ebx ; push the mac
push ax
call IPv4_dest_to_dev
inc [IP_PACKETS_TX+edi]
mov ebx, [NET_DRV_LIST+edi]
lea eax, [ebx + ETH_DEVICE.mac]
mov edx, esp
mov ecx, [esp + 18]
add ecx, IPv4_Packet.DataOrOptional
mov di , ETHER_IPv4
call ETH_output
jz .error
add esp, 6 ; pop the mac
mov [edi + IPv4_Packet.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
mov [edi + IPv4_Packet.TypeOfService], 0 ; nothing special, just plain ip packet
mov [edi + IPv4_Packet.TotalLength], cx
rol [edi + IPv4_Packet.TotalLength], 8 ; internet byte order
mov [edi + IPv4_Packet.FlagsAndFragmentOffset], 0x0000
mov [edi + IPv4_Packet.HeaderChecksum], 0
popw word [edi + IPv4_Packet.TimeToLive] ; ttl shl 8 + protocol
; [edi + IPv4_Packet.Protocol]
popw [edi + IPv4_Packet.Identification] ; fragment id
popd [edi + IPv4_Packet.SourceAddress]
popd [edi + IPv4_Packet.DestinationAddress]
pop ecx
IPv4_checksum edi
add edi, IPv4_Packet.DataOrOptional
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", ebx
ret
.error:
add esp, 6
.arp_error:
add esp, 4+4+4+2+2
.too_large:
DEBUGF 1,"IPv4_create_packet: Failed\n"
sub edi, edi
ret
;--------------------------------------------------------
;
;
; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented
; dword [esp+4] = buffer size
; esi = pointer to ip header in that buffer
; ecx = max size of fragments
;
; OUT: /
;
;--------------------------------------------------------
align 4
IPv4_fragment:
DEBUGF 1,"IPv4_fragment\n"
and ecx, not 111b ; align 4
cmp ecx, IPv4_Packet.DataOrOptional + 8 ; must be able to put at least 8 bytes
jl .err2
push esi ecx
mov eax, [esi + IPv4_Packet.DestinationAddress]
call ARP_IP_to_MAC
pop ecx esi
cmp eax, -1
je .not_found
jz .err2
push ebx
push ax
jmp .send
mov ebx, [NET_DRV_LIST]
lea eax, [ebx + ETH_DEVICE.mac]
push eax
.broadcast:
push word -1
push dword -1
.send:
call IPv4_dest_to_dev
inc [IP_PACKETS_TX+4*edi]
mov edx, [NET_DRV_LIST + 4*edi]
lea eax, [edx + ETH_DEVICE.mac]
mov ebx, esp
mov ecx, [esp+18] ;; 18 or 22 ??
add ecx, IPv4_Packet.DataOrOptional
push esi ; ptr to ip header
sub ecx, 20 ; substract header size
push ecx ; max data size
push dword 0 ; offset
.new_fragment:
DEBUGF 1,"Ipv4_fragment - new_fragmentn"
mov eax, [esp + 3*4]
lea ebx, [esp + 4*4]
mov di , ETHER_IPv4
;;; TODO: detect if packet is too large for ethernet, if so, call IPv4_fragment
call ETH_create_packet ;;; TODO: figure out a way to make this work with other protocols too
add esp, 6
test edi, edi
jz .exit
call ETH_output
mov [edi + IPv4_Packet.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
mov [edi + IPv4_Packet.TypeOfService], 0
xchg ch, cl
cmp edi, -1
jz .err
; copy header
mov esi, [esp + 2*4]
mov ecx, 5 ; 5 dwords: TODO: use IHL field of the header!
rep movsd
; copy data
mov esi, [esp + 2*4]
add esi, 20
add esi, [esp] ; offset
mov ecx, [esp + 1*4]
DEBUGF 1,"IPv4_fragment - copying data (%u bytes)\n", ecx
rep movsb
; now, correct header
mov ecx, [esp + 1*4]
add ecx, 20
xchg cl, ch
mov [edi + IPv4_Packet.TotalLength], cx
mov [edi + IPv4_Packet.FlagsAndFragmentOffset], 0x0000
mov [edi + IPv4_Packet.TimeToLive], 128
mov ecx, [esp] ; offset
xchg cl, ch
; cmp dword[esp + 4*4], 0 ; last fragment?;<<<<<<
; je .last_fragment
or cx, 1 shl 2 ; more fragments
; .last_fragment:
mov [edi + IPv4_Packet.FlagsAndFragmentOffset], cx
mov [edi + IPv4_Packet.HeaderChecksum], 0
pop cx
mov [edi + IPv4_Packet.Protocol], cl
pop cx
mov [edi + IPv4_Packet.Identification], cx
pop ecx
mov [edi + IPv4_Packet.SourceAddress], ecx
pop ecx
mov [edi + IPv4_Packet.DestinationAddress], ecx
push eax edx esi
mov esi, edi
call IPv4_checksum
pop esi edx eax ecx
add edi, IPv4_Packet.DataOrOptional
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
mov ecx, [esp + 1*4]
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", ebx
push edx eax
IPv4_checksum edi
call [ebx + NET_DEVICE.transmit]
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
mov ecx, [esp+4]
add [esp], ecx
mov ecx, [esp+3*4+6+4] ; ptr to begin of buff
add ecx, [esp+3*4+6+4+4] ; buff size
sub ecx, [esp+2*4] ; ptr to ip header
add ecx, [esp] ; offset
DEBUGF 1,"Ipv4_fragment - bytes remaining: %u\n", ecx
cmp ecx, [esp+1*4]
jge .new_fragment
mov [esp+4], ecx ; set fragment size to remaining packet size
jmp .new_fragment
.err:
DEBUGF 1,"Ipv4_fragment - failed\n"
.done:
add esp, 12 + 4 + 6
.err2:
DEBUGF 1,"Ipv4_fragment - dumping\n"
call kernel_free
add esp, 4
ret
.not_found:
DEBUGF 1,"Create IPv4 Packet - ARP entry not found!\n"
;;;;;;
.exit:
add esp, 16
.exit_:
DEBUGF 1,"Create IPv4 Packet - failed\n"
and edi, 0
ret
align 4
IPv4_checksum:
; This is the fast procedure to create or check a IP header without options
;
; To create a new checksum, the checksum field must be set to 0 before computation
;
; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct
xor edx, edx
add dl, [esi+1]
adc dh, [esi+0]
adc dl, [esi+3]
adc dh, [esi+2]
adc dl, [esi+5]
adc dh, [esi+4]
adc dl, [esi+7]
adc dh, [esi+6]
adc dl, [esi+9]
adc dh, [esi+8]
; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation
adc dl, [esi+13]
adc dh, [esi+12]
adc dl, [esi+15]
adc dh, [esi+14]
adc dl, [esi+17]
adc dh, [esi+16]
adc dl, [esi+19]
adc dh, [esi+18]
adc edx, 0
call checksum_2
neg word [esi+10] ; zero will stay zero so we just get the checksum
add word [esi+10], dx ; , else we will get (new checksum - old checksum) in the end, wich should be 0 :)
ret
;---------------------------------------------------------------------------
;
; IPv4_dest_to_dev
;
; IN: Destination IP in eax
; OUT: device id in edi
; IN: eax = Destination IP
; OUT: edi = device id * 4
;
;---------------------------------------------------------------------------
align 4
IPv4_dest_to_dev:
DEBUGF 1,"IPv4 destination to device: "
cmp eax, 0xffffffff
je .invalid
xor edi, edi
mov ecx, MAX_IP
.loop:
mov ebx, [IP_LIST+edi] ; we dont need to worry about non exisiting ip interfaces
and ebx, [SUBNET_LIST+edi] ; they have IP and SUBNET set to all one's, so they will have no match except 255.255.255.255
; (only a moron would insert that ip into this function..)
mov ebx, [IP_LIST+edi]
and ebx, [SUBNET_LIST+edi]
jz .next
mov edx, eax
and edx, [SUBNET_LIST+edi]
cmp ebx, edx
je .found_it
.next:
add edi, 4
loop .loop
xor edi, edi ; if none found, use device 0 as default device
.invalid:
xor edi, edi ; if none found, use device 0 as default device
.found_it:
shr edi, 2
DEBUGF 1,"%u\n",edi
DEBUGF 1,"IPv4_dest_to_dev: %u\n", edi
ret
@ -868,8 +928,4 @@ IPv4_API:
add eax, GATEWAY_LIST
mov [eax], ecx
xor eax, eax
ret
ret

View File

@ -56,37 +56,33 @@ endg
;
; This function resets all ethernet variables
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
align 4
ETH_init:
macro ETH_init {
mov [ETH_RUNNING], 0
ret
}
;-----------------------------------------------------------------
;
; ETH_Receiver:
; ETH_input
;
; This function is called by ethernet drivers,
; It pushes the received ethernet packets onto the eth_in_queue
;
; IN: [esp] = Pointer to buffer
; [esp-4] = size of buffer
; [esp+4] = size of buffer
; ebx = pointer to eth_device
; OUT: /
;
;-----------------------------------------------------------------
align 4
ETH_receiver:
ETH_input:
mov eax, [esp]
mov ecx, [esp+4]
DEBUGF 1,"ETH_Handler - size: %u\n", ecx
DEBUGF 1,"ETH_input - size: %u\n", ecx
cmp ecx, 60 ; check packet length
jl .dump
sub ecx, ETH_FRAME.Data
@ -95,10 +91,10 @@ ETH_receiver:
mov ax , [eax + ETH_FRAME.Type]
cmp ax, ETHER_IPv4
je IPv4_handler
je IPv4_input
cmp ax, ETHER_ARP
je ARP_handler
je ARP_input
; cmp ax, ETHER_PPP_DISCOVERY
; je PPPOE_discovery
@ -106,19 +102,19 @@ ETH_receiver:
DEBUGF 2,"Unknown ethernet packet type %x\n", ax
.dump:
DEBUGF 2,"ETH_Handler - dumping\n"
DEBUGF 2,"ETH_input - dumping\n"
call kernel_free
add esp, 4
ret
;-----------------------------------------------------------------
;
; ETH_create_packet
; ETH_output
;
; IN: eax = pointer to source mac
; ebx = pointer to destination mac
; ebx = device ptr
; ecx = packet size
; edx = device number
; edx = pointer to destination mac
; di = protocol
;
; OUT: edi = 0 on error, pointer to buffer otherwise
@ -129,62 +125,60 @@ ETH_receiver:
;
;-----------------------------------------------------------------
align 4
ETH_create_packet:
ETH_output:
DEBUGF 1,"Creating Ethernet Packet (size=%u): \n", ecx
DEBUGF 1,"ETH_output: size=%u device:%x\n", ecx, ebx
push esi
mov esi, [NET_DRV_LIST] ;;; TODO: FIXME
cmp ecx, [esi + NET_DEVICE.mtu]
pop esi
cmp ecx, [ebx + NET_DEVICE.mtu]
jg .exit
push ecx di eax ebx edx
push ecx ; << 1
push di eax edx ; << 2
add ecx, ETH_FRAME.Data
push ecx
push ecx
call kernel_alloc
push ecx ; << 3
push ecx ; << 4
call kernel_alloc ; >> 4
test eax, eax
jz .out_of_ram
mov edi, eax
test edi, edi
jz .pop_exit
pop ecx
pop edx
pop ecx ; >> 3
pop esi
pop esi ; >> 2
movsd
movsw
pop esi
pop esi ; >> 2
movsd
movsw
pop ax
pop ax ; >> 2
stosw
lea eax, [edi - ETH_FRAME.Data] ; Set eax to buffer start
mov edx, ecx ; Set ebx to complete buffer size
pop ecx
mov edx, ecx ; Set edx to complete buffer size
xor ebx, ebx ;;;; TODO: Fixme
mov ebx, [NET_DRV_LIST + ebx]
pop ecx ; >> 1
cmp edx, 46 + ETH_FRAME.Data ; If data size is less then 46, add padding bytes
jge .continue
mov edx, 46 + ETH_FRAME.Data
.continue:
DEBUGF 1,"done: %x size:%u device:%x\n", eax, edx, ebx
cmp edx, 60-1 ; minimum ethernet packet size
jle .adjust_size
DEBUGF 1,"ETH_output: done: %x total size: %u\n", eax, edx
ret
.pop_exit:
DEBUGF 2,"Out of ram space!!\n"
add esp, 18
and edi, 0
.adjust_size:
mov edx, 60
ret
.out_of_ram:
DEBUGF 2,"ETH_output: Out of ram space!!\n"
add esp, 3*4+2+4
sub edi, edi
ret
.exit:
DEBUGF 2,"Packet too large!\n"
and edi, 0
DEBUGF 2,"ETH_output: Packet too large!\n"
sub edi, edi
;;; dec edi
ret

View File

@ -109,21 +109,16 @@ endg
;
; ICMP_init
;
; This function resets all ICMP variables
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
align 4
ICMP_init:
macro ICMP_init {
xor eax, eax
mov edi, ICMP_PACKETS_TX
mov ecx, 2*MAX_IP
rep stosd
ret
}
@ -235,7 +230,7 @@ ICMP_input:
call IPv4_dest_to_dev
cmp edi,-1
je .dump
inc [ICMP_PACKETS_RX+4*edi]
inc [ICMP_PACKETS_RX+edi]
DEBUGF 1,"Found valid ICMP packet for socket %x\n", esi
@ -284,10 +279,10 @@ ICMP_output:
push esi edi edx
add ecx, ICMP_Packet.Data
mov di , IP_PROTO_ICMP
mov di , IP_PROTO_ICMP SHL 8 + 128 ; TTL
shr edx, 16
call IPv4_create_packet
call IPv4_output
jz .exit
DEBUGF 1,"full icmp packet size: %u\n", edx

View File

@ -5,11 +5,13 @@
;; ;;
;; SOCKET.INC ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; based on code by mike.dld ;;
;; Written by hidnplayr@kolibrios.org, ;;
;; and Clevermouse. ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; Based on code by mike.dld ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -31,9 +33,7 @@ virtual at 0
.errorcode dd ?
.options dd ?
.SO_SND.SB_CC dd ? ;;;;; socket options: number of bytes in socket
.SO_RCV.SB_CC dd ?
.state dd ? ;;;;;;;;;
.state dd ?
.end:
end virtual
@ -51,15 +51,6 @@ virtual at SOCKET.end
.end:
end virtual
virtual at SOCKET.end
SOCKET_virtual:
.ConnectedTo dd ? ; Socket number of other socket this one is connected to
.end:
end virtual
virtual at IP_SOCKET.end
TCP_SOCKET:
@ -114,7 +105,6 @@ virtual at IP_SOCKET.end
;----------------------
; Transmit timing stuff
.t_idle dd ?
.t_rtt dd ?
.t_rtseq dd ?
@ -125,7 +115,6 @@ virtual at IP_SOCKET.end
;-----------------
; Out-of-band data
.t_oobflags dd ?
.t_iobc dd ?
.t_softerror dd ?
@ -133,7 +122,6 @@ virtual at IP_SOCKET.end
;---------
; RFC 1323
.SND_SCALE db ? ; Scale factor
.RCV_SCALE db ?
.request_r_scale db ?
@ -146,12 +134,11 @@ virtual at IP_SOCKET.end
;-------
; Timers
.timer_retransmission dw ? ; rexmt
.timer_retransmission dw ? ; rexmt
.timer_ack dw ?
.timer_persist dw ?
.timer_keepalive dw ? ; keepalive/syn timeout
.timer_timed_wait dw ? ; also used as 2msl timer
.timer_keepalive dw ? ; keepalive/syn timeout
.timer_timed_wait dw ? ; also used as 2msl timer
.end:
end virtual
@ -176,9 +163,32 @@ virtual at IP_SOCKET.end
.end:
end virtual
struc RING_BUFFER {
.start_ptr dd ? ; Pointer to start of buffer
.end_ptr dd ? ; pointer to end of buffer
.read_ptr dd ? ; Read pointer
.write_ptr dd ? ; Write pointer
.size dd ? ; Number of bytes buffered
}
virtual at 0
RING_BUFFER RING_BUFFER
end virtual
virtual at TCP_SOCKET.end
rcv RING_BUFFER
snd RING_BUFFER
STREAM_SOCKET:
.end:
end virtual
struct socket_queue_entry
; .owner dd ?
.data_ptr dd ?
.buf_ptr dd ?
.data_size dd ?
@ -186,7 +196,6 @@ struct socket_queue_entry
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
@ -204,24 +213,41 @@ endg
;
; SOCKET_init
;
; -
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
align 4
socket_init:
macro SOCKET_init {
xor eax, eax
mov edi, net_sockets
mov ecx, 4
rep stosd
mov [last_UDP_port], MIN_EPHEMERAL_PORT
mov [last_TCP_port], MIN_EPHEMERAL_PORT
;--- for random port --
ret
mov al, 0x0 ; set up 1s timer
out 0x70, al
in al, 0x71
;----------------------
@@:
pseudo_random eax
cmp ax, MIN_EPHEMERAL_PORT
jl @r
cmp ax, MAX_EPHEMERAL_PORT
jg @r
mov [last_UDP_port], ax
@@:
pseudo_random eax
cmp ax, MIN_EPHEMERAL_PORT
jl @r
cmp ax, MAX_EPHEMERAL_PORT
jg @r
mov [last_TCP_port], ax
}
;-----------------------------------------------------------------
@ -232,11 +258,20 @@ socket_init:
align 4
sys_socket:
cmp ebx, 8 ; highest possible number
jg s_error
lea ebx, [.table + 4*ebx]
jg @f
lea ebx, [sock_sysfn_table + 4*ebx]
jmp dword [ebx]
@@:
cmp ebx, 255
jz SOCKET_debug
.table:
s_error:
DEBUGF 1,"socket error\n"
mov dword [esp+32], -1
ret
sock_sysfn_table:
dd SOCKET_open ; 0
dd SOCKET_close ; 1
dd SOCKET_bind ; 2
@ -249,12 +284,6 @@ sys_socket:
; dd SOCKET_set_opt ; 9
s_error:
DEBUGF 1,"socket error\n"
mov dword [esp+32], -1
ret
;-----------------------------------------------------------------
;
@ -280,6 +309,40 @@ SOCKET_open:
mov [esp+32], edi
cmp ecx, AF_INET4
jnz .no_stream
push [IP_LIST] ;;;;
pop [eax + IP_SOCKET.LocalIP] ;;;;
cmp edx, IP_PROTO_TCP
jnz .no_stream
mov esi, eax
stdcall kernel_alloc, SOCKET_MAXDATA
mov [esi + rcv.start_ptr], eax
mov [esi + rcv.write_ptr], eax
mov [esi + rcv.read_ptr], eax
mov [esi + rcv.size], 0
add eax, SOCKET_MAXDATA
mov [esi + rcv.end_ptr], eax
stdcall kernel_alloc, SOCKET_MAXDATA
mov [esi + snd.start_ptr], eax
mov [esi + snd.write_ptr], eax
mov [esi + snd.read_ptr], eax
mov [esi + snd.size], 0
add eax, SOCKET_MAXDATA
mov [esi + snd.end_ptr], eax
ret
.no_stream:
push edi
init_queue (eax + SOCKET_QUEUE_LOCATION)
pop edi
ret
@ -347,9 +410,6 @@ SOCKET_bind:
DEBUGF 1,"using local port: %u\n", bx
mov word [eax + UDP_SOCKET.LocalPort], bx
mov ebx, dword [edx + 4]
mov dword [eax + IP_SOCKET.LocalIP], ebx
DEBUGF 1,"local ip: %u.%u.%u.%u\n",\
[eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\
[eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1
@ -411,21 +471,11 @@ SOCKET_connect:
.tcp:
; set sequence number
mov ebx, [TCP_sequence_num]
add [TCP_sequence_num], 6400
mov [eax + TCP_SOCKET.ISS], ebx
mov [eax + TCP_SOCKET.timer_keepalive], 120 ; 120*630ms => 75,6 seconds
lea ebx, [eax + SOCKET.lock]
call wait_mutex
; fill in remote port and IP
;;;;;; mov [eax + TCP_SOCKET.wndsizeTimer], 0 ; Reset the window timer.
mov bx , word [edx + 2]
mov [eax + TCP_SOCKET.RemotePort], bx
DEBUGF 1,"remote port: %u\n", bx
@ -435,21 +485,25 @@ SOCKET_connect:
; check if local port and IP is ok
cmp [eax + IP_SOCKET.LocalIP], 0
jne @f
push [IP_LIST] ;;;;; device zero = default
pop [eax + IP_SOCKET.LocalIP]
@@:
cmp [eax + TCP_SOCKET.LocalPort], 0
jne @f
call SOCKET_find_port
@@:
DEBUGF 1,"local port: %u\n", [eax + TCP_SOCKET.LocalPort]:2
DEBUGF 1,"remote port: %u\n", [eax + TCP_SOCKET.LocalPort]:2
;;;;;
mov [eax + TCP_SOCKET.timer_persist], 0
mov [eax + TCP_SOCKET.t_state], TCB_SYN_SENT
mov ebx, [TCP_sequence_num]
add [TCP_sequence_num], 6400
mov [eax + TCP_SOCKET.ISS], ebx
mov [eax + TCP_SOCKET.timer_keepalive], 120 ; 120*640ms => 75,6 seconds
; mov [eax + TCP_SOCKET.t_state], TCB_SYN_SENT
;;;; mov [ebx + TCP_SOCKET.timer_retransmission],
push eax
call TCP_output
pop eax
mov [eax + SOCKET.lock], 0
@ -583,11 +637,11 @@ SOCKET_close:
test [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED ;;;;;;
jz .free
call TCP_output
;;; call TCP_output
mov dword [esp+32], 0
;;; mov dword [esp+32], 0
ret
;;; ret
; state must be LISTEN, SYN_SENT, CLOSED or maybe even invalid
; so, we may destroy the socket
@ -688,6 +742,12 @@ SOCKET_send:
.af_inet4:
DEBUGF 1,"af_inet4\n"
cmp [eax + IP_SOCKET.LocalIP], 0
jne @f
mov ebx, [IP_LIST] ;;;;
mov dword [eax + IP_SOCKET.LocalIP], ebx
@@:
cmp [eax + SOCKET.Type], IP_PROTO_TCP
je .tcp
@ -790,6 +850,35 @@ SOCKET_get_opt:
ret
;-----------------------------------------------------------------
;
; SOCKET_debug
;
; Copies socket variables to application buffer
;
; IN: ecx = socket number
; edx = pointer to buffer
;
; OUT: -1 on error
;-----------------------------------------------------------------
align 4
SOCKET_debug:
DEBUGF 1,"socket_debug\n"
call SOCKET_num_to_ptr
jz s_error
mov esi, eax
mov edi, edx
mov ecx, SOCKETBUFFSIZE/4
rep movsd
mov dword [esp+32], 0
ret
;-----------------------------------------------------------------
;
; SOCKET_find_port
@ -939,6 +1028,188 @@ SOCKET_input:
ret
;-----------------------------------------------------------------
;
; SOCKET_ring_add
;
; Adds data to a stream socket
;
; IN: eax = ptr to ring struct
; ecx = data size
; esi = ptr to data
;
; OUT: eax = number of bytes stored
;
;-----------------------------------------------------------------
align 4
SOCKET_ring_add:
DEBUGF 1,"SOCKET_ring_add: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
mov edi, [eax + RING_BUFFER.size]
add edi, ecx
cmp edi, SOCKET_MAXDATA
jg .too_large
mov [eax + RING_BUFFER.size], edi ; update size
.copy:
push ecx ;<<<< 1
mov edi, [eax + RING_BUFFER.write_ptr] ; set write ptr in edi
add [eax + RING_BUFFER.write_ptr], ecx ; update write pointer
mov edx, [eax + RING_BUFFER.end_ptr]
cmp edx, [eax + RING_BUFFER.write_ptr]
jg .copy_in_2
je .wrap_write_ptr
.copy_more:
push ecx
and ecx, 3
rep movsb
pop ecx
shr ecx, 2
rep movsd
pop ecx ; >>>> 1/2
DEBUGF 2,"Copied %u bytes\n", ecx
ret
.too_large:
mov ecx, SOCKET_MAXDATA ; calculate number of bytes available in buffer
sub ecx, [eax + RING_BUFFER.size]
jz .full
mov [eax + RING_BUFFER.size], SOCKET_MAXDATA ; update size, we will fill buffer completely
jmp .copy
.full:
DEBUGF 2,"Ring buffer is full!\n"
xor ecx, ecx
ret
.copy_in_2:
DEBUGF 1,"Copying in 2 passes\n"
mov edx, ecx
mov ecx, [eax + RING_BUFFER.end_ptr] ; find number of bytes till end of buffer
sub ecx, edi
sub edx, ecx
push edx ; <<<< 2
mov edi, [eax + RING_BUFFER.start_ptr]
call .copy_more
.wrap_write_ptr:
sub [eax + RING_BUFFER.write_ptr], SOCKET_MAXDATA ; update write pointer
jmp .copy_more
;-----------------------------------------------------------------
;
; SOCKET_ring_read
;
; reads the data, but let the data remain in the buffer
;
; IN: eax = ptr to ring struct
; ecx = buffer size
; edi = ptr to buffer
;
; OUT: eax = number of bytes read
;
;-----------------------------------------------------------------
align 4
SOCKET_ring_read:
DEBUGF 1,"SOCKET_ring_read: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
cmp [eax + RING_BUFFER.size], ecx ; update size
jl .too_large
mov esi, [eax + RING_BUFFER.read_ptr] ; update read ptr
.copy:
push ecx ;<<<< 1
mov edx, [eax + RING_BUFFER.read_ptr]
add edx, ecx
cmp edx, [eax + RING_BUFFER.end_ptr]
jg .copy_in_2
.copy_more:
push ecx
and ecx, 3
rep movsb
pop ecx
shr ecx, 2
rep movsd
pop ecx ; >>>> 1/2
DEBUGF 2,"Copied %u bytes\n", ecx
ret
.too_large:
mov ecx, [eax + RING_BUFFER.size]
jmp .copy
.full:
DEBUGF 2,"Ring buffer is full!\n"
xor ecx, ecx
ret
.copy_in_2:
DEBUGF 1,"Copying in 2 passes\n"
mov edx, ecx
mov ecx, [eax + RING_BUFFER.end_ptr] ; find number of bytes till end of buffer
sub ecx, edi
sub edx, ecx
push edx ; <<<< 2
mov esi, [eax + RING_BUFFER.start_ptr]
call .copy_more
;-----------------------------------------------------------------
;
; SOCKET_ring_free
;
; Free's some bytes from the ringbuffer
;
; IN: eax = ptr to ring struct
; ecx = data size
;
; OUT: ecx = number of bytes free-ed
;
;-----------------------------------------------------------------
align 4
SOCKET_ring_free:
DEBUGF 1,"Trying to free %u bytes of data from ring %x\n", ecx, eax
cmp ecx, [eax + RING_BUFFER.size]
jle .go_for_it
cmp ecx, SOCKET_MAXDATA ;;;;
jg .moron_input
mov ecx, [eax + RING_BUFFER.size]
.go_for_it:
sub [eax + RING_BUFFER.size], ecx
add [eax + RING_BUFFER.read_ptr], ecx
mov edx, [eax + RING_BUFFER.end_ptr]
cmp [eax + RING_BUFFER.read_ptr], edx
jl @f
sub [eax + RING_BUFFER.read_ptr], SOCKET_MAXDATA ;;;;;
@@:
ret
.moron_input:
xor ecx, ecx
ret
;-----------------------------------------------------------------
;
; SOCKET_notify_owner
@ -1011,7 +1282,7 @@ SOCKET_alloc:
push ecx ebx
stdcall kernel_alloc, SOCKETBUFFSIZE
DEBUGF 1, "socket_alloc: %x ", eax
DEBUGF 1, "SOCKET_alloc: ptr=%x\n", eax
or eax, eax
jz .exit
@ -1023,17 +1294,14 @@ SOCKET_alloc:
rep stosd
pop edi eax
init_queue (eax + SOCKET_QUEUE_LOCATION)
; find first free socket number and use it
mov ebx, net_sockets
xor ecx, ecx
.next_socket_number:
inc ecx
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
test ebx, ebx
jz .last_socket
cmp [ebx + SOCKET.Number], ecx
jne .next_socket
@ -1042,23 +1310,21 @@ SOCKET_alloc:
.last_socket:
mov [eax + SOCKET.Number], ecx
DEBUGF 1, "(number: %u)\n", ecx
DEBUGF 1, "SOCKET_alloc: number=%u\n", ecx
mov edi, ecx
; Fill in PID
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx
; add socket to the list by changing pointers
; add socket to the list by re-arranging some pointers
mov ebx, [net_sockets + SOCKET.NextPtr]
mov [eax + SOCKET.PrevPtr], net_sockets
mov [eax + SOCKET.NextPtr], ebx
or ebx, ebx
test ebx, ebx
jz @f
add ebx, SOCKET.lock ; lock the next socket
call wait_mutex
@ -1068,9 +1334,7 @@ SOCKET_alloc:
@@:
mov [net_sockets + SOCKET.NextPtr], eax
mov edi, ecx
or eax, eax ; used to clear zero flag
or eax, eax ; used to clear zero flag
.exit:
pop ebx ecx
@ -1101,6 +1365,16 @@ SOCKET_free:
DEBUGF 1, "freeing socket..\n"
cmp [eax + SOCKET.Domain], AF_INET4
jnz .no_stream
cmp [eax + SOCKET.Type], IP_PROTO_TCP
jnz .no_stream
stdcall kernel_free, [eax + rcv.start_ptr]
stdcall kernel_free, [eax + snd.start_ptr]
.no_stream:
push eax ; this will be passed to kernel_free
mov ebx, [eax + SOCKET.NextPtr]
mov eax, [eax + SOCKET.PrevPtr]
@ -1126,6 +1400,39 @@ SOCKET_free:
ret
; socket nr in ebx
; new socket nr in eax
; preserver edx
align 4
SOCKET_fork:
;; Exit if backlog queue is full
; mov ax, [ebx + TCP_SOCKET.backlog_cur]
; cmp ax, [ebx + TCP_SOCKET.backlog]
; jae .exit
; Allocate new socket
call SOCKET_alloc
;;; jz .fail
; Copy structure from current socket to new, (including lock!)
; We start at PID to reserve the socket num, and the 2 pointers at beginning of socket
lea esi, [edx + SOCKET.PID]
lea edi, [eax + SOCKET.PID]
mov ecx, (TCP_SOCKET.end - SOCKET.PID + 3)/4
rep movsd
;; Push pointer to new socket to queue
; movzx ecx, [ebx + TCP_SOCKET.backlog_cur]
; inc [ebx + TCP_SOCKET.backlog_cur]
; mov [ebx + TCP_SOCKET.end + ecx*4], eax
;;;; mov [eax + IP_SOCKET.RemoteIP], esi ; IP source address
ret
;---------------------------------------------------
;
; SOCKET_num_to_ptr

View File

@ -66,14 +66,16 @@ SOCK_DGRAM equ 2
SOCK_RAW equ 3
; Socket options
SO_ACCEPTCON equ 1
SO_ACCEPTCON equ 1
SOCKET_MAXDATA equ 4096
SOCKET_MAXDATA equ 4096*32 ; must be 4096*(power of 2) where 'power of 2' is at least 8
; Network driver types
NET_TYPE_ETH equ 1
NET_TYPE_SLIP equ 2
MAX_backlog equ 20 ; backlog for stream sockets
virtual at 0
@ -92,6 +94,8 @@ virtual at 0
.packets_tx dd ? ;
.packets_rx dd ? ;
; .chksum dd ? ; bitmask stating available checksum routines on hardware
.end:
end virtual
@ -102,6 +106,7 @@ macro pseudo_random reg {
add reg, [esp]
rol reg, 5
xor reg, [timer_ticks]
add reg, [CPU_FREQ]
imul reg, 214013
xor reg, 0xdeadbeef
rol reg, 9
@ -111,7 +116,7 @@ macro ntohld reg {
rol word reg, 8
rol dword reg, 16
rol word reg, 8
rol word reg , 8
}
@ -122,6 +127,18 @@ macro ntohlw reg {
}
macro packet_to_debug { ; set esi to packet you want to print, ecx to number of bytes
local .loop
.loop:
lodsb
DEBUGF 1,"%x ", eax:2
loop @r
}
include "queue.inc"
include "ethernet.inc"
@ -161,25 +178,23 @@ align 4
stack_init:
; Init the network drivers list
xor eax, eax
mov edi, NET_RUNNING
mov ecx, MAX_NET_DEVICES + 1
rep stosd
; Call other init procedures
ETH_init
; SLIP_init
; PPPOE_init
call ETH_init
; call SLIP_init
IPv4_init
ICMP_init
call IPv4_init
call ICMP_init
ARP_init
UDP_init
TCP_init
call ARP_init
call UDP_init
call TCP_init
call socket_init
SOCKET_init
mov [net_tmr_count], 0
@ -211,14 +226,14 @@ stack_handler:
test [net_10ms], 0x0f ; 160ms
jnz .exit
; call TCP_timer_160ms
TCP_timer_160ms
test [net_10ms], 0x3f ; 640ms
jnz .exit
; call TCP_timer_640ms
call ARP_decrease_entry_ttls
call IPv4_decrease_fragment_ttls
TCP_timer_640ms
ARP_decrease_entry_ttls
IPv4_decrease_fragment_ttls
.exit:
ret
@ -275,13 +290,13 @@ NET_add_device:
jmp .error
.ethernet:
DEBUGF 1,"Trying to add an ethernet driver\n"
DEBUGF 1,"Trying to add an ethernet device\n"
inc [ETH_RUNNING] ; Indicate that one more ethernet device is up and running
jmp .add_it
.slip:
DEBUGF 1,"Trying to add a slip driver\n"
DEBUGF 1,"Trying to add a slip device\n"
;;;;
jmp .error
@ -490,15 +505,15 @@ checksum_2:
mov ecx, edx
shr ecx, 16
add edx, ecx
add dx, cx
test dx, dx ; it seems that ZF is not set when CF is set :(
not dx
jnz .not_zero
dec dx
.not_zero:
xchg dl, dh
DEBUGF 1,"Checksum: %x\n",dx
DEBUGF 1,"Checksum: %x\n", dx
ret

File diff suppressed because it is too large Load Diff

View File

@ -40,19 +40,62 @@ endg
;
; This function resets all UDP variables
;
; IN: /
; OUT: /
;
;-----------------------------------------------------------------
align 4
UDP_init:
macro UDP_init {
xor eax, eax
mov edi, UDP_PACKETS_TX
mov ecx, 2*MAX_IP
rep stosd
}
ret
macro UDP_checksum IP1, IP2 { ; esi = ptr to udp packet, ecx = packet size, destroys: ecx, edx
; Pseudoheader
mov edx, IP_PROTO_UDP
add dl, [IP1+1+4]
adc dh, [IP1+0+4]
adc dl, [IP1+3+4]
adc dh, [IP1+2+4]
adc dl, [IP2+1+8]
adc dh, [IP2+0+8]
adc dl, [IP2+3+8]
adc dh, [IP2+2+8]
adc dl, cl ; byte[esi+UDP_Packet.Length+1]
adc dh, ch ; byte[esi+UDP_Packet.Length+0]
; Done with pseudoheader, now do real header
adc dl, byte[esi+UDP_Packet.SourcePort+1]
adc dh, byte[esi+UDP_Packet.SourcePort+0]
adc dl, byte[esi+UDP_Packet.DestinationPort+1]
adc dh, byte[esi+UDP_Packet.DestinationPort+0]
adc dl, byte[esi+UDP_Packet.Length+1]
adc dh, byte[esi+UDP_Packet.Length+0]
adc edx, 0
; Done with header, now do data
push esi
movzx ecx, [esi+UDP_Packet.Length]
rol cx , 8
sub cx , UDP_Packet.Data
add esi, UDP_Packet.Data
call checksum_1
call checksum_2
pop esi
add [esi+UDP_Packet.Checksum], dx ; this final instruction will set or clear ZF :)
}
;-----------------------------------------------------------------
@ -62,11 +105,11 @@ UDP_init:
; Called by IPv4_input,
; this procedure will inject the udp data diagrams in the application sockets.
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
; pointer to device struct in ebx
; UDP Packet size in ecx
; pointer to UDP Packet in edx
; IN: [esp] = Pointer to buffer
; [esp+4] = size of buffer
; ebx = ptr to device struct
; ecx = UDP Packet size
; edx = ptr to UDP header
;
; esi = ipv4 source address
; edi = ipv4 dest address
@ -80,18 +123,18 @@ UDP_input:
DEBUGF 1,"UDP_input, size:%u\n", ecx
; First validate, checksum:
cmp [edx + UDP_Packet.Checksum], 0
jz .no_checksum
xchg edi, esi ; save ipv4 source address to edi so we can use it later
neg [esi+UDP_Packet.Checksum] ; substract chechksum from 0
jz .no_checksum ; if checksum is zero, it is considered valid and we continue processing
; otherwise, we will re-calculate the checksum and add it to this value, thus creating 0 when it is correct
push edx
push esi edi
push edi
push esi
mov esi, edx
call UDP_checksum ; this destroys edx, ecx and esi (but not edi...)
UDP_checksum (esp), (esp+4)
pop edi
pop esi ; we dont need it, but it is smaller then add esp, 4
pop edx
cmp [edx + UDP_Packet.Checksum], 0
jnz .checksum_mismatch
.no_checksum:
@ -168,12 +211,6 @@ UDP_input:
DEBUGF 2,"UDP_Handler - checksum mismatch\n"
; mov esi, edx
; @@: ;
; lodsb ;
; DEBUGF 2,"%x ", eax:2 ;
; loop @r ;
.dump:
call kernel_free
add esp, 4 ; pop (balance stack)
@ -207,26 +244,23 @@ UDP_output:
DEBUGF 1,"local port: %u\n", dx
rol dx, 8
mov ebx, [eax + IP_SOCKET.LocalIP]
mov eax, [eax + IP_SOCKET.RemoteIP]
mov di , IP_PROTO_UDP
mov di, IP_PROTO_UDP shl 8 + 128
sub esp, 8 ; Data ptr and data size will be placed here
add ecx, UDP_Packet.Data
;;; TODO: fragment id
push edx esi
call IPv4_create_packet
call IPv4_output
jz .fail
mov [esp + 8], eax ; pointer to buffer start
mov [esp + 8 + 4], edx ; buffer size
rol cx, 8
mov [edi + UDP_Packet.Length], cx
ror cx, 8
rol [edi + UDP_Packet.Length], 8
pop esi
push edi ecx
@ -240,13 +274,11 @@ UDP_output:
pop ecx edi
pop dword [edi + UDP_Packet.SourcePort]
mov [edi + UDP_Packet.Checksum], 0 ; set it to zero, to calculate checksum
; Checksum
mov esi, edi
pushd [edi-4] ; destination address ; TODO: fix this, IPv4 packet could have options..
pushd [edi-8] ; source address
call UDP_checksum
mov [edi + UDP_Packet.Checksum], 0
UDP_checksum (edi-4), (edi-8) ; TODO: fix this, IPv4 packet could have options..
inc [UDP_PACKETS_TX]
@ -254,81 +286,15 @@ UDP_output:
call [ebx + NET_DEVICE.transmit]
ret
.fail:
add esp, 8+8
DEBUGF 1,"UDP_output: failed\n"
add esp, 4+4+8
xor eax, eax
ret
;-----------------------------------------------------------------
;
; UDP_checksum
;
; This is the fast procedure to create or check a UDP header
; - To create a new checksum, the checksum field must be set to 0 before computation
; - To check an existing checksum, leave the checksum as is,
; and it will be 0 after this procedure, if it was correct
;
; IN: push source ip
; push dest ip
; esi = packet ptr
;
; OUT: checksum is filled in in packet! (but also in dx)
;
;-----------------------------------------------------------------
align 4
UDP_checksum:
; Pseudoheader
mov edx, IP_PROTO_UDP ; NO shl 8 here ! (it took me ages to figure this one out)
add dl, [esp+1+4]
adc dh, [esp+0+4]
adc dl, [esp+3+4]
adc dh, [esp+2+4]
adc dl, [esp+1+8]
adc dh, [esp+0+8]
adc dl, [esp+3+8]
adc dh, [esp+2+8]
adc dl, cl ; byte[esi+UDP_Packet.Length+1]
adc dh, ch ; byte[esi+UDP_Packet.Length+0]
; Done with pseudoheader, now do real header
adc dl, byte[esi+UDP_Packet.SourcePort+1]
adc dh, byte[esi+UDP_Packet.SourcePort+0]
adc dl, byte[esi+UDP_Packet.DestinationPort+1]
adc dh, byte[esi+UDP_Packet.DestinationPort+0]
adc dl, byte[esi+UDP_Packet.Length+1]
adc dh, byte[esi+UDP_Packet.Length+0]
adc edx, 0
; Done with header, now do data
push esi
movzx ecx, [esi+UDP_Packet.Length]
rol cx , 8
sub cx , UDP_Packet.Data
add esi, UDP_Packet.Data
call checksum_1
call checksum_2
pop esi
neg [esi+UDP_Packet.Checksum] ; zero will stay zero so we just get the checksum
add [esi+UDP_Packet.Checksum], dx ; , else we will get (new checksum - old checksum) in the end, wich should be 0 :)
ret 8
;---------------------------------------------------------------------------
;
; UDP_API