]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
slirp: forward ICMP through datagram sockets
authorStefan Reinauer <stefan.reinauer@coreboot.org>
Thu, 28 May 2026 00:21:35 +0000 (17:21 -0700)
committerStefan Reinauer <stefan.reinauer@coreboot.org>
Tue, 2 Jun 2026 22:33:30 +0000 (15:33 -0700)
Enable datagram ICMP forwarding, keep the host sockets nonblocking,
and strip host IP headers before delivering ICMP replies back to the
emulated Ethernet device.

slirp/icmp_var.h
slirp/ip_icmp.cpp
slirp/slirp.cpp
slirp/slirp.h
slirp/socket.cpp
slirp/udp.cpp

index a50fd65c605a0136b29824d6d3042c59548408d7..8f0fede5b40a9070a612129738211109c3c71022 100644 (file)
@@ -61,7 +61,7 @@ struct icmpstat {
 }
 
 extern struct icmpstat icmpstat;
-#if 0
+#if SLIRP_ICMP
 extern struct socket icmp; 
 extern struct socket *icmp_last_so;
 #endif
index 94378f7073b1aa08c13bdf28fe1728dccb6a4831..c39f0f02b958e6d2cff39ba73fd98c59e39093b7 100644 (file)
@@ -88,6 +88,7 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
     if (so->s == -1) {
         return -1;
     }
+    fd_nonblock(so->s);
 
     so->so_m = m;
     so->so_faddr = ip->ip_dst;
@@ -164,9 +165,9 @@ void icmp_input(struct mbuf *m, int hlen)
   DEBUG_ARG("icmp_type = %d", icp->icmp_type);
   switch (icp->icmp_type) {
   case ICMP_ECHO:
-    icp->icmp_type = ICMP_ECHOREPLY;
     ip->ip_len += hlen;                     /* since ip_input subtracts this */
     if (ip->ip_dst.s_addr == alias_addr.s_addr) {
+      icp->icmp_type = ICMP_ECHOREPLY;
       icmp_reflect(m);
     } else {
       struct socket *so;
@@ -176,6 +177,7 @@ void icmp_input(struct mbuf *m, int hlen)
          if (icmp_send(so, m, hlen) == 0)
         return;
 #endif
+         icp->icmp_type = ICMP_ECHOREPLY;
          if(udp_attach(so) == -1) {
        DEBUG_MISC(("icmp_input udp_attach errno = %d-%s\n", 
                    errno,strerror(errno)));
@@ -431,6 +433,7 @@ void icmp_receive(struct socket *so)
     int hlen = ip->ip_hl << 2;
     u_char error_code;
     struct icmp *icp;
+    uae_u8 reply[2048];
     int id, len;
 
     m->m_data += hlen;
@@ -438,8 +441,40 @@ void icmp_receive(struct socket *so)
     icp = mtod(m, struct icmp *);
 
     id = icp->icmp_id;
-    len = recv(so->s, (char*)icp, m->m_len, 0);
-    icp->icmp_id = id;
+    len = recv(so->s, (char*)reply, sizeof(reply), 0);
+    if (len > 0) {
+        int offset = 0;
+        int reply_len;
+
+        if (len >= (int)sizeof(struct ip) && (reply[0] >> 4) == 4) {
+            int iphlen = (reply[0] & 0x0f) << 2;
+            struct ip *reply_ip = (struct ip*)reply;
+            if (iphlen >= (int)sizeof(struct ip) && iphlen <= len &&
+                reply_ip->ip_p == IPPROTO_ICMP) {
+                offset = iphlen;
+            }
+        }
+
+        reply_len = len - offset;
+        if (reply_len <= 0) {
+            errno = EPROTO;
+            len = -1;
+        } else {
+            if ((size_t)reply_len > M_ROOM(m)) {
+                char *base = (m->m_flags & M_EXT) ? m->m_ext : m->m_dat;
+                m_inc(m, (int)(m->m_data - base + reply_len));
+            }
+            if ((size_t)reply_len > M_ROOM(m)) {
+                errno = ENOMEM;
+                len = -1;
+            } else {
+                memcpy(m->m_data, reply + offset, reply_len);
+                m->m_len = reply_len;
+                icp = mtod(m, struct icmp *);
+                icp->icmp_id = id;
+            }
+        }
+    }
 
     m->m_data -= hlen;
     m->m_len += hlen;
index 7798273ac8f04ff1046190cdb2bcf04bb2e25d8e..d8e5b23f0a41971ab6fa4c64f97d095150683ec2 100644 (file)
@@ -302,7 +302,7 @@ int slirp_select_fill(INT_PTR *pnfds,
                        }
                }
 
-#if 0
+#if SLIRP_ICMP
         /*
          * ICMP sockets
          */
@@ -533,7 +533,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
                        }
                }
 
-#if 0
+#if SLIRP_ICMP
         /*
          * Check incoming ICMP relies.
          */
index 255f827a1391339d94f13224d65952c8015716a1..40b737c1350474631bebc98f719ac91eceffe500 100644 (file)
@@ -11,7 +11,7 @@
 #include "sysconfig.h"
 #include "slirp_config.h"
 
-#define SLIRP_ICMP 0
+#define SLIRP_ICMP 1
 
 #ifdef _WIN32
 #include <stdint.h>
index cd4d5dec4d4b6f7287ab914f8bf1f400ff3324d3..80fd8f3b4e147edcaded0c0d5a9bd4d193264c79 100644 (file)
@@ -397,6 +397,8 @@ void sorecvfrom(struct socket *so)
            u_char code=ICMP_UNREACH_PORT;
 
                int error = WSAGetLastError();
+           if(len == -1 && IS_EAGAIN(error))
+             return;
            if(error  == WSAEHOSTUNREACH) code=ICMP_UNREACH_HOST;
            else if(error  == WSAENETUNREACH) code=ICMP_UNREACH_NET;
            
@@ -440,6 +442,10 @@ void sorecvfrom(struct socket *so)
            u_char code=ICMP_UNREACH_PORT;
                int error = WSAGetLastError();
 
+           if (IS_EAGAIN(error)) {
+             m_free(m);
+             return;
+           }
            if(error == WSAEHOSTUNREACH) code=ICMP_UNREACH_HOST;
            else if(error == WSAENETUNREACH) code=ICMP_UNREACH_NET;
            
index 3fea58b6c0b2a04b6c036cf1bf93035da85cf71b..0c204c065164712c703c135f840eaf07250f1d5e 100644 (file)
@@ -334,6 +334,7 @@ SLIRP_SOCKET udp_attach(struct socket *so)
         * (sendto() on an unbound socket will bind it), it's done
         * here so that emulation of ytalk etc. don't have to do it
         */
+               fd_nonblock(so->s);
                memset(&addr, 0, sizeof(struct sockaddr_in));
                addr.sin_family = AF_INET;
                addr.sin_port = 0;