Added ICMP DLL implementation.

diff --git a/Makefile.in b/Makefile.in
index 6f8cfe5..0dfd0b6 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -38,6 +38,7 @@
 	dlls/dciman32 \
 	dlls/dplayx \
 	dlls/dsound \
+	dlls/icmp \
 	dlls/imagehlp \
 	dlls/imm32 \
 	dlls/lzexpand \
@@ -143,6 +144,7 @@
 	dlls/commdlg/commdlg.o \
 	dlls/crtdll/crtdll.o \
 	dlls/dciman32/dciman32.o \
+	dlls/icmp/icmp.o \
 	dlls/dplayx/dplayx.o \
 	dlls/dsound/dsound.o \
 	dlls/imagehlp/imagehlp.o \
diff --git a/configure b/configure
index 63b7bea..139ff44 100755
--- a/configure
+++ b/configure
@@ -5643,6 +5643,7 @@
 dlls/dciman32/Makefile
 dlls/dplayx/Makefile
 dlls/dsound/Makefile
+dlls/icmp/Makefile
 dlls/imagehlp/Makefile
 dlls/imm32/Makefile
 dlls/lzexpand/Makefile
@@ -5846,6 +5847,7 @@
 dlls/dciman32/Makefile
 dlls/dplayx/Makefile
 dlls/dsound/Makefile
+dlls/icmp/Makefile
 dlls/imagehlp/Makefile
 dlls/imm32/Makefile
 dlls/lzexpand/Makefile
diff --git a/configure.in b/configure.in
index d42a0f1..3f05ff1 100644
--- a/configure.in
+++ b/configure.in
@@ -850,6 +850,7 @@
 dlls/dciman32/Makefile
 dlls/dplayx/Makefile
 dlls/dsound/Makefile
+dlls/icmp/Makefile
 dlls/imagehlp/Makefile
 dlls/imm32/Makefile
 dlls/lzexpand/Makefile
diff --git a/dlls/Makefile.in b/dlls/Makefile.in
index 0efcaf5..fe659bc 100644
--- a/dlls/Makefile.in
+++ b/dlls/Makefile.in
@@ -7,6 +7,7 @@
 	dciman32 \
 	dplayx \
 	dsound \
+	icmp \
 	imagehlp \
 	imm32 \
 	lzexpand \
