diff options
author | 2014-04-03 08:22:10 +0000 | |
---|---|---|
committer | 2014-04-03 08:22:10 +0000 | |
commit | f2dae7260a5debe70a339c3f25224fd87d65499e (patch) | |
tree | 7be3bbe808ec5639a6e6d96396c2b0c20e8e093d | |
parent | Work out mouse scroll wheel effect when the mouse is first detected and (diff) | |
download | wireguard-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.c | 178 | ||||
-rw-r--r-- | sys/net/route.h | 4 | ||||
-rw-r--r-- | sys/netinet6/in6.c | 180 | ||||
-rw-r--r-- | sys/netinet6/in6_var.h | 4 |
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_ */ |