FreeBSD/sys/netinet6/in6.c
/*
 * return the best address out of the same scope. if no address was
 * found, return the first valid address from designated IF.
 */
return the best address out of the same scope. if no address was
found, return the first valid address from designated IF.
return the best address out of the same scope . if no address was found return the first valid address from designated IF .
struct in6_ifaddr *
in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
{
	int dst_scope =	in6_addrscope(dst), blen = -1, tlen;
	struct ifaddr *ifa;
	struct in6_ifaddr *besta = NULL;
	struct in6_ifaddr *dep[2];	
	dep[0] = dep[1] = NULL;
	IF_ADDR_RLOCK(ifp);
	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
		if (ifa->ifa_addr->sa_family != AF_INET6)
			continue;
		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
			continue; 
		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
			continue; 
		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
			continue;
		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
			if (V_ip6_use_deprecated)
				dep[0] = (struct in6_ifaddr *)ifa;
			continue;
		}
		if (dst_scope == in6_addrscope(IFA_IN6(ifa))) {
			if (besta) {
				if (blen == -1)
					blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst);
				tlen = in6_matchlen(IFA_IN6(ifa), dst);
				if (tlen > blen) {
					blen = tlen;
					besta = (struct in6_ifaddr *)ifa;
				}
			} else
				besta = (struct in6_ifaddr *)ifa;
		}
	}
	if (besta) {
		ifa_ref(&besta->ia_ifa);
		IF_ADDR_RUNLOCK(ifp);
		return (besta);
	}
	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
		if (ifa->ifa_addr->sa_family != AF_INET6)
			continue;
		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST)
			continue; 
		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY)
			continue; 
		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED)
			continue;
		if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) {
			if (V_ip6_use_deprecated)
				dep[1] = (struct in6_ifaddr *)ifa;
			continue;
		}
		if (ifa != NULL)
			ifa_ref(ifa);
		IF_ADDR_RUNLOCK(ifp);
		return (struct in6_ifaddr *)ifa;
	}
	if (dep[0]) {
		ifa_ref((struct ifaddr *)dep[0]);
		IF_ADDR_RUNLOCK(ifp);
		return dep[0];
	}
	if (dep[1]) {
		ifa_ref((struct ifaddr *)dep[1]);
		IF_ADDR_RUNLOCK(ifp);
		return dep[1];
	}
	IF_ADDR_RUNLOCK(ifp);
	return NULL;
}
struct in6_ifaddr * in6_ifawithifp ( struct ifnet * ifp , struct in6_addr * dst ) { int dst_scope = in6_addrscope ( dst ) , blen = -1 , tlen ; struct ifaddr * ifa ; struct in6_ifaddr * besta = NULL ; struct in6_ifaddr * dep [ 2 ] ; dep [ 0 ] = dep [ 1 ] = NULL ; IF_ADDR_RLOCK ( ifp ) ; TAILQ_FOREACH ( ifa , & ifp -> if_addrhead , ifa_link ) { if ( ifa -> ifa_addr -> sa_family != AF_INET6 ) continue ; if ( ( ( struct in6_ifaddr * ) ifa ) -> ia6_flags & IN6_IFF_ANYCAST ) continue ; if ( ( ( struct in6_ifaddr * ) ifa ) -> ia6_flags & IN6_IFF_NOTREADY ) continue ; if ( ( ( struct in6_ifaddr * ) ifa ) -> ia6_flags & IN6_IFF_DETACHED ) continue ; if ( ( ( struct in6_ifaddr * ) ifa ) -> ia6_flags & IN6_IFF_DEPRECATED ) { if ( V_ip6_use_deprecated ) dep [ 0 ] = ( struct in6_ifaddr * ) ifa ; continue ; } if ( dst_scope == in6_addrscope ( IFA_IN6 ( ifa ) ) ) { if ( besta ) { if ( blen == -1 ) blen = in6_matchlen ( & besta -> ia_addr . sin6_addr , dst ) ; tlen = in6_matchlen ( IFA_IN6 ( ifa ) , dst ) ; if ( tlen > blen ) { blen = tlen ; besta = ( struct in6_ifaddr * ) ifa ; } } else besta = ( struct in6_ifaddr * ) ifa ; } } if ( besta ) { ifa_ref ( & besta -> ia_ifa ) ; IF_ADDR_RUNLOCK ( ifp ) ; return ( besta ) ; } TAILQ_FOREACH ( ifa , & ifp -> if_addrhead , ifa_link ) { if ( ifa -> ifa_addr -> sa_family != AF_INET6 ) continue ; if ( ( ( struct in6_ifaddr * ) ifa ) -> ia6_flags & IN6_IFF_ANYCAST ) continue ; if ( ( ( struct in6_ifaddr * ) ifa ) -> ia6_flags & IN6_IFF_NOTREADY ) continue ; if ( ( ( struct in6_ifaddr * ) ifa ) -> ia6_flags & IN6_IFF_DETACHED ) continue ; if ( ( ( struct in6_ifaddr * ) ifa ) -> ia6_flags & IN6_IFF_DEPRECATED ) { if ( V_ip6_use_deprecated ) dep [ 1 ] = ( struct in6_ifaddr * ) ifa ; continue ; } if ( ifa != NULL ) ifa_ref ( ifa ) ; IF_ADDR_RUNLOCK ( ifp ) ; return ( struct in6_ifaddr * ) ifa ; } if ( dep [ 0 ] ) { ifa_ref ( ( struct ifaddr * ) dep [ 0 ] ) ; IF_ADDR_RUNLOCK ( ifp ) ; return dep [ 0 ] ; } if ( dep [ 1 ] ) { ifa_ref ( ( struct ifaddr * ) dep [ 1 ] ) ; IF_ADDR_RUNLOCK ( ifp ) ; return dep [ 1 ] ; } IF_ADDR_RUNLOCK ( ifp ) ; return NULL ; }
return the best address out of the same scope.
return the best address out of the same scope .
/* last-resort: deprecated */ /*
	 * We first look for addresses in the same scope.
	 * If there is one, return it.
	 * If two or more, return one which matches the dst longest.
	 * If none, return one of global addresses assigned other ifs.
	 */ /* XXX: is there any case to allow anycast? */ /* don't use this interface */ /*
			 * call in6_matchlen() as few as possible
			 */ /* XXX: is there any case to allow anycast? */ /* don't use this interface */ /* use the last-resort values, that are, deprecated addresses */