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

View File

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

View File

@ -16,19 +16,15 @@
;; ;; ;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$ $Revision$
ARP_NO_ENTRY equ 0 ARP_NO_ENTRY equ 0
ARP_VALID_MAPPING equ 1 ARP_VALID_MAPPING equ 1
ARP_AWAITING_RESPONSE equ 2 ARP_AWAITING_RESPONSE equ 2
ARP_RESPONSE_TIMEOUT equ 3 ARP_RESPONSE_TIMEOUT equ 3
ARP_REQUEST_TTL = 20 ; in seconds ARP_REQUEST_TTL equ 31 ; 20 s
ARP_ENTRY_TTL = 600 ; in seconds ARP_ENTRY_TTL equ 937 ; 600 s
ETHER_ARP equ 0x0608
ARP_REQ_OPCODE equ 0x0100 ; request ARP_REQ_OPCODE equ 0x0100 ; request
ARP_REP_OPCODE equ 0x0200 ; reply ARP_REP_OPCODE equ 0x0200 ; reply
@ -39,7 +35,7 @@ struct ARP_ENTRY
.IP dd ? .IP dd ?
.MAC dp ? .MAC dp ?
.Status dw ? .Status dw ?
.TTL dw ? ; in seconds .TTL dw ?
.size: .size:
ends ends
@ -53,26 +49,16 @@ struct ARP_Packet
.SenderIP dd ? .SenderIP dd ?
.TargetMAC dp ? .TargetMAC dp ?
.TargetIP dd ? .TargetIP dd ?
.size:
ends 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 align 4
uglobal uglobal
NumARP dd ? 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_TX rd MAX_NET_DEVICES
ARP_PACKETS_RX rd MAX_NET_DEVICES ARP_PACKETS_RX rd MAX_NET_DEVICES
@ -88,379 +74,81 @@ endg
; ;
; This function resets all ARP variables ; This function resets all ARP variables
; ;
; IN: /
; OUT: /
;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 macro ARP_init {
ARP_init:
xor eax, eax xor eax, eax
mov [NumARP], eax mov [NumARP], eax
mov edi, ARP_PACKETS_TX mov edi, ARP_PACKETS_TX
mov ecx, 2*MAX_NET_DEVICES mov ecx, 2*MAX_NET_DEVICES
rep stosd 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 ; 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] mov ecx, [NumARP]
test ecx, ecx test ecx, ecx
jz .exit 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 .next:
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:
add esi, ARP_ENTRY.size add esi, ARP_ENTRY.size
loop .loop 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 jmp .exit
.time_out:
cmp [esi + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE
jz .response_timeout
;----------------------------------------------------------------- push esi ecx
; call ARP_del_entry
; ARP_del_entry pop ecx esi
;
; IN: entry # in esi
; OUT: /
;
;-----------------------------------------------------------------
align 4
ARP_del_entry:
DEBUGF 1,"ARP del entry %u, total entrys: %u\n", esi, [NumARP] jmp .next
cmp esi, [NumARP] .response_timeout:
jge .error mov [esi + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT
mov [esi + ARP_ENTRY.TTL], 10
imul esi, ARP_ENTRY.size jmp .next
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
.exit:
}
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;
; ARP_Handler: ; ARP_input
;
; This function handles ARP protocol over ethernet
; (other protocols may follow in the future)
; ;
; IN: Pointer to buffer in [esp] ; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4] ; size of buffer in [esp+4]
@ -469,13 +157,16 @@ ARP_del_entry:
; ;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 align 4
ARP_handler: ARP_input:
DEBUGF 1,"ARP_Handler - start\n" DEBUGF 1,"ARP_Handler - start\n"
cmp ecx, 28 cmp ecx, 28
jl .exit 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 jne .maybe_request
DEBUGF 1,"ARP_Handler - it's a reply packet from %u.%u.%u.%u\n",\ DEBUGF 1,"ARP_Handler - it's a reply packet from %u.%u.%u.%u\n",\
@ -486,10 +177,10 @@ ARP_handler:
jz .exit jz .exit
mov eax, [edx + ARP_Packet.SenderIP] mov eax, [edx + ARP_Packet.SenderIP]
mov esi, ARPTable+ARP_ENTRY.IP mov esi, ARP_table
.loop: .loop:
cmp [esi], eax cmp [esi + ARP_ENTRY.IP], eax
je .gotit je .gotit
add esi, ARP_ENTRY.size add esi, ARP_ENTRY.size
loop .loop loop .loop
@ -497,10 +188,9 @@ ARP_handler:
jmp .exit jmp .exit
.gotit: .gotit:
DEBUGF 1,"ARP_Handler - found matching entry\n" 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 je .exit
DEBUGF 1,"ARP_Handler - updating entry\n" DEBUGF 1,"ARP_Handler - updating entry\n"
@ -516,32 +206,29 @@ ARP_handler:
jmp .exit jmp .exit
;------ ;-----------------------
; Handle Request packets
.maybe_request: .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 jne .exit
call NET_ptr_to_num call NET_ptr_to_num
DEBUGF 1,"ARP Request packet through device: %u\n", edi
inc [ARP_PACKETS_RX+4*edi]
cmp edi, -1 cmp edi, -1
jz .exit jz .exit
DEBUGF 1,"ARP Request packet through device: %u\n", edi
inc [ARP_PACKETS_RX+4*edi]
mov eax, edi mov eax, [IP_LIST+4*edi]
shl eax, 2
add eax, IP_LIST
mov eax, [eax]
cmp eax, [edx + ARP_Packet.TargetIP] ; Is it looking for my IP address? 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 eax
push edi push edi
; OK, it is a request for one of our MAC addresses. Build the frame and send it ; OK, it is a request for one of our MAC addresses.
; We can reuse the buffer. (faster then using ARP_create_packet) ; 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 esi, [edx + ARP_Packet.SenderMAC]
lea edi, [edx + ARP_Packet.TargetMAC] lea edi, [edx + ARP_Packet.TargetMAC]
movsd ; Move Sender Mac to Dest MAC movsd ; Move Sender Mac to Dest MAC
@ -584,6 +271,265 @@ ARP_handler:
ret 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 ; edi = pointer to buffer
; ecx = # entry ; ecx = # entry
imul ecx, ARP_ENTRY.size imul ecx, ARP_ENTRY.size
add ecx, ARPTable add ecx, ARP_table
mov esi, ecx mov esi, ecx
mov ecx, ARP_ENTRY.size/2 mov ecx, ARP_ENTRY.size/2
rep movsw rep movsw
@ -653,16 +599,15 @@ ARP_API:
.write: .write:
; esi = pointer to buffer ; 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 call ARP_add_entry ;out: eax = entry number, -1 on error
ret ret
.remove: .remove:
; ecx = # entry ; ecx = # entry
mov esi, ecx cmp ecx, [NumARP]
jge .error
imul ecx, ARP_ENTRY.size
lea esi, [ARP_table + ecx]
call ARP_del_entry call ARP_del_entry
ret 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) .Data: ; Ip header begins here (we will need the IP header to re-construct the complete packet)
ends 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 align 4
uglobal uglobal
@ -74,30 +141,49 @@ endg
; ;
; This function resets all IP variables ; This function resets all IP variables
; ;
; IN: /
; OUT: /
;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 macro IPv4_init {
IPv4_init:
or eax, -1 xor eax, eax
mov edi, IP_LIST mov edi, IP_LIST
mov ecx, 4*MAX_IP mov ecx, 4*MAX_IP
rep stosd rep stosd
inc eax
mov edi, FRAGMENT_LIST mov edi, FRAGMENT_LIST
mov ecx, FRAGMENT_slot.size*MAX_FRAGMENTS/4 + 2*MAX_IP mov ecx, FRAGMENT_slot.size*MAX_FRAGMENTS/4 + 2*MAX_IP
rep stosd 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 ; Will check if IP Packet isnt damaged
; and call appropriate handler. (TCP/UDP/ICMP/..) ; and call appropriate handler. (TCP/UDP/ICMP/..)
@ -112,7 +198,7 @@ IPv4_init:
; ;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 align 4
IPv4_handler: ; TODO: implement handler for IP options IPv4_input: ; TODO: implement handler for IP options
; TODO2: add code for raw sockets ; TODO2: add code for raw sockets
DEBUGF 1,"IPv4_Handler, packet from: %u.%u.%u.%u ",\ 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 ; Now, re-calculate the checksum
push edx ebx IPv4_checksum edx
mov esi, edx jnz .dump ; if checksum isn't valid then dump packet
call IPv4_checksum
pop ebx edx
cmp [edx + IPv4_Packet.HeaderChecksum], 0
jne .dump ; if checksum isn't valid then dump packet
DEBUGF 1,"IPv4 Checksum is correct\n" 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..) ; mov esi, edx ; This prints the IP packet to the debug board (usefull when using serial output debug..)
; ; ; ;
; @@: ; ; packet_to_debug
; lodsb ;
; DEBUGF 1,"%x ", eax:2 ;
; loop @r ;
jmp .handle_it ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr 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 ; find fragment slot
@ -501,70 +576,15 @@ IPv4_find_fragment_slot:
ret 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
;------------------------------------------------------------------ ;------------------------------------------------------------------
; ;
; ; IPv4_output
; 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
; ;
; IN: eax = dest ip ; IN: eax = dest ip
; ebx = source ip ; ebx = source ip
; ecx = data length ; ecx = data length
; dx = fragment id ;;;; ; dx = fragment id
; di = protocol ; di = TTL shl 8 + protocol
; ;
; OUT: eax = pointer to buffer start ; OUT: eax = pointer to buffer start
; ebx = pointer to device struct (needed for sending procedure) ; ebx = pointer to device struct (needed for sending procedure)
@ -574,184 +594,224 @@ IPv4_fragment:
; ;
;------------------------------------------------------------------ ;------------------------------------------------------------------
align 4 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 cmp ecx, 65500 ; Max IPv4 packet size
jg .exit_ jg .too_large
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: ;
push ecx eax ebx dx di push ecx eax ebx dx di
cmp eax, -1
je .broadcast ; If it is broadcast, just send
call ARP_IP_to_MAC 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 cmp eax, -1
je .not_found jz .err2
push ebx push ebx
push ax 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: push esi ; ptr to ip header
call IPv4_dest_to_dev sub ecx, 20 ; substract header size
inc [IP_PACKETS_TX+4*edi] push ecx ; max data size
mov edx, [NET_DRV_LIST + 4*edi] push dword 0 ; offset
lea eax, [edx + ETH_DEVICE.mac]
mov ebx, esp .new_fragment:
mov ecx, [esp+18] ;; 18 or 22 ?? DEBUGF 1,"Ipv4_fragment - new_fragmentn"
add ecx, IPv4_Packet.DataOrOptional
mov eax, [esp + 3*4]
lea ebx, [esp + 4*4]
mov di , ETHER_IPv4 mov di , ETHER_IPv4
;;; TODO: detect if packet is too large for ethernet, if so, call IPv4_fragment call ETH_output
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
mov [edi + IPv4_Packet.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header) cmp edi, -1
mov [edi + IPv4_Packet.TypeOfService], 0 jz .err
xchg ch, cl
; 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.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 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 ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
mov esi, edi mov ecx, [esp + 1*4]
call IPv4_checksum
pop esi edx eax ecx
add edi, IPv4_Packet.DataOrOptional
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 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 ; IPv4_dest_to_dev
; ;
; IN: Destination IP in eax ; IN: eax = Destination IP
; OUT: device id in edi ; OUT: edi = device id * 4
; ;
;--------------------------------------------------------------------------- ;---------------------------------------------------------------------------
align 4 align 4
IPv4_dest_to_dev: IPv4_dest_to_dev:
DEBUGF 1,"IPv4 destination to device: " cmp eax, 0xffffffff
je .invalid
xor edi, edi xor edi, edi
mov ecx, MAX_IP mov ecx, MAX_IP
.loop: .loop:
mov ebx, [IP_LIST+edi] ; we dont need to worry about non exisiting ip interfaces mov ebx, [IP_LIST+edi]
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 and ebx, [SUBNET_LIST+edi]
; (only a moron would insert that ip into this function..) jz .next
mov edx, eax mov edx, eax
and edx, [SUBNET_LIST+edi] and edx, [SUBNET_LIST+edi]
cmp ebx, edx cmp ebx, edx
je .found_it je .found_it
.next:
add edi, 4 add edi, 4
loop .loop loop .loop
.invalid:
xor edi, edi ; if none found, use device 0 as default device xor edi, edi ; if none found, use device 0 as default device
.found_it: .found_it:
shr edi, 2 DEBUGF 1,"IPv4_dest_to_dev: %u\n", edi
DEBUGF 1,"%u\n",edi
ret ret
@ -869,7 +929,3 @@ IPv4_API:
mov [eax], ecx mov [eax], ecx
xor eax, eax xor eax, eax
ret ret

