Apply by doing: cd /usr/src patch -p0 < 021_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);