1,6 → 1,6 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; IPv4.INC ;; |
22,35 → 22,38 |
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: |
struct IPv4_header |
|
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 ? |
|
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: |
|
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 |
|
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 |
|
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) |
; Ip header begins here (we will need the IP header to re-construct the complete packet) |
ends |
|
|
65,7 → 68,7 |
IP_PACKETS_TX rd MAX_IP |
IP_PACKETS_RX rd MAX_IP |
|
FRAGMENT_LIST rb MAX_FRAGMENTS*FRAGMENT_slot.size |
FRAGMENT_LIST rb MAX_FRAGMENTS * sizeof.FRAGMENT_slot |
endg |
|
|
84,7 → 87,7 |
rep stosd |
|
mov edi, FRAGMENT_LIST |
mov ecx, FRAGMENT_slot.size*MAX_FRAGMENTS/4 + 2*MAX_IP |
mov ecx, sizeof.FRAGMENT_slot*MAX_FRAGMENTS/4 + 2*MAX_IP |
rep stosd |
|
} |
200,20 → 203,20 |
; 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 |
[edx + IPv4_header.SourceAddress]:1,[edx + IPv4_header.SourceAddress + 1]:1,[edx + IPv4_header.SourceAddress + 2]:1,[edx + IPv4_header.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 |
[edx + IPv4_header.DestinationAddress]:1,[edx + IPv4_header.DestinationAddress + 1]:1,[edx + IPv4_header.DestinationAddress + 2]:1,[edx + IPv4_header.DestinationAddress + 3]:1 |
|
;------------------------------------------- |
; Check if the packet still has time to live |
|
cmp byte [edx + IPv4_Packet.TimeToLive], 0 |
cmp byte [edx + IPv4_header.TimeToLive], 0 |
je .dump |
|
;-------------------------------------- |
; First, check if IP packet has options |
|
movzx eax, [edx + IPv4_Packet.VersionAndIHL] |
movzx eax, [edx + IPv4_header.VersionAndIHL] |
and al , 0x0f ; get IHL(header length) |
cmp al , 0x05 ; IHL!= 5*4(20 bytes) |
jnz .has_options |
235,7 → 238,7 |
; check if it matches local ip |
|
mov eax, [IP_LIST+edi] |
cmp [edx + IPv4_Packet.DestinationAddress], eax |
cmp [edx + IPv4_header.DestinationAddress], eax |
je .ip_ok |
|
; check for broadcast |
243,17 → 246,17 |
mov eax, [SUBNET_LIST+edi] |
not eax |
or eax, [IP_LIST+edi] |
cmp [edx + IPv4_Packet.DestinationAddress], eax |
cmp [edx + IPv4_header.DestinationAddress], eax |
je .ip_ok |
|
; or a special broadcast |
|
cmp [edx + IPv4_Packet.DestinationAddress], -1 |
cmp [edx + IPv4_header.DestinationAddress], -1 |
je .ip_ok |
|
; maybe it's a multicast then |
|
mov eax, [edx + IPv4_Packet.DestinationAddress] |
mov eax, [edx + IPv4_header.DestinationAddress] |
and eax, 0xff000000 |
; cmp eax, 224 shl 24 |
; je .ip_ok |
277,10 → 280,10 |
;---------------------------------- |
; Check if the packet is fragmented |
|
test [edx + IPv4_Packet.FlagsAndFragmentOffset], 1 shl 5 ; Is 'more fragments' flag set ? |
test [edx + IPv4_header.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 |
test [edx + IPv4_header.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 |
|
;------------------------------------------------------------------- |
287,10 → 290,10 |
; 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, [edx + IPv4_Packet.VersionAndIHL] ; Calculate Header length by using IHL field |
movzx eax, [edx + IPv4_header.VersionAndIHL] ; Calculate Header length by using IHL field |
and eax, 0x0000000f ; |
shl eax, 2 ; |
movzx ecx, [edx + IPv4_Packet.TotalLength] ; Calculate length of encapsulated Packet |
movzx ecx, [edx + IPv4_header.TotalLength] ; Calculate length of encapsulated Packet |
xchg cl , ch ; |
sub ecx, eax ; |
|
297,9 → 300,9 |
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] |
mov esi, [edx + IPv4_header.SourceAddress] ; These values might be of interest to the higher protocols |
mov edi, [edx + IPv4_header.DestinationAddress] ; |
mov al , [edx + IPv4_header.Protocol] |
pop edx ; Offset to data (tcp/udp/icmp/.. Packet) |
|
cmp al , IP_PROTO_TCP |
326,11 → 329,11 |
|
|
.has_fragments: |
movzx eax, [edx + IPv4_Packet.FlagsAndFragmentOffset] |
movzx eax, [edx + IPv4_header.FlagsAndFragmentOffset] |
xchg al , ah |
shl ax , 3 |
|
DEBUGF 1,"Fragmented packet, offset:%u, id:%x\n", ax, [edx + IPv4_Packet.Identification]:4 |
DEBUGF 1,"Fragmented packet, offset:%u, id:%x\n", ax, [edx + IPv4_header.Identification]:4 |
|
test ax , ax ; Is this the first packet of the fragment? |
jz .is_first_fragment |
379,17 → 382,17 |
.find_free_slot: |
cmp word [esi + FRAGMENT_slot.ttl], 0 |
je .found_free_slot |
add esi, FRAGMENT_slot.size |
add esi, sizeof.FRAGMENT_slot |
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 [esi + FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl |
mov ax , [edx + IPv4_Packet.Identification] |
mov ax , [edx + IPv4_header.Identification] |
mov [esi + FRAGMENT_slot.id], ax |
mov eax,[edx + IPv4_Packet.SourceAddress] |
mov eax,[edx + IPv4_header.SourceAddress] |
mov [esi + FRAGMENT_slot.SrcIP], eax |
mov eax, [edx + IPv4_Packet.DestinationAddress] |
mov eax, [edx + IPv4_header.DestinationAddress] |
mov [esi + FRAGMENT_slot.DstIP], eax |
pop eax |
mov [esi + FRAGMENT_slot.ptr], eax |
420,11 → 423,11 |
.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, [esi + FRAGMENT_entry.Data + IPv4_Packet.TotalLength] ; Add total length |
mov cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length |
xchg cl, ch |
DEBUGF 1,"Packet size: %u\n", cx |
add ax, cx |
movzx cx, [esi + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL] ; Sub Header length |
movzx cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Sub Header length |
and cx, 0x000F |
shl cx, 2 |
DEBUGF 1,"Header size: %u\n", cx |
440,7 → 443,7 |
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 |
mov cx, [edx + IPv4_header.TotalLength] ; Note: This time we dont substract Header length |
xchg cl , ch |
DEBUGF 1,"Packet size: %u\n", cx |
add ax , cx |
447,7 → 450,7 |
DEBUGF 1,"Total Received data size: %u\n", eax |
|
push eax |
mov ax , [edx + IPv4_Packet.FlagsAndFragmentOffset] |
mov ax , [edx + IPv4_header.FlagsAndFragmentOffset] |
xchg al , ah |
shl ax , 3 |
add cx , ax |
465,18 → 468,18 |
mov edx, [esp+4] ; Get pointer to first fragment entry back in edx |
|
.rebuild_packet_loop: |
movzx ecx, [edx + FRAGMENT_entry.Data + IPv4_Packet.FlagsAndFragmentOffset] ; Calculate the fragment offset |
movzx ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.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, [edx + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL] ; Find header size (in ebx) of fragment |
movzx ebx, [edx + sizeof.FRAGMENT_entry + IPv4_header.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, [edx + FRAGMENT_entry.Data + IPv4_Packet.TotalLength] ; Calculate total length of fragment |
lea esi, [edx + sizeof.FRAGMENT_entry] ; Set esi to the correct begin of fragment |
movzx ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.TotalLength] ; Calculate total length of fragment |
xchg cl, ch ; intel byte order |
|
cmp edi, eax ; Is this packet the first fragment ? |
504,7 → 507,7 |
pop ecx |
xchg cl, ch |
mov edx, eax |
mov [edx + IPv4_Packet.TotalLength], cx |
mov [edx + IPv4_header.TotalLength], cx |
add esp, 8 |
|
xchg cl, ch ; |
550,11 → 553,11 |
;;; TODO: the RFC says we should check protocol number too |
|
push eax ebx ecx edx |
mov ax , [edx + IPv4_Packet.Identification] |
mov ax , [edx + IPv4_header.Identification] |
mov ecx, MAX_FRAGMENTS |
mov esi, FRAGMENT_LIST |
mov ebx, [edx + IPv4_Packet.SourceAddress] |
mov edx, [edx + IPv4_Packet.DestinationAddress] |
mov ebx, [edx + IPv4_header.SourceAddress] |
mov edx, [edx + IPv4_header.DestinationAddress] |
.find_slot: |
cmp [esi + FRAGMENT_slot.id], ax |
jne .try_next |
563,7 → 566,7 |
cmp [esi + FRAGMENT_slot.DstIP], edx |
je .found_slot |
.try_next: |
add esi, FRAGMENT_slot.size |
add esi, sizeof.FRAGMENT_slot |
loop .find_slot |
; pop edx ebx |
or esi, -1 |
617,7 → 620,7 |
lea eax, [ebx + ETH_DEVICE.mac] |
mov edx, esp |
mov ecx, [esp + 18] |
add ecx, IPv4_Packet.DataOrOptional |
add ecx, sizeof.IPv4_header |
mov di , ETHER_IPv4 |
call ETH_output |
jz .error |
624,22 → 627,22 |
|
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 |
pop 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] |
mov [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header) |
mov [edi + IPv4_header.TypeOfService], 0 ; nothing special, just plain ip packet |
mov [edi + IPv4_header.TotalLength], cx |
rol [edi + IPv4_header.TotalLength], 8 ; internet byte order |
mov [edi + IPv4_header.FlagsAndFragmentOffset], 0x0000 |
mov [edi + IPv4_header.HeaderChecksum], 0 |
pop word [edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol |
; [edi + IPv4_header.Protocol] |
popw [edi + IPv4_header.Identification] ; fragment id |
popd [edi + IPv4_header.SourceAddress] |
popd [edi + IPv4_header.DestinationAddress] |
|
pop ecx |
|
IPv4_checksum edi |
add edi, IPv4_Packet.DataOrOptional |
add edi, sizeof.IPv4_header |
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", ebx |
ret |
|
694,7 → 697,7 |
lea eax, [ebx + ETH_DEVICE.mac] |
mov edx, esp |
mov ecx, [esp + 6+4] |
add ecx, IPv4_Packet.DataOrOptional |
add ecx, sizeof.IPv4_header |
mov di, ETHER_IPv4 |
call ETH_output |
jz .error |
711,22 → 714,22 |
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] |
; [edi + IPv4_header.VersionAndIHL] ; IPv4, normal length (no Optional header) |
; [edi + IPv4_header.TypeOfService] ; nothing special, just plain ip packet |
; [edi + IPv4_header.TotalLength] |
; [edi + IPv4_header.TotalLength] ; internet byte order |
; [edi + IPv4_header.FlagsAndFragmentOffset] |
|
mov [edi + IPv4_Packet.HeaderChecksum], 0 |
mov [edi + IPv4_header.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] |
; [edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol |
; [edi + IPv4_header.Protocol] |
; [edi + IPv4_header.Identification] ; fragment id |
; [edi + IPv4_header.SourceAddress] |
; [edi + IPv4_header.DestinationAddress] |
|
IPv4_checksum edi ;;;; todo: checksum for IP packet with options! |
add edi, IPv4_Packet.DataOrOptional |
add edi, sizeof.IPv4_header |
DEBUGF 1,"IPv4 Packet for device %x created successfully\n", ebx |
call [ebx + NET_DEVICE.transmit] |
ret |
760,11 → 763,11 |
|
and ecx, not 111b ; align 4 |
|
cmp ecx, IPv4_Packet.DataOrOptional + 8 ; must be able to put at least 8 bytes |
cmp ecx, sizeof.IPv4_header + 8 ; must be able to put at least 8 bytes |
jb .err2 |
|
push esi ecx |
mov eax, [esi + IPv4_Packet.DestinationAddress] |
mov eax, [esi + IPv4_header.DestinationAddress] |
call ARP_IP_to_MAC |
pop ecx esi |
cmp eax, -1 |
779,7 → 782,7 |
|
|
push esi ; ptr to ip header |
sub ecx, IPv4_Packet.DataOrOptional ; substract header size |
sub ecx, sizeof.IPv4_header ; substract header size |
push ecx ; max data size |
push dword 0 ; offset |
|
802,7 → 805,7 |
|
; copy data |
mov esi, [esp + 2*4] |
add esi, IPv4_Packet.DataOrOptional |
add esi, sizeof.IPv4_header |
add esi, [esp] ; offset |
|
mov ecx, [esp + 1*4] |
811,9 → 814,9 |
|
; now, correct header |
mov ecx, [esp + 1*4] |
add ecx, IPv4_Packet.DataOrOptional |
add ecx, sizeof.IPv4_header |
xchg cl, ch |
mov [edi + IPv4_Packet.TotalLength], cx |
mov [edi + IPv4_header.TotalLength], cx |
|
mov ecx, [esp] ; offset |
xchg cl, ch |
822,9 → 825,9 |
; je .last_fragment |
or cx, 1 shl 2 ; more fragments |
; .last_fragment: |
mov [edi + IPv4_Packet.FlagsAndFragmentOffset], cx |
mov [edi + IPv4_header.FlagsAndFragmentOffset], cx |
|
mov [edi + IPv4_Packet.HeaderChecksum], 0 |
mov [edi + IPv4_header.HeaderChecksum], 0 |
|
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet |
mov ecx, [esp + 1*4] |