diff --git a/dlls/icmp/.cvsignore b/dlls/icmp/.cvsignore
new file mode 100644
index 0000000..f540160
--- /dev/null
+++ b/dlls/icmp/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+icmp.spec.c
diff --git a/dlls/icmp/Makefile.in b/dlls/icmp/Makefile.in
new file mode 100644
index 0000000..a65a090
--- /dev/null
+++ b/dlls/icmp/Makefile.in
@@ -0,0 +1,19 @@
+DEFS      = @DLLFLAGS@ -D__WINE__
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = icmp
+
+SPEC_SRCS = icmp.spec
+
+C_SRCS = icmp_main.c 
+
+all: $(MODULE).o
+
+@MAKE_RULES@
+
+### Dependencies:
+
+
+
diff --git a/dlls/icmp/icmp.spec b/dlls/icmp/icmp.spec
new file mode 100644
index 0000000..e394f68
--- /dev/null
+++ b/dlls/icmp/icmp.spec
@@ -0,0 +1,13 @@
+name icmp
+type win32
+
+1  stdcall  IcmpCloseHandle(ptr) IcmpCloseHandle
+2  stdcall  IcmpCreateFile()     IcmpCreateFile
+3  stub  IcmpParseReplies
+4  stub  IcmpSendEcho2
+5  stdcall  IcmpSendEcho(ptr long ptr long ptr ptr long long) IcmpSendEcho
+6  stub  do_echo_rep
+7  stub  do_echo_req
+8  stub  register_icmp
+
+
diff --git a/dlls/icmp/icmp_main.c b/dlls/icmp/icmp_main.c
new file mode 100644
index 0000000..93e20ea
--- /dev/null
+++ b/dlls/icmp/icmp_main.c
@@ -0,0 +1,472 @@
+/*
+ * ICMP
+ *
+ * Francois Gouget, 1999, based on the work of
+ *   RW Hall, 1999, based on public domain code PING.C by Mike Muus (1983) 
+ *   and later works (c) 1989 Regents of Univ. of California - see copyright 
+ *   notice at end of source-code.
+ */
+
+/* Future work:
+ * - Systems like FreeBSD don't seem to support the IP_TTL option and maybe others.
+ *   But using IP_HDRINCL and building the IP header by hand might work.
+ * - Not all IP options are supported.
+ * - Are ICMP handles real handles, i.e. inheritable and all? There might be some 
+ *   more work to do here, including server side stuff with synchronization.
+ * - Is it correct to use malloc for the internal buffer, for allocating the 
+ *   handle's structure?
+ * - This API should probably be thread safe. Is it really?
+ * - Using the winsock functions has not been tested.
+ */
+
+
+#define __USE_BSD
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <sys/time.h>
+#include <malloc.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include "windef.h"
+#include "winbase.h"
+#ifdef ICMP_WIN
+#include "winsock.h"
+#endif
+
+#include "winerror.h"
+#include "wine/ipexport.h"
+#include "wine/icmpapi.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(icmp)
+
+/* Define the following macro to use the winsock functions */
+/*#define ICMP_WIN*/
+
+#ifdef ICMP_WIN
+/* FIXME: should we include winsock.h ???*/
+SOCKET WINAPI WINSOCK_socket(INT af, INT type, INT protocol);
+INT WINAPI WINSOCK_sendto(SOCKET s, char *buf, INT len, INT flags, struct sockaddr *to, INT tolen);
+INT WINAPI WINSOCK_recvfrom(SOCKET s, char *buf,INT len, INT flags, struct sockaddr *from, INT *fromlen32);
+INT WINAPI WINSOCK_shutdown(SOCKET s, INT how);
+#endif
+
+
+#ifdef ICMP_WIN
+#define ISOCK_SOCKET                SOCKET
+#define ISOCK_ISVALID(a)            ((a)!=INVALID_SOCKET)
+#define ISOCK_getsockopt(a,b,c,d,e) WINSOCK_getsockopt(a,b,c,d,e)
+#define ISOCK_recvfrom(a,b,c,d,e,f) WINSOCK_recvfrom(a,b,c,d,e,f)
+#define ISOCK_select(a,b,c,d,e)     WINSOCK_select(a,b,c,d,e)
+#define ISOCK_sendto(a,b,c,d,e,f)   WINSOCK_sendto(a,b,c,d,e,f)
+#define ISOCK_setsockopt(a,b,c,d,e) WINSOCK_setsockopt(a,b,c,d,e)
+#define ISOCK_shutdown(a,b)         WINSOCK_shutdown(a,b)
+#define ISOCK_socket(a,b,c)         WINSOCK_socket(a,b,c)
+#else
+#define ISOCK_SOCKET                int
+#define ISOCK_ISVALID(a)            ((a)>=0)
+#define ISOCK_getsockopt(a,b,c,d,e) getsockopt(a,b,c,d,e)
+#define ISOCK_recvfrom(a,b,c,d,e,f) recvfrom(a,b,c,d,e,f)
+#define ISOCK_select(a,b,c,d,e)     select(a,b,c,d,e)
+#define ISOCK_setsockopt(a,b,c,d,e) setsockopt(a,b,c,d,e)
+#define ISOCK_sendto(a,b,c,d,e,f)   sendto(a,b,c,d,e,f)
+#define ISOCK_shutdown(a,b)         shutdown(a,b)
+#define ISOCK_socket(a,b,c)         socket(a,b,c)
+#endif
+
+typedef struct {
+    ISOCK_SOCKET sid;
+    IP_OPTION_INFORMATION default_opts;
+} icmp_t;
+
+#define IP_OPTS_UNKNOWN     0
+#define IP_OPTS_DEFAULT     1
+#define IP_OPTS_CUSTOM      2
+
+/* The sequence number is unique process wide, so that all threads 
+ * have a distinct sequence number.
+ */
+static LONG icmp_sequence=0;
+
+static int in_cksum(u_short *addr, int len)
+{
+    int nleft=len;
+    u_short *w = addr;
+    int sum = 0;
+    u_short answer = 0;
+
+    while (nleft > 1) {
+        sum += *w++;
+        nleft -= 2;
+    }
+
+    if (nleft == 1) {
+        *(u_char *)(&answer) = *(u_char *)w;
+        sum += answer;
+    }
+
+    sum = (sum >> 16) + (sum & 0xffff);
+    sum  += (sum >> 16);
+    answer = ~sum;
+    return(answer);
+}
+
+
+
+/*
+ * Exported Routines.
+ */
+
+HANDLE WINAPI IcmpCreateFile(VOID)
+{
+    icmp_t* icp;
+
+    ISOCK_SOCKET sid=ISOCK_socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
+    if (!ISOCK_ISVALID(sid)) {
+        MESSAGE("WARNING: Trying to use ICMP will fail unless running as root\n");
+        SetLastError(ERROR_ACCESS_DENIED);
+        return INVALID_HANDLE_VALUE;
+    }
+
+    icp=malloc(sizeof(*icp));
+    if (icp==NULL) {
+        SetLastError(IP_NO_RESOURCES);
+        return INVALID_HANDLE_VALUE;
+    }
+    icp->sid=sid;
+    icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN;
+    return (HANDLE)icp;
+}
+
+
+BOOL WINAPI IcmpCloseHandle(HANDLE  IcmpHandle)
+{
+    icmp_t* icp=(icmp_t*)IcmpHandle;
+
+    ISOCK_shutdown(icp->sid,2);
+    free(icp);
+    return TRUE;
+}
+
+
+DWORD WINAPI IcmpSendEcho(
+    HANDLE                   IcmpHandle,
+    IPAddr                   DestinationAddress,
+    LPVOID                   RequestData,
+    WORD                     RequestSize,
+    PIP_OPTION_INFORMATION   RequestOptions,
+    LPVOID                   ReplyBuffer,
+    DWORD                    ReplySize,
+    DWORD                    Timeout
+    )
+{
+    icmp_t* icp=(icmp_t*)IcmpHandle;
+    unsigned char* reqbuf;
+    int reqsize;
+
+    struct icmp_echo_reply* ier;
+    struct ip* ip_header;
+    struct icmp* icmp_header;
+    char* endbuf;
+    int ip_header_len;
+    int maxlen;
+    fd_set fdr;
+    struct timeval timeout,send_time,recv_time;
+    struct sockaddr_in addr;
+    int addrlen;
+    unsigned short id,seq,cksum;
+    int res;
+
+    if (ReplySize<sizeof(ICMP_ECHO_REPLY)+ICMP_MINLEN) {
+        SetLastError(IP_BUF_TOO_SMALL);
+        return 0;
+    }
+    /* check the request size against SO_MAX_MSG_SIZE using getsockopt */
+
+    /* Prepare the request */
+    id=getpid() & 0xFFFF;
+    seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF;
+
+    reqsize=ICMP_MINLEN+RequestSize;
+    reqbuf=malloc(reqsize);
+    if (reqbuf==NULL) {
+        SetLastError(ERROR_OUTOFMEMORY);
+        return 0;
+    }
+
+    icmp_header=(struct icmp*)reqbuf;
+    icmp_header->icmp_type=ICMP_ECHO;
+    icmp_header->icmp_code=0;
+    icmp_header->icmp_cksum=0;
+    icmp_header->icmp_id=id;
+    icmp_header->icmp_seq=seq;
+    memcpy(reqbuf+ICMP_MINLEN, RequestData, RequestSize);
+    icmp_header->icmp_cksum=cksum=in_cksum((u_short*)reqbuf,reqsize);
+
+    addr.sin_family=AF_INET;
+    addr.sin_addr.s_addr=DestinationAddress;
+    addr.sin_port=0;
+
+    if (RequestOptions!=NULL) {
+        int val;
+        if (icp->default_opts.OptionsSize==IP_OPTS_UNKNOWN) {
+            int len;
+            /* Before we mess with the options, get the default values */
+            len=sizeof(val);
+            ISOCK_getsockopt(icp->sid,SOL_IP,IP_TTL,&val,&len);
+            icp->default_opts.Ttl=val;
+
+            len=sizeof(val);
+            ISOCK_getsockopt(icp->sid,SOL_IP,IP_TOS,&val,&len);
+            icp->default_opts.Tos=val;
+            /* FIXME: missing: handling of IP 'flags', and all the other options */
+        }
+
+        val=RequestOptions->Ttl;
+        ISOCK_setsockopt(icp->sid,SOL_IP,IP_TTL,&val,sizeof(val));
+        val=RequestOptions->Tos;
+        ISOCK_setsockopt(icp->sid,SOL_IP,IP_TOS,&val,sizeof(val));
+        /* FIXME:  missing: handling of IP 'flags', and all the other options */
+
+        icp->default_opts.OptionsSize=IP_OPTS_CUSTOM;
+    } else if (icp->default_opts.OptionsSize==IP_OPTS_CUSTOM) {
+        int val;
+
+        /* Restore the default options */
+        val=icp->default_opts.Ttl;
+        ISOCK_setsockopt(icp->sid,SOL_IP,IP_TTL,&val,sizeof(val));
+        val=icp->default_opts.Tos;
+        ISOCK_setsockopt(icp->sid,SOL_IP,IP_TOS,&val,sizeof(val));
+        /* FIXME: missing: handling of IP 'flags', and all the other options */
+
+        icp->default_opts.OptionsSize=IP_OPTS_DEFAULT;
+    }
+
+    /* Get ready for receiving the reply
+     * Do it before we send the request to minimize the risk of introducing delays
+     */
+    FD_ZERO(&fdr);
+    FD_SET(icp->sid,&fdr);
+    timeout.tv_sec=Timeout/1000;
+    timeout.tv_usec=(Timeout % 1000)*1000;
+    addrlen=sizeof(addr);
+    ier=ReplyBuffer;
+    ip_header=ReplyBuffer+sizeof(ICMP_ECHO_REPLY);
+    endbuf=ReplyBuffer+ReplySize;
+    maxlen=ReplySize-sizeof(ICMP_ECHO_REPLY);
+
+    /* Send the packet */
+    TRACE("Sending %d bytes (RequestSize=%d) to %s\n", reqsize, RequestSize, inet_ntoa(addr.sin_addr));
+#if 0
+    if (TRACE_ON(icmp)){
+        unsigned char* buf=(unsigned char*)reqbuf;
+        int i;
+        printf("Output buffer:\n");
+        for (i=0;i<reqsize;i++)
+            printf("%2x,", buf[i]);
+        printf("\n");
+    }
+#endif
+
+    gettimeofday(&send_time,NULL);
+    res=ISOCK_sendto(icp->sid, reqbuf, reqsize, 0, (struct sockaddr*)&addr, sizeof(addr));
+    free(reqbuf);
+    if (res<0) {
+        if (errno==EMSGSIZE)
+            SetLastError(IP_PACKET_TOO_BIG);
+        else {
+            switch (errno) {
+            case ENETUNREACH:
+                SetLastError(IP_DEST_NET_UNREACHABLE);
+                break;
+            case EHOSTUNREACH:
+                SetLastError(IP_DEST_NET_UNREACHABLE);
+                break;
+            default:
+                TRACE("unknown error: errno=%d\n",errno);
+                SetLastError(ERROR_UNKNOWN);
+            }
+        }
+        return 0;
+    }
+
+    /* Get the reply */
+    ip_header_len=0; /* because gcc was complaining */
+    while ((res=ISOCK_select(icp->sid+1,&fdr,NULL,NULL,&timeout))>0) {
+        gettimeofday(&recv_time,NULL);
+        res=ISOCK_recvfrom(icp->sid, (char*)ip_header, maxlen, 0, (struct sockaddr*)&addr,&addrlen);
+        TRACE("received %d bytes from %s\n",res, inet_ntoa(addr.sin_addr));
+        ier->Status=IP_REQ_TIMED_OUT;
+
+        /* Check whether we should ignore this packet */
+        if ((ip_header->ip_p==IPPROTO_ICMP) && (res>=sizeof(struct ip)+ICMP_MINLEN)) {
+            ip_header_len=ip_header->ip_hl << 2;
+            icmp_header=(struct icmp*)(((char*)ip_header)+ip_header_len);
+            TRACE("received an ICMP packet of type,code=%d,%d\n",icmp_header->icmp_type,icmp_header->icmp_code);
+            if (icmp_header->icmp_type==ICMP_ECHOREPLY) {
+                if ((icmp_header->icmp_id==id) && (icmp_header->icmp_seq==seq))
+                    ier->Status=IP_SUCCESS;
+            } else {
+                switch (icmp_header->icmp_type) {
+                case ICMP_UNREACH:
+                    switch (icmp_header->icmp_code) {
+                    case ICMP_UNREACH_HOST:
+                    case ICMP_UNREACH_HOST_UNKNOWN:
+                    case ICMP_UNREACH_ISOLATED:
+              	    case ICMP_UNREACH_HOST_PROHIB:
+                    case ICMP_UNREACH_TOSHOST:
+                        ier->Status=IP_DEST_HOST_UNREACHABLE;
+                        break;
+                    case ICMP_UNREACH_PORT:
+                        ier->Status=IP_DEST_PORT_UNREACHABLE;
+                        break;
+                    case ICMP_UNREACH_PROTOCOL:
+                        ier->Status=IP_DEST_PROT_UNREACHABLE;
+                        break;
+                    case ICMP_UNREACH_SRCFAIL:
+                        ier->Status=IP_BAD_ROUTE;
+                        break;
+                    default:
+                        ier->Status=IP_DEST_NET_UNREACHABLE;
+                    }
+                    break;
+                case ICMP_TIMXCEED:
+                    if (icmp_header->icmp_code==ICMP_TIMXCEED_REASS)
+                        ier->Status=IP_TTL_EXPIRED_REASSEM;
+                    else
+                        ier->Status=IP_TTL_EXPIRED_TRANSIT;
+                    break;
+                case ICMP_PARAMPROB:
+                    ier->Status=IP_PARAM_PROBLEM;
+                    break;
+                case ICMP_SOURCEQUENCH:
+                    ier->Status=IP_SOURCE_QUENCH;
+                    break;
+                }
+                if (ier->Status!=IP_REQ_TIMED_OUT) {
+                    struct ip* rep_ip_header;
+                    struct icmp* rep_icmp_header;
+                    /* The ICMP header size of all the packets we accept is the same */
+                    rep_ip_header=(struct ip*)(((char*)icmp_header)+ICMP_MINLEN);
+                    rep_icmp_header=(struct icmp*)(((char*)rep_ip_header)+(rep_ip_header->ip_hl << 2));
+
+		    /* Make sure that this is really a reply to our packet */
+                    if (ip_header_len+ICMP_MINLEN+(rep_ip_header->ip_hl << 2)+ICMP_MINLEN>ip_header->ip_len) {
+			ier->Status=IP_REQ_TIMED_OUT;
+                    } else if ((rep_icmp_header->icmp_type!=ICMP_ECHO) ||
+                        (rep_icmp_header->icmp_code!=0) ||
+                        (rep_icmp_header->icmp_id!=id) ||
+                        (rep_icmp_header->icmp_seq!=seq) ||
+                        (rep_icmp_header->icmp_cksum!=cksum)) {
+                        /* This was not a reply to one of our packets after all */
+                        TRACE("skipping type,code=%d,%d id,seq=%d,%d cksum=%d\n",
+                            rep_icmp_header->icmp_type,rep_icmp_header->icmp_code,
+                            rep_icmp_header->icmp_id,rep_icmp_header->icmp_seq,
+                            rep_icmp_header->icmp_cksum);
+                        TRACE("expected type,code=8,0 id,seq=%d,%d cksum=%d\n",
+                            id,seq,
+                            cksum);
+			ier->Status=IP_REQ_TIMED_OUT;
+		    }
+                }
+	    }                
+	}
+
+        if (ier->Status==IP_REQ_TIMED_OUT) {
+            /* This packet was not for us.
+             * Decrease the timeout so that we don't enter an endless loop even
+             * if we get flooded with ICMP packets that are not for us.
+             */
+            timeout.tv_sec=Timeout/1000-(recv_time.tv_sec-send_time.tv_sec);
+            timeout.tv_usec=(Timeout % 1000)*1000+send_time.tv_usec-(recv_time.tv_usec-send_time.tv_usec);
+            if (timeout.tv_usec<0) {
+                timeout.tv_usec+=1000000;
+                timeout.tv_sec--;
+            }
+            continue;
+        } else {
+            /* This is a reply to our packet */
+            memcpy(&ier->Address,&ip_header->ip_src,sizeof(IPAddr));
+            /* Status is already set */
+            ier->RoundTripTime=(recv_time.tv_sec-send_time.tv_sec)*1000+(recv_time.tv_usec-send_time.tv_usec)/1000;
+            ier->DataSize=res-ip_header_len-ICMP_MINLEN;
+            ier->Reserved=0;
+            ier->Data=endbuf-ier->DataSize;
+            memmove(ier->Data,((char*)ip_header)+ip_header_len+ICMP_MINLEN,ier->DataSize);
+            ier->Options.Ttl=ip_header->ip_ttl;
+            ier->Options.Tos=ip_header->ip_tos;
+            ier->Options.Flags=ip_header->ip_off >> 13;
+            ier->Options.OptionsSize=ip_header_len-sizeof(struct ip);
+            if (ier->Options.OptionsSize!=0) {
+                ier->Options.OptionsData=ier->Data-ier->Options.OptionsSize;
+                /* FIXME: We are supposed to rearrange the option's 'source route' data */
+                memmove(ier->Options.OptionsData,((char*)ip_header)+ip_header_len,ier->Options.OptionsSize);
+                endbuf=ier->Options.OptionsData;
+            } else {
+                ier->Options.OptionsData=NULL;
+                endbuf=ier->Data;
+            }
+
+            /* Prepare for the next packet */
+            ier++;
+            ip_header=(struct ip*)(((char*)ip_header)+sizeof(ICMP_ECHO_REPLY));
+            maxlen=endbuf-(char*)ip_header;
+
+            /* Check out whether there is more but don't wait this time */
+            timeout.tv_sec=0;
+            timeout.tv_usec=0;
+        }
+        FD_ZERO(&fdr);
+        FD_SET(icp->sid,&fdr);
+    }
+    res=ier-(ICMP_ECHO_REPLY*)ReplyBuffer;
+    if (res==0)
+        SetLastError(IP_REQ_TIMED_OUT);
+    TRACE("received %d replies\n",res);
+    return res;
+}
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
diff --git a/include/debugdefs.h b/include/debugdefs.h
index 818041e..f92a39e 100644
--- a/include/debugdefs.h
+++ b/include/debugdefs.h
@@ -59,114 +59,115 @@
 const int dbch_heap = 48;
 const int dbch_hook = 49;
 const int dbch_hotkey = 50;
