Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Oct 2013 09:15:07 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r256604 - user/ae/inet6/sys/netinet6
Message-ID:  <201310160915.r9G9F7hJ099225@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Wed Oct 16 09:15:07 2013
New Revision: 256604
URL: http://svnweb.freebsd.org/changeset/base/256604

Log:
  Add handle_nexthop() function to handle IPV6_NEXTHOP advanced
  socket API option.

Modified:
  user/ae/inet6/sys/netinet6/in6_src.c

Modified: user/ae/inet6/sys/netinet6/in6_src.c
==============================================================================
--- user/ae/inet6/sys/netinet6/in6_src.c	Wed Oct 16 09:12:40 2013	(r256603)
+++ user/ae/inet6/sys/netinet6/in6_src.c	Wed Oct 16 09:15:07 2013	(r256604)
@@ -132,6 +132,8 @@ static int cached_rtlookup(const struct 
 static int check_scopezones(const struct sockaddr_in6 *dst,
     struct route_in6 *ro, u_int fibnum, const struct ip6_moptions *mopts,
     const struct in6_addr *src, const struct ifnet *ifp);
+static int handle_nexthop(struct ip6po_nhinfo *nh, u_int fibnum,
+    struct ifnet **ifpp);
 static int handle_pktinfo(const struct sockaddr_in6 *dst,
     const struct in6_pktinfo* pi, const struct ip6_moptions *mopts,
     struct route_in6 *ro, u_int fibnum, struct ifnet **ifpp,
@@ -487,6 +489,71 @@ handle_pktinfo(const struct sockaddr_in6
 	return (0);
 }
 
+/*
+ * nh - next hop destination and route;
+ * fibnum - FIB number.
+ * ifpp - pointer to outgoing interface.
+ *
+ * NOTE: we can keep this route, it will be freed in the socket
+ * option handling code (see ip6_output.c).
+ */
+static int
+handle_nexthop(struct ip6po_nhinfo *nh, u_int fibnum, struct ifnet **ifpp)
+{
+	struct sockaddr_in6 *sa;
+	struct in6_ifaddr *ia;
+	struct route_in6 *ro;
+	struct ifnet *ifp, *oifp;
+
+	sa = (struct sockaddr_in6 *)nh->ip6po_nhi_nexthop;
+	ro = &nh->ip6po_nhi_route;
+	if (sa->sin6_family != AF_INET6)
+		return (EAFNOSUPPORT);
+	/*
+	 * If *ifpp is not NULL, this means that outgoing interface
+	 * was determined in the PKTINFO handling code.
+	 */
+	oifp = *ifpp;
+
+	/*
+	 * Check that the next hop address is our own.
+	 */
+	ia = in6ifa_ifwithaddr(&sa->sin6_addr, sa->sin6_scope_id);
+	if (ia != NULL) {
+		/* Address is our own. */
+		ifp = ia->ia_ifp;
+		ifa_free(&ia->ia_ifa);
+	} else {
+		/*
+		 * Address is not our own.
+		 * Determine outgoing interface by zone index.
+		 */
+		if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
+			ifp = in6_getlinkifnet(sa->sin6_scope_id);
+		else {
+			if (cached_rtlookup(sa, ro, fibnum) != 0)
+				return (EHOSTUNREACH);
+			/*
+			 * The node identified by that address must be a
+			 * neighbor of the sending host.
+			 */
+			if (ro->ro_rt->rt_flags & RTF_GATEWAY)
+				return (EHOSTUNREACH);
+			ifp = ro->ro_rt->rt_ifp;
+		}
+	}
+	/*
+	 * When the outgoing interface is specified by IPV6_PKTINFO
+	 * as well, the next hop specified by this option must be
+	 * reachable via the specified interface.
+	 */
+	if (ifp == NULL || (oifp != NULL && oifp != ifp))
+		return (EHOSTUNREACH);
+
+	*ifpp = ifp;
+	return (0);
+}
+
 int
 in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
     struct inpcb *inp, struct route_in6 *ro, struct ucred *cred,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310160915.r9G9F7hJ099225>