summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2003-08-26 08:33:13 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2003-08-26 08:33:13 +0000
commitd583950be9e490d1bb31e20cb010348fcb444fd0 (patch)
tree2d6fed11b2386a37ff52c7dd6fc728888e42f162 /sys
parent90cc490af36cf6973651c32141a6a1d7dbadc728 (diff)
mark cloned route with RTF_CLONED. remove RTF_CLONED route when clone parent
disappers. deraadt ok
Diffstat (limited to 'sys')
-rw-r--r--sys/net/route.c119
-rw-r--r--sys/net/route.h3
2 files changed, 109 insertions, 13 deletions
diff --git a/sys/net/route.c b/sys/net/route.c
index d27bdabe4a9..1e7e2486b81 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.36 2003/06/02 23:28:12 millert 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 $ */
/*
@@ -139,6 +139,9 @@ int rttrash; /* routes not in table but not freed */
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
@@ -449,6 +452,67 @@ out:
}
/*
+ * 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
@@ -595,7 +659,7 @@ rtrequest1(req, info, ret_nrt)
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;
@@ -610,6 +674,13 @@ rtrequest1(req, info, ret_nrt)
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 = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL)
+ senderr(ESRCH);
if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
panic ("rtrequest delete");
rt = (struct rtentry *)rn;
@@ -617,6 +688,10 @@ rtrequest1(req, info, ret_nrt)
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);
@@ -632,8 +707,11 @@ rtrequest1(req, info, ret_nrt)
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;
@@ -659,15 +737,6 @@ rtrequest1(req, info, ret_nrt)
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;
@@ -678,6 +747,28 @@ rtrequest1(req, info, ret_nrt)
*/
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);
@@ -685,6 +776,10 @@ rtrequest1(req, info, ret_nrt)
*ret_nrt = rt;
rt->rt_refcnt++;
}
+ if ((rt->rt_flags & RTF_CLONING) != 0) {
+ /* clean up any cloned children */
+ rtflushclone(rnh, rt);
+ }
break;
}
bad:
diff --git a/sys/net/route.h b/sys/net/route.h
index 8c054fc5e7f..cf72b221581 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.h,v 1.17 2003/06/02 23:28:12 millert Exp $ */
+/* $OpenBSD: route.h,v 1.18 2003/08/26 08:33:12 itojun Exp $ */
/* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */
/*
@@ -139,6 +139,7 @@ struct ortentry {
#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 */