Index: /trunk/src/VBox/Devices/Network/slirp/ip_icmp.c
===================================================================
--- /trunk/src/VBox/Devices/Network/slirp/ip_icmp.c	(revision 15034)
+++ /trunk/src/VBox/Devices/Network/slirp/ip_icmp.c	(revision 15035)
@@ -67,10 +67,77 @@
 
 #ifdef VBOX_WITH_SLIRP_ICMP
+int
+icmp_init(PNATState pData)
+{
+        pData->icmp_socket.so_type = IPPROTO_ICMP;
+        pData->icmp_socket.so_state = SS_ISFCONNECTED;
+        pData->icmp_socket.s = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
+        insque(pData, &pData->icmp_socket, &udb);
+        LIST_INIT(&pData->icmp_msg_head);
+        return (0);
+}
+
+/*
+ * ip here is ip header + 64bytes readed from ICMP packet
+ */
+struct icmp_msg *
+icmp_find_original_mbuf(PNATState pData, struct ip *ip)
+{
+    struct mbuf *m0;
+    struct ip *ip0;
+    struct icmp *icp, *icp0;
+    struct icmp_msg *icm;
+    int found = 0;
+    struct socket *head_socket;
+    struct in_addr laddr, faddr;
+    u_int lport, fport;
+
+    switch (ip->ip_p) {
+    case IPPROTO_ICMP:
+        icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
+        LIST_FOREACH(icm, &pData->icmp_msg_head, im_list)
+        {
+            m0 = icm->im_m;
+            ip0 = mtod(m0, struct ip *);
+            AssertRelease(ip0->ip_p == IPPROTO_ICMP);
+            icp0 = (struct icmp *)((char *)ip0 + (ip0->ip_hl << 2));
+            LogRel(("ip(src:%R[IP4], dst:%R[IP4],id:%x) ip0(src:%R[IP4],dst:%R[IP4],id:%x)\n",
+                    ip->ip_src.s_addr,
+                    ip->ip_dst.s_addr,
+                    ip->ip_id,
+                    ip0->ip_src.s_addr,
+                    ip0->ip_dst.s_addr,
+                    ip0->ip_id));
+            LogRel(("icp(id:%x, seq:%x, type=%d) icp0(id:%x, seq:%x)\n",icp->icmp_id, icp->icmp_seq, icp->icmp_type, icp0->icmp_id, icp0->icmp_seq));
+            if (
+                ((icp->icmp_type != ICMP_ECHO && ip->ip_src.s_addr == ip0->ip_dst.s_addr)
+                ||(icp->icmp_type == ICMP_ECHO && ip->ip_dst.s_addr == ip0->ip_dst.s_addr))
+                && icp->icmp_id == icp0->icmp_id
+                && icp->icmp_seq == icp->icmp_seq) {
+                found = 1;
+                break;
+            }
+        }
+    case IPPROTO_UDP:
+        head_socket = &udb;
+    case IPPROTO_TCP:
+        head_socket = (head_socket != NULL ? head_socket : &tcb); /* head_socket could be initialized with udb*/
+    }
+    if (found == 1) {
+        return (icm);
+    }
+    return (NULL);
+}
+
 static int
