nd6_nbr.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,526 行 · 第 1/3 页

C
1,526
字号
		nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;		nd_opt->nd_opt_len = optlen >> 3;		bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);	} else		flags &= ~ND_NA_FLAG_OVERRIDE;	ip6->ip6_plen = htons((u_short)icmp6len);	nd_na->nd_na_flags_reserved = flags;	nd_na->nd_na_cksum = 0;	nd_na->nd_na_cksum =		in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);#ifdef IPSEC	/* Don't lookup socket */	(void)ipsec_setsocket(m, NULL);#endif	ip6_output(m, NULL, NULL, 0, &im6o, NULL);	icmp6_ifstat_inc(ifp, ifs6_out_msg);	icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert);	icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;}caddr_tnd6_ifptomac(ifp)	struct ifnet *ifp;{	switch (ifp->if_type) {	case IFT_ARCNET:	case IFT_ETHER:	case IFT_FDDI:	case IFT_IEEE1394:#ifdef IFT_PROPVIRTUAL	case IFT_PROPVIRTUAL:#endif#ifdef IFT_L2VLAN	case IFT_L2VLAN:#endif#ifdef IFT_IEEE80211	case IFT_IEEE80211:#endif#ifdef __NetBSD__		return LLADDR(ifp->if_sadl);#else		return ((caddr_t)(ifp + 1));#endif		break;	default:		return NULL;	}}TAILQ_HEAD(dadq_head, dadq);struct dadq {	TAILQ_ENTRY(dadq) dad_list;	struct ifaddr *dad_ifa;	int dad_count;		/* max NS to send */	int dad_ns_tcount;	/* # of trials to send NS */	int dad_ns_ocount;	/* NS sent so far */	int dad_ns_icount;	int dad_na_icount;#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)	struct callout dad_timer_ch;#elif defined(__OpenBSD__)	struct timeout dad_timer_ch;#endif};static struct dadq_head dadq;static int dad_init = 0;static struct dadq *nd6_dad_find(ifa)	struct ifaddr *ifa;{	struct dadq *dp;	for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) {		if (dp->dad_ifa == ifa)			return dp;	}	return NULL;}static voidnd6_dad_starttimer(dp, _ticks)	struct dadq *dp;	int _ticks;{#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)	callout_reset(&dp->dad_timer_ch, _ticks,	    (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);#elif defined(__OpenBSD__)	timeout_set(&dp->dad_timer_ch, (void (*) __P((void *)))nd6_dad_timer,	    (void *)dp->dad_ifa);	timeout_add(&dp->dad_timer_ch, _ticks);#else	timeout((void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa,	    _ticks);#endif}static voidnd6_dad_stoptimer(dp)	struct dadq *dp;{#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)	callout_stop(&dp->dad_timer_ch);#elif defined(__OpenBSD__)	timeout_del(&dp->dad_timer_ch);#else	untimeout((void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);#endif}/* * Start Duplicated Address Detection (DAD) for specified interface address. */voidnd6_dad_start(ifa, tick)	struct ifaddr *ifa;	int *tick;	/* minimum delay ticks for IFF_UP event */{	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;	struct dadq *dp;        int ntick;	if (!dad_init) {		TAILQ_INIT(&dadq);		dad_init++;	}	/*	 * If we don't need DAD, don't do it.	 * There are several cases:	 * - DAD is disabled (ip6_dad_count == 0)	 * - the interface address is anycast	 */	if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {		log(LOG_DEBUG,			"nd6_dad_start: called with non-tentative address "			"%s(%s)\n",			ip6_sprintf(&ia->ia_addr.sin6_addr),			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");		return;	}	if (ia->ia6_flags & IN6_IFF_ANYCAST) {		ia->ia6_flags &= ~IN6_IFF_TENTATIVE;		return;	}	if (!ip6_dad_count) {		ia->ia6_flags &= ~IN6_IFF_TENTATIVE;		return;	}	if (!ifa->ifa_ifp)		panic("nd6_dad_start: ifa->ifa_ifp == NULL");	if (!(ifa->ifa_ifp->if_flags & IFF_UP))		return;	if (nd6_dad_find(ifa) != NULL) {		/* DAD already in progress */		return;	}	dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);	if (dp == NULL) {		log(LOG_ERR, "nd6_dad_start: memory allocation failed for "			"%s(%s)\n",			ip6_sprintf(&ia->ia_addr.sin6_addr),			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");		return;	}	bzero(dp, sizeof(*dp));#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)	callout_init(&dp->dad_timer_ch);#elif defined(__OpenBSD__)	bzero(&dp->dad_timer_ch, sizeof(dp->dad_timer_ch));#endif	TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);	nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),	    ip6_sprintf(&ia->ia_addr.sin6_addr)));	/*	 * Send NS packet for DAD, ip6_dad_count times.	 * Note that we must delay the first transmission, if this is the	 * first packet to be sent from the interface after interface	 * (re)initialization.	 */	dp->dad_ifa = ifa;	IFAREF(ifa);	/* just for safety */	dp->dad_count = ip6_dad_count;	dp->dad_ns_icount = dp->dad_na_icount = 0;	dp->dad_ns_ocount = dp->dad_ns_tcount = 0;	if (tick == NULL) {		nd6_dad_ns_output(dp, ifa);                ntick = nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000;	} else {#ifdef __OpenBSD__#define random	arc4random#endif		if (*tick == 0)			ntick = random() % (MAX_RTR_SOLICITATION_DELAY * hz);		else			ntick = *tick + random() % (hz / 2);#ifdef __OpenBSD__#undef random#endif		*tick = ntick;	}        if (ntick <= 0) ntick = 1;  // Defensive        nd6_dad_starttimer(dp, ntick);}/* * terminate DAD unconditionally.  used for address removals. */voidnd6_dad_stop(ifa)	struct ifaddr *ifa;{	struct dadq *dp;	if (!dad_init)		return;	dp = nd6_dad_find(ifa);	if (!dp) {		/* DAD wasn't started yet */		return;	}	nd6_dad_stoptimer(dp);	TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);	free(dp, M_IP6NDP);	dp = NULL;	IFAFREE(ifa);}static voidnd6_dad_timer(ifa)	struct ifaddr *ifa;{	int s;	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;	struct dadq *dp;#ifdef __NetBSD__	s = splsoftnet();	/* XXX */#else	s = splnet();		/* XXX */#endif	/* Sanity check */	if (ia == NULL) {		log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");		goto done;	}	dp = nd6_dad_find(ifa);	if (dp == NULL) {		log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");		goto done;	}	if (ia->ia6_flags & IN6_IFF_DUPLICATED) {		log(LOG_ERR, "nd6_dad_timer: called with duplicated address "			"%s(%s)\n",			ip6_sprintf(&ia->ia_addr.sin6_addr),			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");		goto done;	}	if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {		log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "			"%s(%s)\n",			ip6_sprintf(&ia->ia_addr.sin6_addr),			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");		goto done;	}	/* timeouted with IFF_{RUNNING,UP} check */	if (dp->dad_ns_tcount > dad_maxtry) {		nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",			if_name(ifa->ifa_ifp)));		TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);		free(dp, M_IP6NDP);		dp = NULL;		IFAFREE(ifa);		goto done;	}	/* Need more checks? */	if (dp->dad_ns_ocount < dp->dad_count) {		/*		 * We have more NS to go.  Send NS packet for DAD.		 */		nd6_dad_ns_output(dp, ifa);		nd6_dad_starttimer(dp, 		    nd_ifinfo[ifa->ifa_ifp->if_index].retrans * hz / 1000);	} else {		/*		 * We have transmitted sufficient number of DAD packets.		 * See what we've got.		 */		int duplicate;		duplicate = 0;		if (dp->dad_na_icount) {			/*			 * the check is in nd6_dad_na_input(),			 * but just in case			 */			duplicate++;		}		if (dp->dad_ns_icount) {#if 0 /* heuristics */			/*			 * if			 * - we have sent many(?) DAD NS, and			 * - the number of NS we sent equals to the			 *   number of NS we've got, and			 * - we've got no NA			 * we may have a faulty network card/driver which			 * loops back multicasts to myself.			 */			if (3 < dp->dad_count			 && dp->dad_ns_icount == dp->dad_count			 && dp->dad_na_icount == 0) {				log(LOG_INFO, "DAD questionable for %s(%s): "					"network card loops back multicast?\n",					ip6_sprintf(&ia->ia_addr.sin6_addr),					if_name(ifa->ifa_ifp));				/* XXX consider it a duplicate or not? */				/* duplicate++; */			} else {				/* We've seen NS, means DAD has failed. */				duplicate++;			}#else			/* We've seen NS, means DAD has failed. */			duplicate++;#endif		}		if (duplicate) {			/* (*dp) will be freed in nd6_dad_duplicated() */			dp = NULL;			nd6_dad_duplicated(ifa);		} else {			/*			 * We are done with DAD.  No NA came, no NS came.			 * duplicated address found.			 */			ia->ia6_flags &= ~IN6_IFF_TENTATIVE;			nd6log((LOG_DEBUG,			    "%s: DAD complete for %s - no duplicates found\n",			    if_name(ifa->ifa_ifp),			    ip6_sprintf(&ia->ia_addr.sin6_addr)));			TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);			free(dp, M_IP6NDP);			dp = NULL;#ifdef MIP6			if (mip6_dad_success(ifa) == ENOENT)#endif			IFAFREE(ifa);		}	}done:	splx(s);}voidnd6_dad_duplicated(ifa)	struct ifaddr *ifa;{	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;	struct dadq *dp;	dp = nd6_dad_find(ifa);	if (dp == NULL) {		log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");		return;	}	log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "	    "NS in/out=%d/%d, NA in=%d\n",	    if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),	    dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);	ia->ia6_flags &= ~IN6_IFF_TENTATIVE;	ia->ia6_flags |= IN6_IFF_DUPLICATED;	/* We are done with DAD, with duplicated address found. (failure) */	nd6_dad_stoptimer(dp);	log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",	    if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));	log(LOG_ERR, "%s: manual intervention required\n",	    if_name(ifa->ifa_ifp));	TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);	free(dp, M_IP6NDP);	dp = NULL;#ifdef MIP6	if (mip6_dad_duplicated(ifa) == ENOENT)#endif	IFAFREE(ifa);}static voidnd6_dad_ns_output(dp, ifa)	struct dadq *dp;	struct ifaddr *ifa;{	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;	struct ifnet *ifp = ifa->ifa_ifp;	dp->dad_ns_tcount++;	if ((ifp->if_flags & IFF_UP) == 0) {#if 0		printf("%s: interface down?\n", if_name(ifp));#endif		return;	}	if ((ifp->if_flags & IFF_RUNNING) == 0) {#if 0		printf("%s: interface not running?\n", if_name(ifp));#endif		return;	}	dp->dad_ns_ocount++;	nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);}static voidnd6_dad_ns_input(ifa)	struct ifaddr *ifa;{	struct in6_ifaddr *ia;	struct ifnet *ifp;	const struct in6_addr *taddr6;	struct dadq *dp;	int duplicate;	if (!ifa)		panic("ifa == NULL in nd6_dad_ns_input");	ia = (struct in6_ifaddr *)ifa;	ifp = ifa->ifa_ifp;	taddr6 = &ia->ia_addr.sin6_addr;	duplicate = 0;	dp = nd6_dad_find(ifa);	/* Quickhack - completely ignore DAD NS packets */	if (dad_ignore_ns) {		nd6log((LOG_INFO,		    "nd6_dad_ns_input: ignoring DAD NS packet for "		    "address %s(%s)\n", ip6_sprintf(taddr6),		    if_name(ifa->ifa_ifp)));		return;	}	/*	 * if I'm yet to start DAD, someone else started using this address	 * first.  I have a duplicate and you win.	 */	if (!dp || dp->dad_ns_ocount == 0)		duplicate++;	/* XXX more checks for loopback situation - see nd6_dad_timer too */	if (duplicate) {		dp = NULL;	/* will be freed in nd6_dad_duplicated() */		nd6_dad_duplicated(ifa);	} else {		/*		 * not sure if I got a duplicate.		 * increment ns count and see what happens.		 */		if (dp)			dp->dad_ns_icount++;	}}static voidnd6_dad_na_input(ifa)	struct ifaddr *ifa;{	struct dadq *dp;	if (!ifa)		panic("ifa == NULL in nd6_dad_na_input");	dp = nd6_dad_find(ifa);	if (dp)		dp->dad_na_icount++;	/* remove the address. */	nd6_dad_duplicated(ifa);}

⌨️ 快捷键说明

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