summary refs log tree commit diff stats
path: root/slirp
diff options
context:
space:
mode:
Diffstat (limited to 'slirp')
-rw-r--r--slirp/ip_icmp.c95
-rw-r--r--slirp/ip_icmp.h3
-rw-r--r--slirp/ip_input.c30
-rw-r--r--slirp/ip_output.c4
-rw-r--r--slirp/mbuf.h3
-rw-r--r--slirp/misc.c16
-rw-r--r--slirp/slirp.c39
-rw-r--r--slirp/slirp.h5
-rw-r--r--slirp/socket.c6
-rw-r--r--slirp/tcp_input.c10
-rw-r--r--slirp/tcp_subr.c2
-rw-r--r--slirp/udp.c23
12 files changed, 182 insertions, 54 deletions
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index 751a8e249a..4b43994dbc 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -60,6 +60,52 @@ static const int icmp_flush[19] = {
 /* ADDR MASK REPLY (18) */ 0
 };
 
+void icmp_init(Slirp *slirp)
+{
+    slirp->icmp.so_next = slirp->icmp.so_prev = &slirp->icmp;
+    slirp->icmp_last_so = &slirp->icmp;
+}
+
+static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
+{
+    struct ip *ip = mtod(m, struct ip *);
+    struct sockaddr_in addr;
+
+    so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+    if (so->s == -1) {
+        return -1;
+    }
+
+    so->so_m = m;
+    so->so_faddr = ip->ip_dst;
+    so->so_laddr = ip->ip_src;
+    so->so_iptos = ip->ip_tos;
+    so->so_type = IPPROTO_ICMP;
+    so->so_state = SS_ISFCONNECTED;
+    so->so_expire = curtime + SO_EXPIRE;
+
+    addr.sin_family = AF_INET;
+    addr.sin_addr = so->so_faddr;
+
+    insque(so, &so->slirp->icmp);
+
+    if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
+               (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+        DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n",
+                    errno, strerror(errno)));
+        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
+        icmp_detach(so);
+    }
+
+    return 0;
+}
+
+void icmp_detach(struct socket *so)
+{
+    closesocket(so->s);
+    sofree(so);
+}
+
 /*
  * Process a received ICMP message.
  */
@@ -81,7 +127,7 @@ icmp_input(struct mbuf *m, int hlen)
    */
   if (icmplen < ICMP_MINLEN) {          /* min 8 bytes payload */
   freeit:
-    m_freem(m);
+    m_free(m);
     goto end_error;
   }
 
@@ -97,14 +143,18 @@ 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 == slirp->vhost_addr.s_addr) {
       icmp_reflect(m);
+    } else if (slirp->restricted) {
+        goto freeit;
     } else {
       struct socket *so;
       struct sockaddr_in addr;
       if ((so = socreate(slirp)) == NULL) goto freeit;
+      if (icmp_send(so, m, hlen) == 0) {
+        return;
+      }
       if(udp_attach(so) == -1) {
 	DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
 		    errno,strerror(errno)));
@@ -153,11 +203,11 @@ icmp_input(struct mbuf *m, int hlen)
   case ICMP_TSTAMP:
   case ICMP_MASKREQ:
   case ICMP_REDIRECT:
-    m_freem(m);
+    m_free(m);
     break;
 
   default:
-    m_freem(m);
+    m_free(m);
   } /* swith */
 
 end_error:
@@ -319,6 +369,7 @@ icmp_reflect(struct mbuf *m)
   m->m_len -= hlen;
   icp = mtod(m, struct icmp *);
 
+  icp->icmp_type = ICMP_ECHOREPLY;
   icp->icmp_cksum = 0;
   icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
 
@@ -349,3 +400,39 @@ icmp_reflect(struct mbuf *m)
 
   (void ) ip_output((struct socket *)NULL, m);
 }
