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

📄 ip_mroute.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:

    ip_mrouter = so;

    bzero((caddr_t)mfctable, sizeof(mfctable));
    bzero((caddr_t)nexpire, sizeof(nexpire));

    pim_assert = 0;

    expire_upcalls_ch = timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);

    if (mrtdebug)
	log(LOG_DEBUG, "ip_mrouter_init\n");

    return 0;
}

/*
 * Disable multicast routing
 */
static int
X_ip_mrouter_done()
{
    vifi_t vifi;
    int i;
    struct ifnet *ifp;
    struct ifreq ifr;
    struct mfc *rt;
    struct rtdetq *rte;
    int s;

    s = splnet();

    /*
     * For each phyint in use, disable promiscuous reception of all IP
     * multicasts.
     */
    for (vifi = 0; vifi < numvifs; vifi++) {
	if (viftable[vifi].v_lcl_addr.s_addr != 0 &&
	    !(viftable[vifi].v_flags & VIFF_TUNNEL)) {
	    ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
	    ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr
								= INADDR_ANY;
	    ifp = viftable[vifi].v_ifp;
	    if_allmulti(ifp, 0);
	}
    }
    bzero((caddr_t)tbftable, sizeof(tbftable));
    bzero((caddr_t)viftable, sizeof(viftable));
    numvifs = 0;
    pim_assert = 0;

    untimeout(expire_upcalls, (caddr_t)NULL, expire_upcalls_ch);

    /*
     * Free all multicast forwarding cache entries.
     */
    for (i = 0; i < MFCTBLSIZ; i++) {
	for (rt = mfctable[i]; rt != NULL; ) {
	    struct mfc *nr = rt->mfc_next;

	    for (rte = rt->mfc_stall; rte != NULL; ) {
		struct rtdetq *n = rte->next;

		m_freem(rte->m);
		free(rte, M_MRTABLE);
		rte = n;
	    }
	    free(rt, M_MRTABLE);
	    rt = nr;
	}
    }

    bzero((caddr_t)mfctable, sizeof(mfctable));

    /*
     * Reset de-encapsulation cache
     */
    last_encap_src = 0;
    last_encap_vif = NULL;
    have_encap_tunnel = 0;
 
    ip_mrouter = NULL;

    splx(s);

    if (mrtdebug)
	log(LOG_DEBUG, "ip_mrouter_done\n");

    return 0;
}

#ifndef MROUTE_LKM
int (*ip_mrouter_done)(void) = X_ip_mrouter_done;
#endif

/*
 * Set PIM assert processing global
 */
static int
set_assert(i)
	int i;
{
    if ((i != 1) && (i != 0))
	return EINVAL;

    pim_assert = i;

    return 0;
}

/*
 * Add a vif to the vif table
 */
