diff options
Diffstat (limited to 'slirp')
| -rw-r--r-- | slirp/ip_icmp.c | 95 | ||||
| -rw-r--r-- | slirp/ip_icmp.h | 3 | ||||
| -rw-r--r-- | slirp/ip_input.c | 30 | ||||
| -rw-r--r-- | slirp/ip_output.c | 4 | ||||
| -rw-r--r-- | slirp/mbuf.h | 3 | ||||
| -rw-r--r-- | slirp/misc.c | 16 | ||||
| -rw-r--r-- | slirp/slirp.c | 39 | ||||
| -rw-r--r-- | slirp/slirp.h | 5 | ||||
| -rw-r--r-- | slirp/socket.c | 6 | ||||
| -rw-r--r-- | slirp/tcp_input.c | 10 | ||||
| -rw-r--r-- | slirp/tcp_subr.c | 2 | ||||
| -rw-r--r-- | slirp/udp.c | 23 |
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; } |