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

📄 ip_mroute.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
//==========================================================================
//
//      src/sys/netinet/ip_mroute.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD, 
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================

/*
 * IP multicast forwarding procedures
 *
 * Written by David Waitzman, BBN Labs, August 1988.
 * Modified by Steve Deering, Stanford, February 1989.
 * Modified by Mark J. Steiglitz, Stanford, May, 1991
 * Modified by Van Jacobson, LBL, January 1993
 * Modified by Ajit Thyagarajan, PARC, August 1993
 * Modified by Bill Fenner, PARC, April 1995
 *
 * MROUTING Revision: 3.5
 * $FreeBSD: src/sys/netinet/ip_mroute.c,v 1.56.2.2 2001/07/19 06:37:26 kris Exp $
 */

#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/protosw.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_pcb.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/in_var.h>
#include <netinet/igmp.h>
#include <netinet/ip_mroute.h>
#include <netinet/udp.h>

#ifndef NTOHL
#if BYTE_ORDER != BIG_ENDIAN
#define NTOHL(d) ((d) = ntohl((d)))
#define NTOHS(d) ((d) = ntohs((u_short)(d)))
#define HTONL(d) ((d) = htonl((d)))
#define HTONS(d) ((d) = htons((u_short)(d)))
#else
#define NTOHL(d)
#define NTOHS(d)
#define HTONL(d)
#define HTONS(d)
#endif
#endif

#ifndef MROUTING
extern u_long	_ip_mcast_src __P((int vifi));
extern int	_ip_mforward __P((struct ip *ip, struct ifnet *ifp,
				  struct mbuf *m, struct ip_moptions *imo));
extern int	_ip_mrouter_done __P((void));
extern int	_ip_mrouter_get __P((struct socket *so, struct sockopt *sopt));
extern int	_ip_mrouter_set __P((struct socket *so, struct sockopt *sopt));
extern int	_mrt_ioctl __P((int req, caddr_t data, struct proc *p));

/*
 * Dummy routines and globals used when multicast routing is not compiled in.
 */

struct socket  *ip_mrouter  = NULL;
u_int		rsvpdebug = 0;

int
_ip_mrouter_set(so, sopt)
	struct socket *so;
	struct sockopt *sopt;
{
	return(EOPNOTSUPP);
}

int (*ip_mrouter_set)(struct socket *, struct sockopt *) = _ip_mrouter_set;


int
_ip_mrouter_get(so, sopt)
	struct socket *so;
	struct sockopt *sopt;
{
	return(EOPNOTSUPP);
}

int (*ip_mrouter_get)(struct socket *, struct sockopt *) = _ip_mrouter_get;

int
_ip_mrouter_done()
{
	return(0);
}

int (*ip_mrouter_done)(void) = _ip_mrouter_done;

int
_ip_mforward(ip, ifp, m, imo)
	struct ip *ip;
	struct ifnet *ifp;
	struct mbuf *m;
	struct ip_moptions *imo;
{
	return(0);
}

int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
		   struct ip_moptions *) = _ip_mforward;

int
_mrt_ioctl(int req, caddr_t data, struct proc *p)
{
	return EOPNOTSUPP;
}

int (*mrt_ioctl)(int, caddr_t, struct proc *) = _mrt_ioctl;

void
rsvp_input(m, off)		/* XXX must fixup manually */
	struct mbuf *m;
	int off;
{
    /* Can still get packets with rsvp_on = 0 if there is a local member
     * of the group to which the RSVP packet is addressed.  But in this
     * case we want to throw the packet away.
     */
    if (!rsvp_on) {
	m_freem(m);
	return;
    }
 
    if (ip_rsvpd != NULL) {
	if (rsvpdebug)
	    printf("rsvp_input: Sending packet up old-style socket\n");
	rip_input(m, off);
	return;
    }
    /* Drop the packet */
    m_freem(m);
}

void ipip_input(struct mbuf *m, int off) { /* XXX must fixup manually */
	rip_input(m, off);
}

int (*legal_vif_num)(int) = 0;

/*
 * This should never be called, since IP_MULTICAST_VIF should fail, but
 * just in case it does get called, the code a little lower in ip_output
 * will assign the packet a local address.
 */
