From owner-svn-src-user@FreeBSD.ORG Wed Oct 16 09:25:01 2013 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 2CD1750D; Wed, 16 Oct 2013 09:25:01 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 1A4662DFF; Wed, 16 Oct 2013 09:25:01 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r9G9P0c1004489; Wed, 16 Oct 2013 09:25:00 GMT (envelope-from ae@svn.freebsd.org) Received: (from ae@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r9G9P0R5004488; Wed, 16 Oct 2013 09:25:00 GMT (envelope-from ae@svn.freebsd.org) Message-Id: <201310160925.r9G9P0R5004488@svn.freebsd.org> From: "Andrey V. Elsukov" Date: Wed, 16 Oct 2013 09:25:00 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r256608 - user/ae/inet6/sys/netinet6 X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Oct 2013 09:25:01 -0000 Author: ae Date: Wed Oct 16 09:25:00 2013 New Revision: 256608 URL: http://svnweb.freebsd.org/changeset/base/256608 Log: Rewrite socket options handling code. Use handle_pktinfo(), handle_nexthop() and cached_rtlookup() functions. Jail code should be changed to support scope zones, for now just disable it and mark with XXX. 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:21:40 2013 (r256607) +++ user/ae/inet6/sys/netinet6/in6_src.c Wed Oct 16 09:25:00 2013 (r256608) @@ -559,20 +559,23 @@ in6_selectsrc(struct sockaddr_in6 *dstso struct inpcb *inp, struct route_in6 *ro, struct ucred *cred, struct ifnet **ifpp, struct in6_addr *srcp) { - struct in6_addr dst, tmp; - struct ifnet *ifp = NULL, *oifp = NULL; - struct in6_ifaddr *ia = NULL, *ia_best = NULL; - struct in6_pktinfo *pi = NULL; - int dst_scope = -1, best_scope = -1, best_matchlen = -1; - struct in6_addrpolicy *dst_policy = NULL, *best_policy = NULL; - u_int32_t odstzone; - int prefer_tempaddr; - int error, rule; + struct route_in6 ro6; + struct dstaddr_props dstprops; + struct srcaddr_choice best; struct ip6_moptions *mopts; + struct in6_pktinfo *pi; + struct in6_ifaddr *ia; + struct ifaddr *ifa; + struct ifnet *ifp, *oifp; + u_int fibnum; + int error, done; KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__)); + KASSERT(ifpp != NULL, ("%s: ifpp is NULL", __func__)); + KASSERT(sa6_checkzone(dst) == 0, ("%s: invalid zone information", + __func__)); - dst = dstsock->sin6_addr; /* make a copy for local operation */ + ifp = oifp = NULL; if (ifpp) { /* * Save a possibly passed in ifp for in6_selectsrc. Only @@ -589,82 +592,111 @@ in6_selectsrc(struct sockaddr_in6 *dstso if (inp != NULL) { INP_LOCK_ASSERT(inp); mopts = inp->in6p_moptions; + fibnum = inp->inp_inc.inc_fibnum; } else { mopts = NULL; + fibnum = RT_DEFAULT_FIB; + } + if (ro == NULL) { + ro = &ro6; + bzero(ro, sizeof(*ro)); } /* - * If the source address is explicitly specified by the caller, - * check if the requested source address is indeed a unicast address - * assigned to the node, and can be used as the packet's source - * address. If everything is okay, use the address as source. + * XXX: jail support MUST be added later! */ - if (opts && (pi = opts->ip6po_pktinfo) && - !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) { - struct sockaddr_in6 srcsock; - struct in6_ifaddr *ia6; - - /* get the outgoing interface */ - if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp, - (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB)) - != 0) + if (opts != NULL && (pi = opts->ip6po_pktinfo) != NULL) { + error = handle_pktinfo(dst, pi, mopts, ro, fibnum, + &ifp, srcp, &done); + if (error != 0) return (error); - + if (done != 0) { + /* + * 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. Also, we ignore next hop for multicast + * destinations. + */ + if (!IN6_IS_ADDR_MULTICAST(&dst->sin6_addr) && + opts->ip6po_nexthop != NULL) + error = handle_nexthop(&opts->ip6po_nhinfo, + fibnum, &ifp); + if (error != 0 || ro == &ro6) + RO_RTFREE(ro); + if (error == 0) + *ifpp = ifp; + return (error); + } + } else if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) { /* - * determine the appropriate zone id of the source based on - * the zone of the destination and the outgoing interface. - * If the specified address is ambiguous wrt the scope zone, - * the interface must be specified; otherwise, ifa_ifwithaddr() - * will fail matching the address. + * If the destination address is a multicast address and + * the IPV6_MULTICAST_IF socket option is specified for the + * socket, the interface is used. */ - bzero(&srcsock, sizeof(srcsock)); - srcsock.sin6_family = AF_INET6; - srcsock.sin6_len = sizeof(srcsock); - srcsock.sin6_addr = pi->ipi6_addr; - if (ifp) { - error = in6_setscope(&srcsock.sin6_addr, ifp, NULL); - if (error) - return (error); - } - if (cred != NULL && (error = prison_local_ip6(cred, - &srcsock.sin6_addr, (inp != NULL && - (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0) + if (mopts && mopts->im6o_multicast_ifp) { + ifp = mopts->im6o_multicast_ifp; + } else if (IN6_IS_ADDR_MC_LINKLOCAL(&dst->sin6_addr) || + IN6_IS_ADDR_MC_INTFACELOCAL(&dst->sin6_addr)) { + /* + * Destination multicast address is in the link-local + * or interface-local scope. Use its sin6_scope_id to + * determine outgoing interface. + */ + ifp = in6_getlinkifnet(dst->sin6_scope_id); + } else { + /* + * XXX: Try to lookup route for this multicast + * destination address. + */ + if (cached_rtlookup(dst, ro, fibnum) != 0) + return (EHOSTUNREACH); + ifp = ro->ro_rt->rt_ifp; + } + } else if (opts != NULL && opts->ip6po_nexthop != NULL) { + error = handle_nexthop(&opts->ip6po_nhinfo, fibnum, &ifp); + if (error != 0) return (error); - - ia6 = (struct in6_ifaddr *)ifa_ifwithaddr( - (struct sockaddr *)&srcsock); - if (ia6 == NULL || - (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) { - if (ia6 != NULL) - ifa_free(&ia6->ia_ifa); - return (EADDRNOTAVAIL); - } - pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */ - if (ifpp) - *ifpp = ifp; - bcopy(&ia6->ia_addr.sin6_addr, srcp, sizeof(*srcp)); - ifa_free(&ia6->ia_ifa); - return (0); + } else { + /* + * We don't have any options and destination isn't multicast. + * Use sin6_scope_id for link-local addresses. + * Do a route lookup for global addresses. + */ + if (dst->sin6_scope_id != 0) + ifp = in6_getlinkifnet(dst->sin6_scope_id); + else { + if (cached_rtlookup(dst, ro, fibnum) != 0) + return (EHOSTUNREACH); + ifp = ro->ro_rt->rt_ifp; + } } /* * Otherwise, if the socket has already bound the source, just use it. */ if (inp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { +#if 0 /* XXX: Jail support. */ if (cred != NULL && (error = prison_local_ip6(cred, &inp->in6p_laddr, ((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0) return (error); bcopy(&inp->in6p_laddr, srcp, sizeof(*srcp)); +#endif + if (ro == &ro6) + RO_RTFREE(ro); + *srcp = inp->in6p_laddr; + *ifpp = ifp; return (0); } - /* - * Bypass source address selection and use the primary jail IP + * XXX: Bypass source address selection and use the primary jail IP * if requested. */ +#if 0 if (cred != NULL && !prison_saddrsel_ip6(cred, srcp)) return (0); +#endif /* * If the address is not specified, choose the best one based on