Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 1528 → Rev 1529

/kernel/branches/net/network/ARP.inc
16,20 → 16,16
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
$Revision$
 
 
ARP_NO_ENTRY equ 0
ARP_VALID_MAPPING equ 1
ARP_AWAITING_RESPONSE equ 2
ARP_RESPONSE_TIMEOUT equ 3
 
ARP_REQUEST_TTL = 20 ; in seconds
ARP_ENTRY_TTL = 600 ; in seconds
ARP_REQUEST_TTL equ 31 ; 20 s
ARP_ENTRY_TTL equ 937 ; 600 s
 
ETHER_ARP equ 0x0608
 
ARP_REQ_OPCODE equ 0x0100 ; request
ARP_REP_OPCODE equ 0x0200 ; reply
 
39,7 → 35,7
.IP dd ?
.MAC dp ?
.Status dw ?
.TTL dw ? ; in seconds
.TTL dw ?
.size:
ends
 
53,26 → 49,16
.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
88,15 → 74,10
;
; 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
103,152 → 84,217
mov ecx, 2*MAX_NET_DEVICES
rep stosd
 
ret
}
 
;---------------------------------------------------------------------------
;
; 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 esi, ARP_table
.loop:
cmp [esi + ARP_ENTRY.TTL], 0xffff ; 0xffff = static entry
je .next
 
dec [esi + ARP_ENTRY.TTL]
jz .time_out
 
.next:
add esi, ARP_ENTRY.size
loop .loop
jmp .exit
 
.time_out:
cmp [esi + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE
jz .response_timeout
 
push esi ecx
call ARP_del_entry
pop ecx esi
 
jmp .next
 
.response_timeout:
mov [esi + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT
mov [esi + ARP_ENTRY.TTL], 10
 
jmp .next
 
.exit:
 
}
 
 
;-----------------------------------------------------------------
;
; ARP_IP_to_MAC
; ARP_input
;
; This function resets all ARP variables
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
; packet size (without ethernet header) in ecx
; OUT: /
;
; 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:
ARP_input:
 
DEBUGF 1,"ARP_IP_to_MAC\n"
DEBUGF 1,"ARP_Handler - start\n"
cmp ecx, 28
jl .exit
 
; 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
;---------------------
; Handle Reply packets
 
xor edx, edx ;;; TODO: find device num in edx
cmp word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE
jne .maybe_request
 
mov ebx, [IP_LIST + edx]
and ebx, [SUBNET_LIST + edx]
DEBUGF 1,"ARP_Handler - it's a reply packet from %u.%u.%u.%u\n",\
[edx + ARP_Packet.SenderIP]:1,[edx + ARP_Packet.SenderIP+1]:1,[edx + ARP_Packet.SenderIP+2]:1,[edx + ARP_Packet.SenderIP+3]:1,
 
mov ecx, eax
and ecx, [SUBNET_LIST + edx]
mov ecx, [NumARP]
test ecx, ecx
jz .exit
 
cmp ecx, ebx
je .local
mov eax, [edx + ARP_Packet.SenderIP]
mov esi, ARP_table
 
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
.loop:
cmp [esi + ARP_ENTRY.IP], eax
je .gotit
add esi, ARP_ENTRY.size
loop .scan_loop
.not_in_list:
loop .loop
 
DEBUGF 1,"IP not found on list, preparing for ARP request\n"
jmp .exit
 
; if not, reserve an entry in list and send an ARP request packet
.gotit:
DEBUGF 1,"ARP_Handler - found matching entry\n"
 
cmp [esi+ARP_ENTRY.TTL], 0xffff ; if it is a static entry, dont touch it
je .exit
 
DEBUGF 1,"ARP_Handler - updating entry\n"
 
mov [esi+ARP_ENTRY.Status], ARP_VALID_MAPPING
mov [esi+ARP_ENTRY.TTL], ARP_ENTRY_TTL
 
mov eax, dword [edx + ARP_Packet.SenderMAC]
mov dword [esi+ARP_ENTRY.MAC], eax
mov ax , word [edx + ARP_Packet.SenderMAC + 4]
mov word [esi+ARP_ENTRY.MAC+4], ax
 
jmp .exit
 
 
;-----------------------
; Handle Request packets
 
.maybe_request:
cmp word [edx + ARP_Packet.Opcode], ARP_REQ_OPCODE
jne .exit
 
call NET_ptr_to_num
cmp edi, -1
jz .exit
DEBUGF 1,"ARP Request packet through device: %u\n", edi
inc [ARP_PACKETS_RX+4*edi]
 
mov eax, [IP_LIST+4*edi]
cmp eax, [edx + ARP_Packet.TargetIP] ; Is it looking for my IP address?
jne .exit ; TODO: instead of quitting, update local entrys with matching IP's ?
 
push eax
push edi
 
pushw ARP_REQUEST_TTL
pushw ARP_AWAITING_RESPONSE
pushd 0
pushw 0
pushd eax
call ARP_add_entry
cmp eax, -1
je .full
; 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)
 
