0,0 → 1,509 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ETHERNET.INC ;; |
;; ;; |
;; Ethernet network layer for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
$Revision: 983 $ |
|
MAX_ETH_DEVICES equ MAX_NET_DEVICES |
ETH_QUEUE_SIZE equ 16 |
|
struct 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: ; data [46-1500 bytes] |
ends |
|
struct ETH_DEVICE |
.unload dd ? |
.reset dd ? |
.transmit dd ? |
.set_MAC dd ? |
.get_MAC dd ? |
.set_mode dd ? |
.get_mode dd ? |
|
.bytes_tx dq ? |
.bytes_rx dq ? |
.packets_tx dd ? |
.packets_rx dd ? |
.mode dd ? ; This dword contains cable status (10mbit/100mbit, full/half duplex, auto negotiation or not,..) |
.name dd ? |
.mac dp ? |
ends ; the rest of the device struct depends on the type of device |
|
|
align 4 |
uglobal |
|
ETH_RUNNING dd ? |
ETH_DRV_LIST rd MAX_ETH_DEVICES |
ETH_IN_QUEUE rd 3*ETH_QUEUE_SIZE+3 |
ETH_OUT_QUEUE rd 3*ETH_QUEUE_SIZE+3 |
endg |
|
|
;----------------------------------------------- |
; |
; ETH_init |
; |
; This function resets all ethernet variables |
; |
; IN: / |
; OUT: / |
; |
;----------------------------------------------- |
|
align 4 |
ETH_init: |
|
xor eax, eax |
mov edi, ETH_RUNNING |
mov ecx, (1+MAX_ETH_DEVICES) |
rep stosd |
|
mov dword [ETH_IN_QUEUE], eax |
mov dword [ETH_IN_QUEUE+4], ETH_IN_QUEUE + queue.data |
mov dword [ETH_IN_QUEUE+8], ETH_IN_QUEUE + queue.data |
|
mov dword [ETH_OUT_QUEUE], eax |
mov dword [ETH_OUT_QUEUE+4], ETH_OUT_QUEUE + queue.data |
mov dword [ETH_OUT_QUEUE+8], ETH_OUT_QUEUE + queue.data |
|
ret |
|
|
|
;--------------------------------------------------------- |
; |
; ETH_Add_Device: |
; |
; This function is called by ethernet drivers, |
; to register each running ethernet device to the kernel |
; |
; IN: Pointer to device structure in ebx |
; OUT: Device num in eax, -1 on error |
; |
;--------------------------------------------------------- |
|
align 4 |
ETH_Add_Device: |
|
DEBUGF 1,"ETH_Add_Device: %x\n", ebx |
cmp [ETH_RUNNING], MAX_ETH_DEVICES |
jge .error |
|
mov eax, ebx |
mov ecx, MAX_ETH_DEVICES ; We need to check whole list because a device may be removed without re-organizing list |
mov edi, ETH_DRV_LIST |
|
cld |
repne scasd ; See if device is already in the list |
jz .error |
|
xor eax, eax |
mov ecx, MAX_ETH_DEVICES |
mov edi, ETH_DRV_LIST |
|
repne scasd ; Find empty spot in the list |
jnz .error |
|
sub edi, 4 |
mov [edi], ebx ; add device to list |
|
sub edi, ETH_DRV_LIST ; edi = 4*device num Calculate device number in eax |
mov eax, edi ; edx = 4*device num |
shr eax, 2 |
|
; shr eax, 1 ; edx = 2*device num |
; add edi, eax ; edi = 6*device_num Meanwhile, calculate MAC offset in edi |
; shr eax, 1 ; edx = device num |
; add edi, MAC_LIST ; edi = MAC_LIST+6*device_num |
; push eax |
|
; push edi |
; call [ebx+ETH_DEVICE.get_MAC] ; Get MAC address from driver |
; pop edi |
; |
; stosd ; Write MAC address to the MAC list |
; mov ax, bx ; |
; stosw ; |
|
inc [ETH_RUNNING] ; Indicate that one more ethernet device is up and running |
; pop eax ; Output device num in eax |
DEBUGF 1,"- succes: %u\n",eax |
ret |
|
.error: |
or eax, -1 |
DEBUGF 1,"- fail\n" |
|
ret |
|
|
|
|
;-------------------------------- |
; |
; ETH_Remove_Device: |
; |
; This function is called by ethernet drivers, |
; to unregister ethernet devices from the kernel |
; |
; IN: Pointer to device structure in ebx |
; OUT: eax: -1 on error |
; |
;-------------------------------- |
|
align 4 |
ETH_Remove_Device: |
|
cmp [ETH_RUNNING], 0 |
je .error |
|
mov eax, ebx |
mov ecx, MAX_ETH_DEVICES |
mov edi, ETH_DRV_LIST |
|
repne scasd |
jnz .error |
|
xor eax, eax |
mov dword [edi-4], eax |
|
dec [ETH_RUNNING] |
|
ret |
|
.error: |
or eax, -1 |
|
ret |
|
|
|
;------------------------------------------------------------- |
; |
; ETH_Receiver: |
; |
; This function is called by ethernet drivers, |
; It pushes the received ethernet packets onto the eth_in_queue |
; |
; IN: Pointer to buffer in [esp], size of buffer in [esp-4], pointer to eth_device in ebx |
; OUT: / |
; |
;------------------------------------------------------------- |
|
align 4 |
ETH_Receiver: |
DEBUGF 1,"ETH_Receiver \n" |
|
add_to_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, .gohome |
|
.gohome: |
ret |
|
|
|
|
|
;------------------------------------------------------------- |
; |
; ETH_Handler: |
; |
; Handles all queued eth packets (called from kernel's main_loop) |
; |
; IN: / |
; OUT: / |
; |
;------------------------------------------------------------- |
|
align 4 |
ETH_Handler: |
|
get_from_queue ETH_IN_QUEUE, ETH_QUEUE_SIZE, .gohome |
|
DEBUGF 1,"ETH_Handler - size: %u\n", ecx |
cmp ecx, 60 ; check packet length |
jl .dump |
sub ecx, ETH_FRAME.Data |
|
lea edx, [eax + ETH_FRAME.Data] |
mov ax , [eax + ETH_FRAME.Type] |
|
cmp ax, ETHER_IPv4 |
je IPv4_Handler |
|
cmp ax, ETHER_ARP |
je ARP_Handler |
|
DEBUGF 1,"Unknown ethernet packet type %x\n", ax |
|
.dump: |
DEBUGF 1,"Dumping packet\n" |
call kernel_free |
add esp, 4 |
|
.gohome: |
ret ; return 1. to get more from queue / 2. to caller |
|
|
|
;----------------------------------------------------------------- |
; |
; ETH_Sender: |
; |
; This function sends an ethernet packet to the correct driver. |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; pointer to device struct in ebx |
; OUT: / |
; |
;----------------------------------------------------------------- |
|
align 4 |
ETH_Sender: |
DEBUGF 1,"ETH_Sender \n" |
|
add_to_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, .gohome |
|
.gohome: |
ret |
|
|
align 4 |
ETH_send_queued: |
|
get_from_queue ETH_OUT_QUEUE, ETH_QUEUE_SIZE, .gohome |
|
call ETH_struc2dev ; convert struct ptr to device num (this way we know if driver is still mounted) |
cmp edi, -1 |
je .fail |
|
DEBUGF 1,"ETH_Sender - device: %u\n", edi |
|
jmp [ebx+ETH_DEVICE.transmit] |
|
.fail: |
call kernel_free |
add esp, 4 ; pop (balance stack) |
DEBUGF 1,"ETH_Sender - fail\n" |
.gohome: |
ret |
|
;--------------------------------------------------------------------------- |
; |
; ETH_struc2dev |
; |
; IN: pointer to device struct in ebx |
; |
; OUT: edi is -1 on error, device number otherwise |
; |
;--------------------------------------------------------------------------- |
|
align 4 |
ETH_struc2dev: |
push eax ecx |
|
mov eax, ebx |
mov ecx, MAX_ETH_DEVICES |
mov edi, ETH_DRV_LIST |
|
repne scasd |
jnz .error |
|
sub edi, ETH_DRV_LIST+4 |
shr edi, 2 |
|
pop ecx eax |
ret |
.error: |
or edi, -1 |
pop ecx eax |
|
ret |
|
|
;--------------------------------------------------------------------------- |
; |
; ETH_create_Packet |
; |
; IN: pointer to source mac in eax |
; pointer to destination mac in ebx |
; packet size in ecx |
; device number in edx |
; protocol in di |
; |
; OUT: edi is -1 on error, pointer to buffer otherwise ;; TODO: XCHG EDX AND EBX output parameters |
; eax points to buffer start |
; ebx is size of complete buffer |
; ecx is unchanged (packet size of embedded data) |
; edx is pointer to device structure |
; esi points to procedure wich needs to be called to send packet |
; |
;--------------------------------------------------------------------------- |
|
align 4 |
ETH_create_Packet: |
|
DEBUGF 1,"Creating Ethernet Packet:\n" |
|
cmp ecx, 60-ETH_FRAME.Data |
jl .exit |
cmp ecx, 1514-ETH_FRAME.Data |
jg .exit |
|
push ecx di eax ebx edx |
|
add ecx, ETH_FRAME.Data |
push ecx |
push ecx |
call kernel_alloc |
test eax, eax |
jz .pop_exit |
|
pop ecx |
pop edx |
|
DEBUGF 1,"1" |
mov edi, eax |
pop esi |
movsd |
movsw |
DEBUGF 1,"2" |
pop esi |
movsd |
movsw |
DEBUGF 1,"3" |
pop ax |
stosw |
DEBUGF 1,"4" |
|
lea eax, [edi - ETH_FRAME.Data] ; Set eax to buffer start |
mov ebx, ecx ; Set ebx to complete buffer size |
pop ecx |
mov esi, ETH_Sender |
|
xor edx, edx ;;;; TODO: Fixme |
mov edx, [ETH_DRV_LIST + edx] |
|
DEBUGF 1,"done: %x size:%u device:%x\n", eax, ebx, edx |
ret |
|
.pop_exit: |
add esp, 18 |
.exit: |
or edi, -1 |
ret |
|
|
|
|
;--------------------------------------------------------------------------- |
; |
; ETH_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;--------------------------------------------------------------------------- |
|
align 4 |
ETH_API: |
|
movzx eax, bh |
shl eax, 2 |
|
test bl, bl |
jz .packets_tx ; 0 |
dec bl |
jz .packets_rx ; 1 |
dec bl |
jz .bytes_tx ; 2 |
dec bl |
jz .bytes_rx ; 3 |
dec bl |
jz .read_mac ; 4 |
dec bl |
jz .write_mac ; 5 |
dec bl |
jz .in_queue ; 6 |
dec bl |
jz .out_queue ; 7 |
|
|
.error: |
mov eax, -1 |
ret |
|
.packets_tx: |
add eax, ETH_DRV_LIST |
mov eax, [eax] |
mov eax, [eax + ETH_DEVICE.packets_tx] |
ret |
|
.packets_rx: |
add eax, ETH_DRV_LIST |
mov eax, [eax] |
mov eax, [eax + ETH_DEVICE.packets_rx] |
ret |
|
.bytes_tx: |
add eax, ETH_DRV_LIST |
mov eax, [eax] |
mov eax, dword [eax + ETH_DEVICE.bytes_tx + 4] |
ret |
|
.bytes_rx: |
add eax, ETH_DRV_LIST |
mov eax, [eax] |
mov eax, dword [eax + ETH_DEVICE.bytes_rx + 4] |
ret |
|
.read_mac: |
add eax, ETH_DRV_LIST |
mov eax, [eax] |
; push eax |
; call dword [eax + ETH_DEVICE.get_MAC] |
; pop eax |
movzx ebx, word [eax + ETH_DEVICE.mac] |
mov eax, dword [eax + ETH_DEVICE.mac + 2] |
mov [esp+20+4], ebx ; TODO: fix this ugly code |
ret |
|
.write_mac: |
push ecx |
push dx |
add eax, ETH_DRV_LIST |
mov eax, [eax] |
mov eax, dword [eax + ETH_DEVICE.set_MAC] |
call eax |
ret |
|
.in_queue: |
add eax, ETH_IN_QUEUE |
mov eax, [eax + queue.size] |
ret |
|
.out_queue: |
add eax, ETH_OUT_QUEUE |
mov eax, [eax + queue.size] |
ret |