IPV6 - Attempt to fix tcp46 compatibility listen sockets
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 10 Sep 2009 04:52:01 +0000 (21:52 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 10 Sep 2009 04:52:01 +0000 (21:52 -0700)
* 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
sys/netinet/tcp_syncache.c
sys/netinet/tcp_usrreq.c
sys/netinet/tcp_var.h
sys/netinet6/ip6_demux.c
sys/netinet6/tcp6_var.h

index 2350b2d..767aa7c 100644 (file)
@@ -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.
  */
index a9110c3..129c991 100644 (file)
@@ -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;
        }
index 26e4dd5..67c0d76 100644 (file)
 #include <netinet/ip_var.h>
 #ifdef INET6
 #include <netinet6/ip6_var.h>
+#include <netinet6/tcp6_var.h>
 #endif
 #include <netinet/tcp.h>
 #include <netinet/tcp_fsm.h>
@@ -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 */
 
 /*
index a9c8ae0..fcccef6 100644 (file)
@@ -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 *);
index ba64822..9e52fdb 100644 (file)
@@ -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());
+}
index 92b218d..f97685a 100644 (file)
@@ -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;