; <Some dirty test code>
lea esi, [edx + ARP_Packet.SenderMAC]
lea edi, [edx + ARP_Packet.TargetMAC]
movsd ; Move Sender Mac to Dest MAC
movsw ;
movsd ; Move sender IP to Dest IP
 
; This piece of code waits for an ARP reply
 
mov ebx, eax
pop esi
mov esi, [NET_DRV_LIST + 4*esi]
lea esi, [esi + ETH_DEVICE.mac]
lea edi, [edx + ARP_Packet.SenderMAC]
movsd ; Copy MAC address from in MAC_LIST
movsw ;
pop eax
push ebx
call ARP_create_request
stosd ; Write our IP
 
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:
mov word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE
 
call change_task ; The ARP reply hasnt been received yet, tell the processor to do some other stuff first
; Now, Fill in ETHERNET header
 
mov eax, [esp + 4]
imul eax, ARP_ENTRY.size
add eax, ARPTable
cmp [eax + ARP_ENTRY.Status], ARP_VALID_MAPPING
je .gogogo
mov edi, [esp]
lea esi, [edx + ARP_Packet.TargetMAC]
movsd
movsw
lea esi, [edx + ARP_Packet.SenderMAC]
movsd
movsw
; mov ax , ETHER_ARP
; stosw
 
mov eax, [esp] ; Check if the reply hasnt timed-out yet
cmp [timer_ticks], eax
jl .dirty_loop
DEBUGF 1,"ARP_Handler - Sending reply \n"
 
; </Some dirty test code>
or eax, -1
add esp, 8
call [ebx + NET_DEVICE.transmit]
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
.exit:
call kernel_free
add esp, 4 ; pop (balance stack)
 
.full:
add esp, 4
mov eax, -1
DEBUGF 1,"ARP_Handler - exiting\n"
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
; ARP_output_request
;
; IN: ip in eax
;
; OUT: /
;
;---------------------------------------------------------------------------
align 4
ARP_create_request:
ARP_output_request:
 
DEBUGF 1,"Create ARP Packet\n"
 
call IPv4_dest_to_dev
 
push eax ; DestIP
mov eax, [IP_LIST+4*edi] ; senderIP
push eax
pushd [IP_LIST+edi] ; SenderIP
 
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 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_create_packet
call ETH_output
jz .exit
 
mov ecx, eax
259,16 → 305,18
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] ;
add edi, ARP_Packet.SenderMAC
 
lea esi, [ebx + ETH_DEVICE.mac] ; SenderMac
movsw ;
movsd ;
pop eax ;
pop eax ; SenderIP
stosd ;
mov eax, -1 ; destmac
 
mov eax, -1 ; DestMac
stosd ;
stosw ;
pop eax
pop eax ; DestIP
stosd ;
 
DEBUGF 1,"ARP Packet for device %x created successfully\n", ebx
278,84 → 326,17
ret
 
.exit:
add esp, 8
add esp, 4+4
DEBUGF 1,"Create ARP Packet - failed\n"
mov eax, -1
sub eax, eax
ret
 
 
 
;---------------------------------------------------------------------------
;
; ARP_decrease_entry_ttls
;
; IN: /
; OUT: /
;
;---------------------------------------------------------------------------
align 4
ARP_decrease_entry_ttls:
 
