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

📄 ip6_mroute.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
//==========================================================================
//
//      src/sys/netinet6/ip6_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####
//==========================================================================

/*	$KAME: ip6_mroute.c,v 1.58 2001/12/18 02:36:31 itojun Exp $	*/

/*
 * Copyright (C) 1998 WIDE Project.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*	BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp	*/

/*
 * 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 Fenenr, PARC, April 1994
 *
 * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support
 */

/*
 * XXX it seems that home address option processing should be reverted
 * before calls to socket_send().  see sys/netinet6/dest6.c for details.
 */

#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sockio.h>
#include <sys/protosw.h>
#include <sys/errno.h>
#include <sys/time.h>

#include <net/if.h>
#include <net/route.h>
#include <net/raw_cb.h>

#include <netinet/in.h>
#include <netinet/in_var.h>

#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/ip6_mroute.h>
#include <netinet6/pim6.h>
#include <netinet6/pim6_var.h>

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

static int ip6_mdq __P((struct mbuf *, struct ifnet *, struct mf6c *));
static void phyint_send __P((struct ip6_hdr *, struct mif6 *, struct mbuf *));

static int set_pim6 __P((int *));
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
static int get_pim6 __P((struct mbuf *));
#endif
static int socket_send __P((struct socket *, struct mbuf *,
			    struct sockaddr_in6 *));
static int register_send __P((struct ip6_hdr *, struct mif6 *,
			      struct mbuf *));

/*
 * Globals.  All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
 * except for netstat or debugging purposes.
 */
struct socket  *ip6_mrouter = NULL;
int		ip6_mrouter_ver = 0;
int		ip6_mrtproto = IPPROTO_PIM;    /* for netstat only */
struct mrt6stat	mrt6stat;

#define NO_RTE_FOUND 	0x1
#define RTE_FOUND	0x2

struct mf6c	*mf6ctable[MF6CTBLSIZ];
u_char		n6expire[MF6CTBLSIZ];
#if (defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)) 
struct mif6 mif6table[MAXMIFS];
#else
static struct mif6 mif6table[MAXMIFS];
#endif
#ifdef MRT6DEBUG
u_int		mrt6debug = 0;	  /* debug level 	*/
#define		DEBUG_MFC	0x02
#define		DEBUG_FORWARD	0x04
#define		DEBUG_EXPIRE	0x08
#define		DEBUG_XMIT	0x10
#define         DEBUG_REG       0x20
#define         DEBUG_PIM       0x40
#endif

static void	expire_upcalls __P((void *));
#define		EXPIRE_TIMEOUT	(hz / 4)	/* 4x / second */
#define		UPCALL_EXPIRE	6		/* number of timeouts */

#ifdef INET
#ifdef MROUTING
extern struct socket *ip_mrouter;
#endif
#endif

/*
 * '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.
 */
struct ifnet multicast_register_if;

#define ENCAP_HOPS 64

/*
 * Private variables.
 */
static mifi_t nummifs = 0;
static mifi_t reg_mif_num = (mifi_t)-1;

static struct pim6stat pim6stat;
static int pim6;

/*
 * Hash function for a source, group entry
 */
#define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \				   (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \				   (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \				   (g).s6_addr32[2] ^ (g).s6_addr32[3])

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

#define MF6CFIND(o, g, rt) do { \	struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \	rt = NULL; \	mrt6stat.mrt6s_mfc_lookups++; \	while (_rt) { \		if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \		    IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \		    (_rt->mf6c_stall == NULL)) { \			rt = _rt; \			break; \		} \		_rt = _rt->mf6c_next; \	} \	if (rt == NULL) { \		mrt6stat.mrt6s_mfc_misses++; \	} \} while (0)

/*
 * Macros to compute elapsed time efficiently
 * Borrowed from Van Jacobson's scheduling code
 */
#define TV_DELTA(a, b, delta) do { \	    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); \	       } \	    } \} while (0)

#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
#define UPCALL_MAX	50
u_long upcall_data[UPCALL_MAX + 1];
static void collate();
#endif /* UPCALL_TIMING */

static int get_sg_cnt __P((struct sioc_sg_req6 *));
static int get_mif6_cnt __P((struct sioc_mif_req6 *));
static int ip6_mrouter_init __P((struct socket *, struct mbuf *, int));
static int add_m6if __P((struct mif6ctl *));
static int del_m6if __P((mifi_t *));
static int add_m6fc __P((struct mf6cctl *));
static int del_m6fc __P((struct mf6cctl *));

#ifdef __NetBSD__
static struct callout expire_upcalls_ch = CALLOUT_INITIALIZER;
#elif (defined(__FreeBSD__) && __FreeBSD__ >= 3)
static struct callout expire_upcalls_ch;
#elif defined(__OpenBSD__)
static struct timeout expire_upcalls_ch;
#endif

/*
 * Handle MRT setsockopt commands to modify the multicast routing tables.
 */
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
int
ip6_mrouter_set(so, sopt)
	struct socket *so;
	struct sockopt *sopt;
{
	int	error = 0;
	struct mbuf *m;

