Improved loopback device, separate ARP tables for every interface, added arpstat functionality to netstat, preparing zeroconf to work on multiple interfaces, improved API (fn 76, fn 74), fixed some bugs.

git-svn-id: svn://kolibrios.org@3601 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
hidnplayr
2013-06-05 00:21:20 +00:00
parent c2bc66096c
commit c0fe9dddf7
19 changed files with 420 additions and 431 deletions

View File

@@ -32,36 +32,36 @@ ARP_REP_OPCODE = 0x0200 ; reply
ARP_TABLE_SIZE = 20 ; Size of table
struct ARP_entry
struct ARP_entry
IP dd ?
MAC dp ?
Status dw ?
TTL dw ?
IP dd ?
MAC dp ?
Status dw ?
TTL dw ?
ends
struct ARP_header
struct ARP_header
HardwareType dw ?
ProtocolType dw ?
HardwareSize db ?
ProtocolSize db ?
Opcode dw ?
SenderMAC dp ?
SenderIP dd ?
TargetMAC dp ?
TargetIP dd ?
HardwareType dw ?
ProtocolType dw ?
HardwareSize db ?
ProtocolSize db ?
Opcode dw ?
SenderMAC dp ?
SenderIP dd ?
TargetMAC dp ?
TargetIP dd ?
ends
align 4
uglobal
NumARP dd ?
ARP_table rb ARP_TABLE_SIZE * sizeof.ARP_entry ; TODO: separate ARP table and stats per interface
ARP_table rb NET_DEVICES_MAX*(ARP_TABLE_SIZE * sizeof.ARP_entry)
ARP_entries_num rd NET_DEVICES_MAX
ARP_PACKETS_TX rd NET_DEVICES_MAX
ARP_PACKETS_RX rd NET_DEVICES_MAX
ARP_CONFLICTS rd NET_DEVICES_MAX
@@ -81,10 +81,8 @@ endg
macro ARP_init {
xor eax, eax
mov [NumARP], eax
mov edi, ARP_PACKETS_TX
mov ecx, 3*NET_DEVICES_MAX
mov edi, ARP_entries_num
mov ecx, 4*NET_DEVICES_MAX
rep stosd
}
@@ -111,11 +109,15 @@ local .exit
; 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]
xor edi, edi
.loop_outer:
mov ecx, [ARP_entries_num + 4*edi]
test ecx, ecx
jz .exit
mov esi, ARP_table
mov esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)
imul esi, edi
add esi, ARP_table
.loop:
cmp [esi + ARP_entry.TTL], ARP_STATIC_ENTRY
je .next
@@ -133,9 +135,9 @@ local .exit
cmp [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE
je .response_timeout
push esi ecx
push esi edi ecx
call ARP_del_entry
pop ecx esi
pop ecx edi esi
jmp .next
@@ -146,6 +148,9 @@ local .exit
jmp .next
.exit:
inc edi
cmp edi, NET_DEVICES_MAX
jb .loop_outer
}
@@ -196,11 +201,13 @@ ARP_input:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: It's a reply\n"
mov ecx, [NumARP]
mov ecx, [ARP_entries_num + 4*edi]
test ecx, ecx
jz .exit
mov esi, ARP_table
mov esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)
imul esi, edi
add esi, ARP_table
.loop:
cmp [esi + ARP_entry.IP], eax
je .gotit
@@ -298,22 +305,19 @@ ARP_input:
;
; ARP_output_request
;
; IN: ip in eax
; device in edi
; IN: ebx = device ptr
; eax = IP
; OUT: /
; scratched: probably everything
;
;---------------------------------------------------------------------------
align 4
ARP_output_request:
push eax ; DestIP
pushd [IP_LIST + edi] ; SenderIP
inc [ARP_PACKETS_TX + edi] ; assume we will succeed
push eax
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u\n",\
[esp + 4]:1, [esp + 5]:1, [esp + 6]:1, [esp + 7]:1
mov ebx, [NET_DRV_LIST + edi] ; device ptr
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u device=0x%x\n",\
[esp]:1, [esp + 1]:1, [esp + 2]:1, [esp + 3]:1, ebx
lea eax, [ebx + ETH_DEVICE.mac] ; local device mac
mov edx, ETH_BROADCAST ; broadcast mac
@@ -322,8 +326,6 @@ ARP_output_request:
call ETH_output
jz .exit
mov ecx, eax
mov [edi + ARP_header.HardwareType], 0x0100 ; Ethernet
mov [edi + ARP_header.ProtocolType], 0x0008 ; IP
mov [edi + ARP_header.HardwareSize], 6 ; MAC-addr length
@@ -331,29 +333,29 @@ ARP_output_request:
mov [edi + ARP_header.Opcode], ARP_REQ_OPCODE ; Request
add edi, ARP_header.SenderMAC
lea esi, [ebx + ETH_DEVICE.mac] ; SenderMac
movsw ;
movsd ;
pop eax ; SenderIP
stosd ;
mov eax, -1 ; DestMac
stosd ;
stosw ;
pop eax ; DestIP
stosd ;
; mov esi, [ebx + NET_DEVICE.number]
xor esi, esi ;;;; FIXME
inc esi ;;;;;;;;;
inc [ARP_PACKETS_TX + 4*esi] ; assume we will succeed
lea esi, [IP_LIST + 4*esi] ; SenderIP
movsd
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_output_request: device=%x\n", ebx
mov esi, ETH_BROADCAST ; DestMac
movsw ;
movsd ;
popd [edi] ; DestIP
push edx ecx
push edx eax
call [ebx + NET_DEVICE.transmit]
ret
.exit:
add esp, 4 + 4
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_output_request: failed\n"
sub eax, eax
add esp, 4
DEBUGF DEBUG_NETWORK_ERROR, "ARP_output_request: send failed\n"
ret
@@ -362,50 +364,65 @@ ARP_output_request:
; ARP_add_entry (or update)
;
; IN: esi = ptr to entry (can easily be made on the stack)
; edi = device num
; OUT: eax = entry #, -1 on error
; edi = ptr to newly created entry
; esi = ptr to newly created entry
;
;----------------------------------------------------------------- ; TODO: use a mutex
align 4
ARP_add_entry:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_add_entry: "
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_add_entry: device=%u\n", edi
mov ecx, [NumARP]
mov ecx, [ARP_entries_num + 4*edi]
cmp ecx, ARP_TABLE_SIZE ; list full ?
jae .error
jae .full
xor eax, eax
mov edi, ARP_table
mov ecx, [esi + ARP_entry.IP]
; From this point on, we can only fail if IP has a static entry, or if table is corrupt.
inc [ARP_entries_num + 4*edi] ; assume we will succeed
push edi
xor ecx, ecx
imul edi, ARP_TABLE_SIZE*sizeof.ARP_entry
add edi, ARP_table
mov eax, [edi + ARP_entry.IP]
.loop:
cmp [edi + ARP_entry.Status], ARP_NO_ENTRY ; is this slot empty?
je .add
cmp [edi + ARP_entry.IP], ecx ; if not, check if it doesnt collide
cmp [edi + ARP_entry.IP], eax ; if not, check if it doesnt collide
jne .maybe_next
cmp [edi + ARP_entry.TTL], ARP_STATIC_ENTRY ; ok, its the same IP, update it if not static
jne .add
DEBUGF DEBUG_NETWORK_ERROR, "ARP_add_entry: failed, IP already has a static entry\n"
jmp .error
.maybe_next: ; try the next slot
add edi, sizeof.ARP_entry
inc eax
cmp eax, ARP_TABLE_SIZE
jae .error
jmp .loop
inc ecx
cmp ecx, ARP_TABLE_SIZE
jb .loop
.add:
push ecx
mov ecx, sizeof.ARP_entry/2
rep movsw
inc [NumARP]
sub edi, sizeof.ARP_entry
DEBUGF DEBUG_NETWORK_VERBOSE, "entry=%u\n", eax
pop ecx
lea esi, [edi - sizeof.ARP_entry]
pop edi
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_add_entry: entry=%u\n", ecx
ret
.error:
DEBUGF DEBUG_NETWORK_VERBOSE, "failed\n"
pop edi
dec [ARP_entries_num + 4*edi]
DEBUGF DEBUG_NETWORK_ERROR, "ARP_add_entry_failed\n"
.full:
mov eax, -1
ret
@@ -414,30 +431,36 @@ ARP_add_entry:
;
; ARP_del_entry
;
; IN: esi = ptr to arp entry
; OUT: /
; IN: esi = ptr to arp entry
; edi = device number
; OUT: /
;
;-----------------------------------------------------------------
align 4
ARP_del_entry:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_del_entry: entry=%x entrys=%u\n", esi, [NumARP]
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_del_entry: entry=%x entrys=%u\n", esi, [ARP_entries_num + 4*edi]
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_del_entry: IP=%u.%u.%u.%u\n", \
[esi + ARP_entry.IP]:1, [esi + ARP_entry.IP + 1]:1, [esi + ARP_entry.IP + 2]:1, [esi + ARP_entry.IP + 3]:1
mov ecx, ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry
push edi
imul edi, (ARP_TABLE_SIZE) * sizeof.ARP_entry
lea ecx, [ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry + edi]
sub ecx, esi
shr ecx, 1
; move all trailing entries, sizeof.ARP_entry bytes to left.
mov edi, esi
add esi, sizeof.ARP_entry
rep movsw
; now add an empty entry to the end (erasing previous one)
xor eax, eax
mov ecx, sizeof.ARP_entry/2
rep stosw
dec [NumARP]
pop edi
dec [ARP_entries_num + 4*edi]
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_del_entry: success\n"
ret
@@ -465,7 +488,7 @@ ARP_IP_to_MAC:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: %u.%u", al, ah
rol eax, 16
DEBUGF DEBUG_NETWORK_VERBOSE, ".%u.%u\n", al, ah
DEBUGF DEBUG_NETWORK_VERBOSE, ".%u.%u device: %u\n", al, ah, edi
rol eax, 16
cmp eax, 0xffffffff
@@ -474,7 +497,7 @@ ARP_IP_to_MAC:
;--------------------------------
; Try to find the IP in ARP_table
mov ecx, [NumARP]
mov ecx, [ARP_entries_num + 4*edi]
test ecx, ecx
jz .not_in_list
mov esi, ARP_table + ARP_entry.IP
@@ -482,38 +505,41 @@ ARP_IP_to_MAC:
cmp [esi], eax
je .found_it
add esi, sizeof.ARP_entry
loop .scan_loop
dec ecx
jnz .scan_loop
.not_in_list:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: preparing for ARP request\n"
;--------------------
; Send an ARP request
push eax edi ; save IP for ARP_output_request
; Now create the ARP entry
; Now craft the ARP entry on the stack
pushw ARP_REQUEST_TTL ; TTL
pushw ARP_AWAITING_RESPONSE ; status
pushd 0 ; mac
pushw 0
pushd eax ; ip
mov esi, esp
; Add it to the list
call ARP_add_entry
; Delete the temporary entry
add esp, sizeof.ARP_entry ; clear the entry from stack
; If we could not add it to the list, give up
cmp eax, -1 ; did ARP_add_entry fail?
je .full
mov esi, edi
pop edi eax ; IP in eax, device number in edi, for ARP_output_request
push esi edi
call ARP_output_request ; And send a request
pop edi esi
;-----------------------------------------------
; At this point, we got an ARP entry in the list
; Now send a request packet on the network
pop edi eax ; IP in eax, device number in ebx, for ARP_output_request
push esi edi
mov ebx, [NET_DRV_LIST + 4*edi]
call ARP_output_request
pop edi esi
.found_it:
cmp [esi + ARP_entry.Status], ARP_VALID_MAPPING ; Does it have a MAC assigned?
je .valid
@@ -522,10 +548,10 @@ if ARP_BLOCK
cmp [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE ; Are we waiting for reply from remote end?
jne .give_up
push esi
push esi edi
mov esi, 10 ; wait 10 ms
call delay_ms
pop esi
pop edi esi
jmp .found_it ; now check again
else
@@ -536,8 +562,8 @@ end if
.valid:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: found MAC\n"
movzx eax, word[esi + ARP_entry.MAC]
mov ebx, dword[esi + ARP_entry.MAC + 2]
movzx eax, word[edi + ARP_entry.MAC]
mov ebx, dword[edi + ARP_entry.MAC + 2]
ret
.full:
@@ -606,17 +632,19 @@ ARP_api:
ret
.entries:
mov eax, [NumARP]
mov eax, [ARP_entries_num + eax]
ret
.read:
cmp ecx, [NumARP]
cmp ecx, [ARP_entries_num + eax]
jae .error
shr eax, 2
imul eax, sizeof.ARP_entry*ARP_TABLE_SIZE
add eax, ARP_table
; edi = pointer to buffer
; ecx = # entry
imul ecx, sizeof.ARP_entry
add ecx, ARP_table
mov esi, ecx
lea esi, [eax + ecx]
mov ecx, sizeof.ARP_entry/2
rep movsw
@@ -625,20 +653,24 @@ ARP_api:
.write:
; esi = pointer to buffer
mov edi, eax
shr edi, 2
call ARP_add_entry ; out: eax = entry number, -1 on error
ret
.remove:
; ecx = # entry
cmp ecx, [NumARP]
cmp ecx, [ARP_entries_num + eax]
jae .error
imul ecx, sizeof.ARP_entry
lea esi, [ARP_table + ecx]
mov edi, eax
shr edi, 2
call ARP_del_entry
ret
.send_announce:
mov edi, eax
mov ebx, [NET_DRV_LIST + eax]
mov eax, [IP_LIST + eax]
call ARP_output_request ; now send a gratuitous ARP
ret