-const int dbch_icon = 51;
-const int dbch_imagehlp = 52;
-const int dbch_imagelist = 53;
-const int dbch_imm = 54;
-const int dbch_int = 55;
-const int dbch_int10 = 56;
-const int dbch_int16 = 57;
-const int dbch_int17 = 58;
-const int dbch_int19 = 59;
-const int dbch_int21 = 60;
-const int dbch_int31 = 61;
-const int dbch_io = 62;
-const int dbch_ipaddress = 63;
-const int dbch_key = 64;
-const int dbch_keyboard = 65;
-const int dbch_ldt = 66;
-const int dbch_listbox = 67;
-const int dbch_listview = 68;
-const int dbch_local = 69;
-const int dbch_mci = 70;
-const int dbch_mcianim = 71;
-const int dbch_mciavi = 72;
-const int dbch_mcimidi = 73;
-const int dbch_mciwave = 74;
-const int dbch_mdi = 75;
-const int dbch_menu = 76;
-const int dbch_message = 77;
-const int dbch_metafile = 78;
-const int dbch_midi = 79;
-const int dbch_mmaux = 80;
-const int dbch_mmio = 81;
-const int dbch_mmsys = 82;
-const int dbch_mmtime = 83;
-const int dbch_module = 84;
-const int dbch_monthcal = 85;
-const int dbch_mpr = 86;
-const int dbch_msacm = 87;
-const int dbch_msg = 88;
-const int dbch_msvideo = 89;
-const int dbch_nativefont = 90;
-const int dbch_nonclient = 91;
-const int dbch_ntdll = 92;
-const int dbch_ole = 93;
-const int dbch_pager = 94;
-const int dbch_palette = 95;
-const int dbch_pidl = 96;
-const int dbch_print = 97;
-const int dbch_process = 98;
-const int dbch_profile = 99;
-const int dbch_progress = 100;
-const int dbch_prop = 101;
-const int dbch_propsheet = 102;
-const int dbch_psapi = 103;
-const int dbch_psdrv = 104;
-const int dbch_ras = 105;
-const int dbch_rebar = 106;
-const int dbch_reg = 107;
-const int dbch_region = 108;
-const int dbch_relay = 109;
-const int dbch_resource = 110;
-const int dbch_scroll = 111;
-const int dbch_security = 112;
-const int dbch_segment = 113;
-const int dbch_seh = 114;
-const int dbch_selector = 115;
-const int dbch_sendmsg = 116;
-const int dbch_server = 117;
-const int dbch_shell = 118;
-const int dbch_snoop = 119;
-const int dbch_sound = 120;
-const int dbch_static = 121;
-const int dbch_statusbar = 122;
-const int dbch_storage = 123;
-const int dbch_stress = 124;
-const int dbch_string = 125;
-const int dbch_syscolor = 126;
-const int dbch_system = 127;
-const int dbch_tab = 128;
-const int dbch_tapi = 129;
-const int dbch_task = 130;
-const int dbch_text = 131;
-const int dbch_thread = 132;
-const int dbch_thunk = 133;
-const int dbch_timer = 134;
-const int dbch_toolbar = 135;
-const int dbch_toolhelp = 136;
-const int dbch_tooltips = 137;
-const int dbch_trackbar = 138;
-const int dbch_treeview = 139;
-const int dbch_ttydrv = 140;
-const int dbch_tweak = 141;
-const int dbch_typelib = 142;
-const int dbch_updown = 143;
-const int dbch_ver = 144;
-const int dbch_virtual = 145;
-const int dbch_vxd = 146;
-const int dbch_wave = 147;
-const int dbch_win = 148;
-const int dbch_win16drv = 149;
-const int dbch_win32 = 150;
-const int dbch_wing = 151;
-const int dbch_winsock = 152;
-const int dbch_winspool = 153;
-const int dbch_wnet = 154;
-const int dbch_x11 = 155;
-const int dbch_x11drv = 156;
+const int dbch_icmp = 51;
+const int dbch_icon = 52;
+const int dbch_imagehlp = 53;
+const int dbch_imagelist = 54;
+const int dbch_imm = 55;
+const int dbch_int = 56;
+const int dbch_int10 = 57;
+const int dbch_int16 = 58;
+const int dbch_int17 = 59;
+const int dbch_int19 = 60;
+const int dbch_int21 = 61;
+const int dbch_int31 = 62;
+const int dbch_io = 63;
+const int dbch_ipaddress = 64;
+const int dbch_key = 65;
+const int dbch_keyboard = 66;
+const int dbch_ldt = 67;
+const int dbch_listbox = 68;
+const int dbch_listview = 69;
+const int dbch_local = 70;
+const int dbch_mci = 71;
+const int dbch_mcianim = 72;
+const int dbch_mciavi = 73;
+const int dbch_mcimidi = 74;
+const int dbch_mciwave = 75;
+const int dbch_mdi = 76;
+const int dbch_menu = 77;
+const int dbch_message = 78;
+const int dbch_metafile = 79;
+const int dbch_midi = 80;
+const int dbch_mmaux = 81;
+const int dbch_mmio = 82;
+const int dbch_mmsys = 83;
+const int dbch_mmtime = 84;
+const int dbch_module = 85;
+const int dbch_monthcal = 86;
+const int dbch_mpr = 87;
+const int dbch_msacm = 88;
+const int dbch_msg = 89;
+const int dbch_msvideo = 90;
+const int dbch_nativefont = 91;
+const int dbch_nonclient = 92;
+const int dbch_ntdll = 93;
+const int dbch_ole = 94;
+const int dbch_pager = 95;
+const int dbch_palette = 96;
+const int dbch_pidl = 97;
+const int dbch_print = 98;
+const int dbch_process = 99;
+const int dbch_profile = 100;
+const int dbch_progress = 101;
+const int dbch_prop = 102;
+const int dbch_propsheet = 103;
+const int dbch_psapi = 104;
+const int dbch_psdrv = 105;
+const int dbch_ras = 106;
+const int dbch_rebar = 107;
+const int dbch_reg = 108;
+const int dbch_region = 109;
+const int dbch_relay = 110;
+const int dbch_resource = 111;
+const int dbch_scroll = 112;
+const int dbch_security = 113;
+const int dbch_segment = 114;
+const int dbch_seh = 115;
+const int dbch_selector = 116;
+const int dbch_sendmsg = 117;
+const int dbch_server = 118;
+const int dbch_shell = 119;
+const int dbch_snoop = 120;
+const int dbch_sound = 121;
+const int dbch_static = 122;
+const int dbch_statusbar = 123;
+const int dbch_storage = 124;
+const int dbch_stress = 125;
+const int dbch_string = 126;
+const int dbch_syscolor = 127;
+const int dbch_system = 128;
+const int dbch_tab = 129;
+const int dbch_tapi = 130;
+const int dbch_task = 131;
+const int dbch_text = 132;
+const int dbch_thread = 133;
+const int dbch_thunk = 134;
+const int dbch_timer = 135;
+const int dbch_toolbar = 136;
+const int dbch_toolhelp = 137;
+const int dbch_tooltips = 138;
+const int dbch_trackbar = 139;
+const int dbch_treeview = 140;
+const int dbch_ttydrv = 141;
+const int dbch_tweak = 142;
+const int dbch_typelib = 143;
+const int dbch_updown = 144;
+const int dbch_ver = 145;
+const int dbch_virtual = 146;
+const int dbch_vxd = 147;
+const int dbch_wave = 148;
+const int dbch_win = 149;
+const int dbch_win16drv = 150;
+const int dbch_win32 = 151;
+const int dbch_wing = 152;
+const int dbch_winsock = 153;
+const int dbch_winspool = 154;
+const int dbch_wnet = 155;
+const int dbch_x11 = 156;
+const int dbch_x11drv = 157;
 
