Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 260 → Rev 261

/kernel/trunk/network/eth_drv/ethernet.inc
36,6 → 36,22
;
;********************************************************************
 
ETHER_IP equ 0x0008 ; Reversed from 0800 for intel
ETHER_ARP equ 0x0608 ; Reversed from 0806 for intel
ETHER_RARP equ 0x3580
 
struc ETH_FRAME
{ .DstMAC dp ? ;destination MAC-address [6 bytes]
.SrcMAC dp ? ;source MAC-address [6 bytes]
.Type dw ? ;type of the upper-layer protocol [2 bytes]
.Data db ? ;data [46-1500 bytes]
}
 
virtual at Ether_buffer
ETH_FRAME ETH_FRAME
end virtual
 
 
; Some useful information on data structures
 
; Ethernet Packet - ARP Request example
75,19 → 91,13
; Include individual drivers source files at this point.
; If you create a new driver, include it below.
 
include "rtl8029.inc"
include "i8255x.inc"
include "rtl8139.inc"
include "3c59x.inc"
include "sis900.inc"
include "pcnet32.inc"
include "drivers/rtl8029.inc"
include "drivers/i8255x.inc"
include "drivers/rtl8139.inc"
include "drivers/3c59x.inc"
include "drivers/sis900.inc"
include "drivers/pcnet32.inc"
 
; DEBUGGING_STATE enables or disables output of received and transmitted
; data over the serial port
DEBUGGING_ENABLED equ 1
DEBUGGING_DISABLED equ 0
DEBUGGING_STATE equ DEBUGGING_DISABLED
 
; PCICards
; ========
; PCI vendor and hardware types for hardware supported by the above drivers
173,26 → 183,12
dd 0,0,0,0,0 ; end of list marker, do not remove
endg
 
; PCI Bus defines
PCI_HEADER_TYPE equ 0x0e ;8 bit
PCI_BASE_ADDRESS_0 equ 0x10 ;32 bit
PCI_BASE_ADDRESS_5 equ 0x24 ;32 bits
PCI_BASE_ADDRESS_SPACE_IO equ 0x01
PCI_VENDOR_ID equ 0x00 ;16 bit
PCI_BASE_ADDRESS_IO_MASK equ 0xFFFFFFFC
 
ETHER_IP equ 0x0008 ; Reversed from 0800 for intel
ETHER_ARP equ 0x0608 ; Reversed from 0806 for intel
ETHER_RARP equ 0x3580
ARP_REQ_OPCODE equ 0x0100
ARP_REP_OPCODE equ 0x0200
 
uglobal
arp_rx_count: dd 0
ip_rx_count: dd 0
dumped_rx_count: dd 0
ip_tx_count: dd 0
;Net-stack's interface's settings
node_addr: db 0,0,0,0,0,0
gateway_ip: db 0, 0, 0, 0
dns_ip: dd 0
 
eth_rx_data_len: dw 0
eth_status: dd 0
io_addr: dd 0
208,189 → 204,19
drvr_poll: dd 0
drvr_transmit: dd 0
 
; These hold the destination Host identity for ARP responses
remote_ip_add: dd 0
remote_hw_add: db 0, 0, 0, 0, 0, 0
endg
 
iglobal
broadcast_add: db 0xff,0xff,0xff,0xff,0xff,0xff
subnet_mask: dd 0x00ffffff
subnet_mask: dd 0x00ffffff ; 255.255.255.0
endg
 
uglobal
; This is used by getMACfromIP
MACAddress: db 0,0,0,0,0,0
gateway_ip: db 0, 0, 0, 0
dns_ip: dd 0
endg
include "arp.inc" ;arp-protocol functions
include "pci.inc" ;PCI bus access functions
 
; The follow is the ARP Table.
; This table must be manually updated and the kernel recompilied if
; changes are made to it.
; ARP_TABLE_SIZE defines the size of the table
; ARP_TABLE_ENTRIES defines the number of entries in the table
; Each entry is 10 bytes: 4 Byte IP address, 6 byte MAC Address,
; 2 bytes status, 2 bytes TTL ( in seconds )
; Empty entries are filled with zeros
; 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 permanent 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
 
ARP_NO_ENTRY equ 0
ARP_VALID_MAPPING equ 1
ARP_AWAITING_RESPONSE equ 2
ARP_RESPONSE_TIMEOUT equ 3
 
ARP_ENTRY_SIZE equ 14 ; Number of bytes per entry
ARP_TABLE_SIZE equ 20 ; Size of table
ARP_TABLE_ENTRIES equ 0 ; Inital, hardcoded entries
 
uglobal
ARPTable:
times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE db 0
endg
 
