📄 ip6_mroute.c
字号:
//==========================================================================
//
// 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 + -