On 06/06/16(Mon) 16:40, Martin Pieuchot wrote:
> Various functions in our ND implementation look at the type of the
> sending interface to decide what they should do.  Recently sthen@
> found a regression on his p2p link because nd6_output() was doing
> a check that only makes sense for Ethernet interfaces.
> 
> So instead of "skipping" p2p interface in nd6_output() let's move
> the ND resolution code to ether_output().
> 
> Diff below does that by introducing nd6_resolve() which has the
> same semantic as arpresolve().
> 
> I'll properly kill nd6_output() in another diff.

Here's the complete diff as pointed out by mikeb@ and sthen@

Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.237
diff -u -p -r1.237 if_ethersubr.c
--- net/if_ethersubr.c  31 May 2016 07:48:19 -0000      1.237
+++ net/if_ethersubr.c  6 Jun 2016 14:20:22 -0000
@@ -225,9 +225,9 @@ ether_output(struct ifnet *ifp, struct m
                break;
 #ifdef INET6
        case AF_INET6:
-               error = nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst);
+               error = nd6_resolve(ifp, rt, m, dst, edst);
                if (error)
-                       return (error);
+                       return (error == EAGAIN ? 0 : error);
                etype = htons(ETHERTYPE_IPV6);
                break;
 #endif
Index: netinet6/nd6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.184
diff -u -p -r1.184 nd6.c
--- netinet6/nd6.c      6 Jun 2016 10:16:23 -0000       1.184
+++ netinet6/nd6.c      6 Jun 2016 14:26:00 -0000
@@ -1492,16 +1492,22 @@ int
 nd6_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr_in6 *dst,
     struct rtentry *rt0)
 {
-       struct mbuf *m = m0;
-       struct rtentry *rt = rt0;
-       struct llinfo_nd6 *ln = NULL;
-       int error = 0;
+       return (ifp->if_output(ifp, m0, sin6tosa(dst), rt0));
+}
 
-       if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
-               goto sendpkt;
+int
+nd6_resolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
+    struct sockaddr *dst, u_char *desten)
+{
+       struct sockaddr_dl *sdl;
+       struct rtentry *rt;
+       struct llinfo_nd6 *ln = NULL;
+       int error;
 
-       if (nd6_need_cache(ifp) == 0)
-               goto sendpkt;
+       if (m->m_flags & M_MCAST) {
+               ETHER_MAP_IPV6_MULTICAST(&satosin6(dst)->sin6_addr, desten);
+               return (0);
+       }
 
        error = rt_checkgate(rt0, &rt);
        if (error) {
@@ -1524,6 +1530,12 @@ nd6_output(struct ifnet *ifp, struct mbu
                return (EINVAL);
        }
 
+       if (rt->rt_gateway->sa_family != AF_LINK) {
+               printf("%s: something odd happens\n", __func__);
+               m_freem(m);
+               return (EINVAL);
+       }
+
        ln = (struct llinfo_nd6 *)rt->rt_llinfo;
        KASSERT(ln != NULL);
 
@@ -1553,8 +1565,21 @@ nd6_output(struct ifnet *ifp, struct mbu
         * (i.e. its link-layer address is already resolved), just
         * send the packet.
         */
-       if (ln->ln_state > ND6_LLINFO_INCOMPLETE)
-               goto sendpkt;
+       if (ln->ln_state > ND6_LLINFO_INCOMPLETE) {
+               sdl = satosdl(rt->rt_gateway);
+               if (sdl->sdl_alen != ETHER_ADDR_LEN) {
+                       char addr[INET6_ADDRSTRLEN];
+                       log(LOG_DEBUG, "%s: %s: incorrect nd6 information\n",
+                           __func__,
+                           inet_ntop(AF_INET6, &satosin6(dst)->sin6_addr,
+                               addr, sizeof(addr)));
+                       m_freem(m);
+                       return (EINVAL);
+               }
+
+               bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
+               return (0);
+       }
 
        /*
         * There is a neighbor cache entry, but no ethernet address
@@ -1565,6 +1590,7 @@ nd6_output(struct ifnet *ifp, struct mbu
                ln->ln_state = ND6_LLINFO_INCOMPLETE;
        m_freem(ln->ln_hold);
        ln->ln_hold = m;
+
        /*
         * If there has been no NS for the neighbor after entering the
         * INCOMPLETE state, send the first solicitation.
@@ -1572,13 +1598,9 @@ nd6_output(struct ifnet *ifp, struct mbu
        if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) {
                ln->ln_asked++;
                nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans / 1000);
-               nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
+               nd6_ns_output(ifp, NULL, &satosin6(dst)->sin6_addr, ln, 0);
        }
-       return (0);
-
-  sendpkt:
-       error = ifp->if_output(ifp, m, sin6tosa(dst), rt);
-       return (error);
+       return (EAGAIN);
 }
 
 int
@@ -1596,53 +1618,6 @@ nd6_need_cache(struct ifnet *ifp)
        default:
                return (0);
        }
-}
-
-int
-nd6_storelladdr(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
-    struct sockaddr *dst, u_char *desten)
-{
-       struct sockaddr_dl *sdl;
-       struct rtentry *rt;
-       int error;
-
-       if (m->m_flags & M_MCAST) {
-               switch (ifp->if_type) {
-               case IFT_ETHER:
-               case IFT_CARP:
-                       ETHER_MAP_IPV6_MULTICAST(&satosin6(dst)->sin6_addr,
-                                                desten);
-                       return (0);
-                       break;
-               default:
-                       m_freem(m);
-                       return (EINVAL);
-               }
-       }
-
-       error = rt_checkgate(rt0, &rt);
-       if (error) {
-               m_freem(m);
-               return (error);
-       }
-
-       if (rt->rt_gateway->sa_family != AF_LINK) {
-               printf("%s: something odd happens\n", __func__);
-               m_freem(m);
-               return (EINVAL);
-       }
-       sdl = satosdl(rt->rt_gateway);
-       if (sdl->sdl_alen != ETHER_ADDR_LEN) {
-               char addr[INET6_ADDRSTRLEN];
-               log(LOG_DEBUG, "%s: %s: incorrect nd6 information\n", __func__,
-                   inet_ntop(AF_INET6, &satosin6(dst)->sin6_addr,
-                       addr, sizeof(addr)));
-               m_freem(m);
-               return (EINVAL);
-       }
-
-       bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
-       return (0);
 }
 
 /*
Index: netinet6/nd6.h
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.h,v
retrieving revision 1.60
diff -u -p -r1.60 nd6.h
--- netinet6/nd6.h      1 Jun 2016 23:45:19 -0000       1.60
+++ netinet6/nd6.h      6 Jun 2016 14:16:33 -0000
@@ -271,7 +271,7 @@ int nd6_ioctl(u_long, caddr_t, struct if
 void nd6_cache_lladdr(struct ifnet *, struct in6_addr *, char *, int, int, 
int);
 int nd6_output(struct ifnet *, struct mbuf *, struct sockaddr_in6 *,
     struct rtentry *);
-int nd6_storelladdr(struct ifnet *, struct rtentry *, struct mbuf *,
+int nd6_resolve(struct ifnet *, struct rtentry *, struct mbuf *,
         struct sockaddr *, u_char *);
 int nd6_sysctl(int, void *, size_t *, void *, size_t);
 int nd6_need_cache(struct ifnet *);

Reply via email to