iglobal
NumARP: db ARP_TABLE_ENTRIES
endg
 
;***************************************************************************
; Function
; eth_probe
; Description
; Searches for an ethernet card. If found, the card is enabled and
; the ethernet -> IP link established
;
; This function scans the PCI bus looking for a supported device.
; ISA bus is currently not supported.
;
; eax is 0 if no hardware found
;***************************************************************************
eth_probe:
; Find a card on the PCI bus, and get it's address
call scan_bus ; Find the ethernet cards PIC address
xor eax, eax
cmp [io_addr], eax
je ep_00x ; Return 0 in eax if no cards found
 
call dword [drvr_probe] ; Call the drivers probe function
 
mov eax, [io_addr] ; return a non zero value
 
ep_00x:
ret
 
;***************************************************************************
; Function
; ethernet_driver
;
; Description
; The ethernet RX and TX handler
; This is a kernel function, called by stack_handler
;
;***************************************************************************
ethernet_driver:
; Do nothing if the driver is inactive
cmp [ethernet_active], byte 0
je eth_exit
 
call eth_rx
call eth_tx
 
eth_exit:
ret
 
;***************************************************************************
; Function
; eth_rx
;
; Description
; Polls the ethernet card for received data. Extracts if present
; Depending on the Protocol within the packet:
; ARP : Pass to ARP_handler. This may result in an ARP reply
; being tx'ed
; IP : Store in an IP buffer
;
;***************************************************************************
eth_rx:
xor ax, ax
mov [eth_rx_data_len], ax
call dword [drvr_poll] ; Call the drivers poll function
 
mov ax, [eth_rx_data_len]
cmp ax, 0
je erx_exit
 
if DEBUGGING_STATE = DEBUGGING_ENABLED
pusha
mov eax, 0 ;Indicate that this is a received packet
mov cx, [eth_rx_data_len]
mov esi, Ether_buffer
cmp word [esi + 12], ETHER_IP
jnz erxd_done
; cmp byte [esi + 14 + 9], 0x06 ; TCP
; jnz erxd_done
call eth_dump
erxd_done:
popa
end if
 
; Check the protocol. Call appropriate handler
mov eax, Ether_buffer
add eax, 12 ; The address of the protocol word
 
mov ax, [eax]
 
cmp ax, ETHER_ARP
je erx_001 ; It is ARP
 
cmp ax, ETHER_IP
je erx_002 ; It's IP
 
; inc dword [dumped_rx_count]
 
jmp erx_exit ; If not IP or ARP, ignore
 
erx_001:
mov eax, [arp_rx_count]
inc eax
mov [arp_rx_count], eax
 
; At this point, the packet is still in the Ether_buffer
call arp_handler
 
jmp erx_exit
 
erx_002:
mov eax, [ip_rx_count]
inc eax
mov [ip_rx_count], eax
 
; Check to see if the MAC address is in our arp table
; refresh the arp ttl if so
 
mov esi, Ether_buffer
add esi, 6
 
call refreshARP
 
call ether_IP_handler
 
jmp erx_exit
 
erx_exit:
ret
 
;***************************************************************************
; Function
; eth_tx
;
; Description
403,18 → 229,19
; Places buffer on empty queue when the tx routine finished
;
;***************************************************************************
eth_tx:
proc eth_tx stdcall uses ebx esi edi
local MACAddress dp ? ;allocate 6 bytes in the stack
 
; Look for a buffer to tx
mov eax, NET1OUT_QUEUE
call dequeue
cmp ax, NO_BUFFER
je eth_exit ; Exit if no buffer available
je .exit ; Exit if no buffer available
 
push eax
push eax ;save buffer number
 
; convert buffer pointer eax to the absolute address
mov ecx, IPBUFFSIZE
mul ecx
imul eax, IPBUFFSIZE
add eax, IPbuffs
 
; Extract the destination IP
425,94 → 252,37
 
; If the destination address is 255.255.255.255,
; set the MACAddress to all ones ( broadcast )
mov [MACAddress], dword 0xffffffff
mov [MACAddress + 4], word 0xffff
cld
mov esi, broadcast_add
lea edi, [MACAddress]
movsd
movsw
cmp edx, 0xffffffff
je etx_send ; If it is broadcast, just send
je .send ; If it is broadcast, just send
 
call getMACfromIP ; Get the MAC address.
lea eax, [MACAddress] ;cause this is local variable
stdcall arp_table_manager, ARP_TABLE_IP_TO_MAC, edx, eax ;opcode,IP,MAC_ptr - Get the MAC address.
 
cmp eax, ARP_VALID_MAPPING
jz etx_send
je .send
 