+
+void icmp_receive(struct socket *so)
+{
+    struct mbuf *m = so->so_m;
+    struct ip *ip = mtod(m, struct ip *);
+    int hlen = ip->ip_hl << 2;
+    u_char error_code;
+    struct icmp *icp;
+    int id, len;
+
+    m->m_data += hlen;
+    m->m_len -= hlen;
+    icp = mtod(m, struct icmp *);
+
+    id = icp->icmp_id;
+    len = qemu_recv(so->s, icp, m->m_len, 0);
+    icp->icmp_id = id;
+
+    m->m_data -= hlen;
+    m->m_len += hlen;
+
+    if (len == -1 || len == 0) {
+        if (errno == ENETUNREACH) {
+            error_code = ICMP_UNREACH_NET;
+        } else {
+            error_code = ICMP_UNREACH_HOST;
+        }
+        DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno,
+                    strerror(errno)));
+        icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
+    } else {
+        icmp_reflect(so->so_m);
+        so->so_m = NULL; /* Don't m_free() it again! */
+    }
+    icmp_detach(so);
+}
diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h
index 2692822f87..b3da1f2697 100644
--- a/slirp/ip_icmp.h
+++ b/slirp/ip_icmp.h
@@ -153,9 +153,12 @@ struct icmp {
 	(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
 	(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
 
+void icmp_init(Slirp *slirp);
 void icmp_input(struct mbuf *, int);
 void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
                 const char *message);
 void icmp_reflect(struct mbuf *);
+void icmp_receive(struct socket *so);
+void icmp_detach(struct socket *so);
 
 #endif
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index 768ab0cd49..5e67631ab4 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -58,6 +58,7 @@ ip_init(Slirp *slirp)
     slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev = &slirp->ipq.ip_link;
     udp_init(slirp);
     tcp_init(slirp);
+    icmp_init(slirp);
 }
 
 /*
@@ -118,27 +119,6 @@ ip_input(struct mbuf *m)
 		goto bad;
 	}
 
-    if (slirp->restricted) {
-        if ((ip->ip_dst.s_addr & slirp->vnetwork_mask.s_addr) ==
-            slirp->vnetwork_addr.s_addr) {
-            if (ip->ip_dst.s_addr == 0xffffffff && ip->ip_p != IPPROTO_UDP)
-                goto bad;
-        } else {
-            uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
-            struct ex_list *ex_ptr;
-
-            if ((ip->ip_dst.s_addr & inv_mask) == inv_mask) {
-                goto bad;
-            }
-            for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
-                if (ex_ptr->ex_addr.s_addr == ip->ip_dst.s_addr)
-                    break;
-
-            if (!ex_ptr)
-                goto bad;
-        }
-    }
-
 	/* Should drop packet if mbuf too long? hmmm... */
 	if (m->m_len > ip->ip_len)
 	   m_adj(m, ip->ip_len - m->m_len);
@@ -225,7 +205,7 @@ ip_input(struct mbuf *m)
 	}
 	return;
 bad:
-	m_freem(m);
+	m_free(m);
 	return;
 }
 
@@ -318,7 +298,7 @@ ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
 			break;
 		}
 		q = q->ipf_next;
-		m_freem(dtom(slirp, q->ipf_prev));
+		m_free(dtom(slirp, q->ipf_prev));
 		ip_deq(q->ipf_prev);
 	}
 
@@ -384,7 +364,7 @@ insert:
 	return ip;
 
 dropfrag:
-	m_freem(m);
+	m_free(m);
         return NULL;
 }
 
@@ -400,7 +380,7 @@ ip_freef(Slirp *slirp, struct ipq *fp)
 	for (q = fp->frag_link.next; q != (struct ipasfrag*)&fp->frag_link; q = p) {
 		p = q->ipf_next;
 		ip_deq(q);
-		m_freem(dtom(slirp, q));
+		m_free(dtom(slirp, q));
 	}
 	remque(&fp->ip_link);
 	(void) m_free(dtom(slirp, fp));
diff --git a/slirp/ip_output.c b/slirp/ip_output.c
index 542f3180be..c82830fe7d 100644
--- a/slirp/ip_output.c
+++ b/slirp/ip_output.c
@@ -159,7 +159,7 @@ sendorfree:
 		if (error == 0)
 			if_output(so, m);
 		else
-			m_freem(m);
+			m_free(m);
 	}
     }
 
