Hi,

Some checks in nd6_resolve() do not require kernel lock.  The analog
code for ARP has been unlocked in if_ether.c revision 1.250 since
2022/06/27 20:47:10.

ok?

bluhm

Index: netinet6/nd6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.273
diff -u -p -r1.273 nd6.c
--- netinet6/nd6.c      2 May 2023 06:06:13 -0000       1.273
+++ netinet6/nd6.c      2 May 2023 18:44:23 -0000
@@ -1260,15 +1260,12 @@ nd6_resolve(struct ifnet *ifp, struct rt
                return (0);
        }
 
-       /* XXXSMP there is a MP race in nd6_resolve() */
-       KERNEL_LOCK();
        uptime = getuptime();
        rt = rt_getll(rt0);
 
        if (ISSET(rt->rt_flags, RTF_REJECT) &&
            (rt->rt_expire == 0 || rt->rt_expire > uptime)) {
                m_freem(m);
-               KERNEL_UNLOCK();
                return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
        }
 
@@ -1291,6 +1288,11 @@ nd6_resolve(struct ifnet *ifp, struct rt
                goto bad;
        }
 
+       KERNEL_LOCK();
+       if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
+               KERNEL_UNLOCK();
+               goto bad;
+       }
        ln = (struct llinfo_nd6 *)rt->rt_llinfo;
        KASSERT(ln != NULL);
 
@@ -1321,6 +1323,8 @@ nd6_resolve(struct ifnet *ifp, struct rt
         * send the packet.
         */
        if (ln->ln_state > ND6_LLINFO_INCOMPLETE) {
+               KERNEL_UNLOCK();
+
                sdl = satosdl(rt->rt_gateway);
                if (sdl->sdl_alen != ETHER_ADDR_LEN) {
                        char addr[INET6_ADDRSTRLEN];
@@ -1332,7 +1336,6 @@ nd6_resolve(struct ifnet *ifp, struct rt
                }
 
                bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
-               KERNEL_UNLOCK();
                return (0);
        }
 
@@ -1374,7 +1377,6 @@ nd6_resolve(struct ifnet *ifp, struct rt
 
 bad:
        m_freem(m);
-       KERNEL_UNLOCK();
        return (EINVAL);
 }
 

Reply via email to