-#define DEBUG_CHANNEL_COUNT 157
+#define DEBUG_CHANNEL_COUNT 158
 
 char __debug_msg_enabled[DEBUG_CHANNEL_COUNT][DEBUG_CLASS_COUNT] = {
 {1, 1, 0, 0},
@@ -325,6 +326,7 @@
 {1, 1, 0, 0},
 {1, 1, 0, 0},
 {1, 1, 0, 0},
+{1, 1, 0, 0},
 {1, 1, 0, 0}
 };
 
@@ -380,6 +382,7 @@
 "heap",
 "hook",
 "hotkey",
+"icmp",
 "icon",
 "imagehlp",
 "imagelist",
diff --git a/include/wine/icmpapi.h b/include/wine/icmpapi.h
new file mode 100644
index 0000000..df2717f
--- /dev/null
+++ b/include/wine/icmpapi.h
@@ -0,0 +1,33 @@
+/*
+ * Interface to the ICMP functions.
+ *
+ * This header is not part of the standard headers, it is usually 
+ * delivered separately and this is why it is not directly in 'include'.
+ *
+ * Depends on ipexport.h (there is no include directive in the original)
+ */
+
+#ifndef __WINE_ICMPAPI_H
+#define __WINE_ICMPAPI_H
+
+HANDLE WINAPI IcmpCreateFile(
+    VOID
+    );
+
+BOOL WINAPI IcmpCloseHandle(
+    HANDLE  IcmpHandle
+    );
+
+DWORD WINAPI IcmpSendEcho(
+    HANDLE                 IcmpHandle,
+    IPAddr                 DestinationAddress,
+    LPVOID                 RequestData,
+    WORD                   RequestSize,
+    PIP_OPTION_INFORMATION RequestOptions,
+    LPVOID                 ReplyBuffer,
+    DWORD                  ReplySize,
+    DWORD                  Timeout
+    );
+
+
+#endif /* __WINE_ICMPAPI_H */
diff --git a/include/wine/ipexport.h b/include/wine/ipexport.h
new file mode 100644
index 0000000..c383d7c0
--- /dev/null
+++ b/include/wine/ipexport.h
@@ -0,0 +1,86 @@
+/*
+ * Defines the types and macros used by the ICMP API, see icmpapi.h.
+ *
+ * This header is not part of the standard headers, it is usually 
+ * delivered separately and this is why it is not directly in 'include'.
+ */
+
+#ifndef __WINE_IPEXPORT_H
+#define __WINE_IPEXPORT_H
+
+typedef unsigned long   IPAddr;
+typedef unsigned long   IPMask;
+typedef unsigned long   IP_STATUS;
+
+struct ip_option_information
+{
+    unsigned char  Ttl;
+    unsigned char  Tos;
+    unsigned char  Flags;
+    unsigned char  OptionsSize;
+    unsigned char* OptionsData;
+};
+
+#define IP_FLAG_DF      0x2
+
+#define IP_OPT_EOL      0
+#define IP_OPT_NOP      1
+#define IP_OPT_SECURITY 0x82
+#define IP_OPT_LSRR     0x83
+#define IP_OPT_SSRR     0x89
+#define IP_OPT_RR       0x7
+#define IP_OPT_TS       0x44
+#define IP_OPT_SID      0x88
+
+#define MAX_OPT_SIZE    40
+
+
+struct icmp_echo_reply
+{
+    IPAddr                       Address;
+    unsigned long                Status;
+    unsigned long                RoundTripTime;
+    unsigned short               DataSize;
+    unsigned short               Reserved;
+    void*                        Data;
+    struct ip_option_information Options;
+};
+
+typedef struct ip_option_information IP_OPTION_INFORMATION, *PIP_OPTION_INFORMATION;
+
+typedef struct icmp_echo_reply ICMP_ECHO_REPLY, *PICMP_ECHO_REPLY;
+
+
+#define IP_STATUS_BASE              11000
+
+#define IP_SUCCESS                  0
+#define IP_BUF_TOO_SMALL            (IP_STATUS_BASE + 1)
+#define IP_DEST_NET_UNREACHABLE     (IP_STATUS_BASE + 2)
+#define IP_DEST_HOST_UNREACHABLE    (IP_STATUS_BASE + 3)
+#define IP_DEST_PROT_UNREACHABLE    (IP_STATUS_BASE + 4)
+#define IP_DEST_PORT_UNREACHABLE    (IP_STATUS_BASE + 5)
+#define IP_NO_RESOURCES             (IP_STATUS_BASE + 6)
+#define IP_BAD_OPTION               (IP_STATUS_BASE + 7)
+#define IP_HW_ERROR                 (IP_STATUS_BASE + 8)
+#define IP_PACKET_TOO_BIG           (IP_STATUS_BASE + 9)
+#define IP_REQ_TIMED_OUT            (IP_STATUS_BASE + 10)
+#define IP_BAD_REQ                  (IP_STATUS_BASE + 11)
+#define IP_BAD_ROUTE                (IP_STATUS_BASE + 12)
+#define IP_TTL_EXPIRED_TRANSIT      (IP_STATUS_BASE + 13)
+#define IP_TTL_EXPIRED_REASSEM      (IP_STATUS_BASE + 14)
+#define IP_PARAM_PROBLEM            (IP_STATUS_BASE + 15)
+#define IP_SOURCE_QUENCH            (IP_STATUS_BASE + 16)
+#define IP_OPTION_TOO_BIG           (IP_STATUS_BASE + 17)
+#define IP_BAD_DESTINATION          (IP_STATUS_BASE + 18)
+
+#define IP_ADDR_DELETED             (IP_STATUS_BASE + 19)
+#define IP_SPEC_MTU_CHANGE          (IP_STATUS_BASE + 20)
+#define IP_MTU_CHANGE               (IP_STATUS_BASE + 21)
+#define IP_UNLOAD                   (IP_STATUS_BASE + 22)
+
+#define IP_GENERAL_FAILURE          (IP_STATUS_BASE + 50)
+#define MAX_IP_STATUS               IP_GENERAL_FAILURE
+#define IP_PENDING                  (IP_STATUS_BASE + 255)
+
+
+#endif /* __WINE_IPEXPORT_H */
diff --git a/loader/loadorder.c b/loader/loadorder.c
index a340c8b..101a8b2 100644
--- a/loader/loadorder.c
+++ b/loader/loadorder.c
@@ -56,6 +56,7 @@
 	{"wnaspi32,wow32",		"builtin"},
 	{"system,display,wprocs	",	"builtin"},
 	{"wineps",			"builtin"},
