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

📄 ip_mroute.c

📁 完整的TCP/IP源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	vifp->v_lcl_grps[vifp->v_lcl_grps_n++] = gcp->lgc_gaddr;	if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group)		vifp->v_cached_result = 1;	splx(s);	return (0);}/* * Delete the the local multicast group associated with the vif * indexed by gcp->lgc_vifi. */static intdel_lgrp(gcp)	register struct lgrplctl *gcp;{	register struct vif *vifp;	register int i, error, s;	if (gcp->lgc_vifi >= numvifs)		return (EINVAL);	vifp = viftable + gcp->lgc_vifi;	if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL))		return (EADDRNOTAVAIL);	s = splnet();	if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group)		vifp->v_cached_result = 0;	error = EADDRNOTAVAIL;	for (i = 0; i < vifp->v_lcl_grps_n; ++i)		if (same(&gcp->lgc_gaddr, &vifp->v_lcl_grps[i])) {			error = 0;			vifp->v_lcl_grps_n--;			bcopy((caddr_t)&vifp->v_lcl_grps[i + 1],			    (caddr_t)&vifp->v_lcl_grps[i],			    (vifp->v_lcl_grps_n - i) * sizeof(struct in_addr));			error = 0;			break;		}	splx(s);	return (error);}/* * Return 1 if gaddr is a member of the local group list for vifp. */static intgrplst_member(vifp, gaddr)	register struct vif *vifp;	struct in_addr gaddr;{	register int i, s;	register u_long addr;	mrtstat.mrts_grp_lookups++;	addr = gaddr.s_addr;	if (addr == vifp->v_cached_group)		return (vifp->v_cached_result);	mrtstat.mrts_grp_misses++;	for (i = 0; i < vifp->v_lcl_grps_n; ++i)		if (addr == vifp->v_lcl_grps[i].s_addr) {			s = splnet();			vifp->v_cached_group = addr;			vifp->v_cached_result = 1;			splx(s);			return (1);		}	s = splnet();	vifp->v_cached_group = addr;	vifp->v_cached_result = 0;	splx(s);	return (0);}/* * A simple hash function: returns MRTHASHMOD of the low-order octet of * the argument's network or subnet number. */static u_longnethash(in)	struct in_addr in;{	register u_long n;	n = in_netof(in);	while ((n & 0xff) == 0)		n >>= 8;	return (MRTHASHMOD(n));}/* * Add an mrt entry */static intadd_mrt(mrtcp)	register struct mrtctl *mrtcp;{	struct mrt *rt;	u_long hash;	int s;	if (rt = mrtfind(mrtcp->mrtc_origin)) {		/* Just update the route */		s = splnet();		rt->mrt_parent = mrtcp->mrtc_parent;		VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children);		VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves);		splx(s);		return (0);	}	s = splnet();	MALLOC (rt, struct mrt *, sizeof(*rt), MT_MRTABLE, M_DONTWAIT); 	if (rt == NULL) {		splx(s);		return (ENOBUFS);	}	/*	 * insert new entry at head of hash chain	 */	rt->mrt_origin = mrtcp->mrtc_origin;	rt->mrt_originmask = mrtcp->mrtc_originmask;	rt->mrt_parent = mrtcp->mrtc_parent;	VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children);	VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves);	/* link into table */	hash = nethash(mrtcp->mrtc_origin);	rt->mrt_next = mrttable[hash];	mrttable[hash] = rt;	splx(s);	return (0);}/* * Delete an mrt entry */static intdel_mrt(origin)	register struct in_addr *origin;{	register struct mrt *rt, *prev_rt;	register u_long hash = nethash(*origin);	register int s;	for (prev_rt = rt = mrttable[hash]; rt; prev_rt = rt, rt = rt->mrt_next)		if (origin->s_addr == rt->mrt_origin.s_addr)			break;	if (!rt)		return (ESRCH);	s = splnet();	if (rt == cached_mrt)		cached_mrt = NULL;	if (prev_rt == rt)		mrttable[hash] = rt->mrt_next;	else		prev_rt->mrt_next = rt->mrt_next;	FREE(rt, M_MRTABLE);	splx(s);	return (0);}/* * Find a route for a given origin IP address. */static struct mrt *mrtfind(origin)	struct in_addr origin;{	register struct mrt *rt;	register u_int hash;	register int s;	mrtstat.mrts_mrt_lookups++;	if (cached_mrt != NULL &&	    (origin.s_addr & cached_originmask) == cached_origin)		return (cached_mrt);	mrtstat.mrts_mrt_misses++;	hash = nethash(origin);	for (rt = mrttable[hash]; rt; rt = rt->mrt_next)		if ((origin.s_addr & rt->mrt_originmask.s_addr) ==		    rt->mrt_origin.s_addr) {			s = splnet();			cached_mrt = rt;			cached_origin = rt->mrt_origin.s_addr;			cached_originmask = rt->mrt_originmask.s_addr;			splx(s);			return (rt);		}	return (NULL);}/* * IP multicast forwarding function. This function assumes that the packet * pointed to by "ip" 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 IP multicast group. * * The packet is returned unscathed to the caller, unless it is tunneled * or erroneous, in which case a non-zero return value tells the caller to * discard it. */#define IP_HDR_LEN  20	/* # bytes of fixed IP header (excluding options) */#define TUNNEL_LEN  12  /* # bytes of IP option for tunnel encapsulation  */static intip_mforward(m, ifp)	register struct mbuf *m;	register struct ifnet *ifp;{	register struct ip *ip = mtod(m, struct ip *);	register struct mrt *rt;	register struct vif *vifp;	register int vifi;	register u_char *ipoptions;	u_long tunnel_src;	if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||	    (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) {		/*		 * Packet arrived via a physical interface.		 */		tunnel_src = 0;	} else {		/*		 * Packet arrived through a tunnel.		 *		 * A tunneled packet has a single NOP option and a		 * two-element loose-source-and-record-route (LSRR)		 * option immediately following the fixed-size part of		 * the IP header.  At this point in processing, the IP		 * header should contain the following IP addresses:		 *		 * original source          - in the source address field		 * destination group        - in the destination address field		 * remote tunnel end-point  - in the first  element of LSRR		 * one of this host's addrs - in the second element of LSRR		 *		 * NOTE: RFC-1075 would have the original source and		 * remote tunnel end-point addresses swapped.  However,		 * that could cause delivery of ICMP error messages to		 * innocent applications on intermediate routing		 * hosts!  Therefore, we hereby change the spec.		 */		/*		 * Verify that the tunnel options are well-formed.		 */		if (ipoptions[0] != IPOPT_NOP ||		    ipoptions[2] != 11 ||	/* LSRR option length   */		    ipoptions[3] != 12 ||	/* LSRR address pointer */		    (tunnel_src = *(u_long *)(&ipoptions[4])) == 0) {			mrtstat.mrts_bad_tunnel++;			return (1);		}		/*		 * Delete the tunnel options from the packet.		 */		ovbcopy((caddr_t)(ipoptions + TUNNEL_LEN), (caddr_t)ipoptions,		    (unsigned)(m->m_len - (IP_HDR_LEN + TUNNEL_LEN)));		m->m_len -= TUNNEL_LEN;		ip->ip_len -= TUNNEL_LEN;		ip->ip_hl -= TUNNEL_LEN >> 2;	}	/*	 * Don't forward a packet with time-to-live of zero or one,	 * or a packet destined to a local-only group.	 */	if (ip->ip_ttl <= 1 ||	    ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP)		return ((int)tunnel_src);	/*	 * Don't forward if we don't have a route for the packet's origin.	 */	if (!(rt = mrtfind(ip->ip_src))) {		mrtstat.mrts_no_route++;		return ((int)tunnel_src);	}	/*	 * Don't forward if it didn't arrive from the parent vif for its origin.	 */	vifi = rt->mrt_parent;	if (tunnel_src == 0 ) {		if ((viftable[vifi].v_flags & VIFF_TUNNEL) ||		    viftable[vifi].v_ifp != ifp )			return ((int)tunnel_src);	} else {		if (!(viftable[vifi].v_flags & VIFF_TUNNEL) ||		    viftable[vifi].v_rmt_addr.s_addr != tunnel_src )			return ((int)tunnel_src);	}	/*	 * For each vif, decide if a copy of the packet should be forwarded.	 * Forward if:	 *		- the ttl exceeds the vif's threshold AND	 *		- the vif is a child in the origin's route AND	 *		- ( the vif is not a leaf in the origin's route OR	 *		    the destination group has members on the vif )	 *	 * (This might be speeded up with some sort of cache -- someday.)	 */	for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) {		if (ip->ip_ttl > vifp->v_threshold &&		    VIFM_ISSET(vifi, rt->mrt_children) &&		    (!VIFM_ISSET(vifi, rt->mrt_leaves) ||		    grplst_member(vifp, ip->ip_dst))) {			if (vifp->v_flags & VIFF_TUNNEL)				tunnel_send(m, vifp);			else				phyint_send(m, vifp);		}	}	return ((int)tunnel_src);}static voidphyint_send(m, vifp)	register struct mbuf *m;	register struct vif *vifp;{	register struct ip *ip = mtod(m, struct ip *);	register struct mbuf *mb_copy;	register struct ip_moptions *imo;	register int error;	struct ip_moptions simo;	mb_copy = m_copy(m, 0, M_COPYALL);	if (mb_copy == NULL)		return;	imo = &simo;	imo->imo_multicast_ifp = vifp->v_ifp;	imo->imo_multicast_ttl = ip->ip_ttl - 1;	imo->imo_multicast_loop = 1;	error = ip_output(mb_copy, NULL, NULL, IP_FORWARDING, imo);}static voidtunnel_send(m, vifp)	register struct mbuf *m;	register struct vif *vifp;{	register struct ip *ip = mtod(m, struct ip *);	register struct mbuf *mb_copy, *mb_opts;	register struct ip *ip_copy;	register int error;	register u_char *cp;	/*	 * Make sure that adding the tunnel options won't exceed the	 * maximum allowed number of option bytes.	 */	if (ip->ip_hl > (60 - TUNNEL_LEN) >> 2) {		mrtstat.mrts_cant_tunnel++;		return;	}	/* 	 * Get a private copy of the IP header so that changes to some 	 * of the IP fields don't damage the original header, which is	 * examined later in ip_input.c.	 */	mb_copy = m_copy(m, IP_HDR_LEN, M_COPYALL);	if (mb_copy == NULL)		return;	mb_opts = mHdrClGet(M_DONTWAIT, MT_HEADER, CL_SIZE_128, TRUE);	if (mb_opts == NULL) {		m_freem(mb_copy);		return;	}	/*	 * Make mb_opts be the new head of the packet chain.	 * Any options of the packet were left in the old packet chain head	 */	mb_opts->m_next = mb_copy;	mb_opts->m_len = IP_HDR_LEN + TUNNEL_LEN;	mb_opts->m_data += MSIZE - mb_opts->m_len;	ip_copy = mtod(mb_opts, struct ip *);	/*	 * Copy the base ip header to the new head mbuf.	 */	*ip_copy = *ip;	ip_copy->ip_ttl--;	ip_copy->ip_dst = vifp->v_rmt_addr;	/* remote tunnel end-point */	/*	 * Adjust the ip header length to account for the tunnel options.	 */	ip_copy->ip_hl += TUNNEL_LEN >> 2;	ip_copy->ip_len += TUNNEL_LEN;	/*	 * Add the NOP and LSRR after the base ip header	 */	cp = (u_char *)(ip_copy + 1);	*cp++ = IPOPT_NOP;	*cp++ = IPOPT_LSRR;	*cp++ = 11;		/* LSRR option length */	*cp++ = 8;		/* LSSR pointer to second element */	*(u_long*)cp = vifp->v_lcl_addr.s_addr;	/* local tunnel end-point */	cp += 4;	*(u_long*)cp = ip->ip_dst.s_addr;		/* destination group */	error = ip_output(mb_opts, NULL, NULL, IP_FORWARDING, NULL);}

⌨️ 快捷键说明

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