⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 in6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	case SIOCCIFPREFIX_IN6:	case SIOCSGIFPREFIX_IN6:	case SIOCGIFPREFIX_IN6:		log(LOG_NOTICE,		    "prefix ioctls are now invalidated. "		    "please use ifconfig.\n");		return(EOPNOTSUPP);	}	switch (cmd) {	case SIOCSSCOPE6:		return(scope6_set(ifp, ifr->ifr_ifru.ifru_scope_id));	case SIOCGSCOPE6:		return(scope6_get(ifp, ifr->ifr_ifru.ifru_scope_id));	case SIOCGSCOPE6DEF:		return(scope6_get_default(ifr->ifr_ifru.ifru_scope_id));	}	switch (cmd) {	case SIOCALIFADDR:	case SIOCDLIFADDR:		/* fall through */	case SIOCGLIFADDR:#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)		return in6_lifaddr_ioctl(so, cmd, data, ifp, p);#else		return in6_lifaddr_ioctl(so, cmd, data, ifp);#endif	}	/*	 * Find address for this interface, if it exists.	 *	 * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation	 * only, and used the first interface address as the target of other	 * operations (without checking ifra_addr).  This was because netinet	 * code/API assumed at most 1 interface address per interface.	 * Since IPv6 allows a node to assign multiple addresses	 * on a single interface, we almost always look and check the	 * presence of ifra_addr, and reject invalid ones here.	 * It also decreases duplicated code among SIOC*_IN6 operations.	 */	switch (cmd) {	case SIOCAIFADDR_IN6:	case SIOCSIFPHYADDR_IN6:		sa6 = &ifra->ifra_addr;		break;	case SIOCSIFADDR_IN6:	case SIOCGIFADDR_IN6:	case SIOCSIFDSTADDR_IN6:	case SIOCSIFNETMASK_IN6:	case SIOCGIFDSTADDR_IN6:	case SIOCGIFNETMASK_IN6:	case SIOCDIFADDR_IN6:	case SIOCGIFPSRCADDR_IN6:	case SIOCGIFPDSTADDR_IN6:	case SIOCGIFAFLAG_IN6:	case SIOCSNDFLUSH_IN6:	case SIOCSPFXFLUSH_IN6:	case SIOCSRTRFLUSH_IN6:	case SIOCGIFALIFETIME_IN6:	case SIOCSIFALIFETIME_IN6:	case SIOCGIFSTAT_IN6:	case SIOCGIFSTAT_ICMP6:		sa6 = &ifr->ifr_addr;		break;	default:		sa6 = NULL;		break;	}	if (sa6 && sa6->sin6_family == AF_INET6) {		if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {			if (sa6->sin6_addr.s6_addr16[1] == 0) {				/* link ID is not embedded by the user */				sa6->sin6_addr.s6_addr16[1] =					htons(ifp->if_index);			} else if (sa6->sin6_addr.s6_addr16[1] !=				    htons(ifp->if_index)) {				return(EINVAL);	/* link ID contradicts */			}			if (sa6->sin6_scope_id) {				if (sa6->sin6_scope_id !=				    (u_int32_t)ifp->if_index)					return(EINVAL);				sa6->sin6_scope_id = 0; /* XXX: good way? */			}		}		ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);	} else		ia = NULL;	switch (cmd) {	case SIOCSIFADDR_IN6:	case SIOCSIFDSTADDR_IN6:	case SIOCSIFNETMASK_IN6:		/*		 * Since IPv6 allows a node to assign multiple addresses		 * on a single interface, SIOCSIFxxx ioctls are deprecated.		 */		return(EINVAL);	case SIOCDIFADDR_IN6:		/*		 * for IPv4, we look for existing in_ifaddr here to allow		 * "ifconfig if0 delete" to remove the first IPv4 address on		 * the interface.  For IPv6, as the spec allows multiple		 * interface address from the day one, we consider "remove the		 * first one" semantics to be not preferable.		 */		if (ia == NULL)			return(EADDRNOTAVAIL);		/* FALLTHROUGH */	case SIOCAIFADDR_IN6:		/*		 * We always require users to specify a valid IPv6 address for		 * the corresponding operation.		 */		if (ifra->ifra_addr.sin6_family != AF_INET6 ||		    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))			return(EAFNOSUPPORT);		break;	case SIOCGIFADDR_IN6:		/* This interface is basically deprecated. use SIOCGIFCONF. */		/* fall through */	case SIOCGIFAFLAG_IN6:	case SIOCGIFNETMASK_IN6:	case SIOCGIFDSTADDR_IN6:	case SIOCGIFALIFETIME_IN6:		/* must think again about its semantics */		if (ia == NULL)			return(EADDRNOTAVAIL);		break;	case SIOCSIFALIFETIME_IN6:	    {		struct in6_addrlifetime *lt;		if (ia == NULL)			return(EADDRNOTAVAIL);		/* sanity for overflow - beware unsigned */		lt = &ifr->ifr_ifru.ifru_lifetime;		if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME		 && lt->ia6t_vltime + time_second < time_second) {			return EINVAL;		}		if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME		 && lt->ia6t_pltime + time_second < time_second) {			return EINVAL;		}		break;	    }	}	switch (cmd) {	case SIOCGIFADDR_IN6:		ifr->ifr_addr = ia->ia_addr;		break;	case SIOCGIFDSTADDR_IN6:		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)			return(EINVAL);		/*		 * XXX: should we check if ifa_dstaddr is NULL and return		 * an error?		 */		ifr->ifr_dstaddr = ia->ia_dstaddr;		break;	case SIOCGIFNETMASK_IN6:		ifr->ifr_addr = ia->ia_prefixmask;		break;	case SIOCGIFAFLAG_IN6:		ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags;		break;	case SIOCGIFSTAT_IN6:		if (ifp == NULL)			return EINVAL;		if (in6_ifstat == NULL || ifp->if_index >= in6_ifstatmax		 || in6_ifstat[ifp->if_index] == NULL) {			/* return EAFNOSUPPORT? */			bzero(&ifr->ifr_ifru.ifru_stat,				sizeof(ifr->ifr_ifru.ifru_stat));		} else			ifr->ifr_ifru.ifru_stat = *in6_ifstat[ifp->if_index];		break;	case SIOCGIFSTAT_ICMP6:		if (ifp == NULL)			return EINVAL;		if (icmp6_ifstat == NULL || ifp->if_index >= icmp6_ifstatmax ||		    icmp6_ifstat[ifp->if_index] == NULL) {			/* return EAFNOSUPPORT? */			bzero(&ifr->ifr_ifru.ifru_stat,				sizeof(ifr->ifr_ifru.ifru_icmp6stat));		} else			ifr->ifr_ifru.ifru_icmp6stat =				*icmp6_ifstat[ifp->if_index];		break;	case SIOCGIFALIFETIME_IN6:		ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime;		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {			time_t maxexpire;			struct in6_addrlifetime *retlt = &ifr->ifr_ifru.ifru_lifetime;			/*			 * XXX: adjust expiration time assuming time_t is			 * signed.			 */			maxexpire = (-1) &				~(1 << ((sizeof(maxexpire) * 8) - 1));			if (ia->ia6_lifetime.ia6t_vltime < 			    maxexpire - ia->ia6_updatetime) {				retlt->ia6t_expire = ia->ia6_updatetime +					ia->ia6_lifetime.ia6t_vltime;			} else				retlt->ia6t_expire = maxexpire;		}		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {			time_t maxexpire;			struct in6_addrlifetime *retlt = &ifr->ifr_ifru.ifru_lifetime;			/*			 * XXX: adjust expiration time assuming time_t is			 * signed.			 */			maxexpire = (-1) &				~(1 << ((sizeof(maxexpire) * 8) - 1));			if (ia->ia6_lifetime.ia6t_pltime < 			    maxexpire - ia->ia6_updatetime) {				retlt->ia6t_preferred = ia->ia6_updatetime +					ia->ia6_lifetime.ia6t_pltime;			} else				retlt->ia6t_preferred = maxexpire;		}		break;	case SIOCSIFALIFETIME_IN6:		ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime;		/* for sanity */		if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {			ia->ia6_lifetime.ia6t_expire =				time_second + ia->ia6_lifetime.ia6t_vltime;		} else			ia->ia6_lifetime.ia6t_expire = 0;		if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {			ia->ia6_lifetime.ia6t_preferred =				time_second + ia->ia6_lifetime.ia6t_pltime;		} else			ia->ia6_lifetime.ia6t_preferred = 0;		break;	case SIOCAIFADDR_IN6:	{		int i, error = 0;		struct nd_prefix pr0, *pr;		/*		 * first, make or update the interface address structure,		 * and link it to the list.		 */		if ((error = in6_update_ifa(ifp, ifra, ia)) != 0)			return(error);		if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))		    == NULL) {		    	/*			 * this can happen when the user specify the 0 valid			 * lifetime.			 */			break;		}		/*		 * then, make the prefix on-link on the interface.		 * XXX: we'd rather create the prefix before the address, but		 * we need at least one address to install the corresponding		 * interface route, so we configure the address first.		 */		/*		 * convert mask to prefix length (prefixmask has already		 * been validated in in6_update_ifa().		 */		bzero(&pr0, sizeof(pr0));		pr0.ndpr_ifp = ifp;		pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,					     NULL);		if (pr0.ndpr_plen == 128)			break;	/* we don't need to install a host route. */		pr0.ndpr_prefix = ifra->ifra_addr;		pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr;		/* apply the mask for safety. */		for (i = 0; i < 4; i++) {			pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=				ifra->ifra_prefixmask.sin6_addr.s6_addr32[i];		}		/*		 * XXX: since we don't have an API to set prefix (not address)		 * lifetimes, we just use the same lifetimes as addresses.		 * The (temporarily) installed lifetimes can be overridden by		 * later advertised RAs (when accept_rtadv is non 0), which is		 * an intended behavior.		 */		pr0.ndpr_raf_onlink = 1; /* should be configurable? */		pr0.ndpr_raf_auto =			((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);		pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;		pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;		/* add the prefix if there's one. */		if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {			/*			 * nd6_prelist_add will install the corresponding			 * interface route.			 */			if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)				return(error);			if (pr == NULL) {				log(LOG_ERR, "nd6_prelist_add succeeded but "				    "no prefix\n");				return(EINVAL); /* XXX panic here? */			}		}		if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&		    ia->ia6_ndpr == NULL) { /* new autoconfed addr */			ia->ia6_ndpr = pr;			pr->ndpr_refcnt++;			/*			 * If this is the first autoconf address from			 * the prefix, create a temporary address			 * as well (when specified).			 */			if (ip6_use_tempaddr && pr->ndpr_refcnt == 1) {				int e;				if ((e = in6_tmpifadd(ia, 1)) != 0) {					log(LOG_NOTICE, "in6_control: failed "					    "to create a temporary address, "					    "errno=%d\n",					    e);				}			}		}		/*		 * this might affect the status of autoconfigured addresses,		 * that is, this address might make other addresses detached.		 */		pfxlist_onlink_check();		break;	}	case SIOCDIFADDR_IN6:	{		int i = 0, purgeprefix = 0;		struct nd_prefix pr0, *pr = NULL;		/*		 * If the address being deleted is the only one that owns		 * the corresponding prefix, expire the prefix as well.		 * XXX: theoretically, we don't have to worry about such		 * relationship, since we separate the address management		 * and the prefix management.  We do this, however, to provide		 * as much backward compatibility as possible in terms of		 * the ioctl operation.		 */		bzero(&pr0, sizeof(pr0));		pr0.ndpr_ifp = ifp;		pr0.ndpr_plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr,					     NULL);		if (pr0.ndpr_plen == 128)			goto purgeaddr;		pr0.ndpr_prefix = ia->ia_addr;		pr0.ndpr_mask = ia->ia_prefixmask.sin6_addr;		for (i = 0; i < 4; i++) {			pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=				ia->ia_prefixmask.sin6_addr.s6_addr32[i];		}		/*		 * The logic of the following condition is a bit complicated.		 * We expire the prefix when		 * 1. the address obeys autoconfiguration and it is the		 *    only owner of the associated prefix, or		 * 2. the address does not obey autoconf and there is no		 *    other owner of the prefix.		 */		if ((pr = nd6_prefix_lookup(&pr0)) != NULL &&		    (((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0 &&		      pr->ndpr_refcnt == 1) ||		     ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0 &&		      pr->ndpr_refcnt == 0)))			purgeprefix = 1;	  purgeaddr:		in6_purgeaddr(&ia->ia_ifa);		if (pr && purgeprefix)			prelist_remove(pr);		break;	}	default:		if (ifp == NULL || ifp->if_ioctl == 0)			return(EOPNOTSUPP);		return((*ifp->if_ioctl)(ifp, cmd, data));	}	return(0);}#ifdef __ECOSextern void _show_ifp(struct ifnet *ifp);#endif/* * Update parameters of an IPv6 interface address. * If necessary, a new entry is created and linked into address chains. * This function is separated from in6_control(). * XXX: should this be performed under splnet()? */static int_in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,                struct in6_ifaddr *ia){	int error = 0, hostIsNew = 0, plen = -1;	struct in6_ifaddr *oia;#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)	struct ifaddr *ifa;#endif	struct sockaddr_in6 dst6;	struct in6_addrlifetime *lt;	struct in6_multi_mship *imm;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)	time_t time_second = (time_t)time.tv_sec;#endif#ifdef MEASURE_PERFORMANCE	int new_ifa = 0;#endif	struct rtentry *rt;	/* Validate parameters */	if (ifp == NULL || ifra == NULL) /* this maybe redundant */		return(EINVAL);	/*	 * The destination address for a p2p link must have a family	 * of AF_UNSPEC or AF_INET6.	 */	if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&	    ifra->ifra_dstaddr.sin6_family != AF_INET6 &&	    ifra->ifra_dstaddr.sin6_family != AF_UNSPEC)		return(EAFNOSUPPORT);	/*	 * validate ifra_prefixmask.  don't check sin6_family, netmask	 * does not carry fields other than sin6_len.	 */	if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6))		return(EINVAL);	/*	 * Because the IPv6 address architecture is classless, we require	 * users to specify a (non 0) prefix length (mask) for a new address.	 * We also require the prefix (when specified) mask is valid, and thus	 * reject a non-consecutive mask.	 */	if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0)		return(EINVAL);	if (ifra->ifra_prefixmask.sin6_len != 0) {		plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,				    (u_char *)&ifra->ifra_prefixmask +				    ifra->ifra_prefixmask.sin6_len);		if (plen <= 0)			return(EINVAL);	}	else {		/*		 * In this case, ia must not be NULL.  We just use its prefix		 * length.		 */

⌨️ 快捷键说明

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