static int
add_vif(vifcp)
    register struct vifctl *vifcp;
{
    register struct vif *vifp = viftable + vifcp->vifc_vifi;
    static struct sockaddr_in sin = {sizeof sin, AF_INET};
    struct ifaddr *ifa;
    struct ifnet *ifp;
    int error, s;
    struct tbf *v_tbf = tbftable + vifcp->vifc_vifi;

    if (vifcp->vifc_vifi >= MAXVIFS)  return EINVAL;
    if (vifp->v_lcl_addr.s_addr != 0) return EADDRINUSE;

    /* Find the interface with an address in AF_INET family */
    sin.sin_addr = vifcp->vifc_lcl_addr;
    ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
    if (ifa == 0) return EADDRNOTAVAIL;
    ifp = ifa->ifa_ifp;

    if (vifcp->vifc_flags & VIFF_TUNNEL) {
	if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) {
		/*
		 * An encapsulating tunnel is wanted.  Tell ipip_input() to
		 * start paying attention to encapsulated packets.
		 */
		if (have_encap_tunnel == 0) {
			have_encap_tunnel = 1;
			for (s = 0; s < MAXVIFS; ++s) {
				multicast_decap_if[s].if_name = "mdecap";
				multicast_decap_if[s].if_unit = s;
			}
		}
		/*
		 * Set interface to fake encapsulator interface
		 */
		ifp = &multicast_decap_if[vifcp->vifc_vifi];
		/*
		 * Prepare cached route entry
		 */
		bzero(&vifp->v_route, sizeof(vifp->v_route));
	} else {
	    log(LOG_ERR, "source routed tunnels not supported\n");
	    return EOPNOTSUPP;
	}
    } else {
	/* Make sure the interface supports multicast */
	if ((ifp->if_flags & IFF_MULTICAST) == 0)
	    return EOPNOTSUPP;

	/* Enable promiscuous reception of all IP multicasts from the if */
	s = splnet();
	error = if_allmulti(ifp, 1);
	splx(s);
	if (error)
	    return error;
    }

    s = splnet();
    /* define parameters for the tbf structure */
    vifp->v_tbf = v_tbf;
    GET_TIME(vifp->v_tbf->tbf_last_pkt_t);
    vifp->v_tbf->tbf_n_tok = 0;
    vifp->v_tbf->tbf_q_len = 0;
    vifp->v_tbf->tbf_max_q_len = MAXQSIZE;
    vifp->v_tbf->tbf_q = vifp->v_tbf->tbf_t = NULL;

    vifp->v_flags     = vifcp->vifc_flags;
    vifp->v_threshold = vifcp->vifc_threshold;
    vifp->v_lcl_addr  = vifcp->vifc_lcl_addr;
    vifp->v_rmt_addr  = vifcp->vifc_rmt_addr;
    vifp->v_ifp       = ifp;
    /* scaling up here allows division by 1024 in critical code */
    vifp->v_rate_limit= vifcp->vifc_rate_limit * 1024 / 1000;
    vifp->v_rsvp_on   = 0;
    vifp->v_rsvpd     = NULL;
    /* initialize per vif pkt counters */
    vifp->v_pkt_in    = 0;
    vifp->v_pkt_out   = 0;
    vifp->v_bytes_in  = 0;
    vifp->v_bytes_out = 0;
    splx(s);

    /* Adjust numvifs up if the vifi is higher than numvifs */
    if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1;

    if (mrtdebug)
	log(LOG_DEBUG, "add_vif #%d, lcladdr %lx, %s %lx, thresh %x, rate %d\n",
	    vifcp->vifc_vifi, 
	    (u_long)ntohl(vifcp->vifc_lcl_addr.s_addr),
	    (vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask",
	    (u_long)ntohl(vifcp->vifc_rmt_addr.s_addr),
	    vifcp->vifc_threshold,
	    vifcp->vifc_rate_limit);    

    return 0;
}

/*
 * Delete a vif from the vif table
 */
