in6_src.c

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

C
1,336
字号
			if ((ia_best->ia6_flags & IN6_IFF_HOME) == 0 &&			    (ia->ia6_flags & IN6_IFF_HOME) != 0) {				REPLACE(4);			}		}#endif /* MIP6 */		/* Rule 5: Prefer outgoing interface */		if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp)			NEXT(5);		if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp)			REPLACE(5);		/*		 * Rule 6: Prefer matching label		 * Note that best_policy should be non-NULL here.		 */		if (dst_policy == NULL)			dst_policy = lookup_addrsel_policy(dstsock);		if (dst_policy->label != ADDR_LABEL_NOTAPP) {			new_policy = lookup_addrsel_policy(&ia->ia_addr);			if (dst_policy->label == best_policy->label &&			    dst_policy->label != new_policy->label)				NEXT(6);			if (dst_policy->label != best_policy->label &&			    dst_policy->label == new_policy->label)				REPLACE(6);		}		/*		 * Rule 7: Prefer public addresses.		 * We allow users to reverse the logic by configuring		 * a sysctl variable, so that privacy conscious users can		 * always prefer temporary addresses.		 */		if (!(ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&		    (ia->ia6_flags & IN6_IFF_TEMPORARY)) {			if (ip6_prefer_tempaddr)				REPLACE(7);			else				NEXT(7);		}		if ((ia_best->ia6_flags & IN6_IFF_TEMPORARY) &&		    !(ia->ia6_flags & IN6_IFF_TEMPORARY)) {			if (ip6_prefer_tempaddr)				NEXT(7);			else				REPLACE(7);		}		/*		 * Rule 8: prefer addresses on alive interfaces.		 * This is a KAME specific rule.		 */		if ((ia_best->ia_ifp->if_flags & IFF_UP) &&		    !(ia->ia_ifp->if_flags & IFF_UP))			NEXT(8);		if (!(ia_best->ia_ifp->if_flags & IFF_UP) &&		    (ia->ia_ifp->if_flags & IFF_UP))			REPLACE(8);		/*		 * Rule 9: prefer addresses on "preferred" interfaces.		 * This is a KAME specific rule.		 */#define NDI_BEST (nd_ifinfo[ia_best->ia_ifp->if_index])#define NDI_NEW  (nd_ifinfo[ia->ia_ifp->if_index])		if ((NDI_BEST.flags & ND6_IFF_PREFER_SOURCE) &&		    !(NDI_NEW.flags & ND6_IFF_PREFER_SOURCE))			NEXT(9);		if (!(NDI_BEST.flags & ND6_IFF_PREFER_SOURCE) &&		    (NDI_NEW.flags & ND6_IFF_PREFER_SOURCE))			REPLACE(9);#undef NDI_BEST#undef NDI_NEW		/*		 * Rule 14: Use longest matching prefix.		 * Note: in the address selection draft, this rule is		 * documented as "Rule 8".  However, since it is also		 * documented that this rule can be overridden, we assign		 * a large number so that it is easy to assign smaller numbers		 * to more preferred rules.		 */		new_matchlen = in6_matchlen(&ia->ia_addr.sin6_addr, dst);		if (best_matchlen < new_matchlen)			REPLACE(14);		if (new_matchlen < best_matchlen)			NEXT(14);		/* Rule 15 is reserved. */		/*		 * Last resort: just keep the current candidate.		 * Or, do we need more rules?		 */		continue;	  replace:		ia_best = ia;		best_scope = (new_scope >= 0 ? new_scope :			      in6_addrscope(&ia_best->ia_addr.sin6_addr));		best_policy = (new_policy ? new_policy :			       lookup_addrsel_policy(&ia_best->ia_addr));		best_matchlen = (new_matchlen >= 0 ? new_matchlen :				 in6_matchlen(&ia_best->ia_addr.sin6_addr,					      dst));	  next:		continue;	  out:		break;	}	if ((ia = ia_best) == NULL) {		*errorp = EADDRNOTAVAIL;		return(NULL);	}	if (ifpp)		*ifpp = ifp;	return(&ia->ia_addr.sin6_addr);}#undef REPLACE#undef BREAK#undef NEXTstatic intin6_selectif(dstsock, opts, mopts, ro, retifp)	struct sockaddr_in6 *dstsock;	struct ip6_pktopts *opts;	struct ip6_moptions *mopts;#ifdef NEW_STRUCT_ROUTE	struct route *ro;#else	struct route_in6 *ro;#endif	struct ifnet **retifp;{	int error, clone;	struct rtentry *rt = NULL;	clone = IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) ? 0 : 1;	if ((error = in6_selectroute(dstsock, opts, mopts, ro, retifp,				     &rt, clone)) != 0) {		return(error);	}	/*	 * Adjust the "outgoing" interface.  If we're going to loop the packet	 * back to ourselves, the ifp would be the loopback interface.	 * However, we'd rather know the interface associated to the	 * destination address (which should probably be one of our own	 * addresses.)	 */	if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp)		*retifp = rt->rt_ifa->ifa_ifp;	return(0);}intin6_selectroute(dstsock, opts, mopts, ro, retifp, retrt, clone)	struct sockaddr_in6 *dstsock;	struct ip6_pktopts *opts;	struct ip6_moptions *mopts;#ifdef NEW_STRUCT_ROUTE	struct route *ro;#else	struct route_in6 *ro;#endif	struct ifnet **retifp;	struct rtentry **retrt;	int clone;		/* meaningful only for bsdi and freebsd. */{	int error = 0;	struct ifnet *ifp = NULL;	struct rtentry *rt = NULL;	struct sockaddr_in6 *sin6_next;	struct in6_pktinfo *pi = NULL;	struct in6_addr *dst = &dstsock->sin6_addr;	/* If the caller specify the outgoing interface explicitly, use it. */	if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {		/* XXX boundary check is assumed to be already done. */#if defined(__FreeBSD__) && __FreeBSD__ >= 5		ifp = ifnet_byindex(pi->ipi6_ifindex);#else		ifp = ifindex2ifnet[pi->ipi6_ifindex];#endif		if (ifp != NULL &&		    (retrt == NULL || IN6_IS_ADDR_MULTICAST(dst))) {			/*			 * we do not have to check nor get the route for			 * multicast.			 */			goto done;		} else			goto getroute;	}	/*	 * If the destination address is a multicast address and the outgoing	 * interface for the address is specified by the caller, use it.	 */	if (IN6_IS_ADDR_MULTICAST(dst) &&	    mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) {		goto done; /* we do not need a route for multicast. */	}  getroute:	/*	 * If the next hop address for the packet is specified by the caller,	 * use it as the gateway.	 */	if (opts && opts->ip6po_nexthop) {#ifdef NEW_STRUCT_ROUTE		struct route *ron;#else		struct route_in6 *ron;#endif		sin6_next = satosin6(opts->ip6po_nexthop);		/* at this moment, we only support AF_INET6 next hops */		if (sin6_next->sin6_family != AF_INET6) {			error = EAFNOSUPPORT; /* or should we proceed? */			goto done;		}		/*		 * If the next hop is an IPv6 address, then the node identified		 * by that address must be a neighbor of the sending host.		 */		ron = &opts->ip6po_nextroute;		if ((ron->ro_rt &&		     (ron->ro_rt->rt_flags & (RTF_UP | RTF_LLINFO)) !=		     (RTF_UP | RTF_LLINFO)) ||		    !SA6_ARE_ADDR_EQUAL(satosin6(&ron->ro_dst), sin6_next)) {			if (ron->ro_rt) {				RTFREE(ron->ro_rt);				ron->ro_rt = NULL;			}			*satosin6(&ron->ro_dst) = *sin6_next;		}		if (ron->ro_rt == NULL) {			rtalloc((struct route *)ron); /* multi path case? */			if (ron->ro_rt == NULL ||			    !(ron->ro_rt->rt_flags & RTF_LLINFO)) {				if (ron->ro_rt) {					RTFREE(ron->ro_rt);					ron->ro_rt = NULL;				}				error = EHOSTUNREACH;				goto done;			}		}		rt = ron->ro_rt;		ifp = rt->rt_ifp;		/*		 * When cloning is required, try to allocate a route to the		 * destination so that the caller can store path MTU		 * information.		 */		if (!clone)			goto done;	}	/*	 * Use a cached route if it exists and is valid, else try to allocate	 * a new one.	 */	if (ro) {		int newroute = 0;		if (ro->ro_rt &&		    (!(ro->ro_rt->rt_flags & RTF_UP) ||		     !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,					dst))) {			RTFREE(ro->ro_rt);			ro->ro_rt = (struct rtentry *)NULL;		}		if (ro->ro_rt == (struct rtentry *)NULL) {			struct sockaddr_in6 *sa6;			/* No route yet, so try to acquire one */			newroute = 1;			bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));			sa6 = (struct sockaddr_in6 *)&ro->ro_dst;			sa6->sin6_family = AF_INET6;			sa6->sin6_len = sizeof(struct sockaddr_in6);			sa6->sin6_addr = *dst;#ifdef SCOPEDROUTING			sa6->sin6_scope_id = dstsock->sin6_scope_id;#endif			if (clone) {#ifdef __bsdi__				rtcalloc((struct route *)ro);#else  /* !bsdi */#ifdef RADIX_MPATH				rtalloc_mpath((struct route *)ro,				    ntohl(dstsock->sin6_addr.s6_addr32[3]));#else				rtalloc((struct route *)ro);#endif /* RADIX_MPATH */#endif /* bsdi */			} else {#ifdef __FreeBSD__				ro->ro_rt = rtalloc1(&((struct route *)ro)						     ->ro_dst, (int)NULL, 0UL);#else#ifdef RADIX_MPATH				rtalloc_mpath((struct route *)ro,				    ntohl(dstsock->sin6_addr.s6_addr32[3]));#else				ro->ro_rt = rtalloc1(&((struct route *)ro)						     ->ro_dst, NULL);#endif /* RADIX_MPATH */#endif /* __FreeBSD__ */			}		}		/*		 * do not care about the result if we have the nexthop		 * explicitly specified.		 */		if (opts && opts->ip6po_nexthop)			goto done;		if (ro->ro_rt) {			ifp = ro->ro_rt->rt_ifp;			if (ifp == NULL) { /* can this really happen? */				RTFREE(ro->ro_rt);				ro->ro_rt = NULL;			}		}		if (ro->ro_rt == NULL)			error = EHOSTUNREACH;		rt = ro->ro_rt;		/*		 * Check if the outgoing interface conflicts with		 * the interface specified by ipi6_ifindex (if specified).		 * Note that loopback interface is always okay.		 * (this may happen when we are sending a packet to one of		 *  our own addresses.)		 */		if (opts && opts->ip6po_pktinfo		    && opts->ip6po_pktinfo->ipi6_ifindex) {			if (!(ifp->if_flags & IFF_LOOPBACK) &&			    ifp->if_index !=			    opts->ip6po_pktinfo->ipi6_ifindex) {				error = EHOSTUNREACH;				goto done;			}		}	}  done:	if (error == EHOSTUNREACH)		ip6stat.ip6s_noroute++;	if (retifp != NULL)		*retifp = ifp;	if (retrt != NULL)		*retrt = rt;	/* rt may be NULL */		return(error);}/* * Default hop limit selection. The precedence is as follows: * 1. Hoplimit value specified via ioctl. * 2. (If the outgoing interface is detected) the current *     hop limit of the interface specified by router advertisement. * 3. The system default hoplimit.*/#ifdef HAVE_NRL_INPCB#define in6pcb		inpcb#define in6p_hops	inp_hops	#endifintin6_selecthlim(struct in6pcb *in6p, struct ifnet *ifp){	if (in6p && in6p->in6p_hops >= 0)		return(in6p->in6p_hops);	else if (ifp)		return(nd_ifinfo[ifp->if_index].chlim);	else		return(ip6_defhlim);}#ifdef HAVE_NRL_INPCB#undef in6pcb#undef in6p_hops#endif#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__OpenBSD__)/* * Find an empty port and set it to the specified PCB. */#ifdef HAVE_NRL_INPCB	/* XXX: I really hate such ugly macros...(jinmei) */#define in6pcb		inpcb#define in6p_socket	inp_socket#define in6p_lport	inp_lport#define in6p_head	inp_head#define in6p_flags	inp_flags#define IN6PLOOKUP_WILDCARD INPLOOKUP_WILDCARD#endifintin6_pcbsetport(struct in6_addr *laddr, struct in6pcb *in6p){	struct socket *so = in6p->in6p_socket;	struct in6pcb *head = in6p->in6p_head;	u_int16_t last_port, lport = 0;	int wild = 0;	void *t;	u_int16_t min, max;	/* XXX: this is redundant when called from in6_pcbbind */	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&	   ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||	    (so->so_options & SO_ACCEPTCONN) == 0))		wild = IN6PLOOKUP_WILDCARD;	if (in6p->in6p_flags & IN6P_LOWPORT) {		min = ip6_lowportmin;		max = ip6_lowportmax;	} else {		min = ip6_anonportmin;		max = ip6_anonportmax;	}	/* value out of range */	if (head->in6p_lport < min)		head->in6p_lport = min;	else if (head->in6p_lport > max)		head->in6p_lport = min;	last_port = head->in6p_lport;	goto startover;	/*to randomize*/	for (;;) {		lport = htons(head->in6p_lport);		if (IN6_IS_ADDR_V4MAPPED(laddr)) {#ifdef HAVE_NRL_INPCB#ifdef INPLOOKUP_WILDCARD6

⌨️ 快捷键说明

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