; No valid entry. Are we waiting for a response?
cmp eax, ARP_AWAITING_RESPONSE
jne etx_001
; No valid entry. Has the request been sent, but timed out?
cmp eax, ARP_RESPONSE_TIMEOUT
je .freebuf
 
.wait_response: ;we wait arp-response
; Re-queue the packet, and exit
pop ebx
mov eax, NET1OUT_QUEUE
call queue
jmp etx_exit
call queue ; Get the buffer back
jmp .exit
 
etx_001:
; HAs the request been sent, but timed out?
cmp eax, ARP_RESPONSE_TIMEOUT
jne etx_002
 
pop eax
call freeBuff
jmp etx_exit
 
etx_002:
; There is no entry. Re queue the request, and ask ARP to send a request
 
; IP address is in edx
push edx
call arp_request
pop ebx
 
; Add an entry in the ARP table, awaiting response
 
cmp byte [NumARP], ARP_TABLE_SIZE
je etx_003 ; We cannot add a new entry in the table
 
inc byte [NumARP]
 
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
sub eax, ARP_ENTRY_SIZE
 
mov [eax + ARPTable], ebx
xor ebx, ebx
mov [eax + ARPTable + 4], ebx
mov [eax + ARPTable + 8], bx
 
; set the status field up - awaiting response
mov cl, 0x00
mov [eax + ARPTable + 10], cl
mov cl, 0x02
mov [eax + ARPTable + 11], cl
 
; Initialise the time to live field - 10s
mov cx, 0x000A
mov [eax + ARPTable + 12], cx
 
etx_003:
pop ebx ; Get the buffer back
mov eax, NET1OUT_QUEUE
call queue
jmp etx_exit
 
etx_send:
xor ecx, ecx
mov ch, [ebx+2]
mov cl, [ebx+3] ; ; Size of IP packet to send
 
mov esi, ebx
 
mov edi, MACAddress
 
if DEBUGGING_STATE = DEBUGGING_ENABLED
pusha
mov cx, 42
mov eax, 1 ; Indicate that this is a tx packet
call eth_dump
popa
end if
 
mov bx, ETHER_IP
.send: ;if ARP_VALID_MAPPING then send the packet
lea edi, [MACAddress] ; Pointer to 48 bit destination address
movzx ecx, word[ebx+2] ; Size of IP packet to send
xchg ch, cl ; because mirror byte-order
mov esi, ebx ; Pointer to packet data
mov bx, ETHER_IP ; Type of packet
call dword [drvr_transmit] ; Call the drivers transmit function
 
; OK, we have sent a packet, so increment the count
519,11 → 289,13
inc dword [ip_tx_count]
 
; And finally, return the buffer to the free queue
.freebuf:
pop eax
call freeBuff
 
etx_exit:
.exit:
ret
endp
 
;***************************************************************************
; Function
554,7 → 326,7
mov edi, eax
 
; get a pointer to the start of the DATA
mov esi, Ether_buffer + 14
mov esi, ETH_FRAME.Data
 
; Now store it all away
mov ecx, IPBUFFSIZE / 4 ; Copy all of the available
571,1131 → 343,94
ret
 
;***************************************************************************
;
; ARP CODE FOLLOWS
;
; The ARP code is used by ethernet drivers to translate an destination
; IP address into an ethernet hardware address. Functions to broadcast
; requests and handle response are (or will be) here.
; The IP layer has no knowledge of ARP, as this is a network interface
; issue
;
;***************************************************************************
 
;***************************************************************************
; Function
; arp_timer
;
; eth_probe
; Description
; Called every 1s
; It is responsible for removing expired routes
; All registers may be destroyed
; Searches for an ethernet card. If found, the card is enabled and
; the ethernet -> IP link established
;
;***************************************************************************
arp_timer:
; loop through all the ARP entries, decrementing each one
; that doesn't have a TTL of 0xFFFF
movzx eax, byte [NumARP]
 
arp_001:
cmp eax, 0
je arp_003
 
push eax
dec eax
mov ecx, ARP_ENTRY_SIZE
mul ecx
cmp word [ eax + ARPTable + 12], 0xFFFF
je arp_002
 
cmp word [ eax + ARPTable + 12], 0
je arp_002
 
dec word [eax + ARPTable + 12]
 
arp_002:
pop eax
dec eax
jmp arp_001
 
; Now, look for entries with a TTL of 0
; Valid entries and response timeout entries get removed
; awaiting response gets converted into a response timeout, with a
; short life time - this allows queued packets to be flushed
arp_003:
movzx edx, byte [NumARP]
cmp edx, 0
je arp_exit
 
