0,0 → 1,447 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ICMP.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: 593 $ |
|
; ICMP types & codes |
|
ICMP_ECHOREPLY equ 0 ; echo reply message |
|
ICMP_UNREACH equ 3 |
ICMP_UNREACH_NET equ 0 ; bad net |
ICMP_UNREACH_HOST equ 1 ; bad host |
ICMP_UNREACH_PROTOCOL equ 2 ; bad protocol |
ICMP_UNREACH_PORT equ 3 ; bad port |
ICMP_UNREACH_NEEDFRAG equ 4 ; IP_DF caused drop |
ICMP_UNREACH_SRCFAIL equ 5 ; src route failed |
ICMP_UNREACH_NET_UNKNOWN equ 6 ; unknown net |
ICMP_UNREACH_HOST_UNKNOWN equ 7 ; unknown host |
ICMP_UNREACH_ISOLATED equ 8 ; src host isolated |
ICMP_UNREACH_NET_PROHIB equ 9 ; prohibited access |
ICMP_UNREACH_HOST_PROHIB equ 10 ; ditto |
ICMP_UNREACH_TOSNET equ 11 ; bad tos for net |
ICMP_UNREACH_TOSHOST equ 12 ; bad tos for host |
ICMP_UNREACH_FILTER_PROHIB equ 13 ; admin prohib |
ICMP_UNREACH_HOST_PRECEDENCE equ 14 ; host prec vio. |
ICMP_UNREACH_PRECEDENCE_CUTOFF equ 15 ; prec cutoff |
|
ICMP_SOURCEQUENCH equ 4 ; Packet lost, slow down |
|
ICMP_REDIRECT equ 5 ; shorter route, codes: |
ICMP_REDIRECT_NET equ 0 ; for network |
ICMP_REDIRECT_HOST equ 1 ; for host |
ICMP_REDIRECT_TOSNET equ 2 ; for tos and net |
ICMP_REDIRECT_TOSHOST equ 3 ; for tos and host |
|
ICMP_ALTHOSTADDR equ 6 ; alternate host address |
ICMP_ECHO equ 8 ; echo service |
ICMP_ROUTERADVERT equ 9 ; router advertisement |
ICMP_ROUTERADVERT_NORMAL equ 0 ; normal advertisement |
ICMP_ROUTERADVERT_NOROUTE_COMMON equ 16 ; selective routing |
|
ICMP_ROUTERSOLICIT equ 10 ; router solicitation |
ICMP_TIMXCEED equ 11 ; time exceeded, code: |
ICMP_TIMXCEED_INTRANS equ 0 ; ttl==0 in transit |
ICMP_TIMXCEED_REASS equ 1 ; ttl==0 in reass |
|
ICMP_PARAMPROB equ 12 ; ip header bad |
ICMP_PARAMPROB_ERRATPTR equ 0 ; error at param ptr |
ICMP_PARAMPROB_OPTABSENT equ 1 ; req. opt. absent |
ICMP_PARAMPROB_LENGTH equ 2 ; bad length |
|
ICMP_TSTAMP equ 13 ; timestamp request |
ICMP_TSTAMPREPLY equ 14 ; timestamp reply |
ICMP_IREQ equ 15 ; information request |
ICMP_IREQREPLY equ 16 ; information reply |
ICMP_MASKREQ equ 17 ; address mask request |
ICMP_MASKREPLY equ 18 ; address mask reply |
ICMP_TRACEROUTE equ 30 ; traceroute |
ICMP_DATACONVERR equ 31 ; data conversion error |
ICMP_MOBILE_REDIRECT equ 32 ; mobile host redirect |
ICMP_IPV6_WHEREAREYOU equ 33 ; IPv6 where-are-you |
ICMP_IPV6_IAMHERE equ 34 ; IPv6 i-am-here |
ICMP_MOBILE_REGREQUEST equ 35 ; mobile registration req |
ICMP_MOBILE_REGREPLY equ 36 ; mobile registreation reply |
ICMP_SKIP equ 39 ; SKIP |
|
ICMP_PHOTURIS equ 40 ; Photuris |
ICMP_PHOTURIS_UNKNOWN_INDEX equ 1 ; unknown sec index |
ICMP_PHOTURIS_AUTH_FAILED equ 2 ; auth failed |
ICMP_PHOTURIS_DECRYPT_FAILED equ 3 ; decrypt failed |
|
|
|
struct ICMP_Packet |
.Type db ? |
.Code db ? |
.Checksum dw ? |
.Identifier dw ? |
.SequenceNumber dw ? |
.Data: |
ends |
|
|
align 4 |
uglobal |
ICMP_PACKETS_TX rd MAX_IP |
ICMP_PACKETS_RX rd MAX_IP |
endg |
|
;----------------------------------------------------------------- |
; |
; ICMP_init |
; |
; This function resets all ICMP variables |
; |
; IN: / |
; OUT: / |
; |
;----------------------------------------------------------------- |
|
align 4 |
ICMP_init: |
|
xor eax, eax |
mov edi, ICMP_PACKETS_TX |
mov ecx, 2*MAX_IP |
rep stosd |
|
ret |
|
|
;-------------------------------- |
; |
; ICMP_Handler: |
; |
; Called by IP_handler, |
; this procedure will send reply's to ICMP echo's etc ;;; TODO: update this to work with fragmented packets too! |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; pointer to device struct in ebx |
; ICMP Packet size in ecx |
; pointer to ICMP Packet data in edx |
; OUT: / |
; |
;-------------------------------- |
|
align 4 |
ICMP_Handler: ;TODO: works only on pure ethernet right now ! |
|
DEBUGF 1,"ICMP_Handler - start\n" |
cmp byte [edx + ICMP_Packet.Type], ICMP_ECHO ; Is this an echo request? discard if not |
jne .check_sockets |
|
mov byte [edx + ICMP_Packet.Type], ICMP_ECHOREPLY ; Change Packet type to reply |
mov word [edx + ICMP_Packet.Checksum], 0 ; Set checksum to 0, needed to calculate new checksum |
|
; exchange dest and source address in IP header |
; exchange dest and source MAC in ETH header |
mov esi, [esp] |
|
mov eax, dword [esi + ETH_FRAME.DstMAC] |
mov ecx, dword [esi + ETH_FRAME.SrcMAC] |
mov dword [esi + ETH_FRAME.SrcMAC], eax |
mov dword [esi + ETH_FRAME.DstMAC], ecx |
|
mov ax, word [esi + ETH_FRAME.DstMAC + 4] |
mov cx, word [esi + ETH_FRAME.SrcMAC + 4] |
mov word [esi + ETH_FRAME.SrcMAC + 4], ax |
mov word [esi + ETH_FRAME.DstMAC + 4], cx |
|
mov eax, dword [esi + ETH_FRAME.Data + IPv4_Packet.SourceAddress] |
mov ecx, dword [esi + ETH_FRAME.Data + IPv4_Packet.DestinationAddress] |
mov dword [esi + ETH_FRAME.Data + IPv4_Packet.DestinationAddress], eax |
mov dword [esi + ETH_FRAME.Data + IPv4_Packet.SourceAddress], ecx |
|
; Recalculate ip header checksum |
; mov esi, [esp] |
add esi, ETH_FRAME.Data ; Point esi to start of IP Packet |
movzx eax, byte [esi + IPv4_Packet.VersionAndIHL] ; Calculate IP Header length by using IHL field |
and eax, 0x0000000F ; |
shl eax, 2 ; |
push ebx edx esi |
stdcall checksum_jb, esi, eax ; calculate the checksum |
pop esi edx ebx |
xchg al, ah ; convert to intel byte order |
; mov esi, [esp] |
mov word [esi + IPv4_Packet.HeaderChecksum], ax ; Store it in the IP Packet header |
|
; Recalculate ICMP CheckSum |
; mov esi, [esp] ; Find length of IP Packet |
movzx eax, word[esi + IPv4_Packet.TotalLength] ; |
xchg ah , al ; |
movzx edi, byte [esi + IPv4_Packet.VersionAndIHL] ; Calculate IP Header length by using IHL field |
and edi, 0x0000000F ; |
shl edi, 2 ; |
sub ax , di ; Now we know the length of ICMP data in eax |
push ebx edx |
stdcall checksum_jb,edx,eax ; Calculate the checksum of icmp data |
pop edx ebx |
xchg al, ah ; Convert to intel byte order |
mov word [edx + ICMP_Packet.Checksum], ax |
|
jmp ETH_Sender |
|
.check_sockets: |
; TODO: validate the header & checksum. Discard buffer if error |
|
; Look for an open ICMP socket |
|
mov esi, net_sockets |
.try_more: |
mov ax , [edx + ICMP_Packet.Identifier] |
.next_socket: |
mov esi, [esi + SOCKET.NextPtr] |
or esi, esi |
jz .dump |
cmp [esi + SOCKET.Type], IP_PROTO_ICMP |
jne .next_socket |
cmp [esi + SOCKET.LocalPort], ax |
jne .next_socket |
|
cmp [esi + SOCKET.rxDataCount],0 ; get # of bytes already in buffer |
jnz .dump ; only one packet at a time may be in the buffer! |
|
cmp ecx, SOCKETBUFFSIZE - SOCKETHEADERSIZE; TODO: fix this problem ! |
jg .dump |
|
DEBUGF 1,"Found valid ICMP packet for socket %x\n", esi |
|
lea ebx, [esi + SOCKET.lock] |
call wait_mutex |
|
; Now, copy data to socket. We have socket address in esi. |
; We have ICMP Packet in edx |
; number of bytes in ecx |
|
; note: we do not strip the header! |
|
DEBUGF 1,"bytes: %u\n", ecx |
|
mov [esi + SOCKET.rxDataCount], ecx |
|
lea edi, [esi + SOCKETHEADERSIZE] |
push esi |
push ecx |
mov esi, edx |
shr ecx, 2 |
rep movsd ; copy the data across |
pop ecx |
and ecx, 3 |
rep movsb |
pop esi |
|
DEBUGF 1,"ICMP socket updated\n" |
|
mov [esi + SOCKET.lock], 0 |
|
; flag an event to the application |
mov eax, [esi + SOCKET.PID] ; get socket owner PID |
mov ecx, 1 |
mov esi, TASK_DATA + TASKDATA.pid |
|
.next_pid: |
cmp [esi], eax |
je .found_pid |
inc ecx |
add esi, 0x20 |
cmp ecx, [TASK_COUNT] |
jbe .next_pid |
|
jmp .dump |
|
.found_pid: |
shl ecx, 8 |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK ; stack event |
|
mov [check_idle_semaphore], 200 |
|
.dump: |
DEBUGF 1,"ICMP_Handler - dumping\n" |
|
call kernel_free |
add esp, 4 ; pop (balance stack) |
|
ret |
|
|
;-------------------------------- |
; |
; ICMP_Handler_fragments: |
; |
; Called by IP_handler, |
; this procedure will send reply's to ICMP echo's etc |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; pointer to device struct in ebx |
; ICMP Packet size in ecx |
; pointer to ICMP Packet data in edx |
; OUT: / |
; |
;-------------------------------- |
|
align 4 |
ICMP_Handler_fragments: ; works only on pure ethernet right now ! |
|
DEBUGF 1,"ICMP_Handler_fragments - start\n" |
|
cmp ecx, 65500 |
jg .dump |
|
cmp byte [edx + ICMP_Packet.Type], ICMP_ECHO ; Is this an echo request? discard if not |
jne .dump |
|
mov esi, [esp] |
|
sub ecx, ICMP_Packet.Data |
mov eax, [esi + IPv4_Packet.SourceAddress] |
mov ebx, [esi + IPv4_Packet.DestinationAddress] |
push word [esi + IPv4_Packet.Identification] |
|
mov di , [edx + ICMP_Packet.Identifier] |
shl edi, 16 |
mov di , [edx + ICMP_Packet.SequenceNumber] |
|
mov esi, edx |
add esi, ICMP_Packet.Data |
pop dx |
shl edx, 16 |
mov dx , ICMP_ECHOREPLY shl 8 + 0 ; Type + Code |
|
call ICMP_create_Packet |
|
.dump: |
DEBUGF 1,"ICMP_Handler_fragments - end\n" |
|
call kernel_free |
add esp, 4 ; pop (balance stack) |
|
ret |
|
;----------------------------------------------------------------- |
; |
; Note: ICMP only works on top of IP protocol :) |
; |
; inputs: |
; |
; eax = dest ip |
; ebx = source ip |
; ecx = data length |
; dh = type |
; dl = code |
; high 16 bits of edx = fragment id (for IP header) |
; esi = data offset |
; edi = identifier shl 16 + sequence number |
; |
;----------------------------------------------------------------- |
|
align 4 |
ICMP_create_Packet: |
|
DEBUGF 1,"Create ICMP Packet\n" |
|
push esi edi edx |
|
add ecx, ICMP_Packet.Data |
mov di , IP_PROTO_ICMP |
shr edx, 16 |
|
call IPv4_create_Packet |
|
DEBUGF 1,"full icmp packet size: %u\n", ebx |
|
cmp edi, -1 |
je .exit |
|
pop eax |
mov word [edi + ICMP_Packet.Type], ax ; Write both type and code bytes at once |
pop eax |
mov [edi + ICMP_Packet.SequenceNumber], ax |
shr eax, 16 |
mov [edi + ICMP_Packet.Identifier], ax |
mov [edi + ICMP_Packet.Checksum], 0 |
|
stdcall checksum_jb, edi , ecx |
xchg al, ah |
mov [edi + ICMP_Packet.Checksum], ax |
|
pop esi |
sub ecx, ICMP_Packet.Data |
add edi, ICMP_Packet.Data |
push cx |
shr cx , 2 |
rep movsd |
pop cx |
and cx , 3 |
rep movsb |
|
sub edi, ebx ;; TODO: find a better way to remember start of packet |
xchg ebx, edx |
mov ecx, [ebx + ETH_DEVICE.transmit] |
push edx edi ecx |
DEBUGF 1,"Sending ICMP Packet\n" |
ret ; Send the packet (create_packet routine outputs pointer to routine to send packet in eax) |
|
.exit: |
add esp, 8 |
ret |
|
|
|
|
;--------------------------------------------------------------------------- |
; |
; ICMP_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 |
ICMP_API: |
|
movzx eax, bh |
shl eax, 2 |
|
test bl, bl |
jz .packets_tx ; 0 |
dec bl |
jz .packets_rx ; 1 |
|
.error: |
mov eax, -1 |
ret |
|
.packets_tx: |
add eax, ICMP_PACKETS_TX |
mov eax, [eax] |
ret |
|
.packets_rx: |
add eax, ICMP_PACKETS_RX |
mov eax, [eax] |
ret |