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

📄 in6_ifattach.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				    ip6_sprintf(&mltaddr.sin6_addr), 
				    error));
			}
		}
	}
}

void
in6_nigroup_detach(name, namelen)
	const char *name;
	int namelen;
{
	struct ifnet *ifp;
	struct sockaddr_in6 mltaddr;
	struct in6_multi *in6m;

	bzero(&mltaddr, sizeof(mltaddr));
	mltaddr.sin6_family = AF_INET6;
	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
	if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
		return;

#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
	for (ifp = ifnet; ifp; ifp = ifp->if_next)
#else
	for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next)
#endif
	{
		mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
		IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
		if (in6m)
			in6_delmulti(in6m);
	}
}
#endif

/*
 * XXX multiple loopback interface needs more care.  for instance,
 * nodelocal address needs to be configured onto only one of them.
 * XXX multiple link-local address case
 */
void
in6_ifattach(ifp, altifp)
	struct ifnet *ifp;
	struct ifnet *altifp;	/* secondary EUI64 source */
{
	static size_t if_indexlim = 8;
	struct in6_ifaddr *ia;
	struct in6_addr in6;

	/* some of the interfaces are inherently not IPv6 capable */
	switch (ifp->if_type) {
#ifdef IFT_BRIDGE	/* OpenBSD 2.8 */
	case IFT_BRIDGE:
		return;
#endif
#if defined(__OpenBSD__) || defined(__NetBSD__)
	case IFT_PROPVIRTUAL:
		if (strncmp("bridge", ifp->if_xname, sizeof("bridge")) == 0 &&
		    '0' <= ifp->if_xname[sizeof("bridge")] &&
		    ifp->if_xname[sizeof("bridge")] <= '9')
			return;
		break;
#endif
#ifdef IFT_PFLOG
	case IFT_PFLOG:
		return;
#endif
	}

	/*
	 * We have some arrays that should be indexed by if_index.
	 * since if_index will grow dynamically, they should grow too.
	 *	struct in6_ifstat **in6_ifstat
	 *	struct icmp6_ifstat **icmp6_ifstat
	 */
	if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
	    if_index >= if_indexlim) {
		size_t n;
		caddr_t q;
		size_t olim;

		olim = if_indexlim;
		while (if_index >= if_indexlim)
			if_indexlim <<= 1;

		/* grow in6_ifstat */
		n = if_indexlim * sizeof(struct in6_ifstat *);
		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
		bzero(q, n);
		if (in6_ifstat) {
			bcopy((caddr_t)in6_ifstat, q,
				olim * sizeof(struct in6_ifstat *));
			free((caddr_t)in6_ifstat, M_IFADDR);
		}
		in6_ifstat = (struct in6_ifstat **)q;
		in6_ifstatmax = if_indexlim;

		/* grow icmp6_ifstat */
		n = if_indexlim * sizeof(struct icmp6_ifstat *);
		q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
		bzero(q, n);
		if (icmp6_ifstat) {
			bcopy((caddr_t)icmp6_ifstat, q,
				olim * sizeof(struct icmp6_ifstat *));
			free((caddr_t)icmp6_ifstat, M_IFADDR);
		}
		icmp6_ifstat = (struct icmp6_ifstat **)q;
		icmp6_ifstatmax = if_indexlim;
	}

	/* initialize scope identifiers */
	scope6_ifattach(ifp);

	/* initialize NDP variables */
	nd6_ifattach(ifp);

#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
	/* create a multicast kludge storage (if we have not had one) */
	in6_createmkludge(ifp);