u_long
_ip_mcast_src(int vifi) { return INADDR_ANY; }
u_long (*ip_mcast_src)(int) = _ip_mcast_src;

int
ip_rsvp_vif_init(so, sopt)
    struct socket *so;
    struct sockopt *sopt;
{
    return(EINVAL);
}

int
ip_rsvp_vif_done(so, sopt)
    struct socket *so;
    struct sockopt *sopt;
{
    return(EINVAL);
}

void
ip_rsvp_force_done(so)
    struct socket *so;
{
    return;
}

#else /* MROUTING */

#define M_HASCL(m)	((m)->m_flags & M_EXT)

#define INSIZ		sizeof(struct in_addr)
#define	same(a1, a2) \	(bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0)

/*
 * Globals.  All but ip_mrouter and ip_mrtproto could be static,
 * except for netstat or debugging purposes.
 */
#ifndef MROUTE_LKM
struct socket  *ip_mrouter  = NULL;
static struct mrtstat	mrtstat;
#else /* MROUTE_LKM */
extern void	X_ipip_input __P((struct mbuf *m, int iphlen));
extern struct mrtstat mrtstat;
static int ip_mrtproto;
#endif

#define NO_RTE_FOUND 	0x1
#define RTE_FOUND	0x2

static struct mfc	*mfctable[MFCTBLSIZ];
static u_char		nexpire[MFCTBLSIZ];
static struct vif	viftable[MAXVIFS];
static u_int	mrtdebug = 0;	  /* debug level 	*/
#define		DEBUG_MFC	0x02
#define		DEBUG_FORWARD	0x04
#define		DEBUG_EXPIRE	0x08
#define		DEBUG_XMIT	0x10
static u_int  	tbfdebug = 0;     /* tbf debug level 	*/
static u_int	rsvpdebug = 0;	  /* rsvp debug level   */

static struct callout_handle expire_upcalls_ch;

#define		EXPIRE_TIMEOUT	(hz / 4)	/* 4x / second		*/
#define		UPCALL_EXPIRE	6		/* number of timeouts	*/

/*
 * Define the token bucket filter structures
 * tbftable -> each vif has one of these for storing info 
 */

static struct tbf tbftable[MAXVIFS];
#define		TBF_REPROCESS	(hz / 100)	/* 100x / second */

/*
 * 'Interfaces' associated with decapsulator (so we can tell
 * packets that went through it from ones that get reflected
 * by a broken gateway).  These interfaces are never linked into
 * the system ifnet list & no routes point to them.  I.e., packets
 * can't be sent this way.  They only exist as a placeholder for
 * multicast source verification.
 */
static struct ifnet multicast_decap_if[MAXVIFS];

#define ENCAP_TTL 64
#define ENCAP_PROTO IPPROTO_IPIP	/* 4 */

/* prototype IP hdr for encapsulated packets */
static struct ip multicast_encap_iphdr = {
#if BYTE_ORDER == LITTLE_ENDIAN
	sizeof(struct ip) >> 2, IPVERSION,
#else
	IPVERSION, sizeof(struct ip) >> 2,
#endif
	0,				/* tos */
	sizeof(struct ip),		/* total length */
	0,				/* id */
	0,				/* frag offset */
	ENCAP_TTL, ENCAP_PROTO,	
	0,				/* checksum */
};

/*
 * Private variables.
 */
static vifi_t	   numvifs = 0;
static int have_encap_tunnel = 0;

/*
 * one-back cache used by ipip_input to locate a tunnel's vif
 * given a datagram's src ip address.
 */
static u_long last_encap_src;
static struct vif *last_encap_vif;

static u_long	X_ip_mcast_src __P((int vifi));
static int	X_ip_mforward __P((struct ip *ip, struct ifnet *ifp, struct mbuf *m, struct ip_moptions *imo));
static int	X_ip_mrouter_done __P((void));
static int	X_ip_mrouter_get __P((struct socket *so, struct sockopt *m));
static int	X_ip_mrouter_set __P((struct socket *so, struct sockopt *m));
static int	X_legal_vif_num __P((int vif));
static int	X_mrt_ioctl __P((int cmd, caddr_t data));