mov ecx, [NumARP]
test ecx, ecx
jz .exit
 
mov ebx, ARPTable
 
.timer_loop:
 
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
;
; IN: esi = ptr to entry (can easily be made on the stack)
; OUT: eax = entry #, -1 on error
;
;----------------------------------------------------------------- ; TODO: use a mutex
365,28 → 346,29
DEBUGF 1,"ARP add entry: "
 
mov ecx, [NumARP]
test ecx, ecx
test ecx, ecx ; first entry?
jz .add
cmp ecx, ARP_TABLE_SIZE ; list full ?
jge .error
 
mov eax, dword[esp + 4 + ARP_ENTRY.MAC]
mov bx , word[esp + 4 + ARP_ENTRY.MAC + 4]
mov esi, ARPTable
mov eax, dword[esi + ARP_ENTRY.MAC]
mov bx , word[esi + ARP_ENTRY.MAC + 4]
mov edi, ARP_table
 
.loop:
cmp dword [esi + ARP_ENTRY.MAC], eax
jne .maybe_next
cmp word [esi + ARP_ENTRY.MAC + 4], bx
jne .maybe_next
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[esi + ARP_ENTRY.TTL], 0xFFFF ; static entry
cmp dword[edi + ARP_ENTRY.TTL], 0xFFFF ; static entry
jne .notstatic
cmp dword[esp + 4 + ARP_ENTRY.TTL], 0xFFFF
cmp dword[esi + ARP_ENTRY.TTL], 0xFFFF
jne .error
.notstatic:
 
mov ebx, [NumARP]
xchg ebx, ecx
sub ecx, ebx
neg ecx
add ecx, [NumARP]
jmp .add
 
.maybe_next:
394,30 → 376,26
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]
lea edi, [ecx + ARP_table]
mov ecx, ARP_ENTRY.size/2
repz movsw
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 ARP_ENTRY.size
ret
 
.error:
 
DEBUGF 1,"error! \n"
 
mov eax, -1
jmp .exit
ret
 
 
;-----------------------------------------------------------------
424,7 → 402,7
;
; ARP_del_entry
;
; IN: entry # in esi
; IN: esi = ptr to arp entry
; OUT: /
;
;-----------------------------------------------------------------
431,161 → 409,129
align 4
ARP_del_entry:
 
DEBUGF 1,"ARP del entry %u, total entrys: %u\n", esi, [NumARP]
DEBUGF 1,"ARP del entry %x, total entrys: %u\n", esi, [NumARP]
 
cmp esi, [NumARP]
jge .error
 
imul esi, ARP_ENTRY.size
 
mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY.size
mov ecx, ARP_table + (ARP_TABLE_SIZE - 1) * ARP_ENTRY.size
sub ecx, esi
shr ecx, 1
 
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!
mov edi, esi
lea esi, [edi + ARP_ENTRY.size]
rep movsw
 
dec [NumARP] ;decrease arp-entries counter
dec [NumARP]
DEBUGF 1,"ARP entry deleted\n"
.error:
 
ret
 
 
 
 
 
;-----------------------------------------------------------------
;
; ARP_Handler:
; ARP_IP_to_MAC
;
; This function handles ARP protocol over ethernet
; (other protocols may follow in the future)
; This function translates an IP address to a MAC address
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
; packet size (without ethernet header) in ecx
; OUT: /
; 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_handler:
ARP_IP_to_MAC:
 
DEBUGF 1,"ARP_Handler - start\n"
cmp ecx, 28
jl .exit
DEBUGF 1,"ARP_IP_to_MAC\n"
 
cmp word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE ; Is this a reply packet?
jne .maybe_request
cmp eax, 0xffffffff
je .broadcast
 
DEBUGF 1,"ARP_Handler - it's a reply packet from %u.%u.%u.%u\n",\
[edx + ARP_Packet.SenderIP]:1,[edx + ARP_Packet.SenderIP+1]:1,[edx + ARP_Packet.SenderIP+2]:1,[edx + ARP_Packet.SenderIP+3]:1,
; if ((Remote IP & subnet_mask) == (local IP & subnet_mask ))
; destination is on same subnet
; else, destination is remote and must use a gateway
 