View File

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

View File

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

View File

@ -5,8 +5,10 @@
;; ;; ;; ;;
;; SOCKET.INC ;; ;; SOCKET.INC ;;
;; ;; ;; ;;
;; Written by hidnplayr@kolibrios.org ;; ;; Written by hidnplayr@kolibrios.org, ;;
;; based on code by mike.dld ;; ;; and Clevermouse. ;;
;; ;;
;; Based on code by mike.dld ;;
;; ;; ;; ;;
;; GNU GENERAL PUBLIC LICENSE ;; ;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;; ;; Version 2, June 1991 ;;
@ -31,9 +33,7 @@ virtual at 0
.errorcode dd ? .errorcode dd ?
.options dd ? .options dd ?
.SO_SND.SB_CC dd ? ;;;;; socket options: number of bytes in socket .state dd ?
.SO_RCV.SB_CC dd ?
.state dd ? ;;;;;;;;;
.end: .end:
end virtual end virtual
@ -51,15 +51,6 @@ virtual at SOCKET.end
.end: .end:
end virtual 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 virtual at IP_SOCKET.end
TCP_SOCKET: TCP_SOCKET:
@ -114,7 +105,6 @@ virtual at IP_SOCKET.end
;---------------------- ;----------------------
; Transmit timing stuff ; Transmit timing stuff
.t_idle dd ? .t_idle dd ?
.t_rtt dd ? .t_rtt dd ?
.t_rtseq dd ? .t_rtseq dd ?
@ -125,7 +115,6 @@ virtual at IP_SOCKET.end
;----------------- ;-----------------
; Out-of-band data ; Out-of-band data
.t_oobflags dd ? .t_oobflags dd ?
.t_iobc dd ? .t_iobc dd ?
.t_softerror dd ? .t_softerror dd ?
@ -133,7 +122,6 @@ virtual at IP_SOCKET.end
;--------- ;---------
; RFC 1323 ; RFC 1323
.SND_SCALE db ? ; Scale factor .SND_SCALE db ? ; Scale factor
.RCV_SCALE db ? .RCV_SCALE db ?
.request_r_scale db ? .request_r_scale db ?
@ -146,7 +134,6 @@ virtual at IP_SOCKET.end
;------- ;-------
; Timers ; Timers
.timer_retransmission dw ? ; rexmt .timer_retransmission dw ? ; rexmt
.timer_ack dw ? .timer_ack dw ?
.timer_persist dw ? .timer_persist dw ?
@ -176,9 +163,32 @@ virtual at IP_SOCKET.end
.end: .end:
end virtual 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 struct socket_queue_entry
; .owner dd ?
.data_ptr dd ? .data_ptr dd ?
.buf_ptr dd ? .buf_ptr dd ?
.data_size dd ? .data_size dd ?
@ -186,7 +196,6 @@ struct socket_queue_entry
ends ends
MAX_backlog equ 20 ; backlog for stream sockets
SOCKETBUFFSIZE equ 4096 ; in bytes SOCKETBUFFSIZE equ 4096 ; in bytes
SOCKET_QUEUE_SIZE equ 10 ; maximum number ofincoming packets queued for 1 socket SOCKET_QUEUE_SIZE equ 10 ; maximum number ofincoming packets queued for 1 socket
@ -204,24 +213,41 @@ endg
; ;
; SOCKET_init ; SOCKET_init
; ;
; -
;
; IN: /
; OUT: /
;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 macro SOCKET_init {
socket_init:
xor eax, eax xor eax, eax
mov edi, net_sockets mov edi, net_sockets
mov ecx, 4 mov ecx, 4
rep stosd rep stosd
mov [last_UDP_port], MIN_EPHEMERAL_PORT ;--- for random port --
mov [last_TCP_port], MIN_EPHEMERAL_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 align 4
sys_socket: sys_socket:
cmp ebx, 8 ; highest possible number cmp ebx, 8 ; highest possible number
jg s_error jg @f
lea ebx, [.table + 4*ebx] lea ebx, [sock_sysfn_table + 4*ebx]
jmp dword [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_open ; 0
dd SOCKET_close ; 1 dd SOCKET_close ; 1
dd SOCKET_bind ; 2 dd SOCKET_bind ; 2
@ -249,12 +284,6 @@ sys_socket:
; dd SOCKET_set_opt ; 9 ; 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 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 ret
@ -347,9 +410,6 @@ SOCKET_bind:
DEBUGF 1,"using local port: %u\n", bx DEBUGF 1,"using local port: %u\n", bx
mov word [eax + UDP_SOCKET.LocalPort], 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",\ 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 + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\
[eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1 [eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1
@ -411,21 +471,11 @@ SOCKET_connect:
.tcp: .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] lea ebx, [eax + SOCKET.lock]
call wait_mutex call wait_mutex
; fill in remote port and IP ; fill in remote port and IP
;;;;;; mov [eax + TCP_SOCKET.wndsizeTimer], 0 ; Reset the window timer.
mov bx , word [edx + 2] mov bx , word [edx + 2]
mov [eax + TCP_SOCKET.RemotePort], bx mov [eax + TCP_SOCKET.RemotePort], bx
DEBUGF 1,"remote port: %u\n", bx DEBUGF 1,"remote port: %u\n", bx
@ -435,21 +485,25 @@ SOCKET_connect:
; check if local port and IP is ok ; 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 cmp [eax + TCP_SOCKET.LocalPort], 0
jne @f jne @f
call SOCKET_find_port 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 call TCP_output
pop eax
mov [eax + SOCKET.lock], 0 mov [eax + SOCKET.lock], 0
@ -583,11 +637,11 @@ SOCKET_close:
test [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED ;;;;;; test [eax + TCP_SOCKET.t_state], TCB_SYN_RECEIVED ;;;;;;
jz .free 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 ; state must be LISTEN, SYN_SENT, CLOSED or maybe even invalid
; so, we may destroy the socket ; so, we may destroy the socket
@ -688,6 +742,12 @@ SOCKET_send:
.af_inet4: .af_inet4:
DEBUGF 1,"af_inet4\n" 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 cmp [eax + SOCKET.Type], IP_PROTO_TCP
je .tcp je .tcp
@ -790,6 +850,35 @@ SOCKET_get_opt:
ret 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 ; SOCKET_find_port
@ -939,6 +1028,188 @@ SOCKET_input:
ret 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 ; SOCKET_notify_owner
@ -1011,7 +1282,7 @@ SOCKET_alloc:
push ecx ebx push ecx ebx
stdcall kernel_alloc, SOCKETBUFFSIZE stdcall kernel_alloc, SOCKETBUFFSIZE
DEBUGF 1, "socket_alloc: %x ", eax DEBUGF 1, "SOCKET_alloc: ptr=%x\n", eax
or eax, eax or eax, eax
jz .exit jz .exit
@ -1023,17 +1294,14 @@ SOCKET_alloc:
rep stosd rep stosd
pop edi eax pop edi eax
init_queue (eax + SOCKET_QUEUE_LOCATION)
; find first free socket number and use it ; find first free socket number and use it
mov ebx, net_sockets mov ebx, net_sockets
xor ecx, ecx xor ecx, ecx
.next_socket_number: .next_socket_number:
inc ecx inc ecx
.next_socket: .next_socket:
mov ebx, [ebx + SOCKET.NextPtr] mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx test ebx, ebx
jz .last_socket jz .last_socket
cmp [ebx + SOCKET.Number], ecx cmp [ebx + SOCKET.Number], ecx
jne .next_socket jne .next_socket
@ -1042,23 +1310,21 @@ SOCKET_alloc:
.last_socket: .last_socket:
mov [eax + SOCKET.Number], ecx mov [eax + SOCKET.Number], ecx
DEBUGF 1, "SOCKET_alloc: number=%u\n", ecx
DEBUGF 1, "(number: %u)\n", ecx mov edi, ecx
; Fill in PID ; Fill in PID
mov ebx, [TASK_BASE] mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid] mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx 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 ebx, [net_sockets + SOCKET.NextPtr]
mov [eax + SOCKET.PrevPtr], net_sockets mov [eax + SOCKET.PrevPtr], net_sockets
mov [eax + SOCKET.NextPtr], ebx mov [eax + SOCKET.NextPtr], ebx
or ebx, ebx test ebx, ebx
jz @f jz @f
add ebx, SOCKET.lock ; lock the next socket add ebx, SOCKET.lock ; lock the next socket
call wait_mutex call wait_mutex
@ -1068,8 +1334,6 @@ SOCKET_alloc:
@@: @@:
mov [net_sockets + SOCKET.NextPtr], eax 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: .exit:
pop ebx ecx pop ebx ecx
@ -1101,6 +1365,16 @@ SOCKET_free:
DEBUGF 1, "freeing socket..\n" 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 push eax ; this will be passed to kernel_free
mov ebx, [eax + SOCKET.NextPtr] mov ebx, [eax + SOCKET.NextPtr]
mov eax, [eax + SOCKET.PrevPtr] mov eax, [eax + SOCKET.PrevPtr]
@ -1126,6 +1400,39 @@ SOCKET_free:
ret 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 ; SOCKET_num_to_ptr

View File

@ -68,12 +68,14 @@ SOCK_RAW equ 3
; Socket options ; 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 ; Network driver types
NET_TYPE_ETH equ 1 NET_TYPE_ETH equ 1
NET_TYPE_SLIP equ 2 NET_TYPE_SLIP equ 2
MAX_backlog equ 20 ; backlog for stream sockets
virtual at 0 virtual at 0
@ -92,6 +94,8 @@ virtual at 0
.packets_tx dd ? ; .packets_tx dd ? ;
.packets_rx dd ? ; .packets_rx dd ? ;
; .chksum dd ? ; bitmask stating available checksum routines on hardware
.end: .end:
end virtual end virtual
@ -102,6 +106,7 @@ macro pseudo_random reg {
add reg, [esp] add reg, [esp]
rol reg, 5 rol reg, 5
xor reg, [timer_ticks] xor reg, [timer_ticks]
add reg, [CPU_FREQ]
imul reg, 214013 imul reg, 214013
xor reg, 0xdeadbeef xor reg, 0xdeadbeef
rol reg, 9 rol reg, 9
@ -111,7 +116,7 @@ macro ntohld reg {
rol word reg, 8 rol word reg, 8
rol dword reg, 16 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 "queue.inc"
include "ethernet.inc" include "ethernet.inc"
@ -161,25 +178,23 @@ align 4
stack_init: stack_init:
; Init the network drivers list ; Init the network drivers list
xor eax, eax xor eax, eax
mov edi, NET_RUNNING mov edi, NET_RUNNING
mov ecx, MAX_NET_DEVICES + 1 mov ecx, MAX_NET_DEVICES + 1
rep stosd rep stosd
; Call other init procedures ETH_init
; SLIP_init
; PPPOE_init
call ETH_init IPv4_init
; call SLIP_init ICMP_init
call IPv4_init ARP_init
call ICMP_init UDP_init
TCP_init
call ARP_init SOCKET_init
call UDP_init
call TCP_init
call socket_init
mov [net_tmr_count], 0 mov [net_tmr_count], 0
@ -211,14 +226,14 @@ stack_handler:
test [net_10ms], 0x0f ; 160ms test [net_10ms], 0x0f ; 160ms
jnz .exit jnz .exit
; call TCP_timer_160ms TCP_timer_160ms
test [net_10ms], 0x3f ; 640ms test [net_10ms], 0x3f ; 640ms
jnz .exit jnz .exit
; call TCP_timer_640ms TCP_timer_640ms
call ARP_decrease_entry_ttls ARP_decrease_entry_ttls
call IPv4_decrease_fragment_ttls IPv4_decrease_fragment_ttls
.exit: .exit:
ret ret
@ -275,13 +290,13 @@ NET_add_device:
jmp .error jmp .error
.ethernet: .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 inc [ETH_RUNNING] ; Indicate that one more ethernet device is up and running
jmp .add_it jmp .add_it
.slip: .slip:
DEBUGF 1,"Trying to add a slip driver\n" DEBUGF 1,"Trying to add a slip device\n"
;;;; ;;;;
jmp .error jmp .error
@ -490,15 +505,15 @@ checksum_2:
mov ecx, edx mov ecx, edx
shr ecx, 16 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 not dx
jnz .not_zero jnz .not_zero
dec dx dec dx
.not_zero: .not_zero:
xchg dl, dh xchg dl, dh
DEBUGF 1,"Checksum: %x\n",dx DEBUGF 1,"Checksum: %x\n", dx
ret ret

File diff suppressed because it is too large Load Diff

View File

@ -40,19 +40,62 @@ endg
; ;
; This function resets all UDP variables ; This function resets all UDP variables
; ;
; IN: /
; OUT: /
;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 macro UDP_init {
UDP_init:
xor eax, eax xor eax, eax
mov edi, UDP_PACKETS_TX mov edi, UDP_PACKETS_TX
mov ecx, 2*MAX_IP mov ecx, 2*MAX_IP
rep stosd 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, ; Called by IPv4_input,
; this procedure will inject the udp data diagrams in the application sockets. ; this procedure will inject the udp data diagrams in the application sockets.
; ;
; IN: Pointer to buffer in [esp] ; IN: [esp] = Pointer to buffer
; size of buffer in [esp+4] ; [esp+4] = size of buffer
; pointer to device struct in ebx ; ebx = ptr to device struct
; UDP Packet size in ecx ; ecx = UDP Packet size
; pointer to UDP Packet in edx ; edx = ptr to UDP header
; ;
; esi = ipv4 source address ; esi = ipv4 source address
; edi = ipv4 dest address ; edi = ipv4 dest address
@ -80,18 +123,18 @@ UDP_input:
DEBUGF 1,"UDP_input, size:%u\n", ecx DEBUGF 1,"UDP_input, size:%u\n", ecx
; First validate, checksum: ; First validate, checksum:
cmp [edx + UDP_Packet.Checksum], 0 neg [esi+UDP_Packet.Checksum] ; substract chechksum from 0
jz .no_checksum 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
xchg edi, esi ; save ipv4 source address to edi so we can use it later
push edx push edx
push esi edi push edi
push esi
mov esi, edx 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 pop edx
cmp [edx + UDP_Packet.Checksum], 0
jnz .checksum_mismatch jnz .checksum_mismatch
.no_checksum: .no_checksum:
@ -168,12 +211,6 @@ UDP_input:
DEBUGF 2,"UDP_Handler - checksum mismatch\n" DEBUGF 2,"UDP_Handler - checksum mismatch\n"
; mov esi, edx
; @@: ;
; lodsb ;
; DEBUGF 2,"%x ", eax:2 ;
; loop @r ;
.dump: .dump:
call kernel_free call kernel_free
add esp, 4 ; pop (balance stack) add esp, 4 ; pop (balance stack)
@ -207,26 +244,23 @@ UDP_output:
DEBUGF 1,"local port: %u\n", dx DEBUGF 1,"local port: %u\n", dx
rol dx, 8 rol dx, 8
mov ebx, [eax + IP_SOCKET.LocalIP] mov ebx, [eax + IP_SOCKET.LocalIP]
mov eax, [eax + IP_SOCKET.RemoteIP] 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 sub esp, 8 ; Data ptr and data size will be placed here
add ecx, UDP_Packet.Data add ecx, UDP_Packet.Data
;;; TODO: fragment id ;;; TODO: fragment id
push edx esi push edx esi
call IPv4_create_packet call IPv4_output
jz .fail jz .fail
mov [esp + 8], eax ; pointer to buffer start mov [esp + 8], eax ; pointer to buffer start
mov [esp + 8 + 4], edx ; buffer size mov [esp + 8 + 4], edx ; buffer size
rol cx, 8
mov [edi + UDP_Packet.Length], cx mov [edi + UDP_Packet.Length], cx
ror cx, 8 rol [edi + UDP_Packet.Length], 8
pop esi pop esi
push edi ecx push edi ecx
@ -240,13 +274,11 @@ UDP_output:
pop ecx edi pop ecx edi
pop dword [edi + UDP_Packet.SourcePort] pop dword [edi + UDP_Packet.SourcePort]
mov [edi + UDP_Packet.Checksum], 0 ; set it to zero, to calculate checksum
; Checksum ; Checksum
mov esi, edi mov esi, edi
pushd [edi-4] ; destination address ; TODO: fix this, IPv4 packet could have options.. mov [edi + UDP_Packet.Checksum], 0
pushd [edi-8] ; source address UDP_checksum (edi-4), (edi-8) ; TODO: fix this, IPv4 packet could have options..
call UDP_checksum
inc [UDP_PACKETS_TX] inc [UDP_PACKETS_TX]
@ -254,81 +286,15 @@ UDP_output:
call [ebx + NET_DEVICE.transmit] call [ebx + NET_DEVICE.transmit]
ret ret
.fail: .fail:
add esp, 8+8 DEBUGF 1,"UDP_output: failed\n"
add esp, 4+4+8
xor eax, eax
ret 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 ; UDP_API