kolibrios/kernel/branches/net/network/IPv4.inc
hidnplayr 8a7ebf6b32 fix in ARPcfg application
added pci ids of dec21x4x cards to netcfg
bugfixes in dex21x4x driver, pcnet32 driver, rtl8139 driver and sis900 driver
new network program (ICMP) to ping computers, uses new RAW socket code (experimental)

git-svn-id: svn://kolibrios.org@1541 a494cfbc-eb01-0410-851d-a64ba20cac60
2010-07-30 21:54:27 +00:00

1019 lines
25 KiB
PHP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; IPv4.INC ;;
;; ;;
;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;;
;; Based on the work of [Johnny_B] and [smb] ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
MAX_FRAGMENTS equ 64
MAX_IP equ MAX_NET_DEVICES
IP_MAX_INTERFACES equ MAX_IP
struct IPv4_Packet
.VersionAndIHL db ? ; Version[0-3 bits] and IHL(header length)[4-7 bits]
.TypeOfService db ? ; precedence [7-5] minimize delay [4], maximize throughput [3], maximize riliability [2] minimize momentary cost [1] and zero [0]
.TotalLength dw ?
.Identification dw ?
.FlagsAndFragmentOffset dw ? ; Flags[0-2] and FragmentOffset[3-15]
.TimeToLive db ? ;
.Protocol db ?
.HeaderChecksum dw ?
.SourceAddress dd ?
.DestinationAddress dd ?
.DataOrOptional:
ends
struct FRAGMENT_slot
.ttl dw ? ; Time to live for this entry, 0 for empty slot's
.id dw ? ; Identification field from IP header
.SrcIP dd ? ; .. from IP header
.DstIP dd ? ; .. from IP header
.ptr dd ? ; Pointer to first packet
.size:
ends
struct FRAGMENT_entry ; This structure will replace the ethernet header in fragmented ip packets
.PrevPtr dd ? ; Pointer to previous fragment entry (-1 for first packet)
.NextPtr dd ? ; Pointer to next fragment entry (-1 for last packet)
.Owner dd ? ; Pointer to structure of driver
rb 2 ; to match ethernet header size ; TODO: fix this hack
.Data: ; Ip header begins here (we will need the IP header to re-construct the complete packet)
ends
align 4
uglobal
IP_LIST rd MAX_IP
SUBNET_LIST rd MAX_IP
DNS_LIST rd MAX_IP
GATEWAY_LIST rd MAX_IP
IP_PACKETS_TX rd MAX_IP
IP_PACKETS_RX rd MAX_IP
FRAGMENT_LIST rb MAX_FRAGMENTS*FRAGMENT_slot.size
endg
;-----------------------------------------------------------------
;
; IPv4_init
;
; This function resets all IP variables
;
;-----------------------------------------------------------------
macro IPv4_init {
xor eax, eax
mov edi, IP_LIST
mov ecx, 4*MAX_IP
rep stosd
mov edi, FRAGMENT_LIST
mov ecx, FRAGMENT_slot.size*MAX_FRAGMENTS/4 + 2*MAX_IP
rep stosd
}
;-----------------------------------------------------------------
;
; 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
}
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
}
;-----------------------------------------------------------------
;
; IPv4_input:
;
; Will check if IP Packet isnt damaged
; and call appropriate handler. (TCP/UDP/ICMP/..)
;
; It will also re-construct fragmented packets
;
; IN: Pointer to buffer in [esp]
; size of buffer in [esp+4]
; pointer to device struct in ebx
; pointer to IP Packet data in edx
; OUT: /
;
;-----------------------------------------------------------------
align 4
IPv4_input: ; TODO: implement handler for IP options
; TODO2: add code for raw sockets
DEBUGF 1,"IPv4_Handler, packet from: %u.%u.%u.%u ",\
[edx + IPv4_Packet.SourceAddress]:1,[edx + IPv4_Packet.SourceAddress + 1]:1,[edx + IPv4_Packet.SourceAddress + 2]:1,[edx + IPv4_Packet.SourceAddress + 3]:1
DEBUGF 1,"to: %u.%u.%u.%u\n",\
[edx + IPv4_Packet.DestinationAddress]:1,[edx + IPv4_Packet.DestinationAddress + 1]:1,[edx + IPv4_Packet.DestinationAddress + 2]:1,[edx + IPv4_Packet.DestinationAddress + 3]:1
;-------------------------------------------
; Check if the packet still has time to live
cmp byte [edx + IPv4_Packet.TimeToLive], 0
je .dump
;--------------------------------------
; First, check if IP packet has options
movzx eax, [edx + IPv4_Packet.VersionAndIHL]
and al , 0x0f ; get IHL(header length)
cmp al , 0x05 ; IHL!= 5*4(20 bytes)
jnz .has_options
;-------------------------------
; Now, re-calculate the checksum
IPv4_checksum edx
jnz .dump ; if checksum isn't valid then dump packet
DEBUGF 1,"IPv4 Checksum is correct\n"
;-----------------------------------
; Check if destination IP is correct
call NET_ptr_to_num
shl edi, 2
; check if it matches local ip
mov eax, dword[IP_LIST+edi]
cmp [edx + IPv4_Packet.DestinationAddress], eax
je .ip_ok
; check for broadcast
mov eax, dword[SUBNET_LIST+edi]
not eax
or eax, dword[IP_LIST+edi]
cmp [edx + IPv4_Packet.DestinationAddress], eax
je .ip_ok
; or a special broadcast
cmp [edx + IPv4_Packet.DestinationAddress], -1
je .ip_ok
; maybe it's a multicast then
mov eax, [edx + IPv4_Packet.DestinationAddress]
and eax, 0xff000000
; cmp eax, 224 shl 24
; je .ip_ok
; or a loopback address
cmp eax, 127 shl 24
je .ip_ok
; or it's not meant for us..
DEBUGF 2,"Destination address does not match!\n"
jmp .dump
;------------------------
; Now we can update stats
.ip_ok:
inc [IP_PACKETS_RX+edi]
;----------------------------------
; Check if the packet is fragmented
test [edx + IPv4_Packet.FlagsAndFragmentOffset], 1 shl 5 ; Is 'more fragments' flag set ?
jnz .has_fragments ; If so, we definately have a fragmented packet
test [edx + IPv4_Packet.FlagsAndFragmentOffset], 0xff1f ; If flag is not set, but there is a fragment offset, the packet is last in series of fragmented packets
jnz .is_last_fragment
;-------------------------------------------------------------------
; No, it's just a regular IP packet, pass it to the higher protocols
.handle_it: ; We reach here if packet hasnt been fragmented, or when it already has been re-constructed
movzx eax, byte [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field
and eax, 0x0000000f ;
shl eax, 2 ;
movzx ecx, word [edx + IPv4_Packet.TotalLength] ; Calculate length of encapsulated Packet
xchg cl , ch ;
sub ecx, eax ;
add eax, edx
push eax
mov esi, [edx + IPv4_Packet.SourceAddress] ; These values might be of interest to the higher protocols
mov edi, [edx + IPv4_Packet.DestinationAddress] ;
mov al , [edx + IPv4_Packet.Protocol]
pop edx ; Offset to data (tcp/udp/icmp/.. Packet)
cmp al , IP_PROTO_TCP
je TCP_input
cmp al , IP_PROTO_UDP
je UDP_input
cmp al , IP_PROTO_ICMP
je ICMP_input
DEBUGF 2,"unknown Internet protocol: %u\n", al
.dump:
DEBUGF 2,"IP_Handler - dumping\n"
; inc [dumped_rx_count]
call kernel_free
add esp, 4 ; pop (balance stack)
ret
;---------------------------
; Fragmented packet handler
.has_fragments:
movzx eax, [edx + IPv4_Packet.FlagsAndFragmentOffset]
xchg al , ah
shl ax , 3
DEBUGF 1,"Fragmented packet, offset:%u, id:%x\n", ax, [edx + IPv4_Packet.Identification]:4
test ax , ax ; Is this the first packet of the fragment?
jz .is_first_fragment
;-------------------------------------------------------
; We have a fragmented IP packet, but it's not the first
DEBUGF 1,"Middle fragmented packet received!\n"
call IPv4_find_fragment_slot
cmp esi, -1
je .dump
mov word [esi + FRAGMENT_slot.ttl], 15 ; Reset the ttl
mov esi, [esi + FRAGMENT_slot.ptr]
or edi, -1
.find_last_entry: ; The following routine will try to find the last entry
cmp edi, [esi + FRAGMENT_entry.PrevPtr]
jne .destroy_slot ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
mov edi, esi
mov esi, [esi + FRAGMENT_entry.NextPtr]
cmp esi, -1
jne .find_last_entry
; We found the last entry (pointer is now in edi)
; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
pop eax ; pointer to packet
mov [edi + FRAGMENT_entry.NextPtr], eax ; update pointer of previous entry to the new entry
mov [eax + FRAGMENT_entry.NextPtr], -1
mov [eax + FRAGMENT_entry.PrevPtr], edi
mov [eax + FRAGMENT_entry.Owner], ebx
add esp, 4
ret
;------------------------------------
; We have received the first fragment
.is_first_fragment:
DEBUGF 1,"First fragmented packet received!\n"
; try to locate a free slot..
mov ecx, MAX_FRAGMENTS
mov esi, FRAGMENT_LIST
.find_free_slot:
cmp word [esi + FRAGMENT_slot.ttl], 0
je .found_free_slot
add esi, FRAGMENT_slot.size
loop .find_free_slot
jmp .dump ; If no free slot was found, dump the packet
.found_free_slot: ; We found a free slot, let's fill in the FRAGMENT_slot structure
mov word [esi + FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl
mov ax , word [edx + IPv4_Packet.Identification]
mov word [esi + FRAGMENT_slot.id], ax
mov eax, dword [edx + IPv4_Packet.SourceAddress]
mov dword [esi + FRAGMENT_slot.SrcIP], eax
mov eax, dword [edx + IPv4_Packet.DestinationAddress]
mov dword [esi + FRAGMENT_slot.DstIP], eax
pop eax
mov dword [esi + FRAGMENT_slot.ptr], eax
; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
mov [eax + FRAGMENT_entry.NextPtr], -1
mov [eax + FRAGMENT_entry.PrevPtr], -1
mov [eax + FRAGMENT_entry.Owner], ebx
add esp, 4 ; balance stack and exit
ret
;-----------------------------------
; We have received the last fragment
.is_last_fragment:
DEBUGF 1,"Last fragmented packet received!\n"
call IPv4_find_fragment_slot
cmp esi, -1
je .dump
mov esi, [esi + FRAGMENT_slot.ptr] ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer
push esi
xor eax, eax
or edi, -1
.count_bytes:
cmp [esi + FRAGMENT_entry.PrevPtr], edi
jne .destroy_slot_pop ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
mov cx, word [esi + FRAGMENT_entry.Data + IPv4_Packet.TotalLength] ; Add total length
xchg cl, ch
DEBUGF 1,"Packet size: %u\n", cx
add ax, cx
movzx cx, byte [esi + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL] ; Sub Header length
and cx, 0x000F
shl cx, 2
DEBUGF 1,"Header size: %u\n", cx
sub ax, cx
mov edi, esi
mov esi, [esi + FRAGMENT_entry.NextPtr]
cmp esi, -1
jne .count_bytes
mov esi, [esp+4]
mov [edi + FRAGMENT_entry.NextPtr], esi ; Add this packet to the chain, this simplifies the following code
mov [esi + FRAGMENT_entry.NextPtr], -1
mov [esi + FRAGMENT_entry.PrevPtr], edi
mov [esi + FRAGMENT_entry.Owner], ebx
mov cx, [edx + IPv4_Packet.TotalLength] ; Note: This time we dont substract Header length
xchg cl , ch
DEBUGF 1,"Packet size: %u\n", cx
add ax , cx
DEBUGF 1,"Total Received data size: %u\n", eax
push eax
mov ax , [edx + IPv4_Packet.FlagsAndFragmentOffset]
xchg al , ah
shl ax , 3
add cx , ax
pop eax
DEBUGF 1,"Total Fragment size: %u\n", ecx
cmp ax, cx
jne .destroy_slot_pop
push eax
push eax
call kernel_alloc
test eax, eax
je .destroy_slot_pop ; If we dont have enough space to allocate the buffer, discard all packets in slot
mov edx, [esp+4] ; Get pointer to first fragment entry back in edx
.rebuild_packet_loop:
movzx ecx, word [edx + FRAGMENT_entry.Data + IPv4_Packet.FlagsAndFragmentOffset] ; Calculate the fragment offset
xchg cl , ch ; intel byte order
shl cx , 3 ; multiply by 8 and clear first 3 bits
DEBUGF 1,"Fragment offset: %u\n", cx
lea edi, [eax + ecx] ; Notice that edi will be equal to eax for first fragment
movzx ebx, byte [edx + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL] ; Find header size (in ebx) of fragment
and bx , 0x000F ;
shl bx , 2 ;
lea esi, [edx + FRAGMENT_entry.Data] ; Set esi to the correct begin of fragment
movzx ecx, word [edx + FRAGMENT_entry.Data + IPv4_Packet.TotalLength] ; Calculate total length of fragment
xchg cl, ch ; intel byte order
cmp edi, eax ; Is this packet the first fragment ?
je .first_fragment
sub cx, bx ; If not, dont copy the header
add esi, ebx ;
.first_fragment:
push cx ; First copy dword-wise, then byte-wise
shr cx, 2 ;
rep movsd ;
pop cx ;
and cx, 3 ;
rep movsb ;
push eax
push edx ; Push pointer to fragment onto stack
mov ebx, [edx + FRAGMENT_entry.Owner] ; we need to remeber the owner, in case this is the last packet
mov edx, [edx + FRAGMENT_entry.NextPtr] ; Set edx to the next pointer
call kernel_free ; free the previous fragment buffer (this uses the value from stack)
pop eax
cmp edx, -1 ; Check if it is last fragment in chain
jne .rebuild_packet_loop
pop ecx ;
xchg cl, ch
mov edx, eax
mov word [edx + IPv4_Packet.TotalLength], cx
add esp, 8
xchg cl, ch ;
push ecx ;;;;
push eax ;;;;
; mov esi, edx ; This prints the IP packet to the debug board (usefull when using serial output debug..)
; ;
; packet_to_debug
jmp .handle_it ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
.destroy_slot_pop:
add esp, 4
.destroy_slot:
DEBUGF 1,"Destroy fragment slot!\n"
; TODO!
jmp .dump
;-----------------------------------
; The IP packet has some options
.has_options:
jmp .dump
;-----------------------------------------------------------------
;
; find fragment slot
;
; IN: pointer to fragmented packet in edx
; OUT: pointer to slot in edi, -1 on error
;
;-----------------------------------------------------------------
align 4
IPv4_find_fragment_slot:
;;; TODO: the RFC says we should check protocol number too
push eax ebx ecx edx
mov ax , word [edx + IPv4_Packet.Identification]
mov ecx, MAX_FRAGMENTS
mov esi, FRAGMENT_LIST
mov ebx, dword [edx + IPv4_Packet.SourceAddress]
mov edx, dword [edx + IPv4_Packet.DestinationAddress]
.find_slot:
cmp word [esi + FRAGMENT_slot.id], ax
jne .try_next
cmp dword [esi + FRAGMENT_slot.SrcIP], ebx
jne .try_next
cmp dword [esi + FRAGMENT_slot.DstIP], edx
je .found_slot
.try_next:
add esi, FRAGMENT_slot.size
loop .find_slot
; pop edx ebx
or esi, -1
; ret
.found_slot:
pop edx ecx ebx eax
ret
;------------------------------------------------------------------
;
; IPv4_output
;
; IN: eax = dest ip
; ebx = source ip
; ecx = data length
; dx = fragment id
; di = TTL shl 8 + protocol
;
; OUT: eax = pointer to buffer start
; ebx = pointer to device struct (needed for sending procedure)
; ecx = unchanged (packet size of embedded data)
; edx = size of complete buffer
; edi = pointer to start of data (0 on error)
;
;------------------------------------------------------------------
align 4
IPv4_output:
DEBUGF 1,"IPv4_create_packet: size=%u\n", ecx
cmp ecx, 65500 ; Max IPv4 packet size
jg .too_large
push ecx eax ebx dx di
call ARP_IP_to_MAC
test eax, 0xffff0000 ; error bits
jnz .arp_error
.continue:
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
;------------------------------------------------------------------
;
; IPv4_output_raw
;
; IN: eax = socket ptr
; ecx = data length
; esi = data ptr
;
; OUT: /
;
;------------------------------------------------------------------
align 4
IPv4_output_raw:
DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
cmp ecx, 1480 ;;;;;
jg .too_large
sub esp, 8
push esi eax
call ARP_IP_to_MAC
test eax, 0xffff0000 ; error bits
jnz .arp_error
.continue:
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 + 6+4]
add ecx, IPv4_Packet.DataOrOptional
mov di, ETHER_IPv4
call ETH_output
jz .error
add esp, 6 ; pop the mac
mov dword[esp+4+4], edx
mov dword[esp+4+4+4], eax
pop eax esi
;; todo: check socket options if we should add header, or just compute checksum
push edi ecx
rep movsb
pop ecx edi
; [edi + IPv4_Packet.VersionAndIHL] ; IPv4, normal length (no Optional header)
; [edi + IPv4_Packet.TypeOfService] ; nothing special, just plain ip packet
; [edi + IPv4_Packet.TotalLength]
; [edi + IPv4_Packet.TotalLength] ; internet byte order
; [edi + IPv4_Packet.FlagsAndFragmentOffset]
mov [edi + IPv4_Packet.HeaderChecksum], 0
; [edi + IPv4_Packet.TimeToLive] ; ttl shl 8 + protocol
; [edi + IPv4_Packet.Protocol]
; [edi + IPv4_Packet.Identification] ; fragment id
; [edi + IPv4_Packet.SourceAddress]
; [edi + IPv4_Packet.DestinationAddress]
IPv4_checksum edi ;;;; todo: checksum for IP packet with options!
add edi, IPv4_Packet.DataOrOptional
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", ebx
call [ebx + NET_DEVICE.transmit]
ret
.error:
add esp, 6
.arp_error:
add esp, 8+4+4
.too_large:
DEBUGF 1,"IPv4_output_raw: 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
jz .err2
push ebx
push ax
mov ebx, [NET_DRV_LIST]
lea eax, [ebx + ETH_DEVICE.mac]
push eax
push esi ; ptr to ip header
sub ecx, 20 ; substract header size
push ecx ; max data size
push dword 0 ; offset
.new_fragment:
DEBUGF 1,"Ipv4_fragment - new_fragmentn"
mov eax, [esp + 3*4]
lea ebx, [esp + 4*4]
mov di , ETHER_IPv4
call ETH_output
cmp edi, -1
jz .err
; 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 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
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
mov ecx, [esp + 1*4]
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
;---------------------------------------------------------------------------
;
; IPv4_dest_to_dev
;
; IN: eax = Destination IP
; OUT: edi = device id * 4
;
;---------------------------------------------------------------------------
align 4
IPv4_dest_to_dev:
cmp eax, 0xffffffff
je .invalid
xor edi, edi
mov ecx, MAX_IP
.loop:
mov ebx, [IP_LIST+edi]
and ebx, [SUBNET_LIST+edi]
jz .next
mov edx, eax
and edx, [SUBNET_LIST+edi]
cmp ebx, edx
je .found_it
.next:
add edi, 4
loop .loop
.invalid:
xor edi, edi ; if none found, use device 0 as default device
.found_it:
DEBUGF 1,"IPv4_dest_to_dev: %u\n", edi
ret
;---------------------------------------------------------------------------
;
; IPv4_get_frgmnt_num
;
; IN: /
; OUT: fragment number in ax
;
;---------------------------------------------------------------------------
align 4
IPv4_get_frgmnt_num:
xor ax, ax ;;; TODO: replace this with real code
ret
;---------------------------------------------------------------------------
;
; IPv4_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
IPv4_API:
movzx eax, bh
shl eax, 2
test bl, bl
jz .packets_tx ; 0
dec bl
jz .packets_rx ; 1
dec bl
jz .read_ip ; 2
dec bl
jz .write_ip ; 3
dec bl
jz .read_dns ; 4
dec bl
jz .write_dns ; 5
dec bl
jz .read_subnet ; 6
dec bl
jz .write_subnet ; 7
dec bl
jz .read_gateway ; 8
dec bl
jz .write_gateway ; 9
.error:
mov eax, -1
ret
.packets_tx:
add eax, IP_PACKETS_TX
mov eax, [eax]
ret
.packets_rx:
add eax, IP_PACKETS_RX
mov eax, [eax]
ret
.read_ip:
add eax, IP_LIST
mov eax, [eax]
ret
.write_ip:
add eax, IP_LIST
mov [eax], ecx
xor eax, eax
ret
.read_dns:
add eax, DNS_LIST
mov eax, [eax]
ret
.write_dns:
add eax, DNS_LIST
mov [eax], ecx
xor eax, eax
ret
.read_subnet:
add eax, SUBNET_LIST
mov eax, [eax]
ret
.write_subnet:
add eax, SUBNET_LIST
mov [eax], ecx
xor eax, eax
ret
.read_gateway:
add eax, GATEWAY_LIST
mov eax, [eax]
ret
.write_gateway:
add eax, GATEWAY_LIST
mov [eax], ecx
xor eax, eax
ret