Apply by doing:
cd /usr/src
patch -p0 < 008_arp.patch
And then rebuild your kernel.
Index: sys/net/route.c
===================================================================
RCS file: /cvs/src/sys/net/route.c,v
retrieving revision 1.35
diff -u -r1.35 route.c
--- net/route.c 2003/02/12 14:41:07 1.35
+++ net/route.c 2003/09/26 21:21:46
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.35 2003/02/12 14:41:07 jason Exp $ */
+/* $OpenBSD: route.c,v 1.37 2003/08/26 08:33:12 itojun Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -143,6 +143,9 @@
struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
static int okaytoclone(u_int, int);
+static int rtdeletemsg(struct rtentry *);
+static int rtflushclone1(struct radix_node *, void *);
+static void rtflushclone(struct radix_node_head *, struct rtentry *);
#ifdef IPSEC
@@ -453,6 +456,67 @@
}
/*
+ * Delete a route and generate a message
+ */
+static int
+rtdeletemsg(rt)
+ struct rtentry *rt;
+{
+ int error;
+ struct rt_addrinfo info;
+
+ /*
+ * Request the new route so that the entry is not actually
+ * deleted. That will allow the information being reported to
+ * be accurate (and consistent with route_output()).
+ */
+ bzero((caddr_t)&info, sizeof(info));
+ info.rti_info[RTAX_DST] = rt_key(rt);
+ info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+ info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
+ info.rti_flags = rt->rt_flags;
+ error = rtrequest1(RTM_DELETE, &info, &rt);
+
+ rt_missmsg(RTM_DELETE, &info, info.rti_flags, error);
+
+ /* Adjust the refcount */
+ if (error == 0 && rt->rt_refcnt <= 0) {
+ rt->rt_refcnt++;
+ rtfree(rt);
+ }
+ return (error);
+}
+
+static int
+rtflushclone1(rn, arg)
+ struct radix_node *rn;
+ void *arg;
+{
+ struct rtentry *rt, *parent;
+
+ rt = (struct rtentry *)rn;
+ parent = (struct rtentry *)arg;
+ if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent)
+ rtdeletemsg(rt);
+ return 0;
+}
+
+static void
+rtflushclone(rnh, parent)
+ struct radix_node_head *rnh;
+ struct rtentry *parent;
+{
+
+#ifdef DIAGNOSTIC
+ if (!parent || (parent->rt_flags & RTF_CLONING) == 0)
+ panic("rtflushclone: called with a non-cloning route");
+ if (!rnh->rnh_walktree)
+ panic("rtflushclone: no rnh_walktree");
+#endif
+ rnh->rnh_walktree(rnh, rtflushclone1, (void *)parent);
+}
+
+/*
* Routing table ioctl interface.
*/
int
@@ -599,7 +663,7 @@
struct rtentry **ret_nrt;
{
int s = splsoftnet(); int error = 0;
- register struct rtentry *rt;
+ register struct rtentry *rt, *crt;
register struct radix_node *rn;
register struct radix_node_head *rnh;
struct ifaddr *ifa;
@@ -614,6 +678,11 @@
case RTM_DELETE:
if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL)
senderr(ESRCH);
+ rt = (struct rtentry *)rn;
+ if ((rt->rt_flags & RTF_CLONING) != 0) {
+ /* clean up any cloned children */
+ rtflushclone(rnh, rt);
+ }
if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
panic ("rtrequest delete");
rt = (struct rtentry *)rn;
@@ -621,6 +690,10 @@
rt = rt->rt_gwroute; RTFREE(rt);
(rt = (struct rtentry *)rn)->rt_gwroute = NULL;
}
+ if (rt->rt_parent) {
+ rt->rt_parent->rt_refcnt--;
+ rt->rt_parent = NULL;
+ }
rt->rt_flags &= ~RTF_UP;
if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
ifa->ifa_rtrequest(RTM_DELETE, rt, info);
@@ -636,8 +709,11 @@
case RTM_RESOLVE:
if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)
senderr(EINVAL);
+ if ((rt->rt_flags & RTF_CLONING) == 0)
+ senderr(EINVAL);
ifa = rt->rt_ifa;
- flags = rt->rt_flags & ~RTF_CLONING;
+ flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);
+ flags |= RTF_CLONED;
gateway = rt->rt_gateway;
if ((netmask = rt->rt_genmask) == NULL)
flags |= RTF_HOST;
@@ -663,15 +739,6 @@
rt_maskedcopy(dst, ndst, netmask);
} else
Bcopy(dst, ndst, dst->sa_len);
- rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
- rnh, rt->rt_nodes);
- if (rn == NULL) {
- if (rt->rt_gwroute)
- rtfree(rt->rt_gwroute);
- Free(rt_key(rt));
- Free(rt);
- senderr(EEXIST);
- }
ifa->ifa_refcnt++;
rt->rt_ifa = ifa;
rt->rt_ifp = ifa->ifa_ifp;
@@ -682,12 +749,38 @@
*/
rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
rt->rt_parent = *ret_nrt; /* Back ptr. to parent. */
+ rt->rt_parent->rt_refcnt++;
+ }
+ rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
+ rnh, rt->rt_nodes);
+ if (rn == NULL && (crt = rtalloc1(ndst, 0)) != NULL) {
+ /* overwrite cloned route */
+ if ((crt->rt_flags & RTF_CLONED) != 0) {
+ rtdeletemsg(crt);
+ rn = rnh->rnh_addaddr((caddr_t)ndst,
+ (caddr_t)netmask, rnh, rt->rt_nodes);
+ }
+ RTFREE(crt);
+ }
+ if (rn == 0) {
+ IFAFREE(ifa);
+ if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent)
+ rtfree(rt->rt_parent);
+ if (rt->rt_gwroute)
+ rtfree(rt->rt_gwroute);
+ Free(rt_key(rt));
+ Free(rt);
+ senderr(EEXIST);
}
if (ifa->ifa_rtrequest)
ifa->ifa_rtrequest(req, rt, info);
if (ret_nrt) {
*ret_nrt = rt;
rt->rt_refcnt++;
+ }
+ if ((rt->rt_flags & RTF_CLONING) != 0) {
+ /* clean up any cloned children */
+ rtflushclone(rnh, rt);
}
break;
}
Index: sys/net/route.h
===================================================================
RCS file: /cvs/src/sys/net/route.h,v
retrieving revision 1.16
diff -u -r1.16 route.h
--- net/route.h 2003/02/12 14:41:07 1.16
+++ net/route.h 2003/09/26 21:21:46
@@ -143,6 +143,7 @@
#define RTF_PROTO3 0x2000 /* protocol specific routing flag */
#define RTF_PROTO2 0x4000 /* protocol specific routing flag */
#define RTF_PROTO1 0x8000 /* protocol specific routing flag */
+#define RTF_CLONED 0x10000 /* this is a cloned route */
#ifndef _KERNEL
/* obsoleted */
Index: sys/netinet/if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.45.4.1
diff -u -r1.45.4.1 if_ether.c
--- netinet/if_ether.c 2003/05/12 04:07:20 1.45.4.1
+++ netinet/if_ether.c 2003/09/26 21:21:49
@@ -719,10 +719,18 @@
rt->rt_refcnt--;
if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
rt->rt_gateway->sa_family != AF_LINK) {
- if (create)
+ if (create) {
log(LOG_DEBUG,
"arplookup: unable to enter address for %s\n",
inet_ntoa(sin.sin_addr));
+ if (rt->rt_refcnt <= 0 &&
+ (rt->rt_flags & RTF_CLONED) != 0) {
+ rtrequest(RTM_DELETE,
+ (struct sockaddr *)rt_key(rt),
+ rt->rt_gateway, rt_mask(rt), rt->rt_flags,
+ 0);
+ }
+ }
return (0);
}
return ((struct llinfo_arp *)rt->rt_llinfo);