static int
del_vif(vifi)
	vifi_t vifi;
{
    register struct vif *vifp = &viftable[vifi];
    register struct mbuf *m;
    struct ifnet *ifp;
    struct ifreq ifr;
    int s;

    if (vifi >= numvifs) return EINVAL;
    if (vifp->v_lcl_addr.s_addr == 0) return EADDRNOTAVAIL;

    s = splnet();

    if (!(vifp->v_flags & VIFF_TUNNEL)) {
	((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
	((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY;
	ifp = vifp->v_ifp;
	if_allmulti(ifp, 0);
    }

    if (vifp == last_encap_vif) {
	last_encap_vif = 0;
	last_encap_src = 0;
    }

    /*
     * Free packets queued at the interface
     */
    while (vifp->v_tbf->tbf_q) {
	m = vifp->v_tbf->tbf_q;
	vifp->v_tbf->tbf_q = m->m_act;
	m_freem(m);
    }

    bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf)));
    bzero((caddr_t)vifp, sizeof (*vifp));

    if (mrtdebug)
      log(LOG_DEBUG, "del_vif %d, numvifs %d\n", vifi, numvifs);

    /* Adjust numvifs down */
    for (vifi = numvifs; vifi > 0; vifi--)
	if (viftable[vifi-1].v_lcl_addr.s_addr != 0) break;
    numvifs = vifi;

    splx(s);

    return 0;
}

/*
 * Add an mfc entry
 */
static int
add_mfc(mfccp)
    struct mfcctl *mfccp;
{
    struct mfc *rt;
    u_long hash;
    struct rtdetq *rte;
    register u_short nstl;
    int s;
    int i;

    MFCFIND(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr, rt);

    /* If an entry already exists, just update the fields */
    if (rt) {
	if (mrtdebug & DEBUG_MFC)
	    log(LOG_DEBUG,"add_mfc update o %lx g %lx p %x\n",
		(u_long)ntohl(mfccp->mfcc_origin.s_addr),
		(u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
		mfccp->mfcc_parent);

	s = splnet();
	rt->mfc_parent = mfccp->mfcc_parent;
	for (i = 0; i < numvifs; i++)
	    rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
	splx(s);
	return 0;
    }

    /* 
     * Find the entry for which the upcall was made and update
     */
    s = splnet();
    hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr);
    for (rt = mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) {

	if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) &&
	    (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) &&
	    (rt->mfc_stall != NULL)) {
  
	    if (nstl++)
		log(LOG_ERR, "add_mfc %s o %lx g %lx p %x dbx %p\n",
		    "multiple kernel entries",
		    (u_long)ntohl(mfccp->mfcc_origin.s_addr),
		    (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
		    mfccp->mfcc_parent, (void *)rt->mfc_stall);

	    if (mrtdebug & DEBUG_MFC)
		log(LOG_DEBUG,"add_mfc o %lx g %lx p %x dbg %p\n",
		    (u_long)ntohl(mfccp->mfcc_origin.s_addr),
		    (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
		    mfccp->mfcc_parent, (void *)rt->mfc_stall);

	    rt->mfc_origin     = mfccp->mfcc_origin;
	    rt->mfc_mcastgrp   = mfccp->mfcc_mcastgrp;
	    rt->mfc_parent     = mfccp->mfcc_parent;
	    for (i = 0; i < numvifs; i++)
		rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
	    /* initialize pkt counters per src-grp */
	    rt->mfc_pkt_cnt    = 0;
	    rt->mfc_byte_cnt   = 0;
	    rt->mfc_wrong_if   = 0;
	    rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;

	    rt->mfc_expire = 0;	/* Don't clean this guy up */
	    nexpire[hash]--;

	    /* free packets Qed at the end of this entry */
	    for (rte = rt->mfc_stall; rte != NULL; ) {
		struct rtdetq *n = rte->next;

		ip_mdq(rte->m, rte->ifp, rt, -1);
		m_freem(rte->m);
#ifdef UPCALL_TIMING
		collate(&(rte->t));
#endif /* UPCALL_TIMING */
		free(rte, M_MRTABLE);
		rte = n;
	    }
	    rt->mfc_stall = NULL;
	}
    }

    /*
     * It is possible that an entry is being inserted without an upcall
     */
    if (nstl == 0) {
	if (mrtdebug & DEBUG_MFC)
	    log(LOG_DEBUG,"add_mfc no upcall h %lu o %lx g %lx p %x\n",
		hash, (u_long)ntohl(mfccp->mfcc_origin.s_addr),
		(u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
		mfccp->mfcc_parent);
	
	for (rt = mfctable[hash]; rt != NULL; rt = rt->mfc_next) {
	    
	    if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) &&
		(rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) {

		rt->mfc_origin     = mfccp->mfcc_origin;
		rt->mfc_mcastgrp   = mfccp->mfcc_mcastgrp;
		rt->mfc_parent     = mfccp->mfcc_parent;
		for (i = 0; i < numvifs; i++)
		    rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
		/* initialize pkt counters per src-grp */
		rt->mfc_pkt_cnt    = 0;
		rt->mfc_byte_cnt   = 0;
		rt->mfc_wrong_if   = 0;
		rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;
		if (rt->mfc_expire)
		    nexpire[hash]--;
		rt->mfc_expire	   = 0;
	    }
	}
	if (rt == NULL) {
	    /* no upcall, so make a new entry */
	    rt = (struct mfc *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT);
	    if (rt == NULL) {
		splx(s);
		return ENOBUFS;
	    }
	    
	    /* insert new entry at head of hash chain */
	    rt->mfc_origin     = mfccp->mfcc_origin;
	    rt->mfc_mcastgrp   = mfccp->mfcc_mcastgrp;
	    rt->mfc_parent     = mfccp->mfcc_parent;
	    for (i = 0; i < numvifs; i++)
		    rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
	    /* initialize pkt counters per src-grp */
	    rt->mfc_pkt_cnt    = 0;
	    rt->mfc_byte_cnt   = 0;
	    rt->mfc_wrong_if   = 0;
	    rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;
	    rt->mfc_expire     = 0;
	    rt->mfc_stall      = NULL;
	    
	    /* link into table */
	    rt->mfc_next = mfctable[hash];
	    mfctable[hash] = rt;
	}
    }
    splx(s);
    return 0;
}

#ifdef UPCALL_TIMING
/*
 * collect delay statistics on the upcalls 
 */
static void collate(t)
register struct timeval *t;
{
    register u_long d;
    register struct timeval tp;
    register u_long delta;
    
    GET_TIME(tp);
    
    if (TV_LT(*t, tp))
    {
	TV_DELTA(tp, *t, delta);
	
	d = delta >> 10;
	if (d > 50)
	    d = 50;
	
	++upcall_data[d];
    }
}
#endif /* UPCALL_TIMING */

/*
 * Delete an mfc entry
 */
static int
del_mfc(mfccp)
    struct mfcctl *mfccp;
{
    struct in_addr 	origin;
    struct in_addr 	mcastgrp;
    struct mfc 		*rt;
    struct mfc	 	**nptr;
    u_long 		hash;
    int s;

    origin = mfccp->mfcc_origin;
    mcastgrp = mfccp->mfcc_mcastgrp;
    hash = MFCHASH(origin.s_addr, mcastgrp.s_addr);

    if (mrtdebug & DEBUG_MFC)
	log(LOG_DEBUG,"del_mfc orig %lx mcastgrp %lx\n",
	    (u_long)ntohl(origin.s_addr), (u_long)ntohl(mcastgrp.s_addr));

    s = splnet();

    nptr = &mfctable[hash];
    while ((rt = *nptr) != NULL) {
	if (origin.s_addr == rt->mfc_origin.s_addr &&
	    mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr &&
	    rt->mfc_stall == NULL)
	    break;

	nptr = &rt->mfc_next;
    }
    if (rt == NULL) {
	splx(s);
	return EADDRNOTAVAIL;
    }

    *nptr = rt->mfc_next;
    free(rt, M_MRTABLE);

    splx(s);

    return 0;
}

/*
 * Send a message to mrouted on the multicast routing socket
 */
static int
socket_send(s, mm, src)
	struct socket *s;
	struct mbuf *mm;
	struct sockaddr_in *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;
}