#endif

	/*
	 * quirks based on interface type
	 */
	switch (ifp->if_type) {
#ifdef IFT_STF
	case IFT_STF:
		/*
		 * 6to4 interface is a very special kind of beast.
		 * no multicast, no linklocal.  RFC2529 specifies how to make
		 * linklocals for 6to4 interface, but there's no use and
		 * it is rather harmful to have one.
		 */
		goto statinit;
#endif
	default:
		break;
	}

	/*
	 * usually, we require multicast capability to the interface
	 */
	if ((ifp->if_flags & IFF_MULTICAST) == 0) {
		log(LOG_INFO, "in6_ifattach: "
		    "%s is not multicast capable, IPv6 not enabled\n",
		    if_name(ifp));
		return;
	}

	/*
	 * assign loopback address for loopback interface.
	 * XXX multiple loopback interface case.
	 */
	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
		in6 = in6addr_loopback;
		if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
			if (in6_ifattach_loopback(ifp) != 0)
				return;
		}
	}

	/*
	 * assign a link-local address, if there's none. 
	 */
	if (ip6_auto_linklocal) {
            int s = splnet();
		ia = in6ifa_ifpforlinklocal(ifp, 0);
		if (ia == NULL) {
			if (in6_ifattach_linklocal(ifp, altifp) == 0) {
				/* linklocal address assigned */
			} else {
				/* failed to assign linklocal address. bark? */
			}
		}
                splx(s);
	}

#ifdef IFT_STF			/* XXX */
statinit:	
#endif

	/* update dynamically. */
	if (in6_maxmtu < ifp->if_mtu)
		in6_maxmtu = ifp->if_mtu;

	if (in6_ifstat[ifp->if_index] == NULL) {
		in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
			malloc(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
		bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
	}
	if (icmp6_ifstat[ifp->if_index] == NULL) {
		icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
			malloc(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
		bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
	}
}

/*
 * NOTE: in6_ifdetach() does not support loopback if at this moment.
 * We don't need this function in bsdi, because interfaces are never removed
 * from the ifnet list in bsdi.
 */
#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802)
void
in6_ifdetach(ifp)
	struct ifnet *ifp;
{
	struct in6_ifaddr *ia, *oia;
	struct ifaddr *ifa, *next;
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
	struct ifaddr *ifaprev = NULL;
#endif
	struct rtentry *rt;
	short rtflags;
	struct sockaddr_in6 sin6;
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
	struct in6_multi *in6m, *in6m_next;
#endif
	struct in6_multi_mship *imm;

	/* remove neighbor management table */
	nd6_purge(ifp);

	/* nuke any of IPv6 addresses we have */
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
	for (ifa = ifp->if_addrlist; ifa; ifa = next)
#else
	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
#endif
	{
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
		next = ifa->ifa_next;
#else
		next = ifa->ifa_list.tqe_next;
#endif
		if (ifa->ifa_addr->sa_family != AF_INET6)
			continue;
		in6_purgeaddr(ifa);
	}

	/* undo everything done by in6_ifattach(), just in case */
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
	for (ifa = ifp->if_addrlist; ifa; ifa = next)
#else
	for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
#endif
	{
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
		next = ifa->ifa_next;
#else
		next = ifa->ifa_list.tqe_next;
#endif


		if (ifa->ifa_addr->sa_family != AF_INET6
		 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
			ifaprev = ifa;
#endif
			continue;
		}

		ia = (struct in6_ifaddr *)ifa;

		/*
		 * leave from multicast groups we have joined for the interface
		 */
		while ((imm = ia->ia6_memberships.lh_first) != NULL) {
			LIST_REMOVE(imm, i6mm_chain);
			in6_leavegroup(imm);
		}

		/* remove from the routing table */
		if ((ia->ia_flags & IFA_ROUTE)
		 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0
#ifdef __FreeBSD__
				, 0UL
#endif
				))) {
			rtflags = rt->rt_flags;
			rtfree(rt);
			rtrequest(RTM_DELETE,
				(struct sockaddr *)&ia->ia_addr,
				(struct sockaddr *)&ia->ia_addr,
				(struct sockaddr *)&ia->ia_prefixmask,
				rtflags, (struct rtentry **)0);
		}

		/* remove from the linked list */
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
		if (ifaprev)
			ifaprev->ifa_next = ifa->ifa_next;
		else
			ifp->if_addrlist = ifa->ifa_next;
#else
		TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
#endif
		IFAFREE(&ia->ia_ifa);

		/* also remove from the IPv6 address chain(itojun&jinmei) */
		oia = ia;
		if (oia == (ia = in6_ifaddr))
			in6_ifaddr = ia->ia_next;
		else {
			while (ia->ia_next && (ia->ia_next != oia))
				ia = ia->ia_next;
			if (ia->ia_next)
				ia->ia_next = oia->ia_next;
			else {
				nd6log((LOG_ERR, 
				    "%s: didn't unlink in6ifaddr from "
				    "list\n", if_name(ifp)));
			}
		}

		IFAFREE(&oia->ia_ifa);
	}