-icmp_attach(PNATState pData, struct socket *so) {
-    AssertRelease(so != NULL);
-    so->s = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
-    insque(pData, so, &udb); /*adding it udb queue*/
-    return (so->s);
+icmp_attach(PNATState pData, struct mbuf *m) {
+    struct icmp_msg *icm;
+    struct ip *ip;
+    ip = mtod(m, struct ip *);
+    Assert(ip->ip_p == IPPROTO_ICMP);
+    icm = malloc(sizeof(struct icmp_msg));
+    icm->im_m = m;
+    LIST_INSERT_HEAD(&pData->icmp_msg_head, icm, im_list);
+    return (0);
 }
 #endif /* VBOX_WITH_SLIRP_ICMP */
@@ -85,4 +152,5 @@
   register struct ip *ip=mtod(m, struct ip *);
   int icmplen=ip->ip_len;
+  int status;
   /* int code; */
 
@@ -123,6 +191,8 @@
     icp->icmp_type = ICMP_ECHOREPLY;
 #endif /* !VBOX_WITH_SLIRP_ICMP */
+
     ip->ip_len += hlen;              /* since ip_input subtracts this */
-    if (ip->ip_dst.s_addr == alias_addr.s_addr) {
+    if (ip->ip_dst.s_addr == alias_addr.s_addr
+    ) {
 #ifdef VBOX_WITH_SLIRP_ICMP
       icp->icmp_type = ICMP_ECHOREPLY;
@@ -132,10 +202,7 @@
       struct socket *so;
       struct sockaddr_in addr;
+#ifndef VBOX_WITH_SLIRP_ICMP
       if ((so = socreate()) == NULL) goto freeit;
-#ifndef VBOX_WITH_SLIRP_ICMP
       if(udp_attach(pData, so) == -1)
-#else
-      if(icmp_attach(pData, so) == -1)
-#endif
       {
         DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
@@ -154,5 +221,4 @@
       so->so_state = SS_ISFCONNECTED;
 
-      /* Send the packet */
       addr.sin_family = AF_INET;
       if ((so->so_faddr.s_addr & htonl(pData->netmask)) == special_addr.s_addr) {
@@ -171,5 +237,4 @@
       }
       addr.sin_port = so->so_fport;
-#ifndef VBOX_WITH_SLIRP_ICMP
       if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
                 (struct sockaddr *)&addr, sizeof(addr)) == -1) {
@@ -180,10 +245,31 @@
       }
 #else /* !VBOX_WITH_SLIRP_ICMP */
-      if(sendto(so->s, icp, icmplen, 0,
+      addr.sin_family = AF_INET;
+      if ((ip->ip_dst.s_addr & htonl(pData->netmask)) == special_addr.s_addr) {
+        /* It's an alias */
+        switch(ntohl(ip->ip_dst.s_addr) & ~pData->netmask) {
+        case CTL_DNS:
+          addr.sin_addr = dns_addr;
+          break;
+        case CTL_ALIAS:
+        default:
+          addr.sin_addr = loopback_addr;
+          break;
+        }
+      } else {
+            addr.sin_addr.s_addr = ip->ip_dst.s_addr;
+      }
+      icmp_attach(pData, m);
+      /* Send the packet */
+      status = setsockopt(pData->icmp_socket.s, IPPROTO_IP, IP_TTL, (void *)&ip->ip_ttl, sizeof(ip->ip_ttl));
+      if (status < 0) {
+            LogRel(("error(%s) occured while setting TTL attribute of IP packet\n", strerror(errno)));
+      }
+      if(sendto(pData->icmp_socket.s, icp, icmplen, 0,
                 (struct sockaddr *)&addr, sizeof(addr)) == -1) {
         DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
                     errno,strerror(errno)));
         icmp_error(pData, m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
-        udp_detach(pData, so);
+        m_free(pData, m);
       }
 
@@ -382,7 +468,7 @@
     m->m_len -= optlen;
   }
-
+  LogRel(("%s, ttl %d msg_type=%d code=%d\n", __FUNCTION__, ip->ip_ttl, icp->icmp_type, icp->icmp_code ));
+#ifndef VBOX_WITH_SLIRP_ICMP
   ip->ip_ttl = MAXTTL;
-#ifndef VBOX_WITH_SLIRP_ICMP
   { /* swap */
     struct in_addr icmp_dst;
Index: /trunk/src/VBox/Devices/Network/slirp/ip_icmp.h
===================================================================
--- /trunk/src/VBox/Devices/Network/slirp/ip_icmp.h	(revision 15034)
+++ /trunk/src/VBox/Devices/Network/slirp/ip_icmp.h	(revision 15035)
@@ -37,4 +37,7 @@
 #ifndef _NETINET_IP_ICMP_H_
 #define _NETINET_IP_ICMP_H_
+#ifdef VBOX_WITH_SLIRP_ICMP
+#include <queue.h>
+#endif
 
 /*
@@ -162,3 +165,15 @@
 void icmp_reflect _P((PNATState, struct mbuf *));
 
+#ifdef VBOX_WITH_SLIRP_ICMP
+struct icmp_msg{
+    LIST_ENTRY(icmp_msg) im_list;
+    struct mbuf *im_m;
+};
+
+LIST_HEAD(icmp_storage, icmp_msg);
+
+int icmp_init _P((PNATState ));
+struct icmp_msg * icmp_find_original_mbuf _P((PNATState , struct ip *));
+#endif /* VBOX_WITH_SLIRP_ICMP */
+
 #endif
Index: /trunk/src/VBox/Devices/Network/slirp/ip_input.c
===================================================================
--- /trunk/src/VBox/Devices/Network/slirp/ip_input.c	(revision 15034)
+++ /trunk/src/VBox/Devices/Network/slirp/ip_input.c	(revision 15035)
@@ -138,9 +138,12 @@
 
         /* check ip_ttl for a correct ICMP reply */
-        if(ip->ip_ttl==0 || ip->ip_ttl==1) {
+        if(ip->ip_ttl==0 || ip->ip_ttl == 1) {
           icmp_error(pData, m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");
           goto bad;
         }
 
+#ifdef VBOX_WITH_SLIRP_ICMP
+        ip->ip_ttl--;
+#endif
         /*
          * Process options and, if not destined for us,
Index: /trunk/src/VBox/Devices/Network/slirp/slirp.c
===================================================================
--- /trunk/src/VBox/Devices/Network/slirp/slirp.c	(revision 15034)
+++ /trunk/src/VBox/Devices/Network/slirp/slirp.c	(revision 15035)
@@ -246,4 +246,7 @@
     if_init(pData);
     ip_init(pData);
+#ifdef VBOX_WITH_SLIRP_ICMP
+    icmp_init(pData);
+#endif /* VBOX_WITH_SLIRP_ICMP */
 
     /* Initialise mbufs *after* setting the MTU */
@@ -555,5 +558,5 @@
              * the session could have more queued if the packets needed
              * to be fragmented.
-             * 
+             *
              * (XXX <= 4 ?)
              */
Index: /trunk/src/VBox/Devices/Network/slirp/slirp_state.h
===================================================================
--- /trunk/src/VBox/Devices/Network/slirp/slirp_state.h	(revision 15034)
+++ /trunk/src/VBox/Devices/Network/slirp/slirp_state.h	(revision 15035)
@@ -21,4 +21,7 @@
 #ifndef _slirp_state_h_
 #define _slirp_state_h_
+#ifdef VBOX_WITH_SLIRP_ICMP
+#include "ip_icmp.h"
+#endif
 
 /** Number of DHCP clients supported by NAT. */
@@ -129,4 +132,8 @@
     struct socket udb;
     struct socket *udp_last_so;
+#ifdef VBOX_WITH_SLIRP_ICMP
+    struct socket icmp_socket;
+    struct icmp_storage icmp_msg_head;
+#endif
 #if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
 # define VBOX_SOCKET_EVENT (pData->phEvents[VBOX_SOCKET_EVENT_INDEX])
Index: /trunk/src/VBox/Devices/Network/slirp/socket.c
===================================================================
--- /trunk/src/VBox/Devices/Network/slirp/socket.c	(revision 15034)
+++ /trunk/src/VBox/Devices/Network/slirp/socket.c	(revision 15035)
@@ -423,13 +423,10 @@
     DEBUG_ARG("so = %lx", (long)so);
 
-    if (so->so_type == IPPROTO_ICMP)
-    {
-        /* This is a "ping" reply */
-        char buff[256];
-        int len;
-
-        len = recvfrom(so->s, buff, sizeof(buff), 0,
-                       (struct sockaddr *)&addr, &addrlen);
-        /* XXX Check if reply is "correct"? */
+        if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
+          char buff[1500];
+          int len;
+          len = recvfrom(so->s, buff, 1500, 0,
+                         (struct sockaddr *)&addr, &addrlen);
+          /* XXX Check if reply is "correct"? */
 
         if(len == -1 || len == 0)
@@ -441,4 +438,5 @@
             else if(errno == ENETUNREACH)
                 code=ICMP_UNREACH_NET;
+
 
             DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
@@ -450,26 +448,63 @@
 #ifdef VBOX_WITH_SLIRP_ICMP
             struct ip *ip;
-            uint32_t dst;
-            ip = mtod(so->so_m, struct ip *);
-            dst = ip->ip_src.s_addr;
-            memcpy(so->so_m->m_data, buff, len); /* ovveride ther tail of old packet */
+            uint32_t dst,src;
+            char ip_copy[256];
+            struct icmp *icp;
+            int old_ip_len;
+            struct mbuf *orig_m;
+            struct icmp_msg *icm;
+
+            ip = (struct ip *)buff;
+            icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
+            Assert(icp->icmp_type != ICMP_ECHO);
+            if (icp->icmp_type >= ICMP_UNREACH ) {
+                ip = &icp->icmp_ip;
+            }
+            icm = icmp_find_original_mbuf(pData, ip);
+            if (icm == NULL) {
+                LogRel(("Can't find the corresponding packet for the received ICMP\n"));
+                return;
+            }
+            orig_m = icm->im_m;
+            Assert(orig_m != NULL);
+
+            LogRel(("ICMP message arrived on socket %d\n", so->s));
+            src = addr.sin_addr.s_addr;
+
+            ip = mtod(orig_m, struct ip *); /* Now ip is old header */
+            old_ip_len = (ip->ip_hl << 2) + 64;
+            memcpy(ip_copy, ip, old_ip_len);
+
+            dst = ip->ip_src.s_addr; /* source address from original IP packet*/
+
+            memcpy(orig_m->m_data, buff, len); /* overide ther tail of old packet */
+            orig_m->m_len = len;
+            ip = mtod(orig_m, struct ip *); /* ip is from mbuf we've overrided */
+
+            icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
+            NTOHS(ip->ip_len);
+            if (icp->icmp_type >= ICMP_UNREACH && icp->icmp_type != ICMP_ECHO) {
+                memcpy(&icp->icmp_ip, ip_copy, old_ip_len); /* according RFC 793 error messages required copy of initial IP header + 64 bit */
+                ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0);  /* high priority for errors */
+            }
             /* the low level expects fields to be in host format so let's convert them*/
-            ip = mtod(so->so_m, struct ip *);
-            NTOHS(ip->ip_len);
             NTOHS(ip->ip_off);
             NTOHS(ip->ip_id);
+            ip->ip_src.s_addr = src;
             ip->ip_dst.s_addr = dst;
-#endif
+            icmp_reflect(pData, orig_m);
+            LIST_REMOVE(icm, im_list);
+            /* Don't call m_free here*/
+            free(icm);
+#else
             icmp_reflect(pData, so->so_m);
             so->so_m = 0; /* Don't m_free() it again! */
-        }
-        /* No need for this socket anymore, udp_detach it */
-        udp_detach(pData, so);
-    }
-    else
-    { 
-        /* A "normal" UDP packet */
-        struct mbuf *m;
-        int len, n;
+#endif
+          }
+          /* No need for this socket anymore, udp_detach it */
+          udp_detach(pData, so);
+        } else {                                /* A "normal" UDP packet */
+          struct mbuf *m;
+          int len, n;
 
         if (!(m = m_get(pData)))
@@ -533,5 +568,5 @@
                 m->m_len = 0;
             }
-#endif            
+#endif
 
             /*
@@ -753,5 +788,5 @@
     so->so_state &= ~(SS_ISFCONNECTING);
     if (so->so_state & SS_FCANTSENDMORE)
-        so->so_state = SS_NOFDREF; /* Don't select it */ 
+        so->so_state = SS_NOFDREF; /* Don't select it */
                                    /* XXX close() here as well? */
     else
Index: /trunk/src/VBox/Devices/Network/slirp/udp.c
===================================================================
--- /trunk/src/VBox/Devices/Network/slirp/udp.c	(revision 15034)
+++ /trunk/src/VBox/Devices/Network/slirp/udp.c	(revision 15035)
@@ -367,8 +367,15 @@
         /* Correctly update list if detaching last socket in list. */
         if (so == udp_last_so) udp_last_so = &udb;
+#ifndef VBOX_WITH_SLIRP_ICMP
         closesocket(so->s);
         /* if (so->so_m) m_free(so->so_m);    done by sofree */
 
         sofree(pData, so);
+#else /*! VBOX_WITH_SLIRP_ICMP */
+        if (so != &pData->icmp_socket) {
+            closesocket(so->s);
+            sofree(pData, so);
+        }
+#endif /* VBOX_WITH_SLIRP_ICMP */
 }
 
