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 + -
显示快捷键?