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,