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

📄 ip_mroute.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 4 页
字号:
    }    /*     * 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 0;    /*     * Determine forwarding vifs from the forwarding cache table     */    s = splnet();    MFCFIND(ip->ip_src.s_addr, ip->ip_dst.s_addr, rt);    /* Entry exists, so forward if necessary */    if (rt != NULL) {	splx(s);	return (ip_mdq(m, ifp, rt, -1));    } else {	/*	 * If we don't have a route for packet's origin,	 * Make a copy of the packet &	 * send message to routing daemon	 */	register struct mbuf *mb_rt;	register struct mbuf *mb_ntry;	register struct mbuf *mb0;	register struct rtdetq *rte;	register struct mbuf *rte_m;	register u_long hash;	register int npkts;	int hlen = ip->ip_hl << 2;#ifdef UPCALL_TIMING	struct timeval tp;	GET_TIME(tp);#endif	mrtstat.mrts_no_route++;	if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC))	    log(LOG_DEBUG, "ip_mforward: no rte s %x g %x\n",		ntohl(ip->ip_src.s_addr),		ntohl(ip->ip_dst.s_addr));	/*	 * Allocate mbufs early so that we don't do extra work if we are	 * just going to fail anyway.  Make sure to pullup the header so	 * that other people can't step on it.	 */	MGET(mb_ntry, M_DONTWAIT, MT_DATA);	if (mb_ntry == NULL) {	    splx(s);	    return ENOBUFS;	}	mb0 = m_copy(m, 0, M_COPYALL);	if (mb0 && (M_HASCL(mb0) || mb0->m_len < hlen))	    mb0 = m_pullup(mb0, hlen);	if (mb0 == NULL) {	    m_free(mb_ntry);	    splx(s);	    return ENOBUFS;	}	/* is there an upcall waiting for this packet? */	hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr);	for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) {	    rt = mtod(mb_rt, struct mfc *);	    if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) &&		(ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) &&		(mb_rt->m_act != NULL))		break;	}	if (mb_rt == NULL) {	    int i;	    struct igmpmsg *im;	    /* no upcall, so make a new entry */	    MGET(mb_rt, M_DONTWAIT, MT_MRTABLE);	    if (mb_rt == NULL) {		m_free(mb_ntry);		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, hlen);	    if (mm == NULL) {		m_free(mb_ntry);		m_freem(mb0);		m_free(mb_rt);		splx(s);		return ENOBUFS;	    }	    /* 	     * Send message to routing daemon to install 	     * a route into the kernel table	     */	    k_igmpsrc.sin_addr = ip->ip_src;	    	    im = mtod(mm, struct igmpmsg *);	    im->im_msgtype	= IGMPMSG_NOCACHE;	    im->im_mbz		= 0;	    mrtstat.mrts_upcalls++;	    if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) {		log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n");		++mrtstat.mrts_upq_sockfull;		m_free(mb_ntry);		m_freem(mb0);		m_free(mb_rt);		splx(s);		return ENOBUFS;	    }	    rt = mtod(mb_rt, struct mfc *);	    /* insert new entry at head of hash chain */	    rt->mfc_origin.s_addr     = ip->ip_src.s_addr;	    rt->mfc_mcastgrp.s_addr   = ip->ip_dst.s_addr;	    rt->mfc_expire	      = UPCALL_EXPIRE;	    nexpire[hash]++;	    for (i = 0; i < numvifs; i++)		rt->mfc_ttls[i] = 0;	    rt->mfc_parent = -1;	    /* link into table */	    mb_rt->m_next  = mfctable[hash];	    mfctable[hash] = mb_rt;	    mb_rt->m_act = NULL;	    rte_m = mb_rt;	} else {	    /* determine if q has overflowed */	    for (rte_m = mb_rt, npkts = 0; rte_m->m_act; rte_m = rte_m->m_act)		npkts++;	    if (npkts > MAX_UPQ) {		mrtstat.mrts_upq_ovflw++;		m_free(mb_ntry);		m_freem(mb0);		splx(s);		return 0;	    }	}	mb_ntry->m_act = NULL;	rte = mtod(mb_ntry, struct rtdetq *);	rte->m 			= mb0;	rte->ifp 		= ifp;#ifdef UPCALL_TIMING	rte->t			= tp;#endif	/* Add this entry to the end of the queue */	rte_m->m_act		= mb_ntry;	splx(s);	return 0;    }		}#ifndef MROUTE_LKMint (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,		   struct ip_moptions *) = X_ip_mforward;#endif/* * Clean up the cache entry if upcall is not serviced */static voidexpire_upcalls(void *unused){    struct mbuf *mb_rt, *m, **nptr;    struct rtdetq *rte;    struct mfc *mfc;    int i;    int s;    s = splnet();    for (i = 0; i < MFCTBLSIZ; i++) {	if (nexpire[i] == 0)	    continue;	nptr = &mfctable[i];	for (mb_rt = *nptr; mb_rt != NULL; mb_rt = *nptr) {	    mfc = mtod(mb_rt, struct mfc *);	    /*	     * Skip real cache entries	     * Make sure it wasn't marked to not expire (shouldn't happen)	     * If it expires now	     */	    if (mb_rt->m_act != NULL &&	        mfc->mfc_expire != 0 &&		--mfc->mfc_expire == 0) {		if (mrtdebug & DEBUG_EXPIRE)		    log(LOG_DEBUG, "expire_upcalls: expiring (%x %x)\n",			ntohl(mfc->mfc_origin.s_addr),			ntohl(mfc->mfc_mcastgrp.s_addr));		/*		 * drop all the packets		 * free the mbuf with the pkt, if, timing info		 */		while (mb_rt->m_act) {		    m = mb_rt->m_act;		    mb_rt->m_act = m->m_act;	     		    rte = mtod(m, struct rtdetq *);		    m_freem(rte->m);		    m_free(m);		}		++mrtstat.mrts_cache_cleanups;		nexpire[i]--;		MFREE(mb_rt, *nptr);	    } else {		nptr = &mb_rt->m_next;	    }	}    }    splx(s);    timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);}/* * Packet forwarding routine once entry in the cache is made */static intip_mdq(m, ifp, rt, xmt_vif)    register struct mbuf *m;    register struct ifnet *ifp;    register struct mfc *rt;    register vifi_t xmt_vif;{    register struct ip  *ip = mtod(m, struct ip *);    register vifi_t vifi;    register struct vif *vifp;    register int plen = ntohs(ip->ip_len);/* * Macro to send packet on vif.  Since RSVP packets don't get counted on * input, they shouldn't get counted on output, so statistics keeping is * seperate. */#define MC_SEND(ip,vifp,m) {                             \                if ((vifp)->v_flags & VIFF_TUNNEL)  	 \                    encap_send((ip), (vifp), (m));       \                else                                     \                    phyint_send((ip), (vifp), (m));      \}    /*     * If xmt_vif is not -1, send on only the requested vif.     *     * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.)     */    if (xmt_vif < numvifs) {	MC_SEND(ip, viftable + xmt_vif, m);	return 1;    }    /*     * Don't forward if it didn't arrive from the parent vif for its origin.     */    vifi = rt->mfc_parent;    if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) {	/* came in the wrong interface */	if (mrtdebug & DEBUG_FORWARD)	    log(LOG_DEBUG, "wrong if: ifp %x vifi %d vififp %x\n",		ifp, vifi, viftable[vifi].v_ifp); 	++mrtstat.mrts_wrong_if;	++rt->mfc_wrong_if;	/*	 * If we are doing PIM assert processing, and we are forwarding	 * packets on this interface, and it is a broadcast medium	 * interface (and not a tunnel), send a message to the routing daemon.	 */	if (pim_assert && rt->mfc_ttls[vifi] &&		(ifp->if_flags & IFF_BROADCAST) &&		!(viftable[vifi].v_flags & VIFF_TUNNEL)) {	    struct sockaddr_in k_igmpsrc;	    struct mbuf *mm;	    struct igmpmsg *im;	    int hlen = ip->ip_hl << 2;	    struct timeval now;	    register u_long delta;	    GET_TIME(now);	    TV_DELTA(rt->mfc_last_assert, now, delta);	    if (delta > ASSERT_MSG_TIME) {		mm = m_copy(m, 0, hlen);		if (mm && (M_HASCL(mm) || mm->m_len < hlen))		    mm = m_pullup(mm, hlen);		if (mm == NULL) {		    return ENOBUFS;		}		rt->mfc_last_assert = now;		im = mtod(mm, struct igmpmsg *);		im->im_msgtype	= IGMPMSG_WRONGVIF;		im->im_mbz		= 0;		im->im_vif		= vifi;		k_igmpsrc.sin_addr = im->im_src;		socket_send(ip_mrouter, mm, &k_igmpsrc);	    }	}	return 0;    }    /* If I sourced this packet, it counts as output, else it was input. */    if (ip->ip_src.s_addr == viftable[vifi].v_lcl_addr.s_addr) {	viftable[vifi].v_pkt_out++;	viftable[vifi].v_bytes_out += plen;    } else {	viftable[vifi].v_pkt_in++;	viftable[vifi].v_bytes_in += plen;    }    rt->mfc_pkt_cnt++;    rt->mfc_byte_cnt += plen;    /*     * For each vif, decide if a copy of the packet should be forwarded.     * Forward if:     *		- the ttl exceeds the vif's threshold     *		- there are group members downstream on interface     */    for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++)	if ((rt->mfc_ttls[vifi] > 0) &&	    (ip->ip_ttl > rt->mfc_ttls[vifi])) {	    vifp->v_pkt_out++;	    vifp->v_bytes_out += plen;	    MC_SEND(ip, vifp, m);	}    return 0;}/* * check if a vif number is legal/ok. This is used by ip_output, to export * numvifs there,  */static intX_legal_vif_num(vif)    int vif;{    if (vif >= 0 && vif < numvifs)       return(1);    else       return(0);}#ifndef MROUTE_LKMint (*legal_vif_num)(int) = X_legal_vif_num;#endif/* * Return the local address used by this vif */static u_longX_ip_mcast_src(vifi)    int vifi;{    if (vifi >= 0 && vifi < numvifs)	return viftable[vifi].v_lcl_addr.s_addr;    else	return INADDR_ANY;}#ifndef MROUTE_LKMu_long (*ip_mcast_src)(int) = X_ip_mcast_src;#endifstatic voidphyint_send(ip, vifp, m)    struct ip *ip;    struct vif *vifp;    struct mbuf *m;{    register struct mbuf *mb_copy;    register int hlen = ip->ip_hl << 2;    /*     * Make a new reference to the packet; make sure that     * the IP header is actually copied, not just referenced,     * so that ip_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 < hlen))	mb_copy = m_pullup(mb_copy, hlen);    if (mb_copy == NULL)	return;    if (vifp->v_rate_limit <= 0)	tbf_send_packet(vifp, mb_copy);    else	tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *), ip->ip_len);}static voidencap_send(ip, vifp, m)    register struct ip *ip;    register struct vif *vifp;    register struct mbuf *m;{    register struct mbuf *mb_copy;    register struct ip *ip_copy;    register int i, len = ip->ip_len;    /*     * copy the old packet & pullup it's IP header into the     * new mbuf so we can modify it.  Try to fill the new     * mbuf since if we don't the ethernet driver will.     */    MGETHDR(mb_copy, M_DONTWAIT, MT_HEADER);    if (mb_copy == NULL)	return;    mb_copy->m_data += max_linkhdr;    mb_copy->m_len = sizeof(multicast_encap_iphdr);    if ((mb_copy->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {	m_freem(mb_copy);	return;    }    i = MHLEN - M_LEADINGSPACE(mb_copy);    if (i > len)	i = len;    mb_copy = m_pullup(mb_copy, i);    if (mb_copy == NULL)	return;    mb_copy->m_pkthdr.len = len + sizeof(multicast_encap_iphdr);    /*     * fill in the encapsulating IP header.     */    ip_copy = mtod(mb_copy, struct ip *);    *ip_copy = multicast_encap_iphdr;    ip_copy->ip_id = htons(ip_id++);    ip_copy->ip_len += len;    ip_copy->ip_src = vifp->v_lcl_addr;    ip_copy->ip_dst = vifp->v_rmt_addr;    /*     * turn the encapsulated IP header back into a valid one.     */    ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr));    --ip->ip_ttl;    HTONS(ip->ip_len);    HTONS(ip->ip_off);    ip->ip_sum = 0;    mb_copy->m_data += sizeof(multicast_encap_iphdr);    ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2);    mb_copy->m_data -= sizeof(multicast_encap_iphdr);    if (vifp->v_rate_limit <= 0)	tbf_send_packet(vifp, mb_copy);    else	tbf_control(vifp, mb_copy, ip, ip_copy->ip_len);}/* * De-encapsulate a packet and feed it back through ip input (this * routine is called whenever IP gets a packet with proto type * ENCAP_PROTO and a local destination address). */void#ifdef MROUTE_LKMX_ipip_input(m, iphlen)#elseipip_input(m, iphlen)#endif	register struct mbuf *m;	int iphlen;{    struct ifnet *ifp = m->m_pkthdr.rcvif;    register struct ip *ip = mtod(m, struct ip *);    register int hlen = ip->ip_hl << 2;    register int s;    register struct ifqueue *ifq;    register struct vif *vifp;    if (!have_encap_tunnel) {	    rip_input(m, iphlen);	    return;    }    /*     * dump the packet if it's not to a multicast destination or if     * we don't have an encapsulating tunnel with the source.     * Note:  This code assumes that the remote site IP address     * uniquely identifies the tunnel (i.e., that this site has     * at most one tunnel with the remote site).     */    if (! IN_MULTICAST(ntohl(((struct ip *)((char *)ip + hlen))->ip_dst.s_addr))) {	++mrtstat.mrts_bad_tunnel;	m_freem(m);	return;    }    if (ip->ip_src.s_addr != last_encap_src) {	register struct vif *vife;		vifp = viftable;	vife = vifp + numvifs;	last_encap_src = ip->ip_src.s_addr;	last_encap_vif = 0;	for ( ; vifp < vife; ++vifp)	    if (vifp->v_rmt_addr.s_addr == ip->ip_src.s_addr) {		if ((vifp->v_flags & (VIFF_TUNNEL|VIFF_SRCRT))		    == VIFF_TUNNEL)		    last_encap_vif = vifp;		break;	    }    }    if ((vifp = last_encap_vif) == 0) {	last_encap_src = 0;	mrtstat.mrts_cant_tunnel++; /*XXX*/	m_freem(m);	if (mrtdebug)          log(LOG_DEBUG, "ip_mforward: no tunnel with %x\n",		ntohl(ip->ip_src.s_addr));	return;    }    ifp = vifp->v_ifp;    if (hlen > IP_HDR_LEN)      ip_stripoptions(m, (struct mbuf *) 0);    m->m_data += IP_HDR_LEN;    m->m_len -= IP_HDR_LEN;    m->m_pkthdr.len -= IP_HDR_LEN;    m->m_pkthdr.rcvif = ifp;    ifq = &ipintrq;    s = splimp();    if (IF_QFULL(ifq)) {	IF_DROP(ifq);	m_freem(m);    } else {	IF_ENQUEUE(ifq, m);	/*	 * normally we would need a "schednetisr(NETISR_IP)"	 * here but we were called by ip_input and it is going	 * to loop back & try to dequeue the packet we just	 * queued as soon as we return so we avoid the	 * unnecessary software interrrupt.	 */    }    splx(s);}/* * Token bucket filter module */static voidtbf_control(vifp, m, ip, p_len)	register struct vif *vifp;	register struct mbuf *m;	register struct ip *ip;	register u_long p_len;{    register struct tbf *t = vifp->v_tbf;    if (p_len > MAX_BKT_SIZE) {	/* drop if packet is too large */	mrtstat.mrts_pkt2large++;	m_freem(m);

⌨️ 快捷键说明

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