Hi,

nd6_resolve() can call nd6_ns_output() without kernel lock.

ok?

bluhm

Index: netinet6/nd6.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.272
diff -u -p -r1.272 nd6.c
--- netinet6/nd6.c      5 Apr 2023 23:01:03 -0000       1.272
+++ netinet6/nd6.c      1 May 2023 07:30:53 -0000
@@ -303,7 +303,8 @@ nd6_llinfo_timer(struct rtentry *rt)
                if (ln->ln_asked < nd6_mmaxtries) {
                        ln->ln_asked++;
                        nd6_llinfo_settimer(ln, RETRANS_TIMER / 1000);
-                       nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
+                       nd6_ns_output(ifp, NULL, &dst->sin6_addr,
+                           &ln->ln_saddr6, 0);
                } else {
                        struct mbuf_list ml;
                        struct mbuf *m;
@@ -336,6 +337,7 @@ nd6_llinfo_timer(struct rtentry *rt)
                        ln = NULL;
                }
                break;
+
        case ND6_LLINFO_REACHABLE:
                if (!ND6_LLINFO_PERMANENT(ln)) {
                        ln->ln_state = ND6_LLINFO_STALE;
@@ -357,14 +359,16 @@ nd6_llinfo_timer(struct rtentry *rt)
                ln->ln_asked = 1;
                ln->ln_state = ND6_LLINFO_PROBE;
                nd6_llinfo_settimer(ln, RETRANS_TIMER / 1000);
-               nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, ln, 0);
+               nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr,
+                   &ln->ln_saddr6, 0);
                break;
+
        case ND6_LLINFO_PROBE:
                if (ln->ln_asked < nd6_umaxtries) {
                        ln->ln_asked++;
                        nd6_llinfo_settimer(ln, RETRANS_TIMER / 1000);
-                       nd6_ns_output(ifp, &dst->sin6_addr,
-                           &dst->sin6_addr, ln, 0);
+                       nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr,
+                           &ln->ln_saddr6, 0);
                } else {
                        nd6_free(rt);
                        ln = NULL;
@@ -1247,7 +1251,9 @@ nd6_resolve(struct ifnet *ifp, struct rt
        struct sockaddr_dl *sdl;
        struct rtentry *rt;
        struct llinfo_nd6 *ln = NULL;
+       struct in6_addr saddr6;
        time_t uptime;
+       int solicit = 0;
 
        if (m->m_flags & M_MCAST) {
                ETHER_MAP_IPV6_MULTICAST(&satosin6(dst)->sin6_addr, desten);
@@ -1357,9 +1363,13 @@ nd6_resolve(struct ifnet *ifp, struct rt
        if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) {
                ln->ln_asked++;
                nd6_llinfo_settimer(ln, RETRANS_TIMER / 1000);
-               nd6_ns_output(ifp, NULL, &satosin6(dst)->sin6_addr, ln, 0);
+               saddr6 = ln->ln_saddr6;
+               solicit = 1;
        }
        KERNEL_UNLOCK();
+
+       if (solicit)
+               nd6_ns_output(ifp, NULL, &satosin6(dst)->sin6_addr, &saddr6, 0);
        return (EAGAIN);
 
 bad:
Index: netinet6/nd6.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6.h,v
retrieving revision 1.97
diff -u -p -r1.97 nd6.h
--- netinet6/nd6.h      5 Apr 2023 21:51:47 -0000       1.97
+++ netinet6/nd6.h      1 May 2023 07:30:53 -0000
@@ -141,7 +141,7 @@ void nd6_na_output(struct ifnet *, const
        const struct in6_addr *, u_long, int, struct sockaddr *);
 void nd6_ns_input(struct mbuf *, int, int);
 void nd6_ns_output(struct ifnet *, const struct in6_addr *,
-       const struct in6_addr *, const struct llinfo_nd6 *, int);
+       const struct in6_addr *, const struct in6_addr *, int);
 caddr_t nd6_ifptomac(struct ifnet *);
 void nd6_dad_start(struct ifaddr *);
 void nd6_dad_stop(struct ifaddr *);
Index: netinet6/nd6_nbr.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.146
diff -u -p -r1.146 nd6_nbr.c
--- netinet6/nd6_nbr.c  28 Apr 2023 14:09:06 -0000      1.146
+++ netinet6/nd6_nbr.c  1 May 2023 07:30:53 -0000
@@ -360,7 +360,7 @@ nd6_ns_input(struct mbuf *m, int off, in
  */
 void
 nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
-    const struct in6_addr *taddr6, const struct llinfo_nd6 *ln, int dad)
+    const struct in6_addr *taddr6, const struct in6_addr *saddr6, int dad)
 {
        struct mbuf *m;
        struct ip6_hdr *ip6;
@@ -423,7 +423,7 @@ nd6_ns_output(struct ifnet *ifp, const s
        bzero(&dst_sa, sizeof(dst_sa));
        src_sa.sin6_family = dst_sa.sin6_family = AF_INET6;
        src_sa.sin6_len = dst_sa.sin6_len = sizeof(struct sockaddr_in6);
-       if (daddr6)
+       if (daddr6 != NULL)
                dst_sa.sin6_addr = *daddr6;
        else {
                dst_sa.sin6_addr.s6_addr16[0] = __IPV6_ADDR_INT16_MLL;
@@ -451,14 +451,13 @@ nd6_ns_output(struct ifnet *ifp, const s
                 * - if taddr is link local saddr6 must be link local as well
                 * Otherwise, we perform the source address selection as usual.
                 */
-               if (ln != NULL)
-                       src_sa.sin6_addr = ln->ln_saddr6;
+               if (saddr6 != NULL)
+                       src_sa.sin6_addr = *saddr6;
 
                if (!IN6_IS_ADDR_LINKLOCAL(taddr6) ||
                    IN6_IS_ADDR_UNSPECIFIED(&src_sa.sin6_addr) ||
                    IN6_IS_ADDR_LINKLOCAL(&src_sa.sin6_addr) ||
                    !in6ifa_ifpwithaddr(ifp, &src_sa.sin6_addr)) {
-
                        struct rtentry *rt;
 
                        rt = rtalloc(sin6tosa(&dst_sa), RT_RESOLVE,

Reply via email to