summaryrefslogtreecommitdiffstats
path: root/sys/net/rtsock.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/rtsock.c')
-rw-r--r--sys/net/rtsock.c126
1 files changed, 123 insertions, 3 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index f842f8be969..57303703912 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -1,7 +1,36 @@
-/* $OpenBSD: rtsock.c,v 1.7 1998/08/24 20:39:40 downsj Exp $ */
+/* $OpenBSD: rtsock.c,v 1.8 1999/12/08 06:50:18 itojun Exp $ */
/* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */
/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
* Copyright (c) 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -68,6 +97,8 @@ static struct mbuf *
static int rt_msg2 __P((int,
struct rt_addrinfo *, caddr_t, struct walkarg *));
static void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *));
+static void rt_setif __P((struct rtentry *, struct sockaddr *,
+ struct sockaddr *, struct sockaddr *));
/* Sleazy use of local variables throughout file, warning!!!! */
#define dst info.rti_info[RTAX_DST]
@@ -99,6 +130,8 @@ route_usrreq(so, req, m, nam, control)
int af = rp->rcb_proto.sp_protocol;
if (af == AF_INET)
route_cb.ip_count--;
+ else if (af == AF_INET6)
+ route_cb.ip6_count--;
else if (af == AF_NS)
route_cb.ns_count--;
else if (af == AF_ISO)
@@ -129,6 +162,8 @@ route_usrreq(so, req, m, nam, control)
}
if (af == AF_INET)
route_cb.ip_count++;
+ else if (af == AF_INET6)
+ route_cb.ip6_count++;
else if (af == AF_NS)
route_cb.ns_count++;
else if (af == AF_ISO)
@@ -159,7 +194,6 @@ route_output(m, va_alist)
struct rt_addrinfo info;
int len, error = 0;
struct ifnet *ifp = 0;
- struct ifaddr *ifa = 0;
struct socket *so;
va_list ap;
@@ -167,7 +201,7 @@ route_output(m, va_alist)
so = va_arg(ap, struct socket *);
va_end(ap);
-
+ bzero(&info, sizeof(info));
#define senderr(e) { error = e; goto flush;}
if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
(m = m_pullup(m, sizeof(int32_t))) == 0))
@@ -219,6 +253,35 @@ route_output(m, va_alist)
error = rtrequest(RTM_ADD, dst, gate, netmask,
rtm->rtm_flags, &saved_nrt);
if (error == 0 && saved_nrt) {
+ /*
+ * If the route request specified an interface with
+ * IFA and/or IFP, we set the requested interface on
+ * the route with rt_setif. It would be much better
+ * to do this inside rtrequest, but that would
+ * require passing the desired interface, in some
+ * form, to rtrequest. Since rtrequest is called in
+ * so many places (roughly 40 in our source), adding
+ * a parameter is to much for us to swallow; this is
+ * something for the FreeBSD developers to tackle.
+ * Instead, we let rtrequest compute whatever
+ * interface it wants, then come in behind it and
+ * stick in the interface that we really want. This
+ * works reasonably well except when rtrequest can't
+ * figure out what interface to use (with
+ * ifa_withroute) and returns ENETUNREACH. Ideally
+ * it shouldn't matter if rtrequest can't figure out
+ * the interface if we're going to explicitly set it
+ * ourselves anyway. But practically we can't
+ * recover here because rtrequest will not do any of
+ * the work necessary to add the route if it can't
+ * find an interface. As long as there is a default
+ * route that leads to some interface, rtrequest will
+ * find an interface, so this problem should be
+ * rarely encountered.
+ * dwiggins@bbn.com
+ */
+
+ rt_setif(saved_nrt, ifpaddr, ifaaddr, gate);
rt_setmetrics(rtm->rtm_inits,
&rtm->rtm_rmx, &saved_nrt->rt_rmx);
saved_nrt->rt_refcnt--;
@@ -287,6 +350,10 @@ route_output(m, va_alist)
case RTM_CHANGE:
if (gate && rt_setgate(rt, rt_key(rt), gate))
senderr(EDQUOT);
+
+#if 1
+ rt_setif(rt, ifpaddr, ifaaddr, gate);
+#else
/* new gateway could require new ifaddr, ifp;
flags may also be different; ifp may be specified
by ll sockaddr when protocol address is ambiguous */
@@ -310,10 +377,13 @@ route_output(m, va_alist)
rt->rt_ifp = ifp;
}
}
+#endif
rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
&rt->rt_rmx);
+#if 0
if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
+#endif
if (genmask)
rt->rt_genmask = genmask;
/*
@@ -387,6 +457,56 @@ rt_setmetrics(which, in, out)
#undef metric
}
+/*
+ * Set route's interface given ifpaddr, ifaaddr, and gateway.
+ */
+static void
+rt_setif(rt, Ifpaddr, Ifaaddr, Gate)
+ struct rtentry *rt;
+ struct sockaddr *Ifpaddr, *Ifaaddr, *Gate;
+{
+ struct ifaddr *ifa = 0;
+ struct ifnet *ifp = 0;
+
+ /* new gateway could require new ifaddr, ifp;
+ flags may also be different; ifp may be specified
+ by ll sockaddr when protocol address is ambiguous */
+ if (Ifpaddr && (ifa = ifa_ifwithnet(Ifpaddr)) &&
+ (ifp = ifa->ifa_ifp) && (Ifaaddr || Gate))
+ ifa = ifaof_ifpforaddr(Ifaaddr ? Ifaaddr : Gate,
+ ifp);
+ else if (Ifpaddr && (ifp = if_withname(Ifpaddr)) ) {
+ ifa = Gate ? ifaof_ifpforaddr(Gate, ifp) :
+ TAILQ_FIRST(&ifp->if_addrlist);
+ }
+ else if ((Ifaaddr && (ifa = ifa_ifwithaddr(Ifaaddr))) ||
+ (Gate && (ifa = ifa_ifwithroute(rt->rt_flags,
+ rt_key(rt), Gate))))
+ ifp = ifa->ifa_ifp;
+ if (ifa) {
+ register struct ifaddr *oifa = rt->rt_ifa;
+ if (oifa != ifa) {
+ if (oifa && oifa->ifa_rtrequest)
+ oifa->ifa_rtrequest(RTM_DELETE,
+ rt, Gate);
+ IFAFREE(rt->rt_ifa);
+ rt->rt_ifa = ifa;
+ ifa->ifa_refcnt++;
+ rt->rt_ifp = ifp;
+ rt->rt_rmx.rmx_mtu = ifp->if_mtu;
+ if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
+ rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, Gate);
+ } else
+ goto call_ifareq;
+ return;
+ }
+ call_ifareq:
+ /* XXX: to reset gateway to correct value, at RTM_CHANGE */
+ if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
+ rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, Gate);
+}
+
+
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))