@@ -167,6 +167,6 @@ done:
 	return (error);
 
 bad:
-	m_freem(m0);
+	m_free(m0);
 	goto done;
 }
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index 97729e24b0..b74544b42b 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -33,9 +33,6 @@
 #ifndef _MBUF_H_
 #define _MBUF_H_
 
-#define m_freem m_free
-
-
 #define MINCSIZE 4096	/* Amount to increase mbuf if too small */
 
 /*
diff --git a/slirp/misc.c b/slirp/misc.c
index 08eba6adc0..6002550361 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -153,11 +153,12 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
 		return 0;
 
 	 case 0:
+                setsid();
+
 		/* Set the DISPLAY */
 		if (do_pty == 2) {
 			(void) close(master);
 #ifdef TIOCSCTTY /* XXXXX */
-			(void) setsid();
 			ioctl(s, TIOCSCTTY, (char *)NULL);
 #endif
 		} else {
@@ -406,4 +407,17 @@ void slirp_connection_info(Slirp *slirp, Monitor *mon)
                        inet_ntoa(dst_addr), ntohs(dst_port),
                        so->so_rcv.sb_cc, so->so_snd.sb_cc);
     }
+
+    for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
+        n = snprintf(buf, sizeof(buf), "  ICMP[%d sec]",
+                     (so->so_expire - curtime) / 1000);
+        src.sin_addr = so->so_laddr;
+        dst_addr = so->so_faddr;
+        memset(&buf[n], ' ', 19 - n);
+        buf[19] = 0;
+        monitor_printf(mon, "%s %3d %15s  -    ", buf, so->s,
+                       src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
+        monitor_printf(mon, "%15s  -    %5d %5d\n", inet_ntoa(dst_addr),
+                       so->so_rcv.sb_cc, so->so_snd.sb_cc);
+    }
 }
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 1593be177e..df787ea1d9 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -373,6 +373,31 @@ void slirp_select_fill(int *pnfds,
 				UPD_NFDS(so->s);
 			}
 		}
+
+                /*
+                 * ICMP sockets
+                 */
+                for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                     so = so_next) {
+                    so_next = so->so_next;
+
+                    /*
+                     * See if it's timed out
+                     */
+                    if (so->so_expire) {
+                        if (so->so_expire <= curtime) {
+                            icmp_detach(so);
+                            continue;
+                        } else {
+                            do_slowtimo = 1; /* Let socket expire */
+                        }
+                    }
+
+                    if (so->so_state & SS_ISFCONNECTED) {
+                        FD_SET(so->s, readfds);
+                        UPD_NFDS(so->s);
+                    }
+                }
 	}
 
         *pnfds = nfds;
@@ -497,7 +522,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
 	 	 	 */
 #ifdef PROBE_CONN
 			if (so->so_state & SS_ISFCONNECTING) {
-			  ret = recv(so->s, (char *)&ret, 0,0);
+                          ret = qemu_recv(so->s, &ret, 0,0);
 
 			  if (ret < 0) {
 			    /* XXX */
@@ -542,6 +567,18 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
                             sorecvfrom(so);
                         }
 		}
+
+                /*
+                 * Check incoming ICMP relies.
+                 */
+                for (so = slirp->icmp.so_next; so != &slirp->icmp;
+                     so = so_next) {
+                     so_next = so->so_next;
+
+                    if (so->s != -1 && FD_ISSET(so->s, readfds)) {
+                        icmp_receive(so);
+                    }
+                }
 	}
 
 	/*
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 954289a8c8..16bb6bae45 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -152,6 +152,7 @@ int inet_aton(const char *cp, struct in_addr *ia);
 #include "tcp_var.h"
 #include "tcpip.h"
 #include "udp.h"
+#include "ip_icmp.h"
 #include "mbuf.h"
 #include "sbuf.h"
 #include "socket.h"
@@ -218,6 +219,10 @@ struct Slirp {
     struct socket udb;
     struct socket *udp_last_so;
 
+    /* icmp states */
+    struct socket icmp;
+    struct socket *icmp_last_so;
+
     /* tftp states */
     char *tftp_prefix;
     struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
