Index: sys/net/if_gre.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/if_gre.c,v
diff -u -p -u -p -r1.184 if_gre.c
--- sys/net/if_gre.c	2 Mar 2025 21:28:31 -0000	1.184
+++ sys/net/if_gre.c	8 Mar 2025 06:39:58 -0000
@@ -1634,7 +1634,7 @@ mgre_output(struct ifnet *ifp, struct mb
 {
 	struct mgre_softc *sc = ifp->if_softc;
 	struct sockaddr *gate;
-	struct rtentry *rt;
+	struct rtentry *rt = NULL;
 	struct m_tag *mtag;
 	int error = 0;
 	sa_family_t af;
@@ -1731,7 +1731,8 @@ mgre_output(struct ifnet *ifp, struct mb
 	m = gre_l3_encap_dst(&sc->sc_tunnel, addr, m, dest->sa_family);
 	if (m == NULL) {
 		ifp->if_oerrors++;
-		return (ENOBUFS);
+		error = ENOBUFS;
+		goto out;
 	}
 
 	m->m_pkthdr.ph_family = dest->sa_family;
@@ -1739,10 +1740,13 @@ mgre_output(struct ifnet *ifp, struct mb
 	error = if_enqueue(ifp, m);
 	if (error)
 		ifp->if_oerrors++;
+out:
+	rtfree(rt);
 	return (error);
 
 drop:
 	m_freem(m);
+	rtfree(rt);
 	return (error);
 }
 
Index: sys/net/route.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/route.c,v
diff -u -p -u -p -r1.443 route.c
--- sys/net/route.c	6 Mar 2025 23:09:02 -0000	1.443
+++ sys/net/route.c	8 Mar 2025 06:39:58 -0000
@@ -324,11 +324,20 @@ rtisvalid(struct rtentry *rt)
 		return (0);
 
 	if (ISSET(rt->rt_flags, RTF_GATEWAY)) {
-		if (rt->rt_gwroute == NULL)
+		struct rtentry *gwroute;
+
+		mtx_enter(&rt->rt_mtx);
+		gwroute = rt->rt_gwroute;
+		if (gwroute == NULL) {
+			mtx_leave(&rt->rt_mtx);
 			return (0);
-		KASSERT(!ISSET(rt->rt_gwroute->rt_flags, RTF_GATEWAY));
-		if (!ISSET(rt->rt_gwroute->rt_flags, RTF_UP))
+		}
+		KASSERT(!ISSET(gwroute->rt_flags, RTF_GATEWAY));
+		if (!ISSET(gwroute->rt_flags, RTF_UP)) {
+			mtx_leave(&rt->rt_mtx);
 			return (0);
+		}
+		mtx_leave(&rt->rt_mtx);
 	}
 
 	return (1);
@@ -599,8 +608,10 @@ rt_putgwroute(struct rtentry *rt, struct
 		mtx_leave(&nhrt->rt_mtx);
 	}
 
+	mtx_enter(&rt->rt_mtx);
 	onhrt = rt->rt_gwroute;
 	rt->rt_gwroute = nhrt;
+	mtx_leave(&rt->rt_mtx);
 
 	if (onhrt != NULL) {
 		mtx_enter(&onhrt->rt_mtx);
@@ -1163,16 +1174,24 @@ rt_setgate(struct rtentry *rt, const str
 
 /*
  * Return the route entry containing the next hop link-layer
- * address corresponding to ``rt''.
+ * address corresponding to ``rt''.  The caller has to free.
  */
 struct rtentry *
 rt_getll(struct rtentry *rt)
 {
 	if (ISSET(rt->rt_flags, RTF_GATEWAY)) {
+		struct rtentry *gwroute;
+
+		mtx_enter(&rt->rt_mtx);
+		gwroute = rt->rt_gwroute;
+		if (gwroute != NULL)
+			rtref(gwroute);
+		mtx_leave(&rt->rt_mtx);
 	 	/* We may return NULL here. */
-		return (rt->rt_gwroute);
+		return (gwroute);
 	}
 
+	rtref(rt);
 	return (rt);
 }
 
Index: sys/net/route.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/route.h,v
diff -u -p -u -p -r1.214 route.h
--- sys/net/route.h	6 Mar 2025 23:09:02 -0000	1.214
+++ sys/net/route.h	8 Mar 2025 06:39:58 -0000
@@ -123,7 +123,7 @@ struct rtentry {
 	caddr_t		 rt_llinfo;	/* [L] pointer to link level info or
 					   an MPLS structure */
 	union {
-		struct rtentry	*_nh;	/* [X] rtentry for rt_gateway */
+		struct rtentry	*_nh;	/* [r] rtentry for rt_gateway */
 		unsigned int	 _ref;	/* [r] # gateway rtentry refs */
 	} RT_gw;
 #define rt_gwroute	 RT_gw._nh
Index: sys/net/rtsock.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/net/rtsock.c,v
diff -u -p -u -p -r1.381 rtsock.c
--- sys/net/rtsock.c	16 Feb 2025 11:39:28 -0000	1.381
+++ sys/net/rtsock.c	8 Mar 2025 06:39:58 -0000
@@ -1343,9 +1343,11 @@ route_cleargateway(struct rtentry *rt, v
 {
 	struct rtentry *nhrt = arg;
 
+	mtx_enter(&rt->rt_mtx);
 	if (ISSET(rt->rt_flags, RTF_GATEWAY) && rt->rt_gwroute == nhrt &&
 	    !ISSET(rt->rt_locks, RTV_MTU))
 		atomic_store_int(&rt->rt_mtu, 0);
+	mtx_leave(&rt->rt_mtx);
 
 	return (0);
 }
Index: sys/netinet/if_ether.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/if_ether.c,v
diff -u -p -u -p -r1.272 if_ether.c
--- sys/netinet/if_ether.c	2 Mar 2025 21:28:32 -0000	1.272
+++ sys/netinet/if_ether.c	8 Mar 2025 06:39:58 -0000
@@ -337,7 +337,7 @@ arpresolve(struct ifnet *ifp, struct rte
 	struct arpcom *ac = (struct arpcom *)ifp;
 	struct llinfo_arp *la;
 	struct sockaddr_dl *sdl;
-	struct rtentry *rt = NULL;
+	struct rtentry *rt;
 	char addr[INET_ADDRSTRLEN];
 	time_t uptime;
 	int refresh = 0, reject = 0;
@@ -357,6 +357,7 @@ arpresolve(struct ifnet *ifp, struct rte
 	if (rt == NULL || (ISSET(rt->rt_flags, RTF_REJECT) &&
 	    (rt->rt_expire == 0 || rt->rt_expire > uptime))) {
 		m_freem(m);
+		rtfree(rt);
 		return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
 	}
 
@@ -404,6 +405,7 @@ arpresolve(struct ifnet *ifp, struct rte
 			    &satosin(dst)->sin_addr.s_addr,
 			    ac->ac_enaddr);
 		}
+		rtfree(rt);
 		return (0);
 	}
 
@@ -472,10 +474,12 @@ arpresolve(struct ifnet *ifp, struct rte
 	if (refresh)
 		arprequest(ifp, &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr,
 		    &satosin(dst)->sin_addr.s_addr, ac->ac_enaddr);
+	rtfree(rt);
 	return (EAGAIN);
 
 bad:
 	m_freem(m);
+	rtfree(rt);
 	return (EINVAL);
 }
 
Index: sys/netinet6/nd6.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet6/nd6.c,v
diff -u -p -u -p -r1.287 nd6.c
--- sys/netinet6/nd6.c	17 Feb 2025 20:31:25 -0000	1.287
+++ sys/netinet6/nd6.c	8 Mar 2025 06:39:58 -0000
@@ -1288,6 +1288,7 @@ nd6_resolve(struct ifnet *ifp, struct rt
 	if (rt == NULL || (ISSET(rt->rt_flags, RTF_REJECT) &&
 	    (rt->rt_expire == 0 || rt->rt_expire > uptime))) {
 		m_freem(m);
+		rtfree(rt);
 		return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
 	}
 
@@ -1357,6 +1358,7 @@ nd6_resolve(struct ifnet *ifp, struct rt
 		}
 
 		bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
+		rtfree(rt);
 		return (0);
 	}
 
@@ -1394,10 +1396,12 @@ nd6_resolve(struct ifnet *ifp, struct rt
 
 	if (solicit)
 		nd6_ns_output(ifp, NULL, &satosin6(dst)->sin6_addr, &saddr6, 0);
+	rtfree(rt);
 	return (EAGAIN);
 
 bad:
 	m_freem(m);
+	rtfree(rt);
 	return (EINVAL);
 }