From 65f3e756b4a281b51547617519a0ec2dd28285c9 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 9 Sep 2009 21:52:01 -0700 Subject: [PATCH] IPV6 - Attempt to fix tcp46 compatibility listen sockets * When creating the accepted socket via the syncache, if the listen socket is INET6 but allows compatibility connections the inp created via sonewconn() will probably set IN6P_IPV6_V6ONLY. This flag must be cleared if the incoming connection is actually IPV4, otherwise tcp6_soport() will not properly fall through to tcp_soport(). * NOTE: Even though the connection is IPV4 the socket's protocol is copied from the listen socket which is INET6. This seems to work ok but it isn't ideal. * When connecting make sure that IPV6 connections use cpu 0 for now (we don't have a proper hash for IPV6 addresses yet). Reported-by: corecode --- sys/netinet/ip_demux.c | 6 ++++ sys/netinet/tcp_syncache.c | 1 + sys/netinet/tcp_usrreq.c | 74 +++++++++++++++++++++++++++++++++++++++++----- sys/netinet/tcp_var.h | 1 + sys/netinet6/ip6_demux.c | 9 ++++++ sys/netinet6/tcp6_var.h | 1 + 6 files changed, 85 insertions(+), 7 deletions(-) diff --git a/sys/netinet/ip_demux.c b/sys/netinet/ip_demux.c index 2350b2d644..767aa7cff0 100644 --- a/sys/netinet/ip_demux.c +++ b/sys/netinet/ip_demux.c @@ -462,6 +462,12 @@ tcp_addrport(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport) laddr, lport)].td_msgport); } +lwkt_port_t +tcp_addrport0(void) +{ + return (&tcp_thread[0].td_msgport); +} + /* * Map a UDP socket to a protocol processing thread. */ diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index a9110c3da3..129c99126a 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -669,6 +669,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) #ifdef INET6 inp->inp_vflag &= ~INP_IPV6; inp->inp_vflag |= INP_IPV4; + inp->inp_flags &= ~IN6P_IPV6_V6ONLY; #endif inp->inp_laddr = sc->sc_inc.inc_laddr; } diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 26e4dd5377..67c0d76e95 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -110,6 +110,7 @@ #include #ifdef INET6 #include +#include #endif #include #include @@ -133,10 +134,12 @@ extern char *tcpstates[]; /* XXX ??? */ static int tcp_attach (struct socket *, struct pru_attach_info *); static int tcp_connect (struct tcpcb *, struct sockaddr *, - struct thread *); + struct thread *); #ifdef INET6 static int tcp6_connect (struct tcpcb *, struct sockaddr *, - struct thread *); + struct thread *); +static int tcp6_connect_oncpu(struct tcpcb *tp, struct sockaddr_in6 *sin6, + struct in6_addr *addr6); #endif /* INET6 */ static struct tcpcb * tcp_disconnect (struct tcpcb *); @@ -1021,6 +1024,23 @@ tcp_connect_handler(netmsg_t netmsg) lwkt_replymsg(&msg->nm_netmsg.nm_lmsg, error); } +struct netmsg_tcp6_connect { + struct netmsg nm_netmsg; + struct tcpcb *nm_tp; + struct sockaddr_in6 *nm_sin6; + struct in6_addr *nm_addr6; +}; + +static void +tcp6_connect_handler(netmsg_t netmsg) +{ + struct netmsg_tcp6_connect *msg = (void *)netmsg; + int error; + + error = tcp6_connect_oncpu(msg->nm_tp, msg->nm_sin6, msg->nm_addr6); + lwkt_replymsg(&msg->nm_netmsg.nm_lmsg, error); +} + #endif /* @@ -1092,16 +1112,14 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) } #ifdef INET6 + static int tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) { - struct inpcb *inp = tp->t_inpcb, *oinp; - struct socket *so = inp->inp_socket; - struct tcpcb *otp; + struct inpcb *inp = tp->t_inpcb; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; struct in6_addr *addr6; - struct rmxp_tao *taop; - struct rmxp_tao tao_noncached; + lwkt_port_t port; int error; if (inp->inp_lport == 0) { @@ -1118,6 +1136,47 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) error = in6_pcbladdr(inp, nam, &addr6, td); if (error) return error; + +#ifdef SMP + port = tcp6_addrport(); /* XXX hack for now, always cpu0 */ + + if (port != &curthread->td_msgport) { + struct netmsg_tcp6_connect msg; + struct route *ro = &inp->inp_route; + + /* + * in_pcbladdr() may have allocated a route entry for us + * on the current CPU, but we need a route entry on the + * inpcb's owner CPU, so free it here. + */ + if (ro->ro_rt != NULL) + RTFREE(ro->ro_rt); + bzero(ro, sizeof(*ro)); + + netmsg_init(&msg.nm_netmsg, &curthread->td_msgport, 0, + tcp6_connect_handler); + msg.nm_tp = tp; + msg.nm_sin6 = sin6; + msg.nm_addr6 = addr6; + error = lwkt_domsg(port, &msg.nm_netmsg.nm_lmsg, 0); + } else +#endif + error = tcp6_connect_oncpu(tp, sin6, addr6); + + return (error); +} + +static int +tcp6_connect_oncpu(struct tcpcb *tp, struct sockaddr_in6 *sin6, + struct in6_addr *addr6) +{ + struct inpcb *inp = tp->t_inpcb; + struct socket *so = inp->inp_socket; + struct inpcb *oinp; + struct tcpcb *otp; + struct rmxp_tao *taop; + struct rmxp_tao tao_noncached; + oinp = in6_pcblookup_hash(inp->inp_cpcbinfo, &sin6->sin6_addr, sin6->sin6_port, IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ? @@ -1178,6 +1237,7 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) return (0); } + #endif /* INET6 */ /* diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index a9c8ae0a1d..fcccef678a 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -584,6 +584,7 @@ int tcp_addrcpu(in_addr_t faddr, in_port_t fport, struct lwkt_port * tcp_addrport(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport); +struct lwkt_port *tcp_addrport0(void); void tcp_canceltimers (struct tcpcb *); struct tcpcb * tcp_close (struct tcpcb *); diff --git a/sys/netinet6/ip6_demux.c b/sys/netinet6/ip6_demux.c index ba64822070..9e52fdb345 100644 --- a/sys/netinet6/ip6_demux.c +++ b/sys/netinet6/ip6_demux.c @@ -62,3 +62,12 @@ tcp6_soport(struct socket *so, struct sockaddr *nam, struct mbuf **m0, int req) /* IPv4 mapped, fall back to IPv4 tcp_soport */ return tcp_soport(so, nam, m0, req); } + +/* + * XXX hack + */ +lwkt_port_t +tcp6_addrport(void) +{ + return(tcp_addrport0()); +} diff --git a/sys/netinet6/tcp6_var.h b/sys/netinet6/tcp6_var.h index 92b218d3f4..f97685acde 100644 --- a/sys/netinet6/tcp6_var.h +++ b/sys/netinet6/tcp6_var.h @@ -89,6 +89,7 @@ struct rtentry *tcp_rtlookup6(struct in_conninfo *); struct lwkt_port *tcp6_soport(struct socket *, struct sockaddr *, struct mbuf **, int); +struct lwkt_port *tcp6_addrport(void); extern struct pr_usrreqs tcp6_usrreqs; -- 2.11.4.GIT