#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
	/* leave from all multicast groups joined */

#if (defined(__FreeBSD__) && __FreeBSD__ >= 4)
	in6_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp);
	in6_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp);
#endif

	for (in6m = LIST_FIRST(&in6_multihead); in6m; in6m = in6m_next) {
		in6m_next = LIST_NEXT(in6m, in6m_entry);
		if (in6m->in6m_ifp != ifp)
			continue;
		in6_delmulti(in6m);
		in6m = NULL;
	}
#endif

#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
	/* cleanup multicast address kludge table, if there is any */
	in6_purgemkludge(ifp);
#endif

	/*
	 * remove neighbor management table.  we call it twice just to make
	 * sure we nuke everything.  maybe we need just one call.
	 * XXX: since the first call did not release addresses, some prefixes
	 * might remain.  We should call nd6_purge() again to release the
	 * prefixes after removing all addresses above.
	 * (Or can we just delay calling nd6_purge until at this point?)
	 */
	nd6_purge(ifp);

	/* remove route to link-local allnodes multicast (ff02::1) */
	bzero(&sin6, sizeof(sin6));
	sin6.sin6_len = sizeof(struct sockaddr_in6);
	sin6.sin6_family = AF_INET6;
	sin6.sin6_addr = in6addr_linklocal_allnodes;
	sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
#ifndef __FreeBSD__
	rt = rtalloc1((struct sockaddr *)&sin6, 0);
#else
	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
#endif
	if (rt && rt->rt_ifp == ifp) {
		rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt),
			rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
		rtfree(rt);
	}
}
#endif

int
in6_get_tmpifid(ifp, retbuf, baseid, generate)
	struct ifnet *ifp;
	u_int8_t *retbuf;
	const u_int8_t *baseid;
	int generate;
{
	u_int8_t nullbuf[8];
	struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];

	bzero(nullbuf, sizeof(nullbuf));
	if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
		/* we've never created a random ID.  Create a new one. */
		generate = 1;
	}

	if (generate) {
		bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));

		/* generate_tmp_ifid will update seedn and buf */
		(void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
					ndi->randomid);
	}
	bcopy(ndi->randomid, retbuf, 8);
	if (generate && bcmp(retbuf, nullbuf, sizeof(nullbuf)) == 0) {
		/* generate_tmp_ifid could not found a good ID. */
		return(-1);
	}

	return(0);
}

void
in6_tmpaddrtimer(ignored_arg)
	void *ignored_arg;
{
	int i;
	struct nd_ifinfo *ndi;
	u_int8_t nullbuf[8];
#ifdef __NetBSD__
	int s = splsoftnet();
#else
	int s = splnet();
#endif

#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
	callout_reset(&in6_tmpaddrtimer_ch,
		      (ip6_temp_preferred_lifetime - ip6_desync_factor -
		       ip6_temp_regen_advance) * hz,
		      in6_tmpaddrtimer, NULL);
#elif defined(__OpenBSD__)
	timeout_set(&in6_tmpaddrtimer_ch, in6_tmpaddrtimer, NULL);
	timeout_add(&in6_tmpaddrtimer_ch, 
	    (ip6_temp_preferred_lifetime - ip6_desync_factor -
	    ip6_temp_regen_advance) * hz);
#else
	timeout(in6_tmpaddrtimer, (caddr_t)0,
		(ip6_temp_preferred_lifetime - ip6_desync_factor -
		 ip6_temp_regen_advance) * hz);
#endif

	bzero(nullbuf, sizeof(nullbuf));
	for (i = 1; i < if_index + 1; i++) {
		ndi = &nd_ifinfo[i];
		if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
			/*
			 * We've been generating a random ID on this interface.
			 * Create a new one.
			 */
			(void)generate_tmp_ifid(ndi->randomseed0,
						ndi->randomseed1,
						ndi->randomid);
		}
	}

	splx(s);
}

⌨️ 快捷键说明

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