ip6_mroute.c

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

C
2,032
字号
	origin = mfccp->mf6cc_origin;	mcastgrp = mfccp->mf6cc_mcastgrp;	hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);#ifdef MRT6DEBUG	if (mrt6debug & DEBUG_MFC)		log(LOG_DEBUG,"del_m6fc orig %s mcastgrp %s\n",		    ip6_sprintf(&origin.sin6_addr),		    ip6_sprintf(&mcastgrp.sin6_addr));#endif#ifdef __NetBSD__	s = splsoftnet();#else	s = splnet();#endif	nptr = &mf6ctable[hash];	while ((rt = *nptr) != NULL) {		if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,				       &rt->mf6c_origin.sin6_addr) &&		    IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr,				       &rt->mf6c_mcastgrp.sin6_addr) &&		    rt->mf6c_stall == NULL)			break;		nptr = &rt->mf6c_next;	}	if (rt == NULL) {		splx(s);		return EADDRNOTAVAIL;	}	*nptr = rt->mf6c_next;	free(rt, M_MRTABLE);	splx(s);	return 0;}static intsocket_send(s, mm, src)	struct socket *s;	struct mbuf *mm;	struct sockaddr_in6 *src;{	if (s) {		if (sbappendaddr(&s->so_rcv,				 (struct sockaddr *)src,				 mm, (struct mbuf *)0) != 0) {			sorwakeup(s);			return 0;		}	}	m_freem(mm);	return -1;}/* * IPv6 multicast forwarding function. This function assumes that the packet * pointed to by "ip6" has arrived on (or is about to be sent to) the interface * pointed to by "ifp", and the packet is to be relayed to other networks * that have members of the packet's destination IPv6 multicast group. * * The packet is returned unscathed to the caller, unless it is * erroneous, in which case a non-zero return value tells the caller to * discard it. */intip6_mforward(ip6, ifp, m)	struct ip6_hdr *ip6;	struct ifnet *ifp;	struct mbuf *m;{	struct mf6c *rt;	struct mif6 *mifp;	struct mbuf *mm;	int s;	mifi_t mifi;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)	long time_second = time.tv_sec;#endif#ifdef MRT6DEBUG	if (mrt6debug & DEBUG_FORWARD)		log(LOG_DEBUG, "ip6_mforward: src %s, dst %s, ifindex %d\n",		    ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst),		    ifp->if_index);#endif	/*	 * Don't forward a packet with Hop limit of zero or one,	 * or a packet destined to a local-only group.	 */	if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||	    IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))		return 0;	ip6->ip6_hlim--;	/*	 * Source address check: do not forward packets with unspecified	 * source. It was discussed in July 2000, on ipngwg mailing list.	 * This is rather more serious than unicast cases, because some	 * MLD packets can be sent with the unspecified source address	 * (although such packets must normally set 1 to the hop limit field).	 */	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {		ip6stat.ip6s_cantforward++;		if (ip6_log_time + ip6_log_interval < time_second) {			ip6_log_time = time_second;			log(LOG_DEBUG,			    "cannot forward "			    "from %s to %s nxt %d received on %s\n",			    ip6_sprintf(&ip6->ip6_src),			    ip6_sprintf(&ip6->ip6_dst),			    ip6->ip6_nxt,			    m->m_pkthdr.rcvif ?			    if_name(m->m_pkthdr.rcvif) : "?");		}		return 0;	}	/*	 * Determine forwarding mifs from the forwarding cache table	 */#ifdef __NetBSD__	s = splsoftnet();#else	s = splnet();#endif	MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);	/* Entry exists, so forward if necessary */	if (rt) {		splx(s);		return (ip6_mdq(m, ifp, rt));	} else {		/*		 * If we don't have a route for packet's origin,		 * Make a copy of the packet &		 * send message to routing daemon		 */		struct mbuf *mb0;		struct rtdetq *rte;		u_long hash;/*		int i, npkts;*/#ifdef UPCALL_TIMING		struct timeval tp;		GET_TIME(tp);#endif /* UPCALL_TIMING */		mrt6stat.mrt6s_no_route++;#ifdef MRT6DEBUG		if (mrt6debug & (DEBUG_FORWARD | DEBUG_MFC))			log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n",			    ip6_sprintf(&ip6->ip6_src),			    ip6_sprintf(&ip6->ip6_dst));#endif		/*		 * Allocate mbufs early so that we don't do extra work if we		 * are just going to fail anyway.		 */		rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE,					      M_NOWAIT);		if (rte == NULL) {			splx(s);			return ENOBUFS;		}		mb0 = m_copy(m, 0, M_COPYALL);		/*		 * Pullup packet header if needed before storing it,		 * as other references may modify it in the meantime.		 */		if (mb0 &&		    (M_HASCL(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))			mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));		if (mb0 == NULL) {			free(rte, M_MRTABLE);			splx(s);			return ENOBUFS;		}			/* is there an upcall waiting for this packet? */		hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);		for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {			if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,					       &rt->mf6c_origin.sin6_addr) &&			    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,					       &rt->mf6c_mcastgrp.sin6_addr) &&			    (rt->mf6c_stall != NULL))				break;		}		if (rt == NULL) {			struct mrt6msg *im;#ifdef MRT6_OINIT			struct omrt6msg *oim;#endif			/* no upcall, so make a new entry */			rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,						  M_NOWAIT);			if (rt == NULL) {				free(rte, M_MRTABLE);				m_freem(mb0);				splx(s);				return ENOBUFS;			}			/*			 * Make a copy of the header to send to the user			 * level process			 */			mm = m_copy(mb0, 0, sizeof(struct ip6_hdr));			if (mm == NULL) {				free(rte, M_MRTABLE);				m_freem(mb0);				free(rt, M_MRTABLE);				splx(s);				return ENOBUFS;			}			/*			 * Send message to routing daemon			 */			sin6.sin6_addr = ip6->ip6_src;				im = NULL;#ifdef MRT6_OINIT			oim = NULL;#endif			switch (ip6_mrouter_ver) {#ifdef MRT6_OINIT			case MRT6_OINIT:				oim = mtod(mm, struct omrt6msg *);				oim->im6_msgtype = MRT6MSG_NOCACHE;				oim->im6_mbz = 0;				break;#endif			case MRT6_INIT:				im = mtod(mm, struct mrt6msg *);				im->im6_msgtype = MRT6MSG_NOCACHE;				im->im6_mbz = 0;				break;			default:				free(rte, M_MRTABLE);				m_freem(mb0);				free(rt, M_MRTABLE);				splx(s);				return EINVAL;			}#ifdef MRT6DEBUG			if (mrt6debug & DEBUG_FORWARD)				log(LOG_DEBUG,				    "getting the iif info in the kernel\n");#endif			for (mifp = mif6table, mifi = 0;			     mifi < nummifs && mifp->m6_ifp != ifp;			     mifp++, mifi++)				;			switch (ip6_mrouter_ver) {#ifdef MRT6_OINIT			case MRT6_OINIT:				oim->im6_mif = mifi;				break;#endif			case MRT6_INIT:				im->im6_mif = mifi;				break;			}			if (socket_send(ip6_mrouter, mm, &sin6) < 0) {				log(LOG_WARNING, "ip6_mforward: ip6_mrouter "				    "socket queue full\n");				mrt6stat.mrt6s_upq_sockfull++;				free(rte, M_MRTABLE);				m_freem(mb0);				free(rt, M_MRTABLE);				splx(s);				return ENOBUFS;			}			mrt6stat.mrt6s_upcalls++;			/* insert new entry at head of hash chain */			bzero(rt, sizeof(*rt));			rt->mf6c_origin.sin6_family = AF_INET6;			rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6);			rt->mf6c_origin.sin6_addr = ip6->ip6_src;			rt->mf6c_mcastgrp.sin6_family = AF_INET6;			rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);			rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;			rt->mf6c_expire = UPCALL_EXPIRE;			n6expire[hash]++;			rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;			/* link into table */			rt->mf6c_next  = mf6ctable[hash];			mf6ctable[hash] = rt;			/* Add this entry to the end of the queue */			rt->mf6c_stall = rte;		} else {			/* determine if q has overflowed */			struct rtdetq **p;			int npkts = 0;			for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)				if (++npkts > MAX_UPQ6) {					mrt6stat.mrt6s_upq_ovflw++;					free(rte, M_MRTABLE);					m_freem(mb0);					splx(s);					return 0;				}			/* Add this entry to the end of the queue */			*p = rte;		}		rte->next = NULL;		rte->m = mb0;		rte->ifp = ifp;#ifdef UPCALL_TIMING		rte->t = tp;#endif /* UPCALL_TIMING */		splx(s);		return 0;	}}/* * Clean up cache entries if upcalls are not serviced * Call from the Slow Timeout mechanism, every half second. */static voidexpire_upcalls(unused)	void *unused;{	struct rtdetq *rte;	struct mf6c *mfc, **nptr;	int i;	int s;#ifdef __NetBSD__	s = splsoftnet();#else	s = splnet();#endif	for (i = 0; i < MF6CTBLSIZ; i++) {		if (n6expire[i] == 0)			continue;		nptr = &mf6ctable[i];		while ((mfc = *nptr) != NULL) {			rte = mfc->mf6c_stall;			/*			 * Skip real cache entries			 * Make sure it wasn't marked to not expire (shouldn't happen)			 * If it expires now			 */			if (rte != NULL &&			    mfc->mf6c_expire != 0 &&			    --mfc->mf6c_expire == 0) {#ifdef MRT6DEBUG				if (mrt6debug & DEBUG_EXPIRE)					log(LOG_DEBUG, "expire_upcalls: expiring (%s %s)\n",					    ip6_sprintf(&mfc->mf6c_origin.sin6_addr),					    ip6_sprintf(&mfc->mf6c_mcastgrp.sin6_addr));#endif				/*				 * drop all the packets				 * free the mbuf with the pkt, if, timing info				 */				do {					struct rtdetq *n = rte->next;					m_freem(rte->m);					free(rte, M_MRTABLE);					rte = n;				} while (rte != NULL);				mrt6stat.mrt6s_cache_cleanups++;				n6expire[i]--;				*nptr = mfc->mf6c_next;				free(mfc, M_MRTABLE);			} else {				nptr = &mfc->mf6c_next;			}		}	}	splx(s);#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)	callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,	    expire_upcalls, NULL);#elif defined(__OpenBSD__)	timeout_set(&expire_upcalls_ch, expire_upcalls, NULL);	timeout_add(&expire_upcalls_ch, EXPIRE_TIMEOUT);#else	timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);#endif}/* * Packet forwarding routine once entry in the cache is made */static intip6_mdq(m, ifp, rt)	struct mbuf *m;	struct ifnet *ifp;	struct mf6c *rt;{	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);	mifi_t mifi, iif;	struct mif6 *mifp;	int plen = m->m_pkthdr.len;/* * Macro to send packet on mif.  Since RSVP packets don't get counted on * input, they shouldn't get counted on output, so statistics keeping is * seperate. */#define MC6_SEND(ip6, mifp, m) do {				\		if ((mifp)->m6_flags & MIFF_REGISTER)		\		    register_send((ip6), (mifp), (m));		\		else						\		    phyint_send((ip6), (mifp), (m));		\} while (0)	/*	 * Don't forward if it didn't arrive from the parent mif	 * for its origin.	 */	mifi = rt->mf6c_parent;	if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) {		/* came in the wrong interface */#ifdef MRT6DEBUG		if (mrt6debug & DEBUG_FORWARD)			log(LOG_DEBUG,			    "wrong if: ifid %d mifi %d mififid %x\n",			    ifp->if_index, mifi,			    mif6table[mifi].m6_ifp->if_index);#endif		mrt6stat.mrt6s_wrong_if++;		rt->mf6c_wrong_if++;		/*		 * If we are doing PIM processing, and we are forwarding		 * packets on this interface, send a message to the		 * routing daemon.		 */		/* have to make sure this is a valid mif */		if (mifi < nummifs && mif6table[mifi].m6_ifp)			if (pim6 && (m->m_flags & M_LOOP) == 0) {				/*				 * Check the M_LOOP flag to avoid an				 * unnecessary PIM assert.				 * XXX: M_LOOP is an ad-hoc hack...				 */				static struct sockaddr_in6 sin6 =				{ sizeof(sin6), AF_INET6 };				struct mbuf *mm;				struct mrt6msg *im;#ifdef MRT6_OINIT				struct omrt6msg *oim;#endif				mm = m_copy(m, 0, sizeof(struct ip6_hdr));				if (mm &&				    (M_HASCL(mm) ||				     mm->m_len < sizeof(struct ip6_hdr)))					mm = m_pullup(mm, sizeof(struct ip6_hdr));				if (mm == NULL)					return ENOBUFS;	#ifdef MRT6_OINIT				oim = NULL;#endif				im = NULL;				switch (ip6_mrouter_ver) {#ifdef MRT6_OINIT				case MRT6_OINIT:					oim = mtod(mm, struct omrt6msg *);					oim->im6_msgtype = MRT6MSG_WRONGMIF;					oim->im6_mbz = 0;					break;#endif				case MRT6_INIT:					im = mtod(mm, struct mrt6msg *);					im->im6_msgtype = MRT6MSG_WRONGMIF;					im->im6_mbz = 0;					break;				default:					m_freem(mm);					return EINVAL;				}				for (mifp = mif6table, iif = 0;				     iif < nummifs && mifp &&					     mifp->m6_ifp != ifp;

⌨️ 快捷键说明

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