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,