+        {"icmp",                        "builtin"},
 	/* we have to use libglide2x.so instead of glide2x.dll ... */
 	{"glide2x",			"so,native"},
 	{NULL,NULL},
diff --git a/relay32/builtin32.c b/relay32/builtin32.c
index 92c8df1..2d52b5c 100644
--- a/relay32/builtin32.c
+++ b/relay32/builtin32.c
@@ -60,6 +60,7 @@
 extern const BUILTIN32_DESCRIPTOR DPLAYX_Descriptor;
 extern const BUILTIN32_DESCRIPTOR DSOUND_Descriptor;
 extern const BUILTIN32_DESCRIPTOR GDI32_Descriptor;
+extern const BUILTIN32_DESCRIPTOR ICMP_Descriptor;
 extern const BUILTIN32_DESCRIPTOR IMAGEHLP_Descriptor;
 extern const BUILTIN32_DESCRIPTOR IMM32_Descriptor;
 extern const BUILTIN32_DESCRIPTOR KERNEL32_Descriptor;
@@ -116,6 +117,7 @@
     { &DPLAYX_Descriptor,   0, 0, NULL },
     { &DSOUND_Descriptor,   0, 0, NULL },
     { &GDI32_Descriptor,    0, 0, NULL },
+    { &ICMP_Descriptor,    0, 0, NULL },
     { &IMAGEHLP_Descriptor, BI32_DANGER, 0, NULL },
     { &IMM32_Descriptor,    0, 0, NULL },
     { &KERNEL32_Descriptor, 0, 0, NULL },
diff --git a/wine.ini b/wine.ini
index 6f55056..ada10dd 100644
--- a/wine.ini
+++ b/wine.ini
@@ -61,7 +61,7 @@
 DefaultLoadOrder = native, elfdll, so, builtin
 
 [DllPairs]
-kernel	= kernel32
+krnl386	= kernel32
 gdi	= gdi32
 user	= user32
 commdlg	= comdlg32
@@ -96,6 +96,7 @@
 wnaspi32, wow32		= builtin
 system, display, wprocs	= builtin
 wineps			= builtin
+icmp                    = builtin
 
 [options]
 AllocSystemColors=100