in6_src.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,336 行 · 第 1/3 页

C
1,336
字号
//==========================================================================////      src/sys/netinet6/in6_src.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/*	$KAME: in6_src.c,v 1.96 2001/12/24 10:39:29 jinmei 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) 1982, 1986, 1991, 1993 *	The Regents of the University of California.  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. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. * *	@(#)in_pcb.c	8.2 (Berkeley) 1/4/94 */#include <sys/param.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/sockio.h>#include <sys/errno.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_var.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/in_pcb.h>#include <netinet6/in6_var.h>#include <netinet/ip6.h>#include <netinet6/ip6_var.h>#include <netinet6/in6_pcb.h>#include <netinet6/nd6.h>#include <netinet6/scope6_var.h> #ifdef MIP6#include <netinet6/mip6.h>#endif /* MIP6 */#if defined(__NetBSD__)extern struct ifnet loif[NLOOP];#endif#define ADDR_LABEL_NOTAPP (-1)struct in6_addrpolicy defaultaddrpolicy;int ip6_prefer_tempaddr = 0;#ifdef NEW_STRUCT_ROUTEstatic int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,			     struct ip6_moptions *, 			     struct route *ro,			     struct ifnet **));#elsestatic int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,			     struct ip6_moptions *, 			     struct route_in6 *ro,			     struct ifnet **));#endifstatic struct in6_addrpolicy *lookup_addrsel_policy __P((struct sockaddr_in6 *));static void init_policy_queue __P((void));static int add_addrsel_policyent __P((struct in6_addrpolicy *));static int delete_addrsel_policyent __P((struct in6_addrpolicy *));static struct in6_addrpolicy *match_addrsel_policy __P((struct sockaddr_in6 *));/* * Return an IPv6 address, which is the most appropriate for a given * destination and user specified options. * If necessary, this function lookups the routing table and returns * an entry to the caller for later use. */#define REPLACE(r) do {\	if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \		sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \		ip6stat.ip6s_sources_rule[(r)]++; \	/* printf("in6_selectsrc: replace %s with %s by %d\n", ia_best ? ip6_sprintf(&ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(&ia->ia_addr.sin6_addr), (r)); */ \ 	goto replace; \} while(0)#define NEXT(r) do {\	if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \		sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \		ip6stat.ip6s_sources_rule[(r)]++; \	/* printf("in6_selectsrc: keep %s against %s by %d\n", ia_best ? ip6_sprintf(&ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(&ia->ia_addr.sin6_addr), (r)); */ \ 	goto next; 		/* XXX: we can't use 'continue' here */ \} while(0)#define BREAK(r) do { \	if ((r) < sizeof(ip6stat.ip6s_sources_rule) / \		sizeof(ip6stat.ip6s_sources_rule[0])) /* check for safety */ \		ip6stat.ip6s_sources_rule[(r)]++; \ 	goto out; 		/* XXX: we can't use 'break' here */ \} while(0)struct in6_addr *in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,              struct ip6_moptions *mopts, struct route *ro,              struct ifnet **ifpp, struct in6_addr *laddr,              int *errorp){	struct in6_addr *dst;	struct ifnet *ifp = 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;#ifdef MIP6	struct hif_softc *sc;#ifdef MIP6_ALLOW_COA_FALLBACK	struct mip6_bu *mbu_dst;	u_int8_t coafallback = 0;#endif#endif	dst = &dstsock->sin6_addr;	*errorp = 0;	if (ifpp)		*ifpp = NULL;	/*	 * 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.	 */	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 ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp))		    != 0) {			return(NULL);		}		/*		 * determine the appropriate zone id of the source based on		 * the zone of the destination and the outgoing interface.		 */		bzero(&srcsock, sizeof(srcsock));		srcsock.sin6_family = AF_INET6;		srcsock.sin6_len = sizeof(srcsock);		srcsock.sin6_addr = pi->ipi6_addr;		if (ifp) {			int64_t zone;			zone = in6_addr2zoneid(ifp, &pi->ipi6_addr);			if (zone < 0) { /* XXX: this should not happen */				*errorp = EINVAL;				return(NULL);			}			srcsock.sin6_scope_id = zone;		}		if ((*errorp = in6_embedscope(&srcsock.sin6_addr, &srcsock))		    != 0) {			return(NULL);		}#ifndef SCOPEDROUTING		srcsock.sin6_scope_id = 0; /* XXX: ifa_ifwithaddr expects 0 */#endif		ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock));		if (ia6 == NULL ||		    (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {			*errorp = EADDRNOTAVAIL;			return(NULL);		}		pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */		if (*ifpp)			*ifpp = ifp;		return(&pi->ipi6_addr);	}	/*	 * Otherwise, if the socket has already bound the source, just use it.	 */	if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))		return(laddr);	/*	 * If the address is not specified, choose the best one based on	 * the outgoing interface and the destination address.	 */	/* get the outgoing interface */	if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)		return(NULL);#ifdef MIP6#ifdef MIP6_ALLOW_COA_FALLBACK	for (sc = TAILQ_FIRST(&hif_softc_list);	     sc;	     sc = TAILQ_NEXT(sc, hif_entry)) {		mbu_dst = mip6_bu_list_find_withpaddr(&sc->hif_bu_list, dst);		if (mbu_dst != NULL)			coafallback = mbu_dst->mbu_coafallback;	}#endif /* MIP6_ALLOW_COA_FALLBACK */#endif /* MIP6 */#ifdef DIAGNOSTIC	if (ifp == NULL)	/* this should not happen */		panic("in6_selectsrc: NULL ifp");#endif	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {		int new_scope = -1, new_matchlen = -1;		struct in6_addrpolicy *new_policy = NULL;		int64_t srczone, dstzone;		struct ifnet *ifp1 = ia->ia_ifp;		/*		 * We'll never take an address that breaks the scope zone		 * of the destination.  We also skip an address if its zone		 * does not contain the outgoing interface.		 * XXX: we should probably use sin6_scope_id here.		 */		if ((dstzone = in6_addr2zoneid(ifp1, dst)) < 0 ||		    dstzone != in6_addr2zoneid(ifp, dst)) {			continue;		}		if ((srczone = in6_addr2zoneid(ifp1, &ia->ia_addr.sin6_addr))		    < 0 ||		    srczone != in6_addr2zoneid(ifp, &ia->ia_addr.sin6_addr)) {			continue;		}		/* avoid unusable addresses */		if ((ia->ia6_flags &		     (IN6_IFF_NOTREADY | IN6_IFF_ANYCAST | IN6_IFF_DETACHED))) {				continue;		}		if (!ip6_use_deprecated && IFA6_IS_DEPRECATED(ia))			continue;		/* Rule 1: Prefer same address */		if (IN6_ARE_ADDR_EQUAL(dst, &ia->ia_addr.sin6_addr)) {			ia_best = ia;			BREAK(1); /* there should be no better candidate */		}		if (ia_best == NULL)			REPLACE(0);		/* Rule 2: Prefer appropriate scope */		if (dst_scope < 0)			dst_scope = in6_addrscope(dst);		new_scope = in6_addrscope(&ia->ia_addr.sin6_addr);		if (IN6_ARE_SCOPE_CMP(best_scope, new_scope) < 0) {			if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0)				REPLACE(2);			NEXT(2);		} else if (IN6_ARE_SCOPE_CMP(new_scope, best_scope) < 0) {			if (IN6_ARE_SCOPE_CMP(new_scope, dst_scope) < 0)				NEXT(2);			REPLACE(2);		}		/*		 * Rule 3: Avoid deprecated addresses.  Note that the case of		 * !ip6_use_deprecated is already rejected above.		 */		if (!IFA6_IS_DEPRECATED(ia_best) && IFA6_IS_DEPRECATED(ia))			NEXT(3);		if (IFA6_IS_DEPRECATED(ia_best) && !IFA6_IS_DEPRECATED(ia))			REPLACE(3);		/* Rule 4: Prefer home addresses */		/*		 * XXX: This is a TODO.  We should probably merge the MIP6		 * case above.		 */#ifdef MIP6		/*		 * If SA is simultaneously a home address and care-of address		 * and SB is not, then prefer SA. Similarly, if SB is		 * simultaneously a home address and care-of address and SA is		 * not, then prefer SB.		 */		{			struct mip6_bu *mbu_ia_best = NULL, *mbu_ia = NULL;			if (ia_best->ia6_flags & IN6_IFF_HOME) {				/*				 * find a binding update entry for ia_best.				 */				for (sc = TAILQ_FIRST(&hif_softc_list);				     sc;				     sc = TAILQ_NEXT(sc, hif_entry)) {					mbu_ia_best = mip6_bu_list_find_home_registration(						&sc->hif_bu_list,						&ia->ia_addr.sin6_addr);					if (mbu_ia_best)						break;				}			}			if (ia->ia6_flags & IN6_IFF_HOME) {				/*				 * find a binding update entry for ia.				 */				for (sc = TAILQ_FIRST(&hif_softc_list);				     sc;				     sc = TAILQ_NEXT(sc, hif_entry)) {					mbu_ia = mip6_bu_list_find_home_registration(						&sc->hif_bu_list,						&ia->ia_addr.sin6_addr);					if (mbu_ia)						break;				}			}			/*			 * if the binding update entry for a certain address			 * exists and its registration status is			 * MIP6_BU_REG_STATE_NOTREG, the address is a home			 * address and a care of addres simultaneously.			 */			if ((mbu_ia_best &&			     (mbu_ia_best->mbu_reg_state			      == MIP6_BU_REG_STATE_NOTREG))			    &&			    !(mbu_ia &&			      (mbu_ia->mbu_reg_state			       == MIP6_BU_REG_STATE_NOTREG))) {				NEXT(4);			}			if (!(mbu_ia_best &&			      (mbu_ia_best->mbu_reg_state			       == MIP6_BU_REG_STATE_NOTREG))			    &&			    (mbu_ia &&			     (mbu_ia->mbu_reg_state			      == MIP6_BU_REG_STATE_NOTREG))) {				REPLACE(4);			}		}#ifdef MIP6_ALLOW_COA_FALLBACK		if (coafallback) {			/*			 * if the peer doesn't recognize a home			 * address destination option, we will use a			 * CoA as a source address instead of a home			 * address we have registered before.  Though			 * this behavior may arouse a mip6 beleiver's			 * anger, is very useful in the current			 * transition period that many hosts don't			 * recognize a home address destination			 * option...			 */			if ((ia_best->ia6_flags & IN6_IFF_HOME) == 0 &&			    (ia->ia6_flags & IN6_IFF_HOME) != 0) {				/* XXX will break stat! */				NEXT(0);			}			if ((ia_best->ia6_flags & IN6_IFF_HOME) != 0 &&			    (ia->ia6_flags & IN6_IFF_HOME) == 0) {				/* XXX will break stat! */				REPLACE(0);			}		} else#endif		{			/*			 * If SA is just a home address and SB is just			 * a care-of address, then prefer			 * SA. Similarly, if SB is just a home address			 * and SA is just a care-of address, then			 * prefer SB.			 */			if ((ia_best->ia6_flags & IN6_IFF_HOME) != 0 &&			    (ia->ia6_flags & IN6_IFF_HOME) == 0) {				NEXT(4);			}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?