ip6_mroute.c

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

C
2,032
字号
				     mifp++, iif++)					;				switch (ip6_mrouter_ver) {#ifdef MRT6_OINIT				case MRT6_OINIT:					oim->im6_mif = iif;					sin6.sin6_addr = oim->im6_src;					break;#endif				case MRT6_INIT:					im->im6_mif = iif;					sin6.sin6_addr = im->im6_src;					break;				}				mrt6stat.mrt6s_upcalls++;				if (socket_send(ip6_mrouter, mm, &sin6) < 0) {#ifdef MRT6DEBUG					if (mrt6debug)						log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");#endif					++mrt6stat.mrt6s_upq_sockfull;					return ENOBUFS;				}	/* if socket Q full */			}		/* if PIM */		return 0;	}			/* if wrong iif */	/* If I sourced this packet, it counts as output, else it was input. */	if (m->m_pkthdr.rcvif == NULL) {		/* XXX: is rcvif really NULL when output?? */		mif6table[mifi].m6_pkt_out++;		mif6table[mifi].m6_bytes_out += plen;	} else {		mif6table[mifi].m6_pkt_in++;		mif6table[mifi].m6_bytes_in += plen;	}	rt->mf6c_pkt_cnt++;	rt->mf6c_byte_cnt += plen;	/*	 * For each mif, forward a copy of the packet if there are group	 * members downstream on the interface.	 */	for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++)		if (IF_ISSET(mifi, &rt->mf6c_ifset)) {			int64_t dscopein, sscopein, dscopeout, sscopeout;			/*			 * check if the outgoing packet is going to break			 * a scope boundary.			 * XXX For packets through PIM register tunnel			 * interface, we believe a routing daemon.			 */			if ((mif6table[rt->mf6c_parent].m6_flags &			     MIFF_REGISTER) == 0 &&			    (mif6table[mifi].m6_flags & MIFF_REGISTER) == 0) {				if ((dscopein = in6_addr2zoneid(ifp, &ip6->ip6_dst)) < 0 ||				    (dscopeout = in6_addr2zoneid(mif6table[mifi].m6_ifp, &ip6->ip6_dst)) < 0 ||				    (sscopein = in6_addr2zoneid(ifp, &ip6->ip6_src)) < 0 ||				    (sscopeout = in6_addr2zoneid(mif6table[mifi].m6_ifp, &ip6->ip6_src)) < 0 ||				    dscopein != dscopeout ||				    sscopein != sscopeout) {					ip6stat.ip6s_badscope++;					continue;				}			}			mifp->m6_pkt_out++;			mifp->m6_bytes_out += plen;			MC6_SEND(ip6, mifp, m);		}	return 0;}static voidphyint_send(ip6, mifp, m)    struct ip6_hdr *ip6;    struct mif6 *mifp;    struct mbuf *m;{	struct mbuf *mb_copy;	struct ifnet *ifp = mifp->m6_ifp;	int error = 0;#ifdef __NetBSD__	int s = splsoftnet();	/* needs to protect static "ro" below. */#else	int s = splnet();	/* needs to protect static "ro" below. */#endif#ifdef NEW_STRUCT_ROUTE	static struct route ro;#else	static struct route_in6 ro;#endif	struct	in6_multi *in6m;	struct sockaddr_in6 *dst6;	/*	 * Make a new reference to the packet; make sure that	 * the IPv6 header is actually copied, not just referenced,	 * so that ip6_output() only scribbles on the copy.	 */	mb_copy = m_copy(m, 0, M_COPYALL);	if (mb_copy &&	    (M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))		mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));	if (mb_copy == NULL) {		splx(s);		return;	}	/* set MCAST flag to the outgoing packet */	mb_copy->m_flags |= M_MCAST;	/*	 * If we sourced the packet, call ip6_output since we may devide	 * the packet into fragments when the packet is too big for the	 * outgoing interface.	 * Otherwise, we can simply send the packet to the interface	 * sending queue.	 */	if (m->m_pkthdr.rcvif == NULL) {		struct ip6_moptions im6o;		im6o.im6o_multicast_ifp = ifp;		/* XXX: ip6_output will override ip6->ip6_hlim */		im6o.im6o_multicast_hlim = ip6->ip6_hlim;		im6o.im6o_multicast_loop = 1;		error = ip6_output(mb_copy, NULL, &ro,				   IPV6_FORWARDING, &im6o, NULL);#ifdef MRT6DEBUG		if (mrt6debug & DEBUG_XMIT)			log(LOG_DEBUG, "phyint_send on mif %d err %d\n",			    mifp - mif6table, error);#endif		splx(s);		return;	}	/*	 * If we belong to the destination multicast group	 * on the outgoing interface, loop back a copy.	 */	dst6 = (struct sockaddr_in6 *)&ro.ro_dst;	IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);	if (in6m != NULL) {		dst6->sin6_len = sizeof(struct sockaddr_in6);		dst6->sin6_family = AF_INET6;		dst6->sin6_addr = ip6->ip6_dst;		ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst);	}	/*	 * Put the packet into the sending queue of the outgoing interface	 * if it would fit in the MTU of the interface.	 */	if (mb_copy->m_pkthdr.len < ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {		dst6->sin6_len = sizeof(struct sockaddr_in6);		dst6->sin6_family = AF_INET6;		dst6->sin6_addr = ip6->ip6_dst;		/*		 * We just call if_output instead of nd6_output here, since		 * we need no ND for a multicast forwarded packet...right?		 */		error = (*ifp->if_output)(ifp, mb_copy,		    (struct sockaddr *)&ro.ro_dst, NULL);#ifdef MRT6DEBUG		if (mrt6debug & DEBUG_XMIT)			log(LOG_DEBUG, "phyint_send on mif %d err %d\n",			    mifp - mif6table, error);#endif	} else {#ifdef MULTICAST_PMTUD		icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);#else#ifdef MRT6DEBUG		if (mrt6debug & DEBUG_XMIT)			log(LOG_DEBUG,			    "phyint_send: packet too big on %s o %s g %s"			    " size %d(discarded)\n",			    if_name(ifp),			    ip6_sprintf(&ip6->ip6_src),			    ip6_sprintf(&ip6->ip6_dst),			    mb_copy->m_pkthdr.len);#endif /* MRT6DEBUG */		m_freem(mb_copy); /* simply discard the packet */#endif	}	splx(s);}static intregister_send(ip6, mif, m)	struct ip6_hdr *ip6;	struct mif6 *mif;	struct mbuf *m;{	struct mbuf *mm;	int i, len = m->m_pkthdr.len;	static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };	struct mrt6msg *im6;#ifdef MRT6DEBUG	if (mrt6debug)		log(LOG_DEBUG, "** IPv6 register_send **\n src %s dst %s\n",		    ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst));#endif	++pim6stat.pim6s_snd_registers;	/* Make a copy of the packet to send to the user level process */	MGETHDR(mm, M_DONTWAIT, MT_HEADER);	if (mm == NULL)		return ENOBUFS;	mm->m_pkthdr.rcvif = NULL;	mm->m_data += max_linkhdr;	mm->m_len = sizeof(struct ip6_hdr);	if ((mm->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {		m_freem(mm);		return ENOBUFS;	}	i = MHLEN - M_LEADINGSPACE(mm);	if (i > len)		i = len;	mm = m_pullup(mm, i);	if (mm == NULL){		m_freem(mm);		return ENOBUFS;	}/* TODO: check it! */	mm->m_pkthdr.len = len + sizeof(struct ip6_hdr);	/*	 * Send message to routing daemon	 */	sin6.sin6_addr = ip6->ip6_src;	im6 = mtod(mm, struct mrt6msg *);	im6->im6_msgtype      = MRT6MSG_WHOLEPKT;	im6->im6_mbz          = 0;	im6->im6_mif = mif - mif6table;	/* iif info is not given for reg. encap.n */	mrt6stat.mrt6s_upcalls++;	if (socket_send(ip6_mrouter, mm, &sin6) < 0) {#ifdef MRT6DEBUG		if (mrt6debug)			log(LOG_WARNING,			    "register_send: ip6_mrouter socket queue full\n");#endif		++mrt6stat.mrt6s_upq_sockfull;		return ENOBUFS;	}	return 0;}/* * PIM sparse mode hook * Receives the pim control messages, and passes them up to the listening * socket, using rip6_input. * The only message processed is the REGISTER pim message; the pim header * is stripped off, and the inner packet is passed to register_mforward. */intpim6_input(mp, offp, proto)	struct mbuf **mp;	int *offp, proto;{	struct pim *pim; /* pointer to a pim struct */	struct ip6_hdr *ip6;	int pimlen;	struct mbuf *m = *mp;	int minlen;	int off = *offp;	++pim6stat.pim6s_rcv_total;	ip6 = mtod(m, struct ip6_hdr *);	pimlen = m->m_pkthdr.len - *offp;	/*	 * Validate lengths	 */	if (pimlen < PIM_MINLEN) {		++pim6stat.pim6s_rcv_tooshort;#ifdef MRT6DEBUG		if (mrt6debug & DEBUG_PIM)			log(LOG_DEBUG,"pim6_input: PIM packet too short\n");#endif		m_freem(m);		return(IPPROTO_DONE);	}	/*	 * if the packet is at least as big as a REGISTER, go ahead	 * and grab the PIM REGISTER header size, to avoid another	 * possible m_pullup() later.	 *	 * PIM_MINLEN       == pimhdr + u_int32 == 8	 * PIM6_REG_MINLEN   == pimhdr + reghdr + eip6hdr == 4 + 4 + 40	 */	minlen = (pimlen >= PIM6_REG_MINLEN) ? PIM6_REG_MINLEN : PIM_MINLEN;	/*	 * Make sure that the IP6 and PIM headers in contiguous memory, and	 * possibly the PIM REGISTER header	 */#ifndef PULLDOWN_TEST	IP6_EXTHDR_CHECK(m, off, minlen, IPPROTO_DONE);	/* adjust pointer */	ip6 = mtod(m, struct ip6_hdr *);	/* adjust mbuf to point to the PIM header */	pim = (struct pim *)((caddr_t)ip6 + off);#else	IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen);	if (pim == NULL) {		pim6stat.pim6s_rcv_tooshort++;		return IPPROTO_DONE;	}#endif#define PIM6_CHECKSUM#ifdef PIM6_CHECKSUM	{		int cksumlen;		/*		 * Validate checksum.		 * If PIM REGISTER, exclude the data packet		 */		if (pim->pim_type == PIM_REGISTER)			cksumlen = PIM_MINLEN;		else			cksumlen = pimlen;		if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) {			++pim6stat.pim6s_rcv_badsum;#ifdef MRT6DEBUG			if (mrt6debug & DEBUG_PIM)				log(LOG_DEBUG,				    "pim6_input: invalid checksum\n");#endif			m_freem(m);			return(IPPROTO_DONE);		}	}#endif /* PIM_CHECKSUM */	/* PIM version check */	if (pim->pim_ver != PIM_VERSION) {		++pim6stat.pim6s_rcv_badversion;#ifdef MRT6DEBUG		log(LOG_ERR,		    "pim6_input: incorrect version %d, expecting %d\n",		    pim->pim_ver, PIM_VERSION);#endif		m_freem(m);		return(IPPROTO_DONE);	}	if (pim->pim_type == PIM_REGISTER) {		/*		 * since this is a REGISTER, we'll make a copy of the register		 * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the		 * routing daemon.		 */		static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 };		struct mbuf *mcp;		struct ip6_hdr *eip6;		u_int32_t *reghdr;		int rc;			++pim6stat.pim6s_rcv_registers;		if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {#ifdef MRT6DEBUG			if (mrt6debug & DEBUG_PIM)				log(LOG_DEBUG,				    "pim6_input: register mif not set: %d\n",				    reg_mif_num);#endif			m_freem(m);			return(IPPROTO_DONE);		}			reghdr = (u_int32_t *)(pim + 1);			if ((ntohl(*reghdr) & PIM_NULL_REGISTER))			goto pim6_input_to_daemon;		/*		 * Validate length		 */		if (pimlen < PIM6_REG_MINLEN) {			++pim6stat.pim6s_rcv_tooshort;			++pim6stat.pim6s_rcv_badregisters;#ifdef MRT6DEBUG			log(LOG_ERR,			    "pim6_input: register packet size too "			    "small %d from %s\n",			    pimlen, ip6_sprintf(&ip6->ip6_src));#endif			m_freem(m);			return(IPPROTO_DONE);		}			eip6 = (struct ip6_hdr *) (reghdr + 1);#ifdef MRT6DEBUG			if (mrt6debug & DEBUG_PIM)			log(LOG_DEBUG,			    "pim6_input[register], eip6: %s -> %s, "			    "eip6 plen %d\n",			    ip6_sprintf(&eip6->ip6_src),			    ip6_sprintf(&eip6->ip6_dst),			    ntohs(eip6->ip6_plen));#endif		/* verify the version number of the inner packet */		if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {			++pim6stat.pim6s_rcv_badregisters;#ifdef MRT6DEBUG			log(LOG_DEBUG, "pim6_input: invalid IP version (%d) "			    "of the inner packet\n",			    (eip6->ip6_vfc & IPV6_VERSION));#endif			m_freem(m);			return(IPPROTO_NONE);		}			/* verify the inner packet is destined to a mcast group */		if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {			++pim6stat.pim6s_rcv_badregisters;#ifdef MRT6DEBUG			if (mrt6debug & DEBUG_PIM)				log(LOG_DEBUG,				    "pim6_input: inner packet of register "				    "is not multicast %s\n",				    ip6_sprintf(&eip6->ip6_dst));#endif			m_freem(m);			return(IPPROTO_DONE);		}			/*		 * make a copy of the whole header to pass to the daemon later.		 */		mcp = m_copy(m, 0, off + PIM6_REG_MINLEN);		if (mcp == NULL) {#ifdef MRT6DEBUG			log(LOG_ERR,			    "pim6_input: pim register: "			    "could not copy register head\n");#endif			m_freem(m);			return(IPPROTO_DONE);		}			/*		 * forward the inner ip6 packet; point m_data at the inner ip6.		 */		m_adj(m, off + PIM_MINLEN);#ifdef MRT6DEBUG		if (mrt6debug & DEBUG_PIM) {			log(LOG_DEBUG,			    "pim6_input: forwarding decapsulated register: "			    "src %s, dst %s, mif %d\n",			    ip6_sprintf(&eip6->ip6_src),			    ip6_sprintf(&eip6->ip6_dst),			    reg_mif_num);		}#endif#if defined(__FreeBSD__) && __FreeBSD__ >= 3#if (__FreeBSD_version >= 410000) 		rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m,				dst.sin6_family, (int)NULL);#else 		rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m,				(struct sockaddr *) &dst, NULL);#endif#else 		rc = looutput(mif6table[reg_mif_num].m6_ifp, m,			      (struct sockaddr *) &dst,			      (struct rtentry *) NULL);#endif			/* prepare the register head to send to the mrouting daemon */		m = mcp;	}	/*	 * Pass the PIM message up to the daemon; if it is a register message	 * pass the 'head' only up to the daemon. This includes the	 * encapsulator ip6 header, pim header, register header and the	 * encapsulated ip6 header.	 */  pim6_input_to_daemon:	rip6_input(&m, offp, proto);	return(IPPROTO_DONE);}

⌨️ 快捷键说明

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