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

📄 in6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL);	}	/*	 * If the destination address on a p2p interface is specified,	 * and the address is a scoped one, validate/set the scope	 * zone identifier.	 */	dst6 = ifra->ifra_dstaddr;	if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) &&	    (dst6.sin6_family == AF_INET6)) {		int64_t zoneid;#ifndef SCOPEDROUTING		if ((error = in6_recoverscope(&dst6,					      &ifra->ifra_dstaddr.sin6_addr,					      ifp)) != 0)			return(error);#endif		if ((zoneid = in6_addr2zoneid(ifp, &dst6.sin6_addr)) < 0)			return(EINVAL);		if (dst6.sin6_scope_id == 0) /* user omit to specify the ID. */			dst6.sin6_scope_id = zoneid;		else if (dst6.sin6_scope_id != zoneid)			return(EINVAL); /* scope ID mismatch. */		if ((error = in6_embedscope(&dst6.sin6_addr, &dst6)) != 0)			return(error);#ifndef SCOPEDROUTING		dst6.sin6_scope_id = 0; /* XXX */#endif	}	/*	 * The destination address can be specified only for a p2p or a	 * loopback interface.  If specified, the corresponding prefix length	 * must be 128.	 */	if (ifra->ifra_dstaddr.sin6_family == AF_INET6) {#ifdef FORCE_P2PPLEN		int i;#endif		if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) {			/* XXX: noisy message */			log(LOG_INFO, "in6_update_ifa: a destination can be "			    "specified for a p2p or a loopback IF only\n");			return(EINVAL);		}		if (plen != 128) {			log(LOG_INFO, "in6_update_ifa: prefixlen should be "			    "128 when dstaddr is specified\n");#ifdef FORCE_P2PPLEN			/*			 * To be compatible with old configurations,			 * such as ifconfig gif0 inet6 2001::1 2001::2			 * prefixlen 126, we override the specified			 * prefixmask as if the prefix length was 128.			 */			ifra->ifra_prefixmask.sin6_len				= sizeof(struct sockaddr_in6); 			for (i = 0; i < 4; i++)				ifra->ifra_prefixmask.sin6_addr.s6_addr32[i] =					0xffffffff;			plen = 128;#else			return(EINVAL);#endif		}	}	/* lifetime consistency check */	lt = &ifra->ifra_lifetime;	if (lt->ia6t_pltime > lt->ia6t_vltime)		return(EINVAL);	if (lt->ia6t_vltime == 0) {		/*		 * the following log might be noisy, but this is a typical		 * configuration mistake or a tool's bug.		 */		log(LOG_INFO,		    "in6_update_ifa: valid lifetime is 0 for %s\n",		    ip6_sprintf(&ifra->ifra_addr.sin6_addr));		if (ia == NULL)			return(0); /* there's nothing to do */	}	/*	 * If this is a new address, allocate a new ifaddr and link it	 * into chains.	 */	if (ia == NULL) {		hostIsNew = 1;		/*		 * When in6_update_ifa() is called in a process of a received		 * RA, it is called under an interrupt context.  So, we should		 * call malloc with M_NOWAIT.		 */		ia = (struct in6_ifaddr *)			malloc(sizeof(*ia), M_IFADDR, M_NOWAIT);		if (ia == NULL)			return (ENOBUFS);		bzero((caddr_t)ia, sizeof(*ia));		LIST_INIT(&ia->ia6_memberships);		/* Initialize the address and masks, and put time stamp */		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;		ia->ia_addr.sin6_family = AF_INET6;		ia->ia_addr.sin6_len = sizeof(ia->ia_addr);		ia->ia6_createtime = ia->ia6_updatetime = time_second;		if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) {			/*			 * XXX: some functions expect that ifa_dstaddr is not			 * NULL for p2p interfaces.			 */			ia->ia_ifa.ifa_dstaddr				= (struct sockaddr *)&ia->ia_dstaddr;		} else {			ia->ia_ifa.ifa_dstaddr = NULL;		}		ia->ia_ifa.ifa_netmask			= (struct sockaddr *)&ia->ia_prefixmask;		ia->ia_ifp = ifp;		if ((oia = in6_ifaddr) != NULL) {			for ( ; oia->ia_next; oia = oia->ia_next)				continue;			oia->ia_next = ia;		} else			in6_ifaddr = ia;#ifdef __NetBSD__		/* gain a refcnt for the link from in6_ifaddr */		IFAREF(&ia->ia_ifa);#endif#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)		if ((ifa = ifp->if_addrlist) != NULL) {			for ( ; ifa->ifa_next; ifa = ifa->ifa_next)				continue;			ifa->ifa_next = ia62ifa(ia);		} else			ifp->if_addrlist = ia62ifa(ia);#else		TAILQ_INSERT_TAIL(&ifp->if_addrlist, &ia->ia_ifa,				  ifa_list);                log_(LOG_ADDR) {                    diag_printf("%s.%d - After inserting %p into list %p\n",                                 __FUNCTION__, __LINE__,                                &ia->ia_ifa, &ifp->if_addrlist);                    _show_ifp(ifp);                }#endif#ifdef __NetBSD__		/* gain another refcnt for the link from if_addrlist */		IFAREF(&ia->ia_ifa);#endif#ifdef MEASURE_PERFORMANCE		new_ifa = 1;#endif	}	/* set prefix mask */	if (ifra->ifra_prefixmask.sin6_len) {		/*		 * We prohibit changing the prefix length of an existing		 * address, because		 * + such an operation should be rare in IPv6, and		 * + the operation would confuse prefix management.		 */		if (ia->ia_prefixmask.sin6_len &&		    in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) {			log(LOG_INFO, "in6_update_ifa: the prefix length of an"			    " existing (%s) address should not be changed\n",			    ip6_sprintf(&ia->ia_addr.sin6_addr));			error = EINVAL;			goto unlink;		}		ia->ia_prefixmask = ifra->ifra_prefixmask;	}	/*	 * If a new destination address is specified, scrub the old one and	 * install the new destination.  Note that the interface must be	 * p2p or loopback (see the check above.) 	 */	if (dst6.sin6_family == AF_INET6 &&	    !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr,				&ia->ia_dstaddr.sin6_addr)) {		int e;		if ((ia->ia_flags & IFA_ROUTE) != 0 &&		    (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST))		    != 0) {			log(LOG_ERR, "in6_update_ifa: failed to remove "			    "a route to the old destination: %s\n",			    ip6_sprintf(&ia->ia_addr.sin6_addr));			/* proceed anyway... */		}		else			ia->ia_flags &= ~IFA_ROUTE;		ia->ia_dstaddr = dst6;	}	/*	 * Set lifetimes.  We do not refer to ia6t_expire and ia6t_preferred	 * to see if the address is deprecated or invalidated, but initialize	 * these members for applications.	 */	ia->ia6_lifetime = ifra->ifra_lifetime;	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;	/* reset the interface and routing table appropriately. */	if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)		goto unlink;	/*	 * Make the address tentative before joining multicast addresses,	 * so that corresponding MLD responses would not have a tentative	 * source address.	 */	ia->ia6_flags = ifra->ifra_flags;	ia->ia6_flags &= ~IN6_IFF_DUPLICATED;	/* safety */#ifdef MIP6	if (hostIsNew && in6if_do_dad(ifp) && mip6_ifa_need_dad(ia))#else /* MIP6 */	if (hostIsNew && in6if_do_dad(ifp))#endif /* MIP6 */		ia->ia6_flags |= IN6_IFF_TENTATIVE;	/*	 * Beyond this point, we should call in6_purgeaddr upon an error,	 * not just go to unlink. 	 */	if ((ifp->if_flags & IFF_MULTICAST) != 0) {		struct sockaddr_in6 mltaddr, mltmask;		if (hostIsNew) {			/*			 * join solicited multicast addr for new host id			 */			struct in6_addr llsol;			bzero(&llsol, sizeof(struct in6_addr));			llsol.s6_addr16[0] = htons(0xff02);			llsol.s6_addr16[1] = htons(ifp->if_index);			llsol.s6_addr32[1] = 0;			llsol.s6_addr32[2] = htonl(1);			llsol.s6_addr32[3] =				ifra->ifra_addr.sin6_addr.s6_addr32[3];			llsol.s6_addr8[12] = 0xff;			imm = in6_joingroup(ifp, &llsol, &error);			if (imm) {				LIST_INSERT_HEAD(&ia->ia6_memberships, imm,				    i6mm_chain);			} else {				log(LOG_ERR,				    "in6_update_ifa: addmulti failed for "				    "%s on %s (errno=%d)\n",				    ip6_sprintf(&llsol), 				    if_name(ifp), error);				goto cleanup;			}		}		bzero(&mltmask, sizeof(mltmask));		mltmask.sin6_len = sizeof(struct sockaddr_in6);		mltmask.sin6_family = AF_INET6;		mltmask.sin6_addr = in6mask32;		/*		 * join link-local all-nodes address		 */		bzero(&mltaddr, sizeof(mltaddr));		mltaddr.sin6_len = sizeof(struct sockaddr_in6);		mltaddr.sin6_family = AF_INET6;		mltaddr.sin6_addr = in6addr_linklocal_allnodes;		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);#ifdef __FreeBSD__		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);#else		rt = rtalloc1((struct sockaddr *)&mltaddr, 0);#endif		if (rt) {			/* 32bit came from "mltmask" */			if (memcmp(&mltaddr.sin6_addr,			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,			    32 / 8)) {				RTFREE(rt);				rt = NULL;			}		}		if (!rt) {#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)			struct rt_addrinfo info;			bzero(&info, sizeof(info));			info.rti_info[RTAX_DST] = (struct sockaddr *)&mltaddr;			info.rti_info[RTAX_GATEWAY] =				(struct sockaddr *)&ia->ia_addr;			info.rti_info[RTAX_NETMASK] =				(struct sockaddr *)&mltmask;			info.rti_info[RTAX_IFA] =				(struct sockaddr *)&ia->ia_addr;			/* XXX: we need RTF_CLONING to fake nd6_rtrequest */			info.rti_flags = RTF_UP | RTF_CLONING;			error = rtrequest1(RTM_ADD, &info, NULL);#else			error = rtrequest(RTM_ADD,					  (struct sockaddr *)&mltaddr,					  (struct sockaddr *)&ia->ia_addr,					  (struct sockaddr *)&mltmask,					  RTF_UP | RTF_CLONING,					  (struct rtentry **)0);#endif			if (error)				goto cleanup;		} else {			RTFREE(rt);		}		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);		if (imm) {			LIST_INSERT_HEAD(&ia->ia6_memberships, imm,			    i6mm_chain);		} else {			log(LOG_WARNING,			    "in6_update_ifa: addmulti failed for "			    "%s on %s (errno=%d)\n",			    ip6_sprintf(&mltaddr.sin6_addr), 			    if_name(ifp), error);			goto cleanup;		}		/*		 * join node information group address		 */#ifdef __FreeBSD__#define hostnamelen	strlen(hostname)#endif		if (in6_nigroup(ifp, hostname, hostnamelen, &mltaddr.sin6_addr)		    == 0) {			imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);			if (imm) {				LIST_INSERT_HEAD(&ia->ia6_memberships, imm,				    i6mm_chain);			} else {				log(LOG_WARNING, "in6_update_ifa: "				    "addmulti failed for "				    "%s on %s (errno=%d)\n",				    ip6_sprintf(&mltaddr.sin6_addr), 				    if_name(ifp), error);				/* XXX not very fatal, go on... */			}		}#ifdef __FreeBSD__#undef hostnamelen#endif		/*		 * join interface-local all-nodes address, on loopback.		 * (ff01::1%ifN, and ff01::%ifN/32)		 */		mltaddr.sin6_addr = in6addr_nodelocal_allnodes;		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);#ifdef __FreeBSD__		rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);#else		rt = rtalloc1((struct sockaddr *)&mltaddr, 0);#endif		if (rt) {			/* 32bit came from "mltmask" */			if (memcmp(&mltaddr.sin6_addr,			    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,			    32 / 8)) {				RTFREE(rt);				rt = NULL;			}		}		if (!rt) {#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)			struct rt_addrinfo info;			bzero(&info, sizeof(info));			info.rti_info[RTAX_DST] = (struct sockaddr *)&mltaddr;			info.rti_info[RTAX_GATEWAY] =				(struct sockaddr *)&ia->ia_addr;			info.rti_info[RTAX_NETMASK] =				(struct sockaddr *)&mltmask;			info.rti_info[RTAX_IFA] =				(struct sockaddr *)&ia->ia_addr;			info.rti_flags = RTF_UP | RTF_CLONING;			error = rtrequest1(RTM_ADD, &info, NULL);#else			error = rtrequest(RTM_ADD,					  (struct sockaddr *)&mltaddr,					  (struct sockaddr *)&ia->ia_addr,					  (struct sockaddr *)&mltmask,					  RTF_UP | RTF_CLONING,					  (struct rtentry **)0);#endif			if (error)				goto cleanup;		} else {			RTFREE(rt);		}		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error);		if (imm) {			LIST_INSERT_HEAD(&ia->ia6_memberships, imm,			    i6mm_chain);		} else {			log(LOG_WARNING, "in6_update_ifa: "			    "addmulti failed for %s on %s "			    "(errno=%d)\n",			    ip6_sprintf(&mltaddr.sin6_addr), 			    if_name(ifp), error);			goto cleanup;		}	}#ifdef MEASURE_PERFORMANCE	{		int s = splnet();		if (new_ifa)			in6h_addifa(ia);		else			in6h_rebuild(0);		splx(s);	}#endif	/*	 * make sure to initialize ND6 information.  this is to workaround	 * issues with interfaces with IPv6 addresses, which have never brought	 * up.  We are assuming that it is safe to nd6_ifattach multiple times.	 */	nd6_ifattach(ifp);	/*	 * Perform DAD, if needed.	 * XXX It may be of use, if we can administratively	 * disable DAD.	 */#ifdef MIP6	if (hostIsNew && in6if_do_dad(ifp) && mip6_ifa_need_dad(ia) &&	    (ifra->ifra_flags & IN6_IFF_NODAD) == 0)#else /* MIP6 */	if (hostIsNew && in6if_do_dad(ifp) &&	    (ifra->ifra_flags & IN6_IFF_NODAD) == 0)#endif /* MIP6 */	{		nd6_dad_start((struct ifaddr *)ia, NULL);	}	return(error);  unlink:	/*	 * XXX: if a change of an existing address failed, keep the entry	 * anyway.	 */	if (hostIsNew)		in6_unlink_ifa(ia, ifp);	return(error);  cleanup:	in6_purgeaddr(&ia->ia_ifa);	return error;}voidin6_purgeaddr(ifa)	struct ifaddr *ifa;{	struct ifnet *ifp = ifa->ifa_ifp;	struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;

⌨️ 快捷键说明

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