	if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT)
		return (EACCES);

	if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
		return (error);
	if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */
		return (error);

	switch (sopt->sopt_name) {
	case MRT6_INIT:
#ifdef MRT6_OINIT
	case MRT6_OINIT:
#endif
		error = ip6_mrouter_init(so, m, sopt->sopt_name);
		break;
	case MRT6_DONE:
		error = ip6_mrouter_done();
		break;
	case MRT6_ADD_MIF:
		error = add_m6if(mtod(m, struct mif6ctl *));
		break;
	case MRT6_DEL_MIF:
		error = del_m6if(mtod(m, mifi_t *));
		break;
	case MRT6_ADD_MFC:
		error = add_m6fc(mtod(m, struct mf6cctl *));
		break;
	case MRT6_DEL_MFC:
		error = del_m6fc(mtod(m, struct mf6cctl *));
		break;
	case MRT6_PIM:
		error = set_pim6(mtod(m, int *));
		break;
	default:
		error = EOPNOTSUPP;
		break;
	}

	(void)m_freem(m);
	return(error);
}
#else
int
ip6_mrouter_set(cmd, so, m)
	int cmd;
	struct socket *so;
	struct mbuf *m;
{
	if (cmd != MRT6_INIT && so != ip6_mrouter)
		return EACCES;

	switch (cmd) {
#ifdef MRT6_OINIT
	case MRT6_OINIT:	return ip6_mrouter_init(so, m, cmd);
#endif
	case MRT6_INIT:		return ip6_mrouter_init(so, m, cmd);
	case MRT6_DONE:		return ip6_mrouter_done();
	case MRT6_ADD_MIF:	return add_m6if(mtod(m, struct mif6ctl *));
	case MRT6_DEL_MIF:	return del_m6if(mtod(m, mifi_t *));
	case MRT6_ADD_MFC:	return add_m6fc(mtod(m, struct mf6cctl *));
	case MRT6_DEL_MFC:	return del_m6fc(mtod(m, struct mf6cctl *));
	case MRT6_PIM:		return set_pim6(mtod(m, int *));
	default:		return EOPNOTSUPP;
	}
}
#endif

/*
 * Handle MRT getsockopt commands
 */
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
int
ip6_mrouter_get(so, sopt)
	struct socket *so;
	struct sockopt *sopt;
{
	int error = 0;

	if (so != ip6_mrouter) return EACCES;

	switch (sopt->sopt_name) {
		case MRT6_PIM:
			error = sooptcopyout(sopt, &pim6, sizeof(pim6));
			break;
	}
	return (error);
}
#else
int
ip6_mrouter_get(cmd, so, m)
	int cmd;
	struct socket *so;
	struct mbuf **m;
{
	struct mbuf *mb;

	if (so != ip6_mrouter) return EACCES;

	*m = mb = m_get(M_WAIT, MT_SOOPTS);

	switch (cmd) {
	case MRT6_PIM:
		return get_pim6(mb);
	default:
		m_free(mb);
		return EOPNOTSUPP;
	}
}
#endif

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

	switch (cmd) {
	case SIOCGETSGCNT_IN6:
		return(get_sg_cnt((struct sioc_sg_req6 *)data));
		break;		/* for safety */
	case SIOCGETMIFCNT_IN6:
		return(get_mif6_cnt((struct sioc_mif_req6 *)data));
		break;		/* for safety */
	default:
		return (EINVAL);
		break;
	}
	return error;
}

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

#ifdef __NetBSD__
	s = splsoftnet();
#else
	s = splnet();
#endif
	MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
	splx(s);
	if (rt != NULL) {
		req->pktcnt = rt->mf6c_pkt_cnt;
		req->bytecnt = rt->mf6c_byte_cnt;
		req->wrong_if = rt->mf6c_wrong_if;
	} else
		return(ESRCH);
#if 0
		req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
#endif

	return 0;
}

/*
 * returns the input and output packet and byte counts on the mif provided
 */
static int
get_mif6_cnt(req)
	struct sioc_mif_req6 *req;
{
	mifi_t mifi = req->mifi;

	if (mifi >= nummifs)
		return EINVAL;

	req->icount = mif6table[mifi].m6_pkt_in;
	req->ocount = mif6table[mifi].m6_pkt_out;
	req->ibytes = mif6table[mifi].m6_bytes_in;
	req->obytes = mif6table[mifi].m6_bytes_out;

	return 0;
}

#if !(defined(__FreeBSD__) && __FreeBSD__ >=3)
/*
 * Get PIM processiong global
 */
static int
get_pim6(m)
	struct mbuf *m;
{
	int *i;

	i = mtod(m, int *);

	*i = pim6;

	return 0;
}
#endif

static int
set_pim6(i)
	int *i;
{
	if ((*i != 1) && (*i != 0))
		return EINVAL;

	pim6 = *i;

	return 0;
}

/*
 * Enable multicast routing
 */
static int
ip6_mrouter_init(so, m, cmd)
	struct socket *so;
	struct mbuf *m;
	int cmd;
{
	int *v;

#ifdef MRT6DEBUG
	if (mrt6debug)
		log(LOG_DEBUG,
		    "ip6_mrouter_init: so_type = %d, pr_protocol = %d\n",
		    so->so_type, so->so_proto->pr_protocol);
#endif

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

	if (!m || (m->m_len != sizeof(int *)))
		return ENOPROTOOPT;

	v = mtod(m, int *);
	if (*v != 1)
		return ENOPROTOOPT;

	if (ip6_mrouter != NULL) return EADDRINUSE;

	ip6_mrouter = so;
	ip6_mrouter_ver = cmd;

	bzero((caddr_t)mf6ctable, sizeof(mf6ctable));

⌨️ 快捷键说明

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