diff --git a/slirp/socket.c b/slirp/socket.c
index 611923424c..77b0c98197 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -71,6 +71,8 @@ sofree(struct socket *so)
       slirp->tcp_last_so = &slirp->tcb;
   } else if (so == slirp->udp_last_so) {
       slirp->udp_last_so = &slirp->udb;
+  } else if (so == slirp->icmp_last_so) {
+      slirp->icmp_last_so = &slirp->icmp;
   }
   m_free(so->so_m);
 
@@ -164,7 +166,7 @@ soread(struct socket *so)
 	nn = readv(so->s, (struct iovec *)iov, n);
 	DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
 #else
-	nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
+	nn = qemu_recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
 #endif
 	if (nn <= 0) {
 		if (nn < 0 && (errno == EINTR || errno == EAGAIN))
@@ -189,7 +191,7 @@ soread(struct socket *so)
 	 */
 	if (n == 2 && nn == iov[0].iov_len) {
             int ret;
-            ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
+            ret = qemu_recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
             if (ret > 0)
                 nn += ret;
         }
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index e4a77310d0..c1214c0659 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -136,7 +136,7 @@ tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
 		i = q->ti_seq + q->ti_len - ti->ti_seq;
 		if (i > 0) {
 			if (i >= ti->ti_len) {
-				m_freem(m);
+				m_free(m);
 				/*
 				 * Try to present any queued data
 				 * at the left window edge to the user.
@@ -170,7 +170,7 @@ tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
 		q = tcpiphdr_next(q);
 		m = tcpiphdr_prev(q)->ti_mbuf;
 		remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
-		m_freem(m);
+		m_free(m);
 	}
 
 	/*
@@ -197,7 +197,7 @@ present:
 		m = ti->ti_mbuf;
 		ti = tcpiphdr_next(ti);
 		if (so->so_state & SS_FCANTSENDMORE)
-			m_freem(m);
+			m_free(m);
 		else {
 			if (so->so_emu) {
 				if (tcp_emu(so,m)) sbappend(so, m);
@@ -451,7 +451,7 @@ findso:
 				acked = ti->ti_ack - tp->snd_una;
 				sbdrop(&so->so_snd, acked);
 				tp->snd_una = ti->ti_ack;
-				m_freem(m);
+				m_free(m);
 
 				/*
 				 * If all outstanding data are acked, stop
@@ -1260,7 +1260,7 @@ dropafterack:
 	 */
 	if (tiflags & TH_RST)
 		goto drop;
-	m_freem(m);
+	m_free(m);
 	tp->t_flags |= TF_ACKNOW;
 	(void) tcp_output(tp);
 	return;
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index b661d2623c..61079b1b2d 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -250,7 +250,7 @@ tcp_close(struct tcpcb *tp)
 		t = tcpiphdr_next(t);
 		m = tcpiphdr_prev(t)->ti_mbuf;
 		remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
-		m_freem(m);
+		m_free(m);
 	}
 	free(tp);
         so->so_tcpcb = NULL;
diff --git a/slirp/udp.c b/slirp/udp.c
index 02b3793e9f..5b060f397b 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -120,23 +120,26 @@ udp_input(register struct mbuf *m, int iphlen)
         /*
          *  handle DHCP/BOOTP
          */
-        if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
-            bootp_input(m);
-            goto bad;
-        }
-
-        if (slirp->restricted) {
-            goto bad;
-        }
+        if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
+            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
+             ip->ip_dst.s_addr == 0xffffffff)) {
+                bootp_input(m);
+                goto bad;
+            }
 
         /*
          *  handle TFTP
          */
-        if (ntohs(uh->uh_dport) == TFTP_SERVER) {
+        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
+            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
             tftp_input(m);
             goto bad;
         }
 
+        if (slirp->restricted) {
+            goto bad;
+        }
+
 	/*
 	 * Locate pcb for datagram.
 	 */
@@ -219,7 +222,7 @@ udp_input(register struct mbuf *m, int iphlen)
 
 	return;
 bad:
-	m_freem(m);
+	m_free(m);
 	return;
 }