static int get_sg_cnt(struct sioc_sg_req *);
static int get_vif_cnt(struct sioc_vif_req *);
static int ip_mrouter_init(struct socket *, int);
static int add_vif(struct vifctl *);
static int del_vif(vifi_t);
static int add_mfc(struct mfcctl *);
static int del_mfc(struct mfcctl *);
static int socket_send(struct socket *, struct mbuf *, struct sockaddr_in *);
static int set_assert(int);
static void expire_upcalls(void *);
static int ip_mdq(struct mbuf *, struct ifnet *, struct mfc *,
		  vifi_t);
static void phyint_send(struct ip *, struct vif *, struct mbuf *);
static void encap_send(struct ip *, struct vif *, struct mbuf *);
static void tbf_control(struct vif *, struct mbuf *, struct ip *, u_long);
static void tbf_queue(struct vif *, struct mbuf *);
static void tbf_process_q(struct vif *);
static void tbf_reprocess_q(void *);
static int tbf_dq_sel(struct vif *, struct ip *);
static void tbf_send_packet(struct vif *, struct mbuf *);
static void tbf_update_tokens(struct vif *);
static int priority(struct vif *, struct ip *);
void multiencap_decap(struct mbuf *);

/*
 * whether or not special PIM assert processing is enabled.
 */
static int pim_assert;
/*
 * Rate limit for assert notification messages, in usec
 */
#define ASSERT_MSG_TIME		3000000

/*
 * Hash function for a source, group entry
 */
#define MFCHASH(a, g) MFCHASHMOD(((a) >> 20) ^ ((a) >> 10) ^ (a) ^ \			((g) >> 20) ^ ((g) >> 10) ^ (g))

/*
 * Find a route for a given origin IP address and Multicast group address
 * Type of service parameter to be added in the future!!!
 */

#define MFCFIND(o, g, rt) { \	register struct mfc *_rt = mfctable[MFCHASH(o,g)]; \	rt = NULL; \	++mrtstat.mrts_mfc_lookups; \	while (_rt) { \		if ((_rt->mfc_origin.s_addr == o) && \		    (_rt->mfc_mcastgrp.s_addr == g) && \		    (_rt->mfc_stall == NULL)) { \			rt = _rt; \			break; \		} \		_rt = _rt->mfc_next; \	} \	if (rt == NULL) { \		++mrtstat.mrts_mfc_misses; \	} \}


/*
 * Macros to compute elapsed time efficiently
 * Borrowed from Van Jacobson's scheduling code
 */
#define TV_DELTA(a, b, delta) { \	    register int xxs; \		\	    delta = (a).tv_usec - (b).tv_usec; \	    if ((xxs = (a).tv_sec - (b).tv_sec)) { \	       switch (xxs) { \		      case 2: \			  delta += 1000000; \			      /* fall through */ \		      case 1: \			  delta += 1000000; \			  break; \		      default: \			  delta += (1000000 * xxs); \	       } \	    } \}

#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \	      (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)

#ifdef UPCALL_TIMING
u_long upcall_data[51];
static void collate(struct timeval *);
#endif /* UPCALL_TIMING */


/*
 * Handle MRT setsockopt commands to modify the multicast routing tables.
 */
static int
X_ip_mrouter_set(so, sopt)
	struct socket *so;
	struct sockopt *sopt;
{
	int	error, optval;
	vifi_t	vifi;
	struct	vifctl vifc;
	struct	mfcctl mfc;

	if (so != ip_mrouter && sopt->sopt_name != MRT_INIT)
		return (EPERM);