mov ecx, [NumARP]
test ecx, ecx
jz .exit
call IPv4_dest_to_dev
mov ebx, [IP_LIST + edi]
and ebx, [SUBNET_LIST + edi]
 
mov eax, [edx + ARP_Packet.SenderIP]
mov esi, ARPTable+ARP_ENTRY.IP
mov ecx, eax
and ecx, [SUBNET_LIST + edi]
 
.loop:
cmp [esi], eax
je .gotit
add esi, ARP_ENTRY.size
loop .loop
cmp ecx, ebx
je .local
 
jmp .exit
mov eax, [GATEWAY_LIST + edi]
DEBUGF 1,"requested IP is not on subnet, using default gateway\n"
 
.gotit:
;--------------------------------
; Try to find the IP in ARP_table
 
DEBUGF 1,"ARP_Handler - found matching entry\n"
.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
 
cmp [esi+ARP_ENTRY.Status], 0x0300 ;if it is a static entry, dont touch it
je .exit
.not_in_list:
DEBUGF 1,"IP not found on list, preparing for ARP request\n"
 
DEBUGF 1,"ARP_Handler - updating entry\n"
;--------------------
; Send an ARP request
 
mov [esi+ARP_ENTRY.Status], ARP_VALID_MAPPING
mov [esi+ARP_ENTRY.TTL], ARP_ENTRY_TTL
 
mov eax, dword [edx + ARP_Packet.SenderMAC]
mov dword [esi+ARP_ENTRY.MAC], eax
mov ax , word [edx + ARP_Packet.SenderMAC + 4]
mov word [esi+ARP_ENTRY.MAC+4], ax
 
jmp .exit
 
 
;------
 
 
.maybe_request:
cmp word [edx + ARP_Packet.Opcode], ARP_REQ_OPCODE ; Is this a request packet?
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
 
mov eax, edi
shl eax, 2
add eax, IP_LIST
mov eax, [eax]
cmp eax, [edx + ARP_Packet.TargetIP] ; Is it looking for my IP address?
jnz .exit
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)
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
 
cld
lea esi, [edx + ARP_Packet.SenderMAC]
lea edi, [edx + ARP_Packet.TargetMAC]
movsd ; Move Sender Mac to Dest MAC
movsw ;
movsd ; Move sender IP to Dest IP
cmp eax, -1
je .full
 
pop esi
mov esi, [NET_DRV_LIST + 4*esi]
lea esi, [esi + ETH_DEVICE.mac]
lea edi, [edx + ARP_Packet.SenderMAC]
movsd ; Copy MAC address from in MAC_LIST
movsw ;
pop eax
stosd ; Write our IP
 
mov word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE
call ARP_output_request
 
; Now, Fill in ETHERNET header
mov eax, -2 ; request send
ret
 
mov edi, [esp]
lea esi, [edx + ARP_Packet.TargetMAC]
movsd
movsw
lea esi, [edx + ARP_Packet.SenderMAC]
movsd
movsw
; mov ax , ETHER_ARP
; stosw
.found_it:
DEBUGF 1,"found IP in ARPTable\n"
cmp [esi + ARP_ENTRY.Status], 1
jne .invalid
 
DEBUGF 1,"ARP_Handler - Sending reply \n"
movzx eax, word [esi+ARP_ENTRY.MAC]
mov ebx, dword[esi+ARP_ENTRY.MAC+2]
ret
 
call [ebx + NET_DEVICE.transmit]
.invalid:
mov eax, -1
ret
 
.exit:
call kernel_free
add esp, 4 ; pop (balance stack)
.full:
DEBUGF 1,"ARP table is full!\n"
pop eax
mov eax, -1
ret
 
DEBUGF 1,"ARP_Handler - exiting\n"
.broadcast:
mov eax, 0x0000ffff
mov ebx, 0xffffffff
ret
 
 
 
 
;-----------------------------------------------------------------
;
; ARP_API
643,7 → 589,7
; 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
 
.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