/*
 * 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
 * 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 int
X_ip_mforward(ip, ifp, m, imo)
    register struct ip *ip;
    struct ifnet *ifp;
    struct mbuf *m;
    struct ip_moptions *imo;
{
    register struct mfc *rt;
    register u_char *ipoptions;
    static struct sockaddr_in 	k_igmpsrc	= { sizeof k_igmpsrc, AF_INET };
    static int srctun = 0;
    register struct mbuf *mm;
    int s;
    vifi_t vifi;
    struct vif *vifp;

    if (mrtdebug & DEBUG_FORWARD)
	log(LOG_DEBUG, "ip_mforward: src %lx, dst %lx, ifp %p\n",
	    (u_long)ntohl(ip->ip_src.s_addr), (u_long)ntohl(ip->ip_dst.s_addr),
	    (void *)ifp);

    if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
	(ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) {
	/*
	 * Packet arrived via a physical interface or
	 * an encapsulated tunnel.
	 */
    } else {
	/*
	 * Packet arrived through a source-route tunnel.
	 * Source-route tunnels are no longer supported.
	 */
	if ((srctun++ % 1000) == 0)
	    log(LOG_ERR,
		"ip_mforward: received source-routed packet from %lx\n",
		(u_long)ntohl(ip->ip_src.s_addr));

	return 1;
    }

    if ((imo) && ((vifi = imo->imo_multicast_vif) < numvifs)) {
	if (ip->ip_ttl < 255)
		ip->ip_ttl++;	/* compensate for -1 in *_send routines */
	if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
	    vifp = viftable + vifi;
	    printf("Sending IPPROTO_RSVP from %lx to %lx on vif %d (%s%s%d)\n",
		ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), vifi,
		(vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "",
		vifp->v_ifp->if_name, vifp->v_ifp->if_unit);
	}
	return (ip_mdq(m, ifp, NULL, vifi));
    }
    if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
	printf("Warning: IPPROTO_RSVP from %lx to %lx without vif option\n",
	    ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr));
	if(!imo)
		printf("In fact, no options were specified at all\n");
    }

    /*

⌨️ 快捷键说明

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