	error = 0;
	switch (sopt->sopt_name) {
	case MRT_INIT:
		error = sooptcopyin(sopt, &optval, sizeof optval, 
				    sizeof optval);
		if (error)
			break;
		error = ip_mrouter_init(so, optval);
		break;

	case MRT_DONE:
		error = ip_mrouter_done();
		break;

	case MRT_ADD_VIF:
		error = sooptcopyin(sopt, &vifc, sizeof vifc, sizeof vifc);
		if (error)
			break;
		error = add_vif(&vifc);
		break;

	case MRT_DEL_VIF:
		error = sooptcopyin(sopt, &vifi, sizeof vifi, sizeof vifi);
		if (error)
			break;
		error = del_vif(vifi);
		break;

	case MRT_ADD_MFC:
	case MRT_DEL_MFC:
		error = sooptcopyin(sopt, &mfc, sizeof mfc, sizeof mfc);
		if (error)
			break;
		if (sopt->sopt_name == MRT_ADD_MFC)
			error = add_mfc(&mfc);
		else
			error = del_mfc(&mfc);
		break;

	case MRT_ASSERT:
		error = sooptcopyin(sopt, &optval, sizeof optval, 
				    sizeof optval);
		if (error)
			break;
		set_assert(optval);
		break;

	default:
		error = EOPNOTSUPP;
		break;
	}
	return (error);
}

#ifndef MROUTE_LKM
int (*ip_mrouter_set)(struct socket *, struct sockopt *) = X_ip_mrouter_set;
#endif

/*
 * Handle MRT getsockopt commands
 */
static int
X_ip_mrouter_get(so, sopt)
	struct socket *so;
	struct sockopt *sopt;
{
	int error;
	static int version = 0x0305; /* !!! why is this here? XXX */

	switch (sopt->sopt_name) {
	case MRT_VERSION:
		error = sooptcopyout(sopt, &version, sizeof version);
		break;

	case MRT_ASSERT:
		error = sooptcopyout(sopt, &pim_assert, sizeof pim_assert);
		break;
	default:
		error = EOPNOTSUPP;
		break;
	}
	return (error);
}

#ifndef MROUTE_LKM
int (*ip_mrouter_get)(struct socket *, struct sockopt *) = X_ip_mrouter_get;
#endif

/*
 * Handle ioctl commands to obtain information from the cache
 */
static int
X_mrt_ioctl(cmd, data)
    int cmd;
    caddr_t data;
{
    int error = 0;

    switch (cmd) {
	case (SIOCGETVIFCNT):
	    return (get_vif_cnt((struct sioc_vif_req *)data));
	    break;
	case (SIOCGETSGCNT):
	    return (get_sg_cnt((struct sioc_sg_req *)data));
	    break;
	default:
	    return (EINVAL);
	    break;
    }
    return error;
}

#ifndef MROUTE_LKM
int (*mrt_ioctl)(int, caddr_t) = X_mrt_ioctl;
#endif

/*
 * returns the packet, byte, rpf-failure count for the source group provided
 */
static int
get_sg_cnt(req)
    register struct sioc_sg_req *req;
{
    register struct mfc *rt;
    int s;

    s = splnet();
    MFCFIND(req->src.s_addr, req->grp.s_addr, rt);
    splx(s);
    if (rt != NULL) {
	req->pktcnt = rt->mfc_pkt_cnt;
	req->bytecnt = rt->mfc_byte_cnt;
	req->wrong_if = rt->mfc_wrong_if;
    } else
	req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;

    return 0;
}

/*
 * returns the input and output packet and byte counts on the vif provided
 */
static int
get_vif_cnt(req)
    register struct sioc_vif_req *req;
{
    register vifi_t vifi = req->vifi;

    if (vifi >= numvifs) return EINVAL;

    req->icount = viftable[vifi].v_pkt_in;
    req->ocount = viftable[vifi].v_pkt_out;
    req->ibytes = viftable[vifi].v_bytes_in;
    req->obytes = viftable[vifi].v_bytes_out;

    return 0;
}

/*
 * Enable multicast routing
 */
static int
ip_mrouter_init(so, version)
	struct socket *so;
	int version;
{
    if (mrtdebug)
	log(LOG_DEBUG,"ip_mrouter_init: so_type = %d, pr_protocol = %d\n",
		so->so_type, so->so_proto->pr_protocol);

    if (so->so_type != SOCK_RAW ||
	so->so_proto->pr_protocol != IPPROTO_IGMP) return EOPNOTSUPP;

    if (version != 1)
	return ENOPROTOOPT;

    if (ip_mrouter != NULL) return EADDRINUSE;

⌨️ 快捷键说明

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