diff options
Diffstat (limited to 'slirp')
| -rw-r--r-- | slirp/bootp.c | 2 | ||||
| -rw-r--r-- | slirp/ip_icmp.c | 23 | ||||
| -rw-r--r-- | slirp/mbuf.c | 2 | ||||
| -rw-r--r-- | slirp/mbuf.h | 2 | ||||
| -rw-r--r-- | slirp/slirp.c | 116 | ||||
| -rw-r--r-- | slirp/slirp.h | 2 | ||||
| -rw-r--r-- | slirp/socket.c | 158 | ||||
| -rw-r--r-- | slirp/socket.h | 51 | ||||
| -rw-r--r-- | slirp/tcp_input.c | 30 | ||||
| -rw-r--r-- | slirp/tcp_subr.c | 40 | ||||
| -rw-r--r-- | slirp/tftp.c | 6 | ||||
| -rw-r--r-- | slirp/udp.c | 74 | ||||
| -rw-r--r-- | slirp/udp.h | 5 |
13 files changed, 318 insertions, 193 deletions
diff --git a/slirp/bootp.c b/slirp/bootp.c index 1baaab1ab1..00272793e0 100644 --- a/slirp/bootp.c +++ b/slirp/bootp.c @@ -325,7 +325,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr); - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); } void bootp_input(struct mbuf *m) diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 23b9f0fa45..592f33a827 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -157,12 +157,12 @@ icmp_input(struct mbuf *m, int hlen) goto freeit; } else { struct socket *so; - struct sockaddr_in addr; + struct sockaddr_storage addr; if ((so = socreate(slirp)) == NULL) goto freeit; if (icmp_send(so, m, hlen) == 0) { return; } - if(udp_attach(so) == -1) { + if (udp_attach(so, AF_INET) == -1) { DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", errno,strerror(errno))); sofree(so); @@ -170,8 +170,10 @@ icmp_input(struct mbuf *m, int hlen) goto end_error; } so->so_m = m; + so->so_ffamily = AF_INET; so->so_faddr = ip->ip_dst; so->so_fport = htons(7); + so->so_lfamily = AF_INET; so->so_laddr = ip->ip_src; so->so_lport = htons(9); so->so_iptos = ip->ip_tos; @@ -179,20 +181,9 @@ icmp_input(struct mbuf *m, int hlen) so->so_state = SS_ISFCONNECTED; /* Send the packet */ - addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == - slirp->vnetwork_addr.s_addr) { - /* It's an alias */ - if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - if (get_dns_addr(&addr.sin_addr) < 0) - addr.sin_addr = loopback_addr; - } else { - addr.sin_addr = loopback_addr; - } - } else { - addr.sin_addr = so->so_faddr; - } - addr.sin_port = so->so_fport; + addr = so->fhost.ss; + sotranslate_out(so, &addr); + if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, (struct sockaddr *)&addr, sizeof(addr)) == -1) { DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", diff --git a/slirp/mbuf.c b/slirp/mbuf.c index 795fc29f98..bc942b63e4 100644 --- a/slirp/mbuf.c +++ b/slirp/mbuf.c @@ -91,7 +91,7 @@ m_get(Slirp *slirp) m->m_len = 0; m->m_nextpkt = NULL; m->m_prevpkt = NULL; - m->arp_requested = false; + m->resolution_requested = false; m->expiration_date = (uint64_t)-1; end_error: DEBUG_ARG("m = %p", m); diff --git a/slirp/mbuf.h b/slirp/mbuf.h index b144f1ce3a..38fedf46de 100644 --- a/slirp/mbuf.h +++ b/slirp/mbuf.h @@ -79,7 +79,7 @@ struct mbuf { int m_len; /* Amount of data in this mbuf */ Slirp *slirp; - bool arp_requested; + bool resolution_requested; uint64_t expiration_date; /* start of dynamic buffer area, must be last element */ union { diff --git a/slirp/slirp.c b/slirp/slirp.c index 35f819afb7..b900775eff 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -23,6 +23,7 @@ */ #include "qemu-common.h" #include "qemu/timer.h" +#include "qemu/error-report.h" #include "sysemu/char.h" #include "slirp.h" #include "hw/hw.h" @@ -234,7 +235,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, slirp->opaque = opaque; - register_savevm(NULL, "slirp", 0, 3, + register_savevm(NULL, "slirp", 0, 4, slirp_state_save, slirp_state_load, slirp); QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry); @@ -762,20 +763,15 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) } } -/* Output the IP packet to the ethernet device. Returns 0 if the packet must be - * re-queued. +/* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no + * packet should be sent, 0 if the packet must be re-queued, 2 if the packet + * is ready to go. */ -int if_encap(Slirp *slirp, struct mbuf *ifm) +static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, + uint8_t ethaddr[ETH_ALEN]) { - uint8_t buf[1600]; - struct ethhdr *eh = (struct ethhdr *)buf; - uint8_t ethaddr[ETH_ALEN]; const struct ip *iph = (const struct ip *)ifm->m_data; - if (ifm->m_len + ETH_HLEN > sizeof(buf)) { - return 1; - } - if (iph->ip_dst.s_addr == 0) { /* 0.0.0.0 can not be a destination address, something went wrong, * avoid making it worse */ @@ -786,7 +782,7 @@ int if_encap(Slirp *slirp, struct mbuf *ifm) struct ethhdr *reh = (struct ethhdr *)arp_req; struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN); - if (!ifm->arp_requested) { + if (!ifm->resolution_requested) { /* If the client addr is not known, send an ARP request */ memset(reh->h_dest, 0xff, ETH_ALEN); memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); @@ -812,22 +808,62 @@ int if_encap(Slirp *slirp, struct mbuf *ifm) rah->ar_tip = iph->ip_dst.s_addr; slirp->client_ipaddr = iph->ip_dst; slirp_output(slirp->opaque, arp_req, sizeof(arp_req)); - ifm->arp_requested = true; + ifm->resolution_requested = true; /* Expire request and drop outgoing packet after 1 second */ ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL; } return 0; } else { - memcpy(eh->h_dest, ethaddr, ETH_ALEN); memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4); /* XXX: not correct */ memcpy(&eh->h_source[2], &slirp->vhost_addr, 4); eh->h_proto = htons(ETH_P_IP); - memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len); - slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN); + + /* Send this */ + return 2; + } +} + +/* Output the IP packet to the ethernet device. Returns 0 if the packet must be + * re-queued. + */ +int if_encap(Slirp *slirp, struct mbuf *ifm) +{ + uint8_t buf[1600]; + struct ethhdr *eh = (struct ethhdr *)buf; + uint8_t ethaddr[ETH_ALEN]; + const struct ip *iph = (const struct ip *)ifm->m_data; + int ret; + + if (ifm->m_len + ETH_HLEN > sizeof(buf)) { return 1; } + + switch (iph->ip_v) { + case IPVERSION: + ret = if_encap4(slirp, ifm, eh, ethaddr); + if (ret < 2) { + return ret; + } + break; + + default: + /* Do not assert while we don't manage IP6VERSION */ + /* assert(0); */ + break; + } + + memcpy(eh->h_dest, ethaddr, ETH_ALEN); + DEBUG_ARGS((dfd, " src = %02x:%02x:%02x:%02x:%02x:%02x\n", + eh->h_source[0], eh->h_source[1], eh->h_source[2], + eh->h_source[3], eh->h_source[4], eh->h_source[5])); + DEBUG_ARGS((dfd, " dst = %02x:%02x:%02x:%02x:%02x:%02x\n", + eh->h_dest[0], eh->h_dest[1], eh->h_dest[2], + eh->h_dest[3], eh->h_dest[4], eh->h_dest[5])); + memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len); + slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN); + return 1; } /* Drop host forwarding rule, return 0 if found. */ @@ -1011,10 +1047,26 @@ static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf) static void slirp_socket_save(QEMUFile *f, struct socket *so) { qemu_put_be32(f, so->so_urgc); - qemu_put_be32(f, so->so_faddr.s_addr); - qemu_put_be32(f, so->so_laddr.s_addr); - qemu_put_be16(f, so->so_fport); - qemu_put_be16(f, so->so_lport); + qemu_put_be16(f, so->so_ffamily); + switch (so->so_ffamily) { + case AF_INET: + qemu_put_be32(f, so->so_faddr.s_addr); + qemu_put_be16(f, so->so_fport); + break; + default: + error_report( + "so_ffamily unknown, unable to save so_faddr and so_fport\n"); + } + qemu_put_be16(f, so->so_lfamily); + switch (so->so_lfamily) { + case AF_INET: + qemu_put_be32(f, so->so_laddr.s_addr); + qemu_put_be16(f, so->so_lport); + break; + default: + error_report( + "so_ffamily unknown, unable to save so_laddr and so_lport\n"); + } qemu_put_byte(f, so->so_iptos); qemu_put_byte(f, so->so_emu); qemu_put_byte(f, so->so_type); @@ -1134,10 +1186,26 @@ static int slirp_socket_load(QEMUFile *f, struct socket *so) return -ENOMEM; so->so_urgc = qemu_get_be32(f); - so->so_faddr.s_addr = qemu_get_be32(f); - so->so_laddr.s_addr = qemu_get_be32(f); - so->so_fport = qemu_get_be16(f); - so->so_lport = qemu_get_be16(f); + so->so_ffamily = qemu_get_be16(f); + switch (so->so_ffamily) { + case AF_INET: + so->so_faddr.s_addr = qemu_get_be32(f); + so->so_fport = qemu_get_be16(f); + break; + default: + error_report( + "so_ffamily unknown, unable to restore so_faddr and so_lport\n"); + } + so->so_lfamily = qemu_get_be16(f); + switch (so->so_lfamily) { + case AF_INET: + so->so_laddr.s_addr = qemu_get_be32(f); + so->so_lport = qemu_get_be16(f); + break; + default: + error_report( + "so_ffamily unknown, unable to restore so_laddr and so_lport\n"); + } so->so_iptos = qemu_get_byte(f); so->so_emu = qemu_get_byte(f); so->so_type = qemu_get_byte(f); diff --git a/slirp/slirp.h b/slirp/slirp.h index ec0a4c2415..239fe2917a 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -327,7 +327,7 @@ void tcp_respond(struct tcpcb *, register struct tcpiphdr *, register struct mbu struct tcpcb * tcp_newtcpcb(struct socket *); struct tcpcb * tcp_close(register struct tcpcb *); void tcp_sockclosed(struct tcpcb *); -int tcp_fconnect(struct socket *); +int tcp_fconnect(struct socket *, unsigned short af); void tcp_connect(struct socket *); int tcp_attach(struct socket *); uint8_t tcp_tos(struct socket *); diff --git a/slirp/socket.c b/slirp/socket.c index 1673e3afce..f7e596859f 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -15,24 +15,26 @@ static void sofcantrcvmore(struct socket *so); static void sofcantsendmore(struct socket *so); -struct socket * -solookup(struct socket *head, struct in_addr laddr, u_int lport, - struct in_addr faddr, u_int fport) +struct socket *solookup(struct socket **last, struct socket *head, + struct sockaddr_storage *lhost, struct sockaddr_storage *fhost) { - struct socket *so; - - for (so = head->so_next; so != head; so = so->so_next) { - if (so->so_lport == lport && - so->so_laddr.s_addr == laddr.s_addr && - so->so_faddr.s_addr == faddr.s_addr && - so->so_fport == fport) - break; - } - - if (so == head) - return (struct socket *)NULL; - return so; + struct socket *so = *last; + + /* Optimisation */ + if (so != head && sockaddr_equal(&(so->lhost.ss), lhost) + && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) { + return so; + } + + for (so = head->so_next; so != head; so = so->so_next) { + if (sockaddr_equal(&(so->lhost.ss), lhost) + && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) { + *last = so; + return so; + } + } + return (struct socket *)NULL; } /* @@ -437,8 +439,9 @@ sowrite(struct socket *so) void sorecvfrom(struct socket *so) { - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); + struct sockaddr_storage addr; + struct sockaddr_storage saddr, daddr; + socklen_t addrlen = sizeof(struct sockaddr_storage); DEBUG_CALL("sorecvfrom"); DEBUG_ARG("so = %p", so); @@ -525,9 +528,21 @@ sorecvfrom(struct socket *so) /* * If this packet was destined for CTL_ADDR, - * make it look like that's where it came from, done by udp_output + * make it look like that's where it came from */ - udp_output(so, m, &addr); + saddr = addr; + sotranslate_in(so, &saddr); + daddr = so->lhost.ss; + + switch (so->so_ffamily) { + case AF_INET: + udp_output(so, m, (struct sockaddr_in *) &saddr, + (struct sockaddr_in *) &daddr, + so->so_iptos); + break; + default: + break; + } } /* rx error */ } /* if ping packet */ } @@ -538,33 +553,20 @@ sorecvfrom(struct socket *so) int sosendto(struct socket *so, struct mbuf *m) { - Slirp *slirp = so->slirp; int ret; - struct sockaddr_in addr; + struct sockaddr_storage addr; DEBUG_CALL("sosendto"); DEBUG_ARG("so = %p", so); DEBUG_ARG("m = %p", m); - addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == - slirp->vnetwork_addr.s_addr) { - /* It's an alias */ - if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - if (get_dns_addr(&addr.sin_addr) < 0) - addr.sin_addr = loopback_addr; - } else { - addr.sin_addr = loopback_addr; - } - } else - addr.sin_addr = so->so_faddr; - addr.sin_port = so->so_fport; - - DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); + addr = so->fhost.ss; + DEBUG_CALL(" sendto()ing)"); + sotranslate_out(so, &addr); /* Don't care what port we get */ ret = sendto(so->s, m->m_data, m->m_len, 0, - (struct sockaddr *)&addr, sizeof (struct sockaddr)); + (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) return -1; @@ -619,6 +621,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, so->so_state &= SS_PERSISTENT_MASK; so->so_state |= (SS_FACCEPTCONN | flags); + so->so_lfamily = AF_INET; so->so_lport = lport; /* Kept in network format */ so->so_laddr.s_addr = laddr; /* Ditto */ @@ -645,6 +648,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); getsockname(s,(struct sockaddr *)&addr,&addrlen); + so->so_ffamily = AF_INET; so->so_fport = addr.sin_port; if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) so->so_faddr = slirp->vhost_addr; @@ -718,3 +722,81 @@ sofwdrain(struct socket *so) else sofcantsendmore(so); } + +/* + * Translate addr in host addr when it is a virtual address + */ +void sotranslate_out(struct socket *so, struct sockaddr_storage *addr) +{ + Slirp *slirp = so->slirp; + struct sockaddr_in *sin = (struct sockaddr_in *)addr; + + switch (addr->ss_family) { + case AF_INET: + if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == + slirp->vnetwork_addr.s_addr) { + /* It's an alias */ + if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { + if (get_dns_addr(&sin->sin_addr) < 0) { + sin->sin_addr = loopback_addr; + } + } else { + sin->sin_addr = loopback_addr; + } + } + + DEBUG_MISC((dfd, " addr.sin_port=%d, " + "addr.sin_addr.s_addr=%.16s\n", + ntohs(sin->sin_port), inet_ntoa(sin->sin_addr))); + break; + + default: + break; + } +} + +void sotranslate_in(struct socket *so, struct sockaddr_storage *addr) +{ + Slirp *slirp = so->slirp; + struct sockaddr_in *sin = (struct sockaddr_in *)addr; + + switch (addr->ss_family) { + case AF_INET: + if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == + slirp->vnetwork_addr.s_addr) { + uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr; + + if ((so->so_faddr.s_addr & inv_mask) == inv_mask) { + sin->sin_addr = slirp->vhost_addr; + } else if (sin->sin_addr.s_addr == loopback_addr.s_addr || + so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { + sin->sin_addr = so->so_faddr; + } + } + break; + + default: + break; + } +} + +/* + * Translate connections from localhost to the real hostname + */ +void sotranslate_accept(struct socket *so) +{ + Slirp *slirp = so->slirp; + + switch (so->so_ffamily) { + case AF_INET: + if (so->so_faddr.s_addr == INADDR_ANY || + (so->so_faddr.s_addr & loopback_mask) == + (loopback_addr.s_addr & loopback_mask)) { + so->so_faddr = slirp->vhost_addr; + } + break; + + default: + break; + } +} diff --git a/slirp/socket.h b/slirp/socket.h index 57e0407ebc..c4afc9494f 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -31,10 +31,21 @@ struct socket { struct tcpiphdr *so_ti; /* Pointer to the original ti within * so_mconn, for non-blocking connections */ int so_urgc; - struct in_addr so_faddr; /* foreign host table entry */ - struct in_addr so_laddr; /* local host table entry */ - uint16_t so_fport; /* foreign port */ - uint16_t so_lport; /* local port */ + union { /* foreign host */ + struct sockaddr_storage ss; + struct sockaddr_in sin; + } fhost; +#define so_faddr fhost.sin.sin_addr +#define so_fport fhost.sin.sin_port +#define so_ffamily fhost.ss.ss_family + + union { /* local host */ + struct sockaddr_storage ss; + struct sockaddr_in sin; + } lhost; +#define so_laddr lhost.sin.sin_addr +#define so_lport lhost.sin.sin_port +#define so_lfamily lhost.ss.ss_family uint8_t so_iptos; /* Type of service */ uint8_t so_emu; /* Is the socket emulated? */ @@ -76,8 +87,31 @@ struct socket { #define SS_HOSTFWD 0x1000 /* Socket describes host->guest forwarding */ #define SS_INCOMING 0x2000 /* Connection was initiated by a host on the internet */ -struct socket * solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int); -struct socket * socreate(Slirp *); +static inline int sockaddr_equal(struct sockaddr_storage *a, + struct sockaddr_storage *b) +{ + if (a->ss_family != b->ss_family) { + return 0; + } + + switch (a->ss_family) { + case AF_INET: + { + struct sockaddr_in *a4 = (struct sockaddr_in *) a; + struct sockaddr_in *b4 = (struct sockaddr_in *) b; + return a4->sin_addr.s_addr == b4->sin_addr.s_addr + && a4->sin_port == b4->sin_port; + } + default: + g_assert_not_reached(); + } + + return 0; +} + +struct socket *solookup(struct socket **, struct socket *, + struct sockaddr_storage *, struct sockaddr_storage *); +struct socket *socreate(Slirp *); void sofree(struct socket *); int soread(struct socket *); void sorecvoob(struct socket *); @@ -94,4 +128,9 @@ struct iovec; /* For win32 */ size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np); int soreadbuf(struct socket *so, const char *buf, int size); +void sotranslate_out(struct socket *, struct sockaddr_storage *); +void sotranslate_in(struct socket *, struct sockaddr_storage *); +void sotranslate_accept(struct socket *); + + #endif /* _SOCKET_H_ */ diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 6b096ecb3c..f24e7060a4 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -227,6 +227,8 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso) int iss = 0; u_long tiwin; int ret; + struct sockaddr_storage lhost, fhost; + struct sockaddr_in *lhost4, *fhost4; struct ex_list *ex_ptr; Slirp *slirp; @@ -320,16 +322,16 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso) * Locate pcb for segment. */ findso: - so = slirp->tcp_last_so; - if (so->so_fport != ti->ti_dport || - so->so_lport != ti->ti_sport || - so->so_laddr.s_addr != ti->ti_src.s_addr || - so->so_faddr.s_addr != ti->ti_dst.s_addr) { - so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport); - if (so) - slirp->tcp_last_so = so; - } + lhost.ss_family = AF_INET; + lhost4 = (struct sockaddr_in *) &lhost; + lhost4->sin_addr = ti->ti_src; + lhost4->sin_port = ti->ti_sport; + fhost.ss_family = AF_INET; + fhost4 = (struct sockaddr_in *) &fhost; + fhost4->sin_addr = ti->ti_dst; + fhost4->sin_port = ti->ti_dport; + + so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost); /* * If the state is CLOSED (i.e., TCB does not exist) then @@ -374,10 +376,8 @@ findso: sbreserve(&so->so_snd, TCP_SNDSPACE); sbreserve(&so->so_rcv, TCP_RCVSPACE); - so->so_laddr = ti->ti_src; - so->so_lport = ti->ti_sport; - so->so_faddr = ti->ti_dst; - so->so_fport = ti->ti_dport; + so->lhost.ss = lhost; + so->fhost.ss = fhost; if ((so->so_iptos = tcp_tos(so)) == 0) so->so_iptos = ((struct ip *)ti)->ip_tos; @@ -584,7 +584,7 @@ findso: goto cont_input; } - if ((tcp_fconnect(so) == -1) && + if ((tcp_fconnect(so, so->so_ffamily) == -1) && #if defined(_WIN32) socket_error() != WSAEWOULDBLOCK #else diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index e161ed2a96..36e325618d 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -324,40 +324,27 @@ tcp_sockclosed(struct tcpcb *tp) * nonblocking. Connect returns after the SYN is sent, and does * not wait for ACK+SYN. */ -int tcp_fconnect(struct socket *so) +int tcp_fconnect(struct socket *so, unsigned short af) { - Slirp *slirp = so->slirp; int ret=0; DEBUG_CALL("tcp_fconnect"); DEBUG_ARG("so = %p", so); - if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) { + ret = so->s = qemu_socket(af, SOCK_STREAM, 0); + if (ret >= 0) { int opt, s=so->s; - struct sockaddr_in addr; + struct sockaddr_storage addr; qemu_set_nonblock(s); socket_set_fast_reuse(s); opt = 1; qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt)); - addr.sin_family = AF_INET; - if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == - slirp->vnetwork_addr.s_addr) { - /* It's an alias */ - if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - if (get_dns_addr(&addr.sin_addr) < 0) - addr.sin_addr = loopback_addr; - } else { - addr.sin_addr = loopback_addr; - } - } else - addr.sin_addr = so->so_faddr; - addr.sin_port = so->so_fport; - - DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " - "addr.sin_addr.s_addr=%.16s\n", - ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); + addr = so->fhost.ss; + DEBUG_CALL(" connect()ing") + sotranslate_out(so, &addr); + /* We don't care what port we get */ ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); @@ -413,6 +400,7 @@ void tcp_connect(struct socket *inso) free(so); /* NOT sofree */ return; } + so->so_lfamily = AF_INET; so->so_laddr = inso->so_laddr; so->so_lport = inso->so_lport; } @@ -430,14 +418,8 @@ void tcp_connect(struct socket *inso) qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); socket_set_nodelay(s); - so->so_fport = addr.sin_port; - so->so_faddr = addr.sin_addr; - /* Translate connections from localhost to the real hostname */ - if (so->so_faddr.s_addr == 0 || - (so->so_faddr.s_addr & loopback_mask) == - (loopback_addr.s_addr & loopback_mask)) { - so->so_faddr = slirp->vhost_addr; - } + so->fhost.sin = addr; + sotranslate_accept(so); /* Close the accept() socket, set right state */ if (inso->so_state & SS_FACCEPTONCE) { diff --git a/slirp/tftp.c b/slirp/tftp.c index a329fb281b..ccb613014a 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -155,7 +155,7 @@ static int tftp_send_oack(struct tftp_session *spt, m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct ip) - sizeof(struct udphdr); - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); return 0; } @@ -193,7 +193,7 @@ static void tftp_send_error(struct tftp_session *spt, m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - sizeof(struct ip) - sizeof(struct udphdr); - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); out: tftp_session_terminate(spt); @@ -243,7 +243,7 @@ static void tftp_send_next_block(struct tftp_session *spt, m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct ip) - sizeof(struct udphdr); - udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); if (nobytes == 512) { tftp_session_update(spt); diff --git a/slirp/udp.c b/slirp/udp.c index fee13b4dbd..92c48c491e 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -70,6 +70,8 @@ udp_input(register struct mbuf *m, int iphlen) int len; struct ip save_ip; struct socket *so; + struct sockaddr_storage lhost; + struct sockaddr_in *lhost4; DEBUG_CALL("udp_input"); DEBUG_ARG("m = %p", m); @@ -151,25 +153,12 @@ udp_input(register struct mbuf *m, int iphlen) /* * Locate pcb for datagram. */ - so = slirp->udp_last_so; - if (so == &slirp->udb || so->so_lport != uh->uh_sport || - so->so_laddr.s_addr != ip->ip_src.s_addr) { - struct socket *tmp; - - for (tmp = slirp->udb.so_next; tmp != &slirp->udb; - tmp = tmp->so_next) { - if (tmp->so_lport == uh->uh_sport && - tmp->so_laddr.s_addr == ip->ip_src.s_addr) { - so = tmp; - break; - } - } - if (tmp == &slirp->udb) { - so = NULL; - } else { - slirp->udp_last_so = so; - } - } + lhost.ss_family = AF_INET; + lhost4 = (struct sockaddr_in *) &lhost; + lhost4->sin_addr = ip->ip_src; + lhost4->sin_port = uh->uh_sport; + + so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL); if (so == NULL) { /* @@ -180,7 +169,7 @@ udp_input(register struct mbuf *m, int iphlen) if (!so) { goto bad; } - if(udp_attach(so) == -1) { + if (udp_attach(so, AF_INET) == -1) { DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", errno,strerror(errno))); sofree(so); @@ -190,6 +179,7 @@ udp_input(register struct mbuf *m, int iphlen) /* * Setup fields */ + so->so_lfamily = AF_INET; so->so_laddr = ip->ip_src; so->so_lport = uh->uh_sport; @@ -202,6 +192,7 @@ udp_input(register struct mbuf *m, int iphlen) */ } + so->so_ffamily = AF_INET; so->so_faddr = ip->ip_dst; /* XXX */ so->so_fport = uh->uh_dport; /* XXX */ @@ -218,6 +209,7 @@ udp_input(register struct mbuf *m, int iphlen) *ip=save_ip; DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + goto bad; } m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ @@ -233,7 +225,7 @@ bad: m_free(m); } -int udp_output2(struct socket *so, struct mbuf *m, +int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, struct sockaddr_in *daddr, int iptos) { @@ -284,35 +276,11 @@ int udp_output2(struct socket *so, struct mbuf *m, return (error); } -int udp_output(struct socket *so, struct mbuf *m, - struct sockaddr_in *addr) - -{ - Slirp *slirp = so->slirp; - struct sockaddr_in saddr, daddr; - - saddr = *addr; - if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == - slirp->vnetwork_addr.s_addr) { - uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr; - - if ((so->so_faddr.s_addr & inv_mask) == inv_mask) { - saddr.sin_addr = slirp->vhost_addr; - } else if (addr->sin_addr.s_addr == loopback_addr.s_addr || - so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { - saddr.sin_addr = so->so_faddr; - } - } - daddr.sin_addr = so->so_laddr; - daddr.sin_port = so->so_lport; - - return udp_output2(so, m, &saddr, &daddr, so->so_iptos); -} - int -udp_attach(struct socket *so) +udp_attach(struct socket *so, unsigned short af) { - if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) { + so->s = qemu_socket(af, SOCK_DGRAM, 0); + if (so->s != -1) { so->so_expire = curtime + SO_EXPIRE; insque(so, &so->slirp->udb); } @@ -375,13 +343,9 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr, socket_set_fast_reuse(so->s); getsockname(so->s,(struct sockaddr *)&addr,&addrlen); - so->so_fport = addr.sin_port; - if (addr.sin_addr.s_addr == 0 || - addr.sin_addr.s_addr == loopback_addr.s_addr) { - so->so_faddr = slirp->vhost_addr; - } else { - so->so_faddr = addr.sin_addr; - } + so->fhost.sin = addr; + sotranslate_accept(so); + so->so_lfamily = AF_INET; so->so_lport = lport; so->so_laddr.s_addr = laddr; if (flags != SS_FACCEPTONCE) diff --git a/slirp/udp.h b/slirp/udp.h index 9bf31fe7be..2f9de3886c 100644 --- a/slirp/udp.h +++ b/slirp/udp.h @@ -76,12 +76,11 @@ struct mbuf; void udp_init(Slirp *); void udp_cleanup(Slirp *); void udp_input(register struct mbuf *, int); -int udp_output(struct socket *, struct mbuf *, struct sockaddr_in *); -int udp_attach(struct socket *); +int udp_attach(struct socket *, unsigned short af); void udp_detach(struct socket *); struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int, int); -int udp_output2(struct socket *so, struct mbuf *m, +int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, struct sockaddr_in *daddr, int iptos); #endif |