; EDX holds the # of entries to search through
mov eax, 0
 
arp_005:
cmp word [ eax + ARPTable + 12], 0
jne arp_004
 
; If it's status code is 0001 or 0003, delete the entry
cmp word [eax + ARPTable + 10], 0x0100
je arp_007
cmp word [eax + ARPTable + 10], 0x0300
je arp_007
 
; The only other valid code is 0002 - indicating a
; timeout while waiting for a response. Change the
; entry to response timed out
 
mov [eax + ARPTable + 10], word 0x0300
mov [eax + ARPTable + 12], word 0x000A
jmp arp_004
 
arp_007:
; Delete this entry
mov edi, ARPTable
add edi, eax
mov esi, edi
add esi, ARP_ENTRY_SIZE
 
mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY_SIZE
sub ecx, eax
 
rep movsb
 
dec byte [NumARP]
jmp arp_006
 
arp_004:
add eax, ARP_ENTRY_SIZE
arp_006:
dec edx
cmp edx, 0
jne arp_005
 
arp_exit:
ret
 
;***************************************************************************
; Function
; arp_request
; This function scans the PCI bus looking for a supported device.
; ISA bus is currently not supported.
;
; Description
; Sends an ARP request on the ethernet
; The requested IP address is in edx
; All registers may be destroyed
;
; eax is 0 if no hardware found
;***************************************************************************
arp_request:
mov ebx, Ether_buffer
mov ax, 0x0100
mov [ebx], ax
add ebx, 2
 
mov ax, 0x0008
mov [ebx], ax
add ebx, 2
 
mov ax, 0x0406
mov [ebx], ax
add ebx, 2
 
mov ax, 0x0100
mov [ebx], ax
add ebx, 2
 
mov ecx, node_addr
mov eax, [ecx]
mov [ebx], eax
add ecx, 4
add ebx, 4
mov ax, [ecx]
mov [ebx], ax
add ebx, 2
mov eax, [stack_ip]
mov [ebx], eax
add ebx, 4
 
eth_probe:
; Find a card on the PCI bus, and get it's address
call scan_bus ; Find the ethernet cards PIC address
xor eax, eax
mov [ebx], eax
add ebx, 4
mov [ebx], ax
cmp [io_addr], eax
je ep_00x ; Return 0 in eax if no cards found
 
add ebx, 2
mov [ebx], edx
call dword [drvr_probe] ; Call the drivers probe function
 
; Now, send it!
mov eax, [io_addr] ; return a non zero value
 
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
mov edi, broadcast_add
 
;if DEBUGGING_STATE = DEBUGGING_ENABLED
; pusha
; mov eax, 1 ; Indicate that this is a tx packet
; mov ecx, 28
; mov esi, Ether_buffer
; call eth_dump
; popa
;end if
 
mov bx, ETHER_ARP
mov ecx, 28
mov esi, Ether_buffer
call dword [drvr_transmit] ; Call the drivers transmit function
ep_00x:
ret
 
;***************************************************************************
; Function
; arp_handler
; ethernet_driver
;
; Description
; Called when an ARP packet is received on the ethernet
; Header + Data is in Ether_buffer[]
; It looks to see if the packet is a request to resolve this Hosts
; IP address. If it is, send the ARP reply packet.
; This Hosts IP address is in dword [stack_ip] ( in network format )
; This Hosts MAC address is in node_addr[6]
; All registers may be destroyed
; The ethernet RX and TX handler
; This is a kernel function, called by stack_handler
;
;***************************************************************************
arp_handler:
; Is this a REQUEST?
; Is this a request for My Host IP
; Yes - So construct a response message.
; Send this message to the ethernet card for transmission
ethernet_driver:
; Do nothing if the driver is inactive
cmp [ethernet_active], byte 0
je eth_exit
 
mov ebx, Ether_buffer
call eth_rx
call eth_tx
 
mov edx, ebx
add edx, 20
mov ax, [edx]
cmp ax, ARP_REQ_OPCODE ; Is this a request packet?
jne arph_resp ; No - so test for response
 
mov edx, ebx
add edx, 38
mov eax, [edx]
 
cmp eax, [stack_ip] ; Is it looking for my IP address?
jne arph_exit ; No - so quit now
 
; OK, it is a request for my MAC address. Build the frame and send it
 
; Save the important data from the original packet
; remote MAC address first
mov ecx, remote_hw_add
mov edx, ebx
add edx, 22 ; edx points to Source h/w address
mov eax, [edx]
mov [ecx], eax
add edx, 4
add ecx, 4
mov ax, [edx]
mov [ecx],ax
 
; and also the remote IP address
add edx, 2
mov eax,[edx]
mov [remote_ip_add], eax
 
; So now we can reuse the packet. ebx still holds the address of
; the header + packet
; We dont need the header ( first 14 bytes )
 
mov edx, ebx
add edx, 20
mov ax, ARP_REP_OPCODE
mov [edx], ax
add edx, 2
 
mov ecx, node_addr
mov eax, [ecx]
mov [edx], eax
add ecx, 4
add edx, 4
mov ax, [ecx]
mov [edx], ax
add edx, 2
mov eax, [stack_ip]
mov [edx], eax
add edx, 4
mov ecx, remote_hw_add
mov eax, [ecx]
mov [edx], eax
add ecx, 4
add edx, 4
mov ax, [ecx]
mov [edx], ax
 
add edx, 2
mov eax, [remote_ip_add]
mov [edx], eax
 
; Now, send it!
 
; Pointer to 48 bit destination address in edi
; Type of packet in bx
; size of packet in ecx
; pointer to packet data in esi
mov edi, remote_hw_add
 
;if DEBUGGING_STATE = DEBUGGING_ENABLED
; pusha
; mov eax, 1 ; Indicate that this is a tx packet
; mov ecx, 28
; mov esi, Ether_buffer + 14
; call eth_dump
; popa
;end if
 
mov bx, ETHER_ARP
mov ecx, 28
mov esi, Ether_buffer + 14
call dword [drvr_transmit] ; Call the drivers transmit function
jmp arph_exit
 
arph_resp:
cmp ax, ARP_REP_OPCODE ; Is this a replypacket?
jne arph_resp ; No - so quit
 
; This was a reply, probably directed at me.
; save the remotes MAC & IP
mov ecx, remote_hw_add
mov edx, ebx
add edx, 22 ; edx points to Source h/w address
mov eax, [edx]
mov [ecx], eax
add edx, 4
add ecx, 4
mov ax, [edx]
mov [ecx],ax
 
; and also the remote IP address
add edx, 2
mov eax,[edx]
mov [remote_ip_add], eax
 
; Now, add an entry in the table for this IP address if it doesn't exist
 
push eax
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
pop edx
movzx ecx, byte [NumARP]
cmp ecx, 0
je arph_002
 
arph_001:
sub eax, ARP_ENTRY_SIZE
cmp [eax + ARPTable], edx
loopnz arph_001 ; Return back if non match
 
jnz arph_002 ; None found, add to end
 
mov ecx, [remote_hw_add]
mov [eax + ARPTable + 4], ecx
mov cx, [remote_hw_add+4]
mov [eax + ARPTable + 8], cx
 
; specify the type - a valid entry
mov cl, 0x00
mov [eax + ARPTable + 10], cl
mov cl, 0x01
mov [eax + ARPTable + 11], cl
 
; Initialise the time to live field - 1 hour
mov cx, 0x0E10
mov [eax + ARPTable + 12], cx
jmp arph_exit
 
arph_002:
 
cmp byte [NumARP], ARP_TABLE_SIZE
je arph_exit
 
inc byte [NumARP]
 
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
sub eax, ARP_ENTRY_SIZE
 
mov ecx, [remote_ip_add]
mov [eax + ARPTable], ecx
mov ecx, [remote_hw_add]
mov [eax + ARPTable + 4], ecx
mov cx, [remote_hw_add+4]
mov [eax + ARPTable + 8], cx
 
mov cl, 0x00
mov [eax + ARPTable + 10], cl
mov cl, 0x01
mov [eax + ARPTable + 11], cl
 
; Initialise the time to live field - 1 hour
mov cx, 0x0E10
mov [eax + ARPTable + 12], cx
 
arph_exit:
eth_exit:
ret
 
; pointer to MAC in esi
refreshARP:
mov ebx, [esi]
mov dx, [esi+4]
push edx
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
pop edx
movzx ecx, byte [NumARP]
cmp ecx, 0
je rf_exit
 
rf_001:
sub eax, ARP_ENTRY_SIZE
cmp [eax + ARPTable+4], ebx
 
je rf_002
loop rf_001
jmp rf_exit
 
rf_002:
cmp [eax + ARPTable+8], dx
je rf_gotone
loop rf_001
jmp rf_exit
 
rf_gotone:
; Initialise the time to live field - 1 hour
mov cx, 0x0E10
mov [eax + ARPTable + 12], cx
 
rf_exit:
ret
 
;***************************************************************************
; Function
; getMACfromIP
; eth_rx
;
; Description
; Takes an IP address in edx and scans the ARP table for
; a matching entry
; If a match is found, it's MAC address is stored in MACAddress.
; Otherwise the value 0 is writen to MACAddress
; eax holds ARP table entry status code ( ARP_ )
; ebx unchanged
; Polls the ethernet card for received data. Extracts if present
; Depending on the Protocol within the packet:
; ARP : Pass to ARP_handler. This may result in an ARP reply
; being tx'ed
; IP : Store in an IP buffer
;
;***************************************************************************
getMACfromIP:
; first, check destination IP to see if it is on 'this' network.
; The test is:
; if ( destIP & subnet_mask == stack_ip & subnet_mask )
; desitnation is local
; else
; destination is remote, so pass to gateway
eth_rx:
xor ax, ax
mov [eth_rx_data_len], ax
call dword [drvr_poll] ; Call the drivers poll function
 
mov eax, edx
and eax, [subnet_mask]
mov ecx, [stack_ip]
and ecx, [subnet_mask]
cmp eax, ecx
je gm0
mov ax, [eth_rx_data_len]
cmp ax, 0
je .exit
 
mov edx, [gateway_ip]
gm0:
push edx
xor eax, eax
mov [MACAddress], eax
mov [MACAddress + 4], ax
 
movzx eax, byte [NumARP]
mov ecx, ARP_ENTRY_SIZE
mul ecx
; Check the protocol. Call appropriate handler
 
pop edx
mov ax, [ETH_FRAME.Type] ; The address of the protocol word
 
movzx ecx, byte [NumARP]
cmp ecx, 0
je gm_none
gm1:
sub eax, ARP_ENTRY_SIZE
cmp [eax + ARPTable], edx
loopnz gm1 ; Return back if non match
jnz gm_none ; Quit if none found
cmp ax, ETHER_IP
je .is_ip ; It's IP
 
; eax holds index
mov ecx, [eax + ARPTable + 4]
mov [MACAddress], ecx
mov cx, [eax + ARPTable + 8]
mov [MACAddress+4], cx
cmp ax, ETHER_ARP
je .is_arp ; It is ARP
 
; Return the entry status in eax
mov ch, [eax + ARPTable + 10]
mov cl, [eax + ARPTable + 11]
movzx eax, cx
jmp gm_exit
jmp .exit ; If not IP or ARP, ignore
 
gm_none:
mov eax, ARP_NO_ENTRY
.is_ip:
inc dword [ip_rx_count]
call ether_IP_handler
jmp .exit
 
gm_exit:
ret
.is_arp:
 
;***************************************************************************
;
; PCI CODE FOLLOWS
;
; the following functions provide access to the PCI interface.
; These functions are used by scan_bus, and also some ethernet drivers
;
;***************************************************************************
; At this point, the packet is still in the Ether_buffer
call arp_handler
 
;***************************************************************************
; Function
; config_cmd
;
; Description
; creates a command dword for use with the PCI bus
; bus # in ebx
; devfn in ecx
; where in edx
;
; command dword returned in eax
; Only eax destroyed
;***************************************************************************
config_cmd:
push ecx
mov eax, ebx
shl eax, 16
or eax, 0x80000000
shl ecx, 8
or eax, ecx
pop ecx
or eax, edx
and eax, 0xFFFFFFFC
ret
 
;***************************************************************************
; Function
; pcibios_read_config_byte
;
; Description
; reads a byte from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; byte returned in al ( rest of eax zero )
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_byte:
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
 
xor eax, eax
and dx, 0x03
add dx, 0xCFC
; and dx, 0xFFC
in al, dx
ret
 
;***************************************************************************
; Function
; pcibios_read_config_word
;
; Description
; reads a word from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; word returned in ax ( rest of eax zero )
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_word:
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
 
xor eax, eax
and dx, 0x02
add dx, 0xCFC
; and dx, 0xFFC
in ax, dx
ret
 
;***************************************************************************
; Function
; pcibios_read_config_dword
;
; Description
; reads a dword from the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; dword returned in eax
; Only eax/edx destroyed
;***************************************************************************
pcibios_read_config_dword:
push edx
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
xor eax, eax
mov dx, 0xCFC
in eax, dx
pop edx
ret
 
;***************************************************************************
; Function
; pcibios_write_config_byte
;
; Description
; write a byte in al to the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; Only eax/edx destroyed
;***************************************************************************
pcibios_write_config_byte:
push ax
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
pop ax
 
and dx, 0x03
add dx, 0xCFC
out dx, al
ret
 
;***************************************************************************
; Function
; pcibios_write_config_word
;
; Description
; write a word in ax to the PCI config space
; bus # in ebx
; devfn in ecx
; where in edx ( ls 16 bits significant )
;
; Only eax/edx destroyed
;***************************************************************************
pcibios_write_config_word:
push ax
call config_cmd
push dx
mov dx, 0xCF8
out dx, eax
pop dx
pop ax
 
and dx, 0x02
add dx, 0xCFC
out dx, ax
ret
 
;***************************************************************************
; Function
; delay_us
;
; Description
; delays for 30 to 60 us
;
; I would prefer this routine to be able to delay for
; a selectable number of microseconds, but this works for now.
;
; If you know a better way to do 2us delay, pleae tell me!
;***************************************************************************
delay_us:
push eax
push ecx
 
mov ecx,2
 
in al,0x61
and al,0x10
mov ah,al
cld
 
dcnt1:
in al,0x61
and al,0x10
cmp al,ah
jz dcnt1
 
mov ah,al
loop dcnt1
 
pop ecx
pop eax
 
ret
 
;***************************************************************************
; Function
; scan_bus
;
; Description
; Scans the PCI bus for a supported device
; If a supported device is found, the drvr_ variables are initialised
; to that drivers functions ( as defined in the PCICards table)
;
; io_addr holds card I/O space. 32 bit, but only LS 16 bits valid
; pci_data holds the PCI vendor + device code
; pci_dev holds PCI bus dev #
; pci_bus holds PCI bus #
;
; io_addr will be zero if no card found
;
;***************************************************************************
scan_bus:
xor eax, eax
mov [hdrtype], al
mov [pci_data], eax
 
xor ebx, ebx ; ebx = bus# 0 .. 255
 
sb_bus_loop:
xor ecx, ecx ; ecx = devfn# 0 .. 254 ( not 255? )
 
sb_devf_loop:
mov eax, ecx
and eax, 0x07
 
cmp eax, 0
jne sb_001
 
mov edx, PCI_HEADER_TYPE
call pcibios_read_config_byte
mov [hdrtype], al
jmp sb_002
 
sb_001:
mov al, [hdrtype]
and al, 0x80
cmp al, 0x80
jne sb_inc_devf
 
sb_002:
mov edx, PCI_VENDOR_ID
call pcibios_read_config_dword
mov [vendor_device], eax
cmp eax, 0xffffffff
je sb_empty
cmp eax, 0
jne sb_check_vendor
 
sb_empty:
mov [hdrtype], byte 0
jmp sb_inc_devf
 
sb_check_vendor:
; iterate though PCICards until end or match found
mov esi, PCICards
 
sb_check:
cmp [esi], dword 0
je sb_inc_devf ; Quit if at last entry
cmp eax, [esi]
je sb_got_card
add esi, PCICARDS_ENTRY_SIZE
jmp sb_check
 
sb_got_card:
; indicate that we have found the card
mov [pci_data], eax
mov [pci_dev], ecx
mov [pci_bus], ebx
 
; Define the driver functions
push eax
mov eax, [esi+4]
mov [drvr_probe], eax
mov eax, [esi+8]
mov [drvr_reset], eax
mov eax, [esi+12]
mov [drvr_poll], eax
mov eax, [esi+16]
mov [drvr_transmit], eax
pop eax
 
mov edx, PCI_BASE_ADDRESS_0
 
sb_reg_check:
call pcibios_read_config_dword
mov [io_addr], eax
and eax, PCI_BASE_ADDRESS_IO_MASK
cmp eax, 0
je sb_inc_reg
mov eax, [io_addr]
and eax, PCI_BASE_ADDRESS_SPACE_IO
cmp eax, 0
je sb_inc_reg
 
mov eax, [io_addr]
and eax, PCI_BASE_ADDRESS_IO_MASK
mov [io_addr], eax
 
sb_exit1:
ret
 
sb_inc_reg:
add edx, 4
cmp edx, PCI_BASE_ADDRESS_5
jbe sb_reg_check
 
sb_inc_devf:
inc ecx
cmp ecx, 255
jb sb_devf_loop
inc ebx
cmp ebx, 256
jb sb_bus_loop
 
; We get here if we didn't find our card
; set io_addr to 0 as an indication
xor eax, eax
mov [io_addr], eax
 
sb_exit2:
ret
 
;***************************************************************************
;
; DEBUGGING CODE FOLLOWS
;
; If debugging data output is not required, ALL code & data below may
; be removed.
;
;***************************************************************************
 
if DEBUGGING_STATE = DEBUGGING_ENABLED
 
;***************************************************************************
; Function
; eth_dump
;
; Description
; Dumps a tx or rx ethernet packet over the rs232 link
; This is a debugging routine that seriously slows down the stack.
; Use with caution.
;
; Baud rate is 57600, 8n1 com1
; eax : type (0 == rx, 1 == tx )
; cx : # of bytes in buffer
; esi : address of buffer start
; edi : pointer to MACAddress ( tx only )
;
;***************************************************************************
eth_dump:
pusha
 
; Set the port to the desired speed
mov ebx, 0x3f8 ; combase
 
mov edx, ebx
add edx, 3 ; data format register
mov al, 0x80 ; enable access to divisor latch
out dx, al
 
mov edx, ebx
add edx, 1 ; interrupt enable register
mov al, 0x00 ; No interruts enabled
out dx, al
 
mov edx, ebx
mov al, 0x20 / 16 ; set baud rate to 57600 0x10 =115200
out dx, al
 
mov edx, ebx
add edx, 3 ; data format register
mov al, 0x03 ; 8 data bits
out dx, al
 
mov edx, ebx
add edx, 4 ; Modem control register
mov al, 0x08 ; out2 enabled. No handshaking.
out dx, al
 
mov edx, ebx
add edx, 1 ; interrupt enable register
mov al, 0x01 ; Receive data interrupt enabled,
out dx, al
 
popa
 
; First, display the type of the buffer.
; If it is a tx buffer, display the macaddress
 
pusha
 
cmp eax, 0
jne dd001
 
mov bl, 0x0a
call tx_byted
mov bl, 0x0d
call tx_byted
 
; Output "RX:"
mov bl, 'R'
call tx_byted
mov bl, 'X'
call tx_byted
mov bl, ':'
call tx_byted
jmp dump_data
 
dd001:
mov bl, 0x0a
call tx_byted
mov bl, 0x0d
call tx_byted
 
; Output TX: xxxxxxxxxxxx
mov bl, 'T'
call tx_byted
mov bl, 'X'
call tx_byted
mov bl, ':'
call tx_byted
mov bl, ' '
call tx_byted
 
; Display MAC address
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
inc edi
xor eax, eax
mov al, [edi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [edi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
dump_data:
popa
 
; OK, we come in here with
; cx == number of byte to send
; esi == buffer start
;
dd_000:
mov bl, 0x0a
call tx_byted
mov bl, 0x0d
call tx_byted
 
mov eax, 16 ; Number of characters on the line
mov edi, esi ; Save first byte position for later
 
push ecx
 
dd_001:
push eax
 
; Print a byte, and a space
xor eax, eax
mov al, [esi]
shr al, 4
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
xor eax, eax
mov al, [esi]
and al, 0x0f
mov bl, [eax + hexchars]
call tx_byted ; byte in bl eax ebx edx destroyed
 
mov bl, ' '
call tx_byted
 
pop eax
 
inc esi
dec ecx
cmp ecx, 0
je dd_0011 ; Print the ASCII format
 
dec eax
 
cmp eax, 0
je dd_002 ; Print the ASCII format
jmp dd_001 ; Print rest of line
 
dd_0011:
; First, complete the 16 bytes of data, by printing spaces
dec eax
cmp eax, 0
je dd_002
 
push eax
mov bl, ' '
call tx_byted
mov bl, ' '
call tx_byted
mov bl, ' '
call tx_byted
pop eax
jmp dd_0011
 
dd_002:
pop ecx
mov esi, edi ; Go back to the start of the line data
 
mov eax, 16
 
outLineAscii:
push eax
 
xor eax, eax
mov al, [esi]
mov bl, '.'
 
cmp al, 0x1F
jle outAscii
cmp al, 0x7e
jge outAscii
 
mov bl, al
 
outAscii:
call tx_byted ; byte in bl eax ebx edx destroyed
 
pop eax
dec ecx
inc esi
cmp ecx, 0
je dd_003
 
dec eax
cmp eax, 0
je dd_003
jmp outLineAscii
 
dd_003:
cmp ecx, 0
je dd_004
jmp dd_000
 
dd_004:
ret
 
;***************************************************************************
; Function
; tx_byte
;
; Description
; Send a byte in bl out of the com port 1
; destroys eax, edx
;
;***************************************************************************
tx_byted:
push ebx ; Save the byte
 
mov ebx, 0x3f8 ; get the com port address
 
; Wait for transmit buffer to empty. This could take 1ms @ 9600baud
 
mov edx, ebx
add edx, 5
 
wait_txd:
in al, dx ; read uart serialisation status
and al, 0x40
cmp al, 0
jz wait_txd ; loop until free
 
mov edx, ebx
pop eax ; restore the byte to send
out dx, al
ret
 
iglobal
; This is used for translating hex to ASCII for display or output
hexchars db '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
endg
end if
 
.exit:
ret