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

📄 in6.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#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.
		 */
		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);

⌨️ 快捷键说明

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