summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2014-04-03 08:22:10 +0000
committermpi <mpi@openbsd.org>2014-04-03 08:22:10 +0000
commitf2dae7260a5debe70a339c3f25224fd87d65499e (patch)
tree7be3bbe808ec5639a6e6d96396c2b0c20e8e093d
parentWork out mouse scroll wheel effect when the mouse is first detected and (diff)
downloadwireguard-openbsd-f2dae7260a5debe70a339c3f25224fd87d65499e.tar.xz
wireguard-openbsd-f2dae7260a5debe70a339c3f25224fd87d65499e.zip
Introduce rt_ifa_{add,del}loop() to replace in6_{add,rem}loop().
Move these functions to a more generic place and make them reuse existing code, they'll be soon used in IPv4 too. Tested by André Lucas, Vigdis and sthen@, thanks! ok sthen@
-rw-r--r--sys/net/route.c178
-rw-r--r--sys/net/route.h4
-rw-r--r--sys/netinet6/in6.c180
-rw-r--r--sys/netinet6/in6_var.h4
4 files changed, 163 insertions, 203 deletions
diff --git a/sys/net/route.c b/sys/net/route.c
index 2b0e08c8648..d0e80e51646 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.157 2014/03/27 10:39:23 mpi Exp $ */
+/* $OpenBSD: route.c,v 1.158 2014/04/03 08:22:10 mpi Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -150,6 +150,9 @@ int rtflushclone1(struct radix_node *, void *, u_int);
void rtflushclone(struct radix_node_head *, struct rtentry *);
int rt_if_remove_rtdelete(struct radix_node *, void *, u_int);
+int rt_ifa_add(struct ifaddr *, int, struct sockaddr *);
+int rt_ifa_del(struct ifaddr *, int, struct sockaddr *);
+
#define LABELID_MAX 50000
struct rt_label {
@@ -1083,67 +1086,46 @@ rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst,
int
rtinit(struct ifaddr *ifa, int cmd, int flags)
{
- struct rtentry *rt;
- struct sockaddr *dst, *deldst;
- struct mbuf *m = NULL;
- struct rtentry *nrt = NULL;
- int error;
- struct rt_addrinfo info;
+ struct sockaddr *dst;
+ int error;
+
+ KASSERT(cmd == RTM_ADD || cmd == RTM_DELETE);
+
+ dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
+
+ if (cmd == RTM_ADD)
+ error = rt_ifa_add(ifa, flags, dst);
+ else
+ error = rt_ifa_del(ifa, flags, dst);
+
+ return (error);
+}
+
+int
+rt_ifa_add(struct ifaddr *ifa, int flags, struct sockaddr *dst)
+{
+ struct rtentry *rt, *nrt = NULL;
struct sockaddr_rtlabel sa_rl;
+ struct rt_addrinfo info;
u_short rtableid = ifa->ifa_ifp->if_rdomain;
+ int error;
- dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
- if (cmd == RTM_DELETE) {
- if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
- m = m_get(M_DONTWAIT, MT_SONAME);
- if (m == NULL)
- return (ENOBUFS);
- deldst = mtod(m, struct sockaddr *);
- rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
- dst = deldst;
- }
- if ((rt = rtalloc1(dst, 0, rtableid)) != NULL) {
- rt->rt_refcnt--;
- /* try to find the right route */
- while (rt && rt->rt_ifa != ifa)
- rt = (struct rtentry *)
- ((struct radix_node *)rt)->rn_dupedkey;
- if (!rt) {
- if (m != NULL)
- (void) m_free(m);
- return (flags & RTF_HOST ? EHOSTUNREACH
- : ENETUNREACH);
- }
- }
- }
- bzero(&info, sizeof(info));
+ memset(&info, 0, sizeof(info));
info.rti_ifa = ifa;
info.rti_flags = flags;
info.rti_info[RTAX_DST] = dst;
- if (cmd == RTM_ADD)
- info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
+ info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
info.rti_info[RTAX_LABEL] =
rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl);
if ((flags & RTF_HOST) == 0)
info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
- error = rtrequest1(cmd, &info, RTP_CONNECTED, &nrt, rtableid);
- if (cmd == RTM_DELETE) {
- if (error == 0 && (rt = nrt) != NULL) {
- rt_newaddrmsg(cmd, ifa, error, nrt);
- if (rt->rt_refcnt <= 0) {
- rt->rt_refcnt++;
- rtfree(rt);
- }
- }
- if (m != NULL)
- (void) m_free(m);
- }
- if (cmd == RTM_ADD && error == 0 && (rt = nrt) != NULL) {
+ error = rtrequest1(RTM_ADD, &info, RTP_CONNECTED, &nrt, rtableid);
+ if (error == 0 && (rt = nrt) != NULL) {
rt->rt_refcnt--;
if (rt->rt_ifa != ifa) {
- printf("rtinit: wrong ifa (%p) was (%p)\n",
+ printf("%s: wrong ifa (%p) was (%p)\n", __func__,
ifa, rt->rt_ifa);
if (rt->rt_ifa->ifa_rtrequest)
rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt);
@@ -1154,12 +1136,110 @@ rtinit(struct ifaddr *ifa, int cmd, int flags)
if (ifa->ifa_rtrequest)
ifa->ifa_rtrequest(RTM_ADD, rt);
}
- rt_newaddrmsg(cmd, ifa, error, nrt);
+ rt_newaddrmsg(RTM_ADD, ifa, error, nrt);
+ }
+ return (error);
+}
+
+int
+rt_ifa_del(struct ifaddr *ifa, int flags, struct sockaddr *dst)
+{
+ struct rtentry *rt, *nrt = NULL;
+ struct mbuf *m = NULL;
+ struct sockaddr *deldst;
+ struct rt_addrinfo info;
+ struct sockaddr_rtlabel sa_rl;
+ u_short rtableid = ifa->ifa_ifp->if_rdomain;
+ int error;
+
+ if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
+ m = m_get(M_DONTWAIT, MT_SONAME);
+ if (m == NULL)
+ return (ENOBUFS);
+ deldst = mtod(m, struct sockaddr *);
+ rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
+ dst = deldst;
+ }
+ if ((rt = rtalloc1(dst, 0, rtableid)) != NULL) {
+ rt->rt_refcnt--;
+ /* try to find the right route */
+ while (rt && rt->rt_ifa != ifa)
+ rt = (struct rtentry *)
+ ((struct radix_node *)rt)->rn_dupedkey;
+ if (!rt) {
+ if (m != NULL)
+ (void) m_free(m);
+ return (flags & RTF_HOST ? EHOSTUNREACH
+ : ENETUNREACH);
+ }
}
+
+ memset(&info, 0, sizeof(info));
+ info.rti_ifa = ifa;
+ info.rti_flags = flags;
+ info.rti_info[RTAX_DST] = dst;
+ info.rti_info[RTAX_LABEL] =
+ rtlabel_id2sa(ifa->ifa_ifp->if_rtlabelid, &sa_rl);
+
+ if ((flags & RTF_HOST) == 0)
+ info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+
+ error = rtrequest1(RTM_DELETE, &info, RTP_CONNECTED, &nrt, rtableid);
+ if (error == 0 && (rt = nrt) != NULL) {
+ rt_newaddrmsg(RTM_DELETE, ifa, error, nrt);
+ if (rt->rt_refcnt <= 0) {
+ rt->rt_refcnt++;
+ rtfree(rt);
+ }
+ }
+ if (m != NULL)
+ m_free(m);
+
return (error);
}
/*
+ * Add ifa's address as a loopback rtentry.
+ */
+void
+rt_ifa_addloop(struct ifaddr *ifa)
+{
+ struct rtentry *rt;
+
+ /* If there is no loopback entry, allocate one. */
+ rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
+ if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
+ (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
+ rt_ifa_add(ifa, RTF_UP| RTF_HOST | RTF_LLINFO, ifa->ifa_addr);
+ if (rt)
+ rt->rt_refcnt--;
+}
+
+/*
+ * Remove loopback rtentry of ifa's addresss if it exists.
+ */
+void
+rt_ifa_delloop(struct ifaddr *ifa)
+{
+ struct rtentry *rt;
+
+ /*
+ * Before deleting, check if a corresponding loopbacked host
+ * route surely exists. With this check, we can avoid to
+ * delete an interface direct route whose destination is same
+ * as the address being removed. This can happen when removing
+ * a subnet-router anycast address on an interface attached
+ * to a shared medium.
+ */
+ rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
+ if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
+ (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0)
+ rt_ifa_del(ifa, RTF_HOST | RTF_LLINFO, ifa->ifa_addr);
+ if (rt)
+ rt->rt_refcnt--;
+}
+
+/*
* Route timer routines. These routes allow functions to be called
* for various routes at any time. This is useful in supporting
* path MTU discovery and redirect route deletion.
diff --git a/sys/net/route.h b/sys/net/route.h
index 90ef5d5d311..7139dcfe7e6 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.h,v 1.89 2014/03/21 10:44:42 mpi Exp $ */
+/* $OpenBSD: route.h,v 1.90 2014/04/03 08:22:10 mpi Exp $ */
/* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */
/*
@@ -402,6 +402,8 @@ struct rtentry *
void rtfree(struct rtentry *);
int rt_getifa(struct rt_addrinfo *, u_int);
int rtinit(struct ifaddr *, int, int);
+void rt_ifa_addloop(struct ifaddr *);
+void rt_ifa_delloop(struct ifaddr *);
int rtioctl(u_long, caddr_t, struct proc *);
void rtredirect(struct sockaddr *, struct sockaddr *,
struct sockaddr *, int, struct sockaddr *,
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 4e063c0bc03..16ef0833f21 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6.c,v 1.133 2014/03/27 10:39:23 mpi Exp $ */
+/* $OpenBSD: in6.c,v 1.134 2014/04/03 08:22:10 mpi Exp $ */
/* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */
/*
@@ -122,156 +122,11 @@ const struct in6_addr in6mask128 = IN6MASK128;
int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t, struct ifnet *);
int in6_ifinit(struct ifnet *, struct in6_ifaddr *, int);
void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
-void in6_ifloop_request(int, struct ifaddr *);
const struct sockaddr_in6 sa6_any = {
sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0
};
-/*
- * Subroutine for in6_ifaddloop() and in6_ifremloop().
- * This routine does actual work.
- */
-void
-in6_ifloop_request(int cmd, struct ifaddr *ifa)
-{
- struct rt_addrinfo info;
- struct rtentry *nrt = NULL;
- int e;
-
- /*
- * We specify the address itself as the gateway, and set the
- * RTF_LLINFO flag, so that the corresponding host route would have
- * the flag, and thus applications that assume traditional behavior
- * would be happy. Note that we assume the caller of the function
- * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest,
- * which changes the outgoing interface to the loopback interface.
- * XXX only table 0 for now
- */
- bzero(&info, sizeof(info));
- info.rti_flags = RTF_UP | RTF_HOST | RTF_LLINFO;
- info.rti_info[RTAX_DST] = ifa->ifa_addr;
- if (cmd != RTM_DELETE)
- info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
- e = rtrequest1(cmd, &info, RTP_CONNECTED, &nrt,
- ifa->ifa_ifp->if_rdomain);
- if (e != 0) {
- char addr[INET6_ADDRSTRLEN];
- log(LOG_ERR, "in6_ifloop_request: "
- "%s operation failed for %s (errno=%d)\n",
- cmd == RTM_ADD ? "ADD" : "DELETE",
- inet_ntop(AF_INET6,
- &ifatoia6(ifa)->ia_addr.sin6_addr, addr, sizeof(addr)),
- e);
- }
-
- /*
- * Make sure rt_ifa be equal to IFA, the second argument of the
- * function.
- * We need this because when we refer to rt_ifa->ia6_flags in
- * ip6_input, we assume that the rt_ifa points to the address instead
- * of the loopback address.
- */
- if (cmd == RTM_ADD && nrt && ifa != nrt->rt_ifa) {
- ifafree(nrt->rt_ifa);
- ifa->ifa_refcnt++;
- nrt->rt_ifa = ifa;
- }
-
- /*
- * Report the addition/removal of the address to the routing socket.
- * XXX: since we called rtinit for a p2p interface with a destination,
- * we end up reporting twice in such a case. Should we rather
- * omit the second report?
- */
- if (nrt) {
- rt_newaddrmsg(cmd, ifa, e, nrt);
- if (cmd == RTM_DELETE) {
- if (nrt->rt_refcnt <= 0) {
- /* XXX: we should free the entry ourselves. */
- nrt->rt_refcnt++;
- rtfree(nrt);
- }
- } else {
- /* the cmd must be RTM_ADD here */
- nrt->rt_refcnt--;
- }
- }
-}
-
-/*
- * Add ownaddr as loopback rtentry. We previously add the route only if
- * necessary (ex. on a p2p link). However, since we now manage addresses
- * separately from prefixes, we should always add the route. We can't
- * rely on the cloning mechanism from the corresponding interface route
- * any more.
- */
-void
-in6_ifaddloop(struct ifaddr *ifa)
-{
- struct rtentry *rt;
-
- /* If there is no loopback entry, allocate one. */
- rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
- if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 ||
- (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
- in6_ifloop_request(RTM_ADD, ifa);
- if (rt)
- rt->rt_refcnt--;
-}
-
-/*
- * Remove loopback rtentry of ownaddr generated by in6_ifaddloop(),
- * if it exists.
- */
-void
-in6_ifremloop(struct ifaddr *ifa)
-{
- struct in6_ifaddr *ia6;
- struct rtentry *rt;
- int ia_count = 0;
-
- /*
- * Some of BSD variants do not remove cloned routes
- * from an interface direct route, when removing the direct route
- * (see comments in net/net_osdep.h). Even for variants that do remove
- * cloned routes, they could fail to remove the cloned routes when
- * we handle multple addresses that share a common prefix.
- * So, we should remove the route corresponding to the deleted address.
- */
-
- /*
- * Delete the entry only if exact one ifa exists. More than one ifa
- * can exist if we assign a same single address to multiple
- * (probably p2p) interfaces.
- * XXX: we should avoid such a configuration in IPv6...
- */
- TAILQ_FOREACH(ia6, &in6_ifaddr, ia_list) {
- if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia6->ia_addr.sin6_addr)) {
- ia_count++;
- if (ia_count > 1)
- break;
- }
- }
-
- if (ia_count == 1) {
- /*
- * Before deleting, check if a corresponding loopbacked host
- * route surely exists. With this check, we can avoid to
- * delete an interface direct route whose destination is same
- * as the address being removed. This can happen when removing
- * a subnet-router anycast address on an interface attached
- * to a shared medium.
- */
- rt = rtalloc1(ifa->ifa_addr, 0, ifa->ifa_ifp->if_rdomain);
- if (rt != NULL && (rt->rt_flags & RTF_HOST) != 0 &&
- (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
- rt->rt_refcnt--;
- in6_ifloop_request(RTM_DELETE, ifa);
- }
- }
-}
-
int
in6_mask2len(struct in6_addr *mask, u_char *lim0)
{
@@ -1151,8 +1006,9 @@ void
in6_purgeaddr(struct ifaddr *ifa)
{
struct ifnet *ifp = ifa->ifa_ifp;
- struct in6_ifaddr *ia6 = ifatoia6(ifa);
+ struct in6_ifaddr *tmp, *ia6 = ifatoia6(ifa);
struct in6_multi_mship *imm;
+ int ia6_count = 0;
/* stop DAD processing */
nd6_dad_stop(ifa);
@@ -1178,8 +1034,32 @@ in6_purgeaddr(struct ifaddr *ifa)
ia6->ia_flags &= ~IFA_ROUTE;
}
- /* Remove ownaddr's loopback rtentry, if it exists. */
- in6_ifremloop(&(ia6->ia_ifa));
+ /* Remove ownaddr's loopback rtentry, if it exists.
+ *
+ * Some of BSD variants do not remove cloned routes from an
+ * interface direct route, when removing the direct route (see
+ * comments in net/net_osdep.h). Even for variants that do
+ * remove cloned routes, they could fail to remove the cloned
+ * routes when we handle multiple addresses that share a common
+ * prefix. So, we should remove the route corresponding to the
+ * deleted address.
+ *
+ * Delete the entry only if exact one ifa exists. More than one
+ * ifa can exist if we assign a same single address to multiple
+ * (probably p2p) interfaces.
+ * XXX: we should avoid such a configuration in IPv6...
+ */
+ TAILQ_FOREACH(tmp, &in6_ifaddr, ia_list) {
+ if (IN6_ARE_ADDR_EQUAL(&tmp->ia_addr.sin6_addr,
+ &ia6->ia_addr.sin6_addr)) {
+ ia6_count++;
+ if (ia6_count > 1)
+ break;
+ }
+ }
+
+ if (ia6_count == 1)
+ rt_ifa_delloop(&(ia6->ia_ifa));
/*
* leave from multicast groups we have joined for the interface
@@ -1517,7 +1397,7 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia6, int newhost)
if (newhost) {
/* set the rtrequest function to create llinfo */
ia6->ia_ifa.ifa_rtrequest = nd6_rtrequest;
- in6_ifaddloop(&(ia6->ia_ifa));
+ rt_ifa_addloop(&(ia6->ia_ifa));
}
return (error);
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index 7ce3d7f76de..ed1786b466c 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_var.h,v 1.48 2014/03/27 10:39:23 mpi Exp $ */
+/* $OpenBSD: in6_var.h,v 1.49 2014/04/03 08:22:10 mpi Exp $ */
/* $KAME: in6_var.h,v 1.55 2001/02/16 12:49:45 itojun Exp $ */
/*
@@ -524,8 +524,6 @@ int in6_matchlen(struct in6_addr *, struct in6_addr *);
int in6_are_prefix_equal(struct in6_addr *, struct in6_addr *, int);
void in6_prefixlen2mask(struct in6_addr *, int);
void in6_purgeprefix(struct ifnet *);
-void in6_ifaddloop(struct ifaddr *);
-void in6_ifremloop(struct ifaddr *);
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_VAR_H_ */