ip6_mroute.c revision 167119
11556Srgrimes/*	$FreeBSD: head/sys/netinet6/ip6_mroute.c 167119 2007-02-28 20:32:25Z bms $	*/
21556Srgrimes/*	$KAME: ip6_mroute.c,v 1.58 2001/12/18 02:36:31 itojun Exp $	*/
31556Srgrimes
41556Srgrimes/*-
51556Srgrimes * Copyright (C) 1998 WIDE Project.
61556Srgrimes * All rights reserved.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. Neither the name of the project nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes/*	BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp	*/
3436150Scharnier
3536150Scharnier/*-
3636150Scharnier * Copyright (c) 1989 Stephen Deering
371556Srgrimes * Copyright (c) 1992, 1993
3899110Sobrien *      The Regents of the University of California.  All rights reserved.
3999110Sobrien *
401556Srgrimes * This code is derived from software contributed to Berkeley by
4117987Speter * Stephen Deering of Stanford University.
4217987Speter *
4317987Speter * Redistribution and use in source and binary forms, with or without
4417987Speter * modification, are permitted provided that the following conditions
4517987Speter * are met:
4617987Speter * 1. Redistributions of source code must retain the above copyright
4717987Speter *    notice, this list of conditions and the following disclaimer.
481556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
491556Srgrimes *    notice, this list of conditions and the following disclaimer in the
501556Srgrimes *    documentation and/or other materials provided with the distribution.
511556Srgrimes * 4. Neither the name of the University nor the names of its contributors
521556Srgrimes *    may be used to endorse or promote products derived from this software
531556Srgrimes *    without specific prior written permission.
541556Srgrimes *
551556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
561556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
571556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
581556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
591556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
601556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
611556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
621556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
631556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
641556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
651556Srgrimes * SUCH DAMAGE.
661556Srgrimes *
671556Srgrimes *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
681556Srgrimes */
691556Srgrimes
701556Srgrimes/*
711556Srgrimes * IP multicast forwarding procedures
721556Srgrimes *
731556Srgrimes * Written by David Waitzman, BBN Labs, August 1988.
7417987Speter * Modified by Steve Deering, Stanford, February 1989.
751556Srgrimes * Modified by Mark J. Steiglitz, Stanford, May, 1991
7625223Ssteve * Modified by Van Jacobson, LBL, January 1993
771556Srgrimes * Modified by Ajit Thyagarajan, PARC, August 1993
781556Srgrimes * Modified by Bill Fenner, PARC, April 1994
791556Srgrimes *
801556Srgrimes * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support
811556Srgrimes */
821556Srgrimes
831556Srgrimes#include "opt_inet.h"
841556Srgrimes#include "opt_inet6.h"
851556Srgrimes
861556Srgrimes#include <sys/param.h>
87157601Sstefanf#include <sys/callout.h>
881556Srgrimes#include <sys/errno.h>
891556Srgrimes#include <sys/kernel.h>
901556Srgrimes#include <sys/lock.h>
911556Srgrimes#include <sys/malloc.h>
921556Srgrimes#include <sys/mbuf.h>
931556Srgrimes#include <sys/protosw.h>
941556Srgrimes#include <sys/signalvar.h>
951556Srgrimes#include <sys/socket.h>
9620425Ssteve#include <sys/socketvar.h>
971556Srgrimes#include <sys/sockio.h>
981556Srgrimes#include <sys/sx.h>
9990111Simp#include <sys/sysctl.h>
10090111Simp#include <sys/syslog.h>
10190111Simp#include <sys/systm.h>
10290111Simp#include <sys/time.h>
1031556Srgrimes
1041556Srgrimes#include <net/if.h>
1051556Srgrimes#include <net/if_types.h>
1061556Srgrimes#include <net/raw_cb.h>
1071556Srgrimes#include <net/route.h>
1081556Srgrimes
1091556Srgrimes#include <netinet/in.h>
1101556Srgrimes#include <netinet/in_var.h>
1111556Srgrimes#include <netinet/icmp6.h>
11290111Simp
11317987Speter#include <netinet/ip6.h>
1141556Srgrimes#include <netinet6/ip6_var.h>
1151556Srgrimes#include <netinet6/scope6_var.h>
1161556Srgrimes#include <netinet6/nd6.h>
1171556Srgrimes#include <netinet6/ip6_mroute.h>
1181556Srgrimes#include <netinet6/ip6protosw.h>
1191556Srgrimes#include <netinet6/pim6.h>
1201556Srgrimes#include <netinet6/pim6_var.h>
1211556Srgrimes
1221556Srgrimesstatic MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry");
1231556Srgrimes
1241556Srgrimes#define M_HASCL(m) ((m)->m_flags & M_EXT)
1251556Srgrimes
1261556Srgrimesstatic int ip6_mdq __P((struct mbuf *, struct ifnet *, struct mf6c *));
1271556Srgrimesstatic void phyint_send __P((struct ip6_hdr *, struct mif6 *, struct mbuf *));
1281556Srgrimes
1291556Srgrimesstatic int set_pim6 __P((int *));
1301556Srgrimesstatic int socket_send __P((struct socket *, struct mbuf *,
13120425Ssteve	    struct sockaddr_in6 *));
13220425Sstevestatic int register_send __P((struct ip6_hdr *, struct mif6 *,
13320425Ssteve	    struct mbuf *));
13420425Ssteve
13520425Ssteveextern struct domain inet6domain;
13620425Ssteve
13720425Ssteve/* XXX: referenced from ip_mroute.c for dynamically loading this code. */
13820425Sstevestruct ip6protosw in6_pim_protosw = {
13920425Ssteve	.pr_type =		SOCK_RAW,
14020425Ssteve	.pr_domain =		&inet6domain,
14120425Ssteve	.pr_protocol =		IPPROTO_PIM,
14220425Ssteve	.pr_flags =		PR_ATOMIC|PR_ADDR|PR_LASTHDR,
14320425Ssteve	.pr_input =		pim6_input,
144104283Stjr	.pr_output =		rip6_output,
145104283Stjr	.pr_ctloutput =		rip6_ctloutput,
146104132Stjr	.pr_usrreqs =		&rip6_usrreqs
1471556Srgrimes};
1481556Srgrimes
1491556Srgrimesstatic int ip6_mrouter_ver = 0;
1501556Srgrimes
15190111SimpSYSCTL_DECL(_net_inet6);
15290111SimpSYSCTL_DECL(_net_inet6_ip6);
1531556SrgrimesSYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM");
1541556Srgrimes
1551556Srgrimesstatic struct mrt6stat mrt6stat;
1561556SrgrimesSYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW,
1571556Srgrimes    &mrt6stat, mrt6stat,
1581556Srgrimes    "Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)");
1591556Srgrimes
1601556Srgrimes#define NO_RTE_FOUND 	0x1
1611556Srgrimes#define RTE_FOUND	0x2
1621556Srgrimes
1631556Srgrimesstatic struct mf6c *mf6ctable[MF6CTBLSIZ];
1641556SrgrimesSYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mf6ctable, CTLFLAG_RD,
1651556Srgrimes    &mf6ctable, sizeof(mf6ctable), "S,*mf6ctable[MF6CTBLSIZ]",
1661556Srgrimes    "Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], "
1671556Srgrimes    "netinet6/ip6_mroute.h)");
1681556Srgrimes
1691556Srgrimesstatic u_char n6expire[MF6CTBLSIZ];
1701556Srgrimes
1711556Srgrimesstatic struct mif6 mif6table[MAXMIFS];
1721556SrgrimesSYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mif6table, CTLFLAG_RD,
1731556Srgrimes    &mif6table, sizeof(mif6table), "S,vif[MAXMIFS]",
1741556Srgrimes    "Multicast Interfaces (struct mif[MAXMIFS], netinet6/ip6_mroute.h)");
1751556Srgrimes
1761556Srgrimes#ifdef MRT6DEBUG
1771556Srgrimesstatic u_int mrt6debug = 0;		/* debug level */
1781556Srgrimes#define DEBUG_MFC	0x02
1791556Srgrimes#define DEBUG_FORWARD	0x04
1801556Srgrimes#define DEBUG_EXPIRE	0x08
18190111Simp#define DEBUG_XMIT	0x10
18290111Simp#define DEBUG_REG	0x20
18325223Ssteve#define DEBUG_PIM	0x40
1841556Srgrimes#endif
1851556Srgrimes
1861556Srgrimesstatic void	expire_upcalls __P((void *));
1871556Srgrimes#define	EXPIRE_TIMEOUT	(hz / 4)	/* 4x / second */
1881556Srgrimes#define	UPCALL_EXPIRE	6		/* number of timeouts */
1891556Srgrimes
1901556Srgrimes#ifdef INET
1911556Srgrimes#ifdef MROUTING
1921556Srgrimesextern struct socket *ip_mrouter;
1931556Srgrimes#endif
1941556Srgrimes#endif
1951556Srgrimes
19617987Speter/*
1971556Srgrimes * 'Interfaces' associated with decapsulator (so we can tell
1981556Srgrimes * packets that went through it from ones that get reflected
1991556Srgrimes * by a broken gateway).  Different from IPv4 register_if,
2001556Srgrimes * these interfaces are linked into the system ifnet list,
2011556Srgrimes * because per-interface IPv6 statistics are maintained in
2021556Srgrimes * ifp->if_afdata.  But it does not have any routes point
2031556Srgrimes * to them.  I.e., packets can't be sent this way.  They
2041556Srgrimes * only exist as a placeholder for multicast source
2051556Srgrimes * verification.
2061556Srgrimes */
2071556Srgrimesstatic struct ifnet *multicast_register_if6;
2081556Srgrimes
2091556Srgrimes#define ENCAP_HOPS 64
2101556Srgrimes
2111556Srgrimes/*
2121556Srgrimes * Private variables.
2131556Srgrimes */
2141556Srgrimesstatic mifi_t nummifs = 0;
2151556Srgrimesstatic mifi_t reg_mif_num = (mifi_t)-1;
2161556Srgrimes
2171556Srgrimesstatic struct pim6stat pim6stat;
21817987SpeterSYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RD,
21990111Simp    &pim6stat, pim6stat,
22017987Speter    "PIM Statistics (struct pim6stat, netinet6/pim_var.h)");
2211556Srgrimes
2221556Srgrimesstatic int pim6;
2231556Srgrimes
2241556Srgrimes/*
2251556Srgrimes * Hash function for a source, group entry
2261556Srgrimes */
2271556Srgrimes#define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
2281556Srgrimes				   (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
2291556Srgrimes				   (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \
2301556Srgrimes				   (g).s6_addr32[2] ^ (g).s6_addr32[3])
2311556Srgrimes
2321556Srgrimes/*
2331556Srgrimes * Find a route for a given origin IPv6 address and Multicast group address.
2341556Srgrimes */
2351556Srgrimes#define MF6CFIND(o, g, rt) do { \
2361556Srgrimes	struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
2371556Srgrimes	rt = NULL; \
2381556Srgrimes	mrt6stat.mrt6s_mfc_lookups++; \
23998157Stjr	while (_rt) { \
24098157Stjr		if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \
2411556Srgrimes		    IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \
2421556Srgrimes		    (_rt->mf6c_stall == NULL)) { \
2431556Srgrimes			rt = _rt; \
2441556Srgrimes			break; \
2451556Srgrimes		} \
2461556Srgrimes		_rt = _rt->mf6c_next; \
2471556Srgrimes	} \
24817987Speter	if (rt == NULL) { \
2491556Srgrimes		mrt6stat.mrt6s_mfc_misses++; \
25017987Speter	} \
2511556Srgrimes} while (/*CONSTCOND*/ 0)
2521556Srgrimes
2531556Srgrimes/*
25494775Sgreid * Macros to compute elapsed time efficiently
25594775Sgreid * Borrowed from Van Jacobson's scheduling code
25694775Sgreid */
25794775Sgreid#define TV_DELTA(a, b, delta) do { \
2581556Srgrimes	    int xxs; \
2591556Srgrimes		\
2601556Srgrimes	    delta = (a).tv_usec - (b).tv_usec; \
2611556Srgrimes	    if ((xxs = (a).tv_sec - (b).tv_sec)) { \
2621556Srgrimes	       switch (xxs) { \
2631556Srgrimes		      case 2: \
2641556Srgrimes			  delta += 1000000; \
2651556Srgrimes			      /* FALLTHROUGH */ \
2661556Srgrimes		      case 1: \
2671556Srgrimes			  delta += 1000000; \
26890111Simp			  break; \
26990111Simp		      default: \
2701556Srgrimes			  delta += (1000000 * xxs); \
2711556Srgrimes	       } \
2721556Srgrimes	    } \
2731556Srgrimes} while (/*CONSTCOND*/ 0)
2741556Srgrimes
2751556Srgrimes#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
2761556Srgrimes	      (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
2771556Srgrimes
2781556Srgrimes#ifdef UPCALL_TIMING
2791556Srgrimes#define UPCALL_MAX	50
2801556Srgrimesstatic u_long upcall_data[UPCALL_MAX + 1];
2811556Srgrimesstatic void collate();
2821556Srgrimes#endif /* UPCALL_TIMING */
2831556Srgrimes
2841556Srgrimesstatic int get_sg_cnt __P((struct sioc_sg_req6 *));
2851556Srgrimesstatic int get_mif6_cnt __P((struct sioc_mif_req6 *));
2861556Srgrimesstatic int ip6_mrouter_init __P((struct socket *, int, int));
2871556Srgrimesstatic int add_m6if __P((struct mif6ctl *));
2881556Srgrimesstatic int del_m6if __P((mifi_t *));
2891556Srgrimesstatic int add_m6fc __P((struct mf6cctl *));
2901556Srgrimesstatic int del_m6fc __P((struct mf6cctl *));
2911556Srgrimes
2921556Srgrimesstatic struct callout expire_upcalls_ch;
2931556Srgrimes
2941556Srgrimesint X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m);
2951556Srgrimesint X_ip6_mrouter_done(void);
2961556Srgrimesint X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt);
2971556Srgrimesint X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt);
2981556Srgrimesint X_mrt6_ioctl(int cmd, caddr_t data);
2991556Srgrimes
3001556Srgrimes/*
3011556Srgrimes * Handle MRT setsockopt commands to modify the multicast routing tables.
3021556Srgrimes */
3031556Srgrimesint
3041556SrgrimesX_ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
3051556Srgrimes{
3061556Srgrimes	int error = 0;
3071556Srgrimes	int optval;
3081556Srgrimes	struct mif6ctl mifc;
3091556Srgrimes	struct mf6cctl mfcc;
3101556Srgrimes	mifi_t mifi;
3111556Srgrimes
31290111Simp	if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT)
31317987Speter		return (EACCES);
3141556Srgrimes
3151556Srgrimes	switch (sopt->sopt_name) {
3161556Srgrimes	case MRT6_INIT:
3171556Srgrimes#ifdef MRT6_OINIT
3181556Srgrimes	case MRT6_OINIT:
3191556Srgrimes#endif
3201556Srgrimes		error = sooptcopyin(sopt, &optval, sizeof(optval),
321157601Sstefanf		    sizeof(optval));
3221556Srgrimes		if (error)
3231556Srgrimes			break;
3241556Srgrimes		error = ip6_mrouter_init(so, optval, sopt->sopt_name);
3251556Srgrimes		break;
3261556Srgrimes	case MRT6_DONE:
3271556Srgrimes		error = X_ip6_mrouter_done();
3281556Srgrimes		break;
3291556Srgrimes	case MRT6_ADD_MIF:
3301556Srgrimes		error = sooptcopyin(sopt, &mifc, sizeof(mifc), sizeof(mifc));
3311556Srgrimes		if (error)
3321556Srgrimes			break;
3331556Srgrimes		error = add_m6if(&mifc);
3341556Srgrimes		break;
335157601Sstefanf	case MRT6_ADD_MFC:
3361556Srgrimes		error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
3371556Srgrimes		if (error)
3381556Srgrimes			break;
3391556Srgrimes		error = add_m6fc(&mfcc);
340157601Sstefanf		break;
3411556Srgrimes	case MRT6_DEL_MFC:
3421556Srgrimes		error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
3431556Srgrimes		if (error)
3441556Srgrimes			break;
3451556Srgrimes		error = del_m6fc(&mfcc);
3461556Srgrimes		break;
3471556Srgrimes	case MRT6_DEL_MIF:
3481556Srgrimes		error = sooptcopyin(sopt, &mifi, sizeof(mifi), sizeof(mifi));
3491556Srgrimes		if (error)
3501556Srgrimes			break;
3511556Srgrimes		error = del_m6if(&mifi);
3521556Srgrimes		break;
3531556Srgrimes	case MRT6_PIM:
3541556Srgrimes		error = sooptcopyin(sopt, &optval, sizeof(optval),
3551556Srgrimes		    sizeof(optval));
3561556Srgrimes		if (error)
3571556Srgrimes			break;
3581556Srgrimes		error = set_pim6(&optval);
3591556Srgrimes		break;
3601556Srgrimes	default:
3611556Srgrimes		error = EOPNOTSUPP;
362157601Sstefanf		break;
3631556Srgrimes	}
3641556Srgrimes
3651556Srgrimes	return (error);
3661556Srgrimes}
3671556Srgrimes
368157601Sstefanf/*
3691556Srgrimes * Handle MRT getsockopt commands
3701556Srgrimes */
3711556Srgrimesint
3721556SrgrimesX_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
3731556Srgrimes{
3741556Srgrimes	int error = 0;
3751556Srgrimes
3761556Srgrimes	if (so != ip6_mrouter)
3771556Srgrimes		return (EACCES);
3781556Srgrimes
3791556Srgrimes	switch (sopt->sopt_name) {
3801556Srgrimes		case MRT6_PIM:
3811556Srgrimes			error = sooptcopyout(sopt, &pim6, sizeof(pim6));
3821556Srgrimes			break;
3831556Srgrimes	}
384100351Stjr	return (error);
3851556Srgrimes}
3861556Srgrimes
3871556Srgrimes/*
3881556Srgrimes * Handle ioctl commands to obtain information from the cache
3891556Srgrimes */
39017987Speterint
3911556SrgrimesX_mrt6_ioctl(int cmd, caddr_t data)
3921556Srgrimes{
3931556Srgrimes	switch (cmd) {
3941556Srgrimes	case SIOCGETSGCNT_IN6:
3951556Srgrimes		return (get_sg_cnt((struct sioc_sg_req6 *)data));
3961556Srgrimes	case SIOCGETMIFCNT_IN6:
3971556Srgrimes		return (get_mif6_cnt((struct sioc_mif_req6 *)data));
3981556Srgrimes	default:
3991556Srgrimes		return (EINVAL);
4001556Srgrimes	}
4011556Srgrimes}
4021556Srgrimes
4031556Srgrimes/*
4041556Srgrimes * returns the packet, byte, rpf-failure count for the source group provided
4051556Srgrimes */
4061556Srgrimesstatic int
4071556Srgrimesget_sg_cnt(req)
4081556Srgrimes	struct sioc_sg_req6 *req;
4091556Srgrimes{
4101556Srgrimes	struct mf6c *rt;
4111556Srgrimes	int s;
4121556Srgrimes
4131556Srgrimes	s = splnet();
4141556Srgrimes	MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
4151556Srgrimes	splx(s);
4161556Srgrimes	if (rt != NULL) {
4171556Srgrimes		req->pktcnt = rt->mf6c_pkt_cnt;
4181556Srgrimes		req->bytecnt = rt->mf6c_byte_cnt;
4191556Srgrimes		req->wrong_if = rt->mf6c_wrong_if;
4201556Srgrimes	} else
4211556Srgrimes		return (ESRCH);
4221556Srgrimes#if 0
4231556Srgrimes		req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
424104283Stjr#endif
425104283Stjr
426104283Stjr	return (0);
427104283Stjr}
428104283Stjr
429104283Stjr/*
4301556Srgrimes * returns the input and output packet and byte counts on the mif provided
4311556Srgrimes */
4321556Srgrimesstatic int
4331556Srgrimesget_mif6_cnt(req)
4341556Srgrimes	struct sioc_mif_req6 *req;
4351556Srgrimes{
4361556Srgrimes	mifi_t mifi = req->mifi;
437157601Sstefanf
4381556Srgrimes	if (mifi >= nummifs)
4391556Srgrimes		return (EINVAL);
4401556Srgrimes
4411556Srgrimes	req->icount = mif6table[mifi].m6_pkt_in;
4421556Srgrimes	req->ocount = mif6table[mifi].m6_pkt_out;
4431556Srgrimes	req->ibytes = mif6table[mifi].m6_bytes_in;
4441556Srgrimes	req->obytes = mif6table[mifi].m6_bytes_out;
4451556Srgrimes
4461556Srgrimes	return (0);
447157601Sstefanf}
44817987Speter
44925223Sstevestatic int
4501556Srgrimesset_pim6(i)
4511556Srgrimes	int *i;
452157601Sstefanf{
453157601Sstefanf	if ((*i != 1) && (*i != 0))
4541556Srgrimes		return (EINVAL);
455157601Sstefanf
4561556Srgrimes	pim6 = *i;
4571556Srgrimes
4581556Srgrimes	return (0);
4591556Srgrimes}
4601556Srgrimes
4611556Srgrimes/*
4621556Srgrimes * Enable multicast routing
4631556Srgrimes */
4641556Srgrimesstatic int
4651556Srgrimesip6_mrouter_init(so, v, cmd)
4661556Srgrimes	struct socket *so;
4671556Srgrimes	int v;
46890111Simp	int cmd;
46990111Simp{
4701556Srgrimes#ifdef MRT6DEBUG
4711556Srgrimes	if (mrt6debug)
4721556Srgrimes		log(LOG_DEBUG,
4731556Srgrimes		    "ip6_mrouter_init: so_type = %d, pr_protocol = %d\n",
4741556Srgrimes		    so->so_type, so->so_proto->pr_protocol);
4751556Srgrimes#endif
47617987Speter
4771556Srgrimes	if (so->so_type != SOCK_RAW ||
4781556Srgrimes	    so->so_proto->pr_protocol != IPPROTO_ICMPV6)
4791556Srgrimes		return (EOPNOTSUPP);
4801556Srgrimes
4811556Srgrimes	if (v != 1)
4821556Srgrimes		return (ENOPROTOOPT);
4831556Srgrimes
4841556Srgrimes	if (ip6_mrouter != NULL)
4851556Srgrimes		return (EADDRINUSE);
4861556Srgrimes
4871556Srgrimes	ip6_mrouter = so;
4881556Srgrimes	ip6_mrouter_ver = cmd;
4891556Srgrimes
4901556Srgrimes	bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
49190111Simp	bzero((caddr_t)n6expire, sizeof(n6expire));
49217987Speter
49320425Ssteve	pim6 = 0;/* used for stubbing out/in pim stuff */
4941556Srgrimes
4951556Srgrimes	callout_init(&expire_upcalls_ch, 0);
4961556Srgrimes	callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
4971556Srgrimes	    expire_upcalls, NULL);
4981556Srgrimes
4991556Srgrimes#ifdef MRT6DEBUG
5001556Srgrimes	if (mrt6debug)
5012111Sdg		log(LOG_DEBUG, "ip6_mrouter_init\n");
5021556Srgrimes#endif
5031556Srgrimes
5041556Srgrimes	return (0);
5051556Srgrimes}
50617987Speter
50717987Speter/*
5081556Srgrimes * Disable multicast routing
5091556Srgrimes */
5101556Srgrimesint
5111556SrgrimesX_ip6_mrouter_done(void)
5121556Srgrimes{
5131556Srgrimes	mifi_t mifi;
5141556Srgrimes	int i;
5151556Srgrimes	struct mf6c *rt;
5161556Srgrimes	struct rtdetq *rte;
5171556Srgrimes	int s;
5181556Srgrimes
5191556Srgrimes	s = splnet();
5201556Srgrimes
5211556Srgrimes	/*
5221556Srgrimes	 * For each phyint in use, disable promiscuous reception of all IPv6
5231556Srgrimes	 * multicasts.
5241556Srgrimes	 */
5251556Srgrimes#ifdef INET
5261556Srgrimes#ifdef MROUTING
5271556Srgrimes	/*
5281556Srgrimes	 * If there is still IPv4 multicast routing daemon,
5291556Srgrimes	 * we remain interfaces to receive all muliticasted packets.
5301556Srgrimes	 * XXX: there may be an interface in which the IPv4 multicast
5311556Srgrimes	 * daemon is not interested...
5321556Srgrimes	 */
5331556Srgrimes	if (!ip_mrouter)
53454884Scracauer#endif
53590111Simp#endif
53617987Speter	{
5371556Srgrimes		for (mifi = 0; mifi < nummifs; mifi++) {
5381556Srgrimes			if (mif6table[mifi].m6_ifp &&
5391556Srgrimes			    !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
5401556Srgrimes				if_allmulti(mif6table[mifi].m6_ifp, 0);
5411556Srgrimes			}
5421556Srgrimes		}
5431556Srgrimes	}
5441556Srgrimes	bzero((caddr_t)mif6table, sizeof(mif6table));
54517987Speter	nummifs = 0;
54617987Speter
54717987Speter	pim6 = 0; /* used to stub out/in pim specific code */
54817987Speter
5491556Srgrimes	callout_stop(&expire_upcalls_ch);
5501556Srgrimes
5511556Srgrimes	/*
5521556Srgrimes	 * Free all multicast forwarding cache entries.
5531556Srgrimes	 */
5541556Srgrimes	for (i = 0; i < MF6CTBLSIZ; i++) {
5551556Srgrimes		rt = mf6ctable[i];
5561556Srgrimes		while (rt) {
5571556Srgrimes			struct mf6c *frt;
5581556Srgrimes
5591556Srgrimes			for (rte = rt->mf6c_stall; rte != NULL; ) {
5601556Srgrimes				struct rtdetq *n = rte->next;
5611556Srgrimes
5621556Srgrimes				m_free(rte->m);
5631556Srgrimes				free(rte, M_MRTABLE6);
5641556Srgrimes				rte = n;
565149016Sstefanf			}
5661556Srgrimes			frt = rt;
5671556Srgrimes			rt = rt->mf6c_next;
5681556Srgrimes			free(frt, M_MRTABLE6);
5691556Srgrimes		}
5701556Srgrimes	}
5711556Srgrimes
5721556Srgrimes	bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
57390111Simp
57490111Simp	/*
5751556Srgrimes	 * Reset register interface
5761556Srgrimes	 */
5771556Srgrimes	if (reg_mif_num != (mifi_t)-1 && multicast_register_if6 != NULL) {
5781556Srgrimes		if_detach(multicast_register_if6);
5791556Srgrimes		if_free(multicast_register_if6);
5801556Srgrimes		reg_mif_num = (mifi_t)-1;
5811556Srgrimes		multicast_register_if6 = NULL;
5821556Srgrimes	}
5831556Srgrimes
5841556Srgrimes	ip6_mrouter = NULL;
5851556Srgrimes	ip6_mrouter_ver = 0;
5861556Srgrimes
5871556Srgrimes	splx(s);
5881556Srgrimes
5891556Srgrimes#ifdef MRT6DEBUG
5901556Srgrimes	if (mrt6debug)
5911556Srgrimes		log(LOG_DEBUG, "ip6_mrouter_done\n");
5921556Srgrimes#endif
5931556Srgrimes
5941556Srgrimes	return (0);
5951556Srgrimes}
5961556Srgrimes
5971556Srgrimesstatic struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
5981556Srgrimes
5991556Srgrimes/*
6001556Srgrimes * Add a mif to the mif table
6011556Srgrimes */
6021556Srgrimesstatic int
6031556Srgrimesadd_m6if(mifcp)
6041556Srgrimes	struct mif6ctl *mifcp;
605117261Sdds{
6061556Srgrimes	struct mif6 *mifp;
6071556Srgrimes	struct ifnet *ifp;
6081556Srgrimes	int error, s;
60990111Simp
61017987Speter	if (mifcp->mif6c_mifi >= MAXMIFS)
6111556Srgrimes		return (EINVAL);
61225223Ssteve	mifp = mif6table + mifcp->mif6c_mifi;
6131556Srgrimes	if (mifp->m6_ifp)
6141556Srgrimes		return (EADDRINUSE); /* XXX: is it appropriate? */
6151556Srgrimes	if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > if_index)
6161556Srgrimes		return (ENXIO);
6171556Srgrimes	ifp = ifnet_byindex(mifcp->mif6c_pifi);
6181556Srgrimes
6191556Srgrimes	if (mifcp->mif6c_flags & MIFF_REGISTER) {
6201556Srgrimes		if (reg_mif_num == (mifi_t)-1) {
6211556Srgrimes			ifp = if_alloc(IFT_OTHER);
6221556Srgrimes
6231556Srgrimes			if_initname(ifp, "register_mif", 0);
6241556Srgrimes			ifp->if_flags |= IFF_LOOPBACK;
6251556Srgrimes			if_attach(ifp);
6261556Srgrimes			multicast_register_if6 = ifp;
6271556Srgrimes			reg_mif_num = mifcp->mif6c_mifi;
6281556Srgrimes			/*
6291556Srgrimes			 * it is impossible to guess the ifindex of the
6301556Srgrimes			 * register interface.  So mif6c_pifi is automatically
6311556Srgrimes			 * calculated.
6321556Srgrimes			 */
6331556Srgrimes			mifcp->mif6c_pifi = ifp->if_index;
6341556Srgrimes		} else {
6351556Srgrimes			ifp = multicast_register_if6;
6361556Srgrimes		}
6371556Srgrimes
6381556Srgrimes	} /* if REGISTER */
6391556Srgrimes	else {
6401556Srgrimes		/* Make sure the interface supports multicast */
6411556Srgrimes		if ((ifp->if_flags & IFF_MULTICAST) == 0)
6421556Srgrimes			return (EOPNOTSUPP);
6431556Srgrimes
6441556Srgrimes		s = splnet();
6451556Srgrimes		error = if_allmulti(ifp, 1);
64690111Simp		splx(s);
64790111Simp		if (error)
6481556Srgrimes			return (error);
6491556Srgrimes	}
6501556Srgrimes
6511556Srgrimes	s = splnet();
6521556Srgrimes	mifp->m6_flags     = mifcp->mif6c_flags;
6531556Srgrimes	mifp->m6_ifp       = ifp;
6541556Srgrimes
6551556Srgrimes	/* initialize per mif pkt counters */
6561556Srgrimes	mifp->m6_pkt_in    = 0;
6571556Srgrimes	mifp->m6_pkt_out   = 0;
6581556Srgrimes	mifp->m6_bytes_in  = 0;
6591556Srgrimes	mifp->m6_bytes_out = 0;
6601556Srgrimes	splx(s);
6611556Srgrimes
6621556Srgrimes	/* Adjust nummifs up if the mifi is higher than nummifs */
6631556Srgrimes	if (nummifs <= mifcp->mif6c_mifi)
6641556Srgrimes		nummifs = mifcp->mif6c_mifi + 1;
66590111Simp
66690111Simp#ifdef MRT6DEBUG
6671556Srgrimes	if (mrt6debug)
6681556Srgrimes		log(LOG_DEBUG,
6691556Srgrimes		    "add_mif #%d, phyint %s\n",
6701556Srgrimes		    mifcp->mif6c_mifi,
6711556Srgrimes		    ifp->if_xname);
6721556Srgrimes#endif
6731556Srgrimes
6741556Srgrimes	return (0);
6751556Srgrimes}
6761556Srgrimes
6771556Srgrimes/*
6781556Srgrimes * Delete a mif from the mif table
6791556Srgrimes */
6801556Srgrimesstatic int
6811556Srgrimesdel_m6if(mifip)
6821556Srgrimes	mifi_t *mifip;
6831556Srgrimes{
6841556Srgrimes	struct mif6 *mifp = mif6table + *mifip;
68590111Simp	mifi_t mifi;
68690111Simp	struct ifnet *ifp;
6871556Srgrimes	int s;
6881556Srgrimes
6891556Srgrimes	if (*mifip >= nummifs)
6901556Srgrimes		return (EINVAL);
6911556Srgrimes	if (mifp->m6_ifp == NULL)
6921556Srgrimes		return (EINVAL);
6931556Srgrimes
6941556Srgrimes	s = splnet();
6951556Srgrimes
6961556Srgrimes	if (!(mifp->m6_flags & MIFF_REGISTER)) {
6971556Srgrimes		/*
6981556Srgrimes		 * XXX: what if there is yet IPv4 multicast daemon
6991556Srgrimes		 *      using the interface?
7001556Srgrimes		 */
7011556Srgrimes		ifp = mifp->m6_ifp;
70290111Simp
70390111Simp		if_allmulti(ifp, 0);
7041556Srgrimes	} else {
7051556Srgrimes		if (reg_mif_num != (mifi_t)-1 &&
7061556Srgrimes		    multicast_register_if6 != NULL) {
7071556Srgrimes			if_detach(multicast_register_if6);
7081556Srgrimes			if_free(multicast_register_if6);
7091556Srgrimes			reg_mif_num = (mifi_t)-1;
7101556Srgrimes			multicast_register_if6 = NULL;
711135856Sdes		}
7121556Srgrimes	}
71325223Ssteve
71425223Ssteve	bzero((caddr_t)mifp, sizeof(*mifp));
715151810Sstefanf
716151810Sstefanf	/* Adjust nummifs down */
71725223Ssteve	for (mifi = nummifs; mifi > 0; mifi--)
71825223Ssteve		if (mif6table[mifi - 1].m6_ifp)
71925223Ssteve			break;
720151810Sstefanf	nummifs = mifi;
72125223Ssteve
72225223Ssteve	splx(s);
72325223Ssteve
72425223Ssteve#ifdef MRT6DEBUG
72525223Ssteve	if (mrt6debug)
72625223Ssteve		log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs);
72725223Ssteve#endif
72825223Ssteve
72925223Ssteve	return (0);
73025223Ssteve}
731151810Sstefanf
732151810Sstefanf/*
733151810Sstefanf * Add an mfc entry
73425223Ssteve */
73525223Sstevestatic int
73625223Ssteveadd_m6fc(mfccp)
73725223Ssteve	struct mf6cctl *mfccp;
73825223Ssteve{
73925223Ssteve	struct mf6c *rt;
740151810Sstefanf	u_long hash;
741151810Sstefanf	struct rtdetq *rte;
742151810Sstefanf	u_short nstl;
743151810Sstefanf	int s;
74425223Ssteve	char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
74525223Ssteve
74625223Ssteve	MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
74725223Ssteve		 mfccp->mf6cc_mcastgrp.sin6_addr, rt);
74825223Ssteve
749151810Sstefanf	/* If an entry already exists, just update the fields */
750151810Sstefanf	if (rt) {
751151810Sstefanf#ifdef MRT6DEBUG
752151810Sstefanf		if (mrt6debug & DEBUG_MFC) {
75325223Ssteve		    log(LOG_DEBUG,
75425223Ssteve			"add_m6fc no upcall h %d o %s g %s p %x\n",
75525223Ssteve			ip6_sprintf(ip6bufo, &mfccp->mf6cc_origin.sin6_addr),
75625223Ssteve			ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr),
75725223Ssteve			mfccp->mf6cc_parent);
75825223Ssteve		}
75925223Ssteve#endif
76025223Ssteve
76125223Ssteve		s = splnet();
76225223Ssteve		rt->mf6c_parent = mfccp->mf6cc_parent;
76325223Ssteve		rt->mf6c_ifset = mfccp->mf6cc_ifset;
76425223Ssteve		splx(s);
76525223Ssteve		return (0);
76625223Ssteve	}
76725223Ssteve
76864704Scracauer	/*
76964704Scracauer	 * Find the entry for which the upcall was made and update
77064704Scracauer	 */
77164704Scracauer	s = splnet();
77264704Scracauer	hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
77364704Scracauer			mfccp->mf6cc_mcastgrp.sin6_addr);
77464704Scracauer	for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
775151810Sstefanf		if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
776151810Sstefanf				       &mfccp->mf6cc_origin.sin6_addr) &&
777151810Sstefanf		    IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
778151810Sstefanf				       &mfccp->mf6cc_mcastgrp.sin6_addr) &&
779151810Sstefanf		    (rt->mf6c_stall != NULL)) {
780151810Sstefanf
781151810Sstefanf			if (nstl++)
78264704Scracauer				log(LOG_ERR,
783151810Sstefanf				    "add_m6fc: %s o %s g %s p %x dbx %p\n",
784151810Sstefanf				    "multiple kernel entries",
785151810Sstefanf				    ip6_sprintf(ip6bufo,
786151810Sstefanf					    &mfccp->mf6cc_origin.sin6_addr),
787151810Sstefanf				    ip6_sprintf(ip6bufg,
788151810Sstefanf					    &mfccp->mf6cc_mcastgrp.sin6_addr),
78964704Scracauer				    mfccp->mf6cc_parent, rt->mf6c_stall);
79064704Scracauer
79164704Scracauer#ifdef MRT6DEBUG
79225223Ssteve			if (mrt6debug & DEBUG_MFC)
79325223Ssteve				log(LOG_DEBUG,
79425223Ssteve				    "add_m6fc o %s g %s p %x dbg %x\n",
795151810Sstefanf				    ip6_sprintf(ip6bufo,
796151810Sstefanf					    &mfccp->mf6cc_origin.sin6_addr),
797151810Sstefanf				    ip6_sprintf(ip6bufg,
798151810Sstefanf					    &mfccp->mf6cc_mcastgrp.sin6_addr),
79925223Ssteve				    mfccp->mf6cc_parent, rt->mf6c_stall);
80025223Ssteve#endif
80125223Ssteve
802151810Sstefanf			rt->mf6c_origin     = mfccp->mf6cc_origin;
803151810Sstefanf			rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
804151810Sstefanf			rt->mf6c_parent     = mfccp->mf6cc_parent;
805151810Sstefanf			rt->mf6c_ifset	    = mfccp->mf6cc_ifset;
80625223Ssteve			/* initialize pkt counters per src-grp */
80725223Ssteve			rt->mf6c_pkt_cnt    = 0;
80825223Ssteve			rt->mf6c_byte_cnt   = 0;
809151810Sstefanf			rt->mf6c_wrong_if   = 0;
810151810Sstefanf
81125223Ssteve			rt->mf6c_expire = 0;	/* Don't clean this guy up */
81225223Ssteve			n6expire[hash]--;
81325223Ssteve
81425223Ssteve			/* free packets Qed at the end of this entry */
81525223Ssteve			for (rte = rt->mf6c_stall; rte != NULL; ) {
81625223Ssteve				struct rtdetq *n = rte->next;
817151810Sstefanf				ip6_mdq(rte->m, rte->ifp, rt);
818151810Sstefanf				m_freem(rte->m);
819151810Sstefanf#ifdef UPCALL_TIMING
820151810Sstefanf				collate(&(rte->t));
821151810Sstefanf#endif /* UPCALL_TIMING */
822151810Sstefanf				free(rte, M_MRTABLE6);
823151810Sstefanf				rte = n;
824151810Sstefanf			}
825151810Sstefanf			rt->mf6c_stall = NULL;
826151810Sstefanf		}
827	}
828
829	/*
830	 * It is possible that an entry is being inserted without an upcall
831	 */
832	if (nstl == 0) {
833#ifdef MRT6DEBUG
834		if (mrt6debug & DEBUG_MFC)
835		    log(LOG_DEBUG,
836			"add_mfc no upcall h %d o %s g %s p %x\n",
837			hash,
838			ip6_sprintf(ip6bufo, &mfccp->mf6cc_origin.sin6_addr),
839			ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr),
840			mfccp->mf6cc_parent);
841#endif
842
843		for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
844
845			if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
846					       &mfccp->mf6cc_origin.sin6_addr)&&
847			    IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
848					       &mfccp->mf6cc_mcastgrp.sin6_addr)) {
849
850				rt->mf6c_origin     = mfccp->mf6cc_origin;
851				rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
852				rt->mf6c_parent     = mfccp->mf6cc_parent;
853				rt->mf6c_ifset	    = mfccp->mf6cc_ifset;
854				/* initialize pkt counters per src-grp */
855				rt->mf6c_pkt_cnt    = 0;
856				rt->mf6c_byte_cnt   = 0;
857				rt->mf6c_wrong_if   = 0;
858
859				if (rt->mf6c_expire)
860					n6expire[hash]--;
861				rt->mf6c_expire	   = 0;
862			}
863		}
864		if (rt == NULL) {
865			/* no upcall, so make a new entry */
866			rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6,
867						  M_NOWAIT);
868			if (rt == NULL) {
869				splx(s);
870				return (ENOBUFS);
871			}
872
873			/* insert new entry at head of hash chain */
874			rt->mf6c_origin     = mfccp->mf6cc_origin;
875			rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
876			rt->mf6c_parent     = mfccp->mf6cc_parent;
877			rt->mf6c_ifset	    = mfccp->mf6cc_ifset;
878			/* initialize pkt counters per src-grp */
879			rt->mf6c_pkt_cnt    = 0;
880			rt->mf6c_byte_cnt   = 0;
881			rt->mf6c_wrong_if   = 0;
882			rt->mf6c_expire     = 0;
883			rt->mf6c_stall = NULL;
884
885			/* link into table */
886			rt->mf6c_next  = mf6ctable[hash];
887			mf6ctable[hash] = rt;
888		}
889	}
890	splx(s);
891	return (0);
892}
893
894#ifdef UPCALL_TIMING
895/*
896 * collect delay statistics on the upcalls
897 */
898static void
899collate(t)
900	struct timeval *t;
901{
902	u_long d;
903	struct timeval tp;
904	u_long delta;
905
906	GET_TIME(tp);
907
908	if (TV_LT(*t, tp))
909	{
910		TV_DELTA(tp, *t, delta);
911
912		d = delta >> 10;
913		if (d > UPCALL_MAX)
914			d = UPCALL_MAX;
915
916		++upcall_data[d];
917	}
918}
919#endif /* UPCALL_TIMING */
920
921/*
922 * Delete an mfc entry
923 */
924static int
925del_m6fc(mfccp)
926	struct mf6cctl *mfccp;
927{
928	struct sockaddr_in6 	origin;
929	struct sockaddr_in6 	mcastgrp;
930	struct mf6c 		*rt;
931	struct mf6c	 	**nptr;
932	u_long 		hash;
933	int s;
934
935	origin = mfccp->mf6cc_origin;
936	mcastgrp = mfccp->mf6cc_mcastgrp;
937	hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);
938
939#ifdef MRT6DEBUG
940	if (mrt6debug & DEBUG_MFC) {
941		char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
942		log(LOG_DEBUG,"del_m6fc orig %s mcastgrp %s\n",
943		    ip6_sprintf(ip6bufo, &origin.sin6_addr),
944		    ip6_sprintf(ip6bufg, &mcastgrp.sin6_addr));
945	}
946#endif
947
948	s = splnet();
949
950	nptr = &mf6ctable[hash];
951	while ((rt = *nptr) != NULL) {
952		if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,
953				       &rt->mf6c_origin.sin6_addr) &&
954		    IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr,
955				       &rt->mf6c_mcastgrp.sin6_addr) &&
956		    rt->mf6c_stall == NULL)
957			break;
958
959		nptr = &rt->mf6c_next;
960	}
961	if (rt == NULL) {
962		splx(s);
963		return (EADDRNOTAVAIL);
964	}
965
966	*nptr = rt->mf6c_next;
967	free(rt, M_MRTABLE6);
968
969	splx(s);
970
971	return (0);
972}
973
974static int
975socket_send(s, mm, src)
976	struct socket *s;
977	struct mbuf *mm;
978	struct sockaddr_in6 *src;
979{
980	if (s) {
981		if (sbappendaddr(&s->so_rcv,
982				 (struct sockaddr *)src,
983				 mm, (struct mbuf *)0) != 0) {
984			sorwakeup(s);
985			return (0);
986		}
987	}
988	m_freem(mm);
989	return (-1);
990}
991
992/*
993 * IPv6 multicast forwarding function. This function assumes that the packet
994 * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
995 * pointed to by "ifp", and the packet is to be relayed to other networks
996 * that have members of the packet's destination IPv6 multicast group.
997 *
998 * The packet is returned unscathed to the caller, unless it is
999 * erroneous, in which case a non-zero return value tells the caller to
1000 * discard it.
1001 *
1002 * NOTE: this implementation assumes that m->m_pkthdr.rcvif is NULL iff
1003 * this function is called in the originating context (i.e., not when
1004 * forwarding a packet from other node).  ip6_output(), which is currently the
1005 * only function that calls this function is called in the originating context,
1006 * explicitly ensures this condition.  It is caller's responsibility to ensure
1007 * that if this function is called from somewhere else in the originating
1008 * context in the future.
1009 */
1010
1011int
1012X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
1013{
1014	struct mf6c *rt;
1015	struct mif6 *mifp;
1016	struct mbuf *mm;
1017	int s;
1018	mifi_t mifi;
1019	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
1020
1021#ifdef MRT6DEBUG
1022	if (mrt6debug & DEBUG_FORWARD)
1023		log(LOG_DEBUG, "ip6_mforward: src %s, dst %s, ifindex %d\n",
1024		    ip6_sprintf(ip6bufs, &ip6->ip6_src),
1025		    ip6_sprintf(ip6bufd, &ip6->ip6_dst),
1026		    ifp->if_index);
1027#endif
1028
1029	/*
1030	 * Don't forward a packet with Hop limit of zero or one,
1031	 * or a packet destined to a local-only group.
1032	 */
1033	if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
1034	    IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
1035		return (0);
1036	ip6->ip6_hlim--;
1037
1038	/*
1039	 * Source address check: do not forward packets with unspecified
1040	 * source. It was discussed in July 2000, on ipngwg mailing list.
1041	 * This is rather more serious than unicast cases, because some
1042	 * MLD packets can be sent with the unspecified source address
1043	 * (although such packets must normally set 1 to the hop limit field).
1044	 */
1045	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1046		ip6stat.ip6s_cantforward++;
1047		if (ip6_log_time + ip6_log_interval < time_second) {
1048			ip6_log_time = time_second;
1049			log(LOG_DEBUG,
1050			    "cannot forward "
1051			    "from %s to %s nxt %d received on %s\n",
1052			    ip6_sprintf(ip6bufs, &ip6->ip6_src),
1053			    ip6_sprintf(ip6bufd, &ip6->ip6_dst),
1054			    ip6->ip6_nxt,
1055			    if_name(m->m_pkthdr.rcvif));
1056		}
1057		return (0);
1058	}
1059
1060	/*
1061	 * Determine forwarding mifs from the forwarding cache table
1062	 */
1063	s = splnet();
1064	MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
1065
1066	/* Entry exists, so forward if necessary */
1067	if (rt) {
1068		splx(s);
1069		return (ip6_mdq(m, ifp, rt));
1070	} else {
1071		/*
1072		 * If we don't have a route for packet's origin,
1073		 * Make a copy of the packet &
1074		 * send message to routing daemon
1075		 */
1076
1077		struct mbuf *mb0;
1078		struct rtdetq *rte;
1079		u_long hash;
1080/*		int i, npkts;*/
1081#ifdef UPCALL_TIMING
1082		struct timeval tp;
1083
1084		GET_TIME(tp);
1085#endif /* UPCALL_TIMING */
1086
1087		mrt6stat.mrt6s_no_route++;
1088#ifdef MRT6DEBUG
1089		if (mrt6debug & (DEBUG_FORWARD | DEBUG_MFC))
1090			log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n",
1091			    ip6_sprintf(ip6bufs, &ip6->ip6_src),
1092			    ip6_sprintf(ip6bufd, &ip6->ip6_dst));
1093#endif
1094
1095		/*
1096		 * Allocate mbufs early so that we don't do extra work if we
1097		 * are just going to fail anyway.
1098		 */
1099		rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE6,
1100					      M_NOWAIT);
1101		if (rte == NULL) {
1102			splx(s);
1103			return (ENOBUFS);
1104		}
1105		mb0 = m_copy(m, 0, M_COPYALL);
1106		/*
1107		 * Pullup packet header if needed before storing it,
1108		 * as other references may modify it in the meantime.
1109		 */
1110		if (mb0 &&
1111		    (M_HASCL(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))
1112			mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
1113		if (mb0 == NULL) {
1114			free(rte, M_MRTABLE6);
1115			splx(s);
1116			return (ENOBUFS);
1117		}
1118
1119		/* is there an upcall waiting for this packet? */
1120		hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
1121		for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
1122			if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
1123					       &rt->mf6c_origin.sin6_addr) &&
1124			    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
1125					       &rt->mf6c_mcastgrp.sin6_addr) &&
1126			    (rt->mf6c_stall != NULL))
1127				break;
1128		}
1129
1130		if (rt == NULL) {
1131			struct mrt6msg *im;
1132#ifdef MRT6_OINIT
1133			struct omrt6msg *oim;
1134#endif
1135
1136			/* no upcall, so make a new entry */
1137			rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6,
1138						  M_NOWAIT);
1139			if (rt == NULL) {
1140				free(rte, M_MRTABLE6);
1141				m_freem(mb0);
1142				splx(s);
1143				return (ENOBUFS);
1144			}
1145			/*
1146			 * Make a copy of the header to send to the user
1147			 * level process
1148			 */
1149			mm = m_copy(mb0, 0, sizeof(struct ip6_hdr));
1150
1151			if (mm == NULL) {
1152				free(rte, M_MRTABLE6);
1153				m_freem(mb0);
1154				free(rt, M_MRTABLE6);
1155				splx(s);
1156				return (ENOBUFS);
1157			}
1158
1159			/*
1160			 * Send message to routing daemon
1161			 */
1162			sin6.sin6_addr = ip6->ip6_src;
1163
1164			im = NULL;
1165#ifdef MRT6_OINIT
1166			oim = NULL;
1167#endif
1168			switch (ip6_mrouter_ver) {
1169#ifdef MRT6_OINIT
1170			case MRT6_OINIT:
1171				oim = mtod(mm, struct omrt6msg *);
1172				oim->im6_msgtype = MRT6MSG_NOCACHE;
1173				oim->im6_mbz = 0;
1174				break;
1175#endif
1176			case MRT6_INIT:
1177				im = mtod(mm, struct mrt6msg *);
1178				im->im6_msgtype = MRT6MSG_NOCACHE;
1179				im->im6_mbz = 0;
1180				break;
1181			default:
1182				free(rte, M_MRTABLE6);
1183				m_freem(mb0);
1184				free(rt, M_MRTABLE6);
1185				splx(s);
1186				return (EINVAL);
1187			}
1188
1189#ifdef MRT6DEBUG
1190			if (mrt6debug & DEBUG_FORWARD)
1191				log(LOG_DEBUG,
1192				    "getting the iif info in the kernel\n");
1193#endif
1194
1195			for (mifp = mif6table, mifi = 0;
1196			     mifi < nummifs && mifp->m6_ifp != ifp;
1197			     mifp++, mifi++)
1198				;
1199
1200			switch (ip6_mrouter_ver) {
1201#ifdef MRT6_OINIT
1202			case MRT6_OINIT:
1203				oim->im6_mif = mifi;
1204				break;
1205#endif
1206			case MRT6_INIT:
1207				im->im6_mif = mifi;
1208				break;
1209			}
1210
1211			if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1212				log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
1213				    "socket queue full\n");
1214				mrt6stat.mrt6s_upq_sockfull++;
1215				free(rte, M_MRTABLE6);
1216				m_freem(mb0);
1217				free(rt, M_MRTABLE6);
1218				splx(s);
1219				return (ENOBUFS);
1220			}
1221
1222			mrt6stat.mrt6s_upcalls++;
1223
1224			/* insert new entry at head of hash chain */
1225			bzero(rt, sizeof(*rt));
1226			rt->mf6c_origin.sin6_family = AF_INET6;
1227			rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6);
1228			rt->mf6c_origin.sin6_addr = ip6->ip6_src;
1229			rt->mf6c_mcastgrp.sin6_family = AF_INET6;
1230			rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
1231			rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;
1232			rt->mf6c_expire = UPCALL_EXPIRE;
1233			n6expire[hash]++;
1234			rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;
1235
1236			/* link into table */
1237			rt->mf6c_next  = mf6ctable[hash];
1238			mf6ctable[hash] = rt;
1239			/* Add this entry to the end of the queue */
1240			rt->mf6c_stall = rte;
1241		} else {
1242			/* determine if q has overflowed */
1243			struct rtdetq **p;
1244			int npkts = 0;
1245
1246			for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
1247				if (++npkts > MAX_UPQ6) {
1248					mrt6stat.mrt6s_upq_ovflw++;
1249					free(rte, M_MRTABLE6);
1250					m_freem(mb0);
1251					splx(s);
1252					return (0);
1253				}
1254
1255			/* Add this entry to the end of the queue */
1256			*p = rte;
1257		}
1258
1259		rte->next = NULL;
1260		rte->m = mb0;
1261		rte->ifp = ifp;
1262#ifdef UPCALL_TIMING
1263		rte->t = tp;
1264#endif /* UPCALL_TIMING */
1265
1266		splx(s);
1267
1268		return (0);
1269	}
1270}
1271
1272/*
1273 * Clean up cache entries if upcalls are not serviced
1274 * Call from the Slow Timeout mechanism, every half second.
1275 */
1276static void
1277expire_upcalls(unused)
1278	void *unused;
1279{
1280	struct rtdetq *rte;
1281	struct mf6c *mfc, **nptr;
1282	int i;
1283	int s;
1284
1285	s = splnet();
1286	for (i = 0; i < MF6CTBLSIZ; i++) {
1287		if (n6expire[i] == 0)
1288			continue;
1289		nptr = &mf6ctable[i];
1290		while ((mfc = *nptr) != NULL) {
1291			rte = mfc->mf6c_stall;
1292			/*
1293			 * Skip real cache entries
1294			 * Make sure it wasn't marked to not expire (shouldn't happen)
1295			 * If it expires now
1296			 */
1297			if (rte != NULL &&
1298			    mfc->mf6c_expire != 0 &&
1299			    --mfc->mf6c_expire == 0) {
1300#ifdef MRT6DEBUG
1301				if (mrt6debug & DEBUG_EXPIRE) {
1302					char ip6bufo[INET6_ADDRSTRLEN];
1303					char ip6bufg[INET6_ADDRSTRLEN];
1304					log(LOG_DEBUG, "expire_upcalls: expiring (%s %s)\n",
1305					    ip6_sprintf(ip6bufo, &mfc->mf6c_origin.sin6_addr),
1306					    ip6_sprintf(ip6bufg, &mfc->mf6c_mcastgrp.sin6_addr));
1307				}
1308#endif
1309				/*
1310				 * drop all the packets
1311				 * free the mbuf with the pkt, if, timing info
1312				 */
1313				do {
1314					struct rtdetq *n = rte->next;
1315					m_freem(rte->m);
1316					free(rte, M_MRTABLE6);
1317					rte = n;
1318				} while (rte != NULL);
1319				mrt6stat.mrt6s_cache_cleanups++;
1320				n6expire[i]--;
1321
1322				*nptr = mfc->mf6c_next;
1323				free(mfc, M_MRTABLE6);
1324			} else {
1325				nptr = &mfc->mf6c_next;
1326			}
1327		}
1328	}
1329	splx(s);
1330	callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
1331	    expire_upcalls, NULL);
1332}
1333
1334/*
1335 * Packet forwarding routine once entry in the cache is made
1336 */
1337static int
1338ip6_mdq(m, ifp, rt)
1339	struct mbuf *m;
1340	struct ifnet *ifp;
1341	struct mf6c *rt;
1342{
1343	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1344	mifi_t mifi, iif;
1345	struct mif6 *mifp;
1346	int plen = m->m_pkthdr.len;
1347	struct in6_addr src0, dst0; /* copies for local work */
1348	u_int32_t iszone, idzone, oszone, odzone;
1349	int error = 0;
1350
1351/*
1352 * Macro to send packet on mif.  Since RSVP packets don't get counted on
1353 * input, they shouldn't get counted on output, so statistics keeping is
1354 * separate.
1355 */
1356
1357#define MC6_SEND(ip6, mifp, m) do {				\
1358	if ((mifp)->m6_flags & MIFF_REGISTER)			\
1359		register_send((ip6), (mifp), (m));		\
1360	else							\
1361		phyint_send((ip6), (mifp), (m));		\
1362} while (/*CONSTCOND*/ 0)
1363
1364	/*
1365	 * Don't forward if it didn't arrive from the parent mif
1366	 * for its origin.
1367	 */
1368	mifi = rt->mf6c_parent;
1369	if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) {
1370		/* came in the wrong interface */
1371#ifdef MRT6DEBUG
1372		if (mrt6debug & DEBUG_FORWARD)
1373			log(LOG_DEBUG,
1374			    "wrong if: ifid %d mifi %d mififid %x\n",
1375			    ifp->if_index, mifi,
1376			    mif6table[mifi].m6_ifp->if_index);
1377#endif
1378		mrt6stat.mrt6s_wrong_if++;
1379		rt->mf6c_wrong_if++;
1380		/*
1381		 * If we are doing PIM processing, and we are forwarding
1382		 * packets on this interface, send a message to the
1383		 * routing daemon.
1384		 */
1385		/* have to make sure this is a valid mif */
1386		if (mifi < nummifs && mif6table[mifi].m6_ifp)
1387			if (pim6 && (m->m_flags & M_LOOP) == 0) {
1388				/*
1389				 * Check the M_LOOP flag to avoid an
1390				 * unnecessary PIM assert.
1391				 * XXX: M_LOOP is an ad-hoc hack...
1392				 */
1393				static struct sockaddr_in6 sin6 =
1394				{ sizeof(sin6), AF_INET6 };
1395
1396				struct mbuf *mm;
1397				struct mrt6msg *im;
1398#ifdef MRT6_OINIT
1399				struct omrt6msg *oim;
1400#endif
1401
1402				mm = m_copy(m, 0, sizeof(struct ip6_hdr));
1403				if (mm &&
1404				    (M_HASCL(mm) ||
1405				     mm->m_len < sizeof(struct ip6_hdr)))
1406					mm = m_pullup(mm, sizeof(struct ip6_hdr));
1407				if (mm == NULL)
1408					return (ENOBUFS);
1409
1410#ifdef MRT6_OINIT
1411				oim = NULL;
1412#endif
1413				im = NULL;
1414				switch (ip6_mrouter_ver) {
1415#ifdef MRT6_OINIT
1416				case MRT6_OINIT:
1417					oim = mtod(mm, struct omrt6msg *);
1418					oim->im6_msgtype = MRT6MSG_WRONGMIF;
1419					oim->im6_mbz = 0;
1420					break;
1421#endif
1422				case MRT6_INIT:
1423					im = mtod(mm, struct mrt6msg *);
1424					im->im6_msgtype = MRT6MSG_WRONGMIF;
1425					im->im6_mbz = 0;
1426					break;
1427				default:
1428					m_freem(mm);
1429					return (EINVAL);
1430				}
1431
1432				for (mifp = mif6table, iif = 0;
1433				     iif < nummifs && mifp &&
1434					     mifp->m6_ifp != ifp;
1435				     mifp++, iif++)
1436					;
1437
1438				switch (ip6_mrouter_ver) {
1439#ifdef MRT6_OINIT
1440				case MRT6_OINIT:
1441					oim->im6_mif = iif;
1442					sin6.sin6_addr = oim->im6_src;
1443					break;
1444#endif
1445				case MRT6_INIT:
1446					im->im6_mif = iif;
1447					sin6.sin6_addr = im->im6_src;
1448					break;
1449				}
1450
1451				mrt6stat.mrt6s_upcalls++;
1452
1453				if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1454#ifdef MRT6DEBUG
1455					if (mrt6debug)
1456						log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
1457#endif
1458					++mrt6stat.mrt6s_upq_sockfull;
1459					return (ENOBUFS);
1460				}	/* if socket Q full */
1461			}		/* if PIM */
1462		return (0);
1463	}			/* if wrong iif */
1464
1465	/* If I sourced this packet, it counts as output, else it was input. */
1466	if (m->m_pkthdr.rcvif == NULL) {
1467		/* XXX: is rcvif really NULL when output?? */
1468		mif6table[mifi].m6_pkt_out++;
1469		mif6table[mifi].m6_bytes_out += plen;
1470	} else {
1471		mif6table[mifi].m6_pkt_in++;
1472		mif6table[mifi].m6_bytes_in += plen;
1473	}
1474	rt->mf6c_pkt_cnt++;
1475	rt->mf6c_byte_cnt += plen;
1476
1477	/*
1478	 * For each mif, forward a copy of the packet if there are group
1479	 * members downstream on the interface.
1480	 */
1481	src0 = ip6->ip6_src;
1482	dst0 = ip6->ip6_dst;
1483	if ((error = in6_setscope(&src0, ifp, &iszone)) != 0 ||
1484	    (error = in6_setscope(&dst0, ifp, &idzone)) != 0) {
1485		ip6stat.ip6s_badscope++;
1486		return (error);
1487	}
1488	for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) {
1489		if (IF_ISSET(mifi, &rt->mf6c_ifset)) {
1490			/*
1491			 * check if the outgoing packet is going to break
1492			 * a scope boundary.
1493			 * XXX For packets through PIM register tunnel
1494			 * interface, we believe a routing daemon.
1495			 */
1496			if (!(mif6table[rt->mf6c_parent].m6_flags &
1497			      MIFF_REGISTER) &&
1498			    !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
1499				if (in6_setscope(&src0, mif6table[mifi].m6_ifp,
1500				    &oszone) ||
1501				    in6_setscope(&dst0, mif6table[mifi].m6_ifp,
1502				    &odzone) ||
1503				    iszone != oszone ||
1504				    idzone != odzone) {
1505					ip6stat.ip6s_badscope++;
1506					continue;
1507				}
1508			}
1509
1510			mifp->m6_pkt_out++;
1511			mifp->m6_bytes_out += plen;
1512			MC6_SEND(ip6, mifp, m);
1513		}
1514	}
1515	return (0);
1516}
1517
1518static void
1519phyint_send(ip6, mifp, m)
1520    struct ip6_hdr *ip6;
1521    struct mif6 *mifp;
1522    struct mbuf *m;
1523{
1524	struct mbuf *mb_copy;
1525	struct ifnet *ifp = mifp->m6_ifp;
1526	int error = 0;
1527	int s = splnet();	/* needs to protect static "ro" below. */
1528	static struct route_in6 ro;
1529	struct	in6_multi *in6m;
1530	struct sockaddr_in6 *dst6;
1531	u_long linkmtu;
1532
1533	/*
1534	 * Make a new reference to the packet; make sure that
1535	 * the IPv6 header is actually copied, not just referenced,
1536	 * so that ip6_output() only scribbles on the copy.
1537	 */
1538	mb_copy = m_copy(m, 0, M_COPYALL);
1539	if (mb_copy &&
1540	    (M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
1541		mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
1542	if (mb_copy == NULL) {
1543		splx(s);
1544		return;
1545	}
1546	/* set MCAST flag to the outgoing packet */
1547	mb_copy->m_flags |= M_MCAST;
1548
1549	/*
1550	 * If we sourced the packet, call ip6_output since we may devide
1551	 * the packet into fragments when the packet is too big for the
1552	 * outgoing interface.
1553	 * Otherwise, we can simply send the packet to the interface
1554	 * sending queue.
1555	 */
1556	if (m->m_pkthdr.rcvif == NULL) {
1557		struct ip6_moptions im6o;
1558
1559		im6o.im6o_multicast_ifp = ifp;
1560		/* XXX: ip6_output will override ip6->ip6_hlim */
1561		im6o.im6o_multicast_hlim = ip6->ip6_hlim;
1562		im6o.im6o_multicast_loop = 1;
1563		error = ip6_output(mb_copy, NULL, &ro,
1564				   IPV6_FORWARDING, &im6o, NULL, NULL);
1565
1566#ifdef MRT6DEBUG
1567		if (mrt6debug & DEBUG_XMIT)
1568			log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
1569			    mifp - mif6table, error);
1570#endif
1571		splx(s);
1572		return;
1573	}
1574
1575	/*
1576	 * If we belong to the destination multicast group
1577	 * on the outgoing interface, loop back a copy.
1578	 */
1579	dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
1580	IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
1581	if (in6m != NULL) {
1582		dst6->sin6_len = sizeof(struct sockaddr_in6);
1583		dst6->sin6_family = AF_INET6;
1584		dst6->sin6_addr = ip6->ip6_dst;
1585		ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst);
1586	}
1587	/*
1588	 * Put the packet into the sending queue of the outgoing interface
1589	 * if it would fit in the MTU of the interface.
1590	 */
1591	linkmtu = IN6_LINKMTU(ifp);
1592	if (mb_copy->m_pkthdr.len <= linkmtu || linkmtu < IPV6_MMTU) {
1593		dst6->sin6_len = sizeof(struct sockaddr_in6);
1594		dst6->sin6_family = AF_INET6;
1595		dst6->sin6_addr = ip6->ip6_dst;
1596		/*
1597		 * We just call if_output instead of nd6_output here, since
1598		 * we need no ND for a multicast forwarded packet...right?
1599		 */
1600		error = (*ifp->if_output)(ifp, mb_copy,
1601		    (struct sockaddr *)&ro.ro_dst, NULL);
1602#ifdef MRT6DEBUG
1603		if (mrt6debug & DEBUG_XMIT)
1604			log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
1605			    mifp - mif6table, error);
1606#endif
1607	} else {
1608		/*
1609		 * pMTU discovery is intentionally disabled by default, since
1610		 * various router may notify pMTU in multicast, which can be
1611		 * a DDoS to a router
1612		 */
1613		if (ip6_mcast_pmtu)
1614			icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, linkmtu);
1615		else {
1616#ifdef MRT6DEBUG
1617			if (mrt6debug & DEBUG_XMIT) {
1618				char ip6bufs[INET6_ADDRSTRLEN];
1619				char ip6bufd[INET6_ADDRSTRLEN];
1620				log(LOG_DEBUG,
1621				    "phyint_send: packet too big on %s o %s "
1622				    "g %s size %d(discarded)\n",
1623				    if_name(ifp),
1624				    ip6_sprintf(ip6bufs, &ip6->ip6_src),
1625				    ip6_sprintf(ip6bufd, &ip6->ip6_dst),
1626				    mb_copy->m_pkthdr.len);
1627			}
1628#endif /* MRT6DEBUG */
1629			m_freem(mb_copy); /* simply discard the packet */
1630		}
1631	}
1632
1633	splx(s);
1634}
1635
1636static int
1637register_send(ip6, mif, m)
1638	struct ip6_hdr *ip6;
1639	struct mif6 *mif;
1640	struct mbuf *m;
1641{
1642	struct mbuf *mm;
1643	int i, len = m->m_pkthdr.len;
1644	static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
1645	struct mrt6msg *im6;
1646
1647#ifdef MRT6DEBUG
1648	if (mrt6debug) {
1649		char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
1650		log(LOG_DEBUG, "** IPv6 register_send **\n src %s dst %s\n",
1651		    ip6_sprintf(ip6bufs, &ip6->ip6_src),
1652		    ip6_sprintf(ip6bufd, &ip6->ip6_dst));
1653	}
1654#endif
1655	++pim6stat.pim6s_snd_registers;
1656
1657	/* Make a copy of the packet to send to the user level process */
1658	MGETHDR(mm, M_DONTWAIT, MT_HEADER);
1659	if (mm == NULL)
1660		return (ENOBUFS);
1661	mm->m_pkthdr.rcvif = NULL;
1662	mm->m_data += max_linkhdr;
1663	mm->m_len = sizeof(struct ip6_hdr);
1664
1665	if ((mm->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {
1666		m_freem(mm);
1667		return (ENOBUFS);
1668	}
1669	i = MHLEN - M_LEADINGSPACE(mm);
1670	if (i > len)
1671		i = len;
1672	mm = m_pullup(mm, i);
1673	if (mm == NULL)
1674		return (ENOBUFS);
1675/* TODO: check it! */
1676	mm->m_pkthdr.len = len + sizeof(struct ip6_hdr);
1677
1678	/*
1679	 * Send message to routing daemon
1680	 */
1681	sin6.sin6_addr = ip6->ip6_src;
1682
1683	im6 = mtod(mm, struct mrt6msg *);
1684	im6->im6_msgtype      = MRT6MSG_WHOLEPKT;
1685	im6->im6_mbz          = 0;
1686
1687	im6->im6_mif = mif - mif6table;
1688
1689	/* iif info is not given for reg. encap.n */
1690	mrt6stat.mrt6s_upcalls++;
1691
1692	if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1693#ifdef MRT6DEBUG
1694		if (mrt6debug)
1695			log(LOG_WARNING,
1696			    "register_send: ip6_mrouter socket queue full\n");
1697#endif
1698		++mrt6stat.mrt6s_upq_sockfull;
1699		return (ENOBUFS);
1700	}
1701	return (0);
1702}
1703
1704/*
1705 * PIM sparse mode hook
1706 * Receives the pim control messages, and passes them up to the listening
1707 * socket, using rip6_input.
1708 * The only message processed is the REGISTER pim message; the pim header
1709 * is stripped off, and the inner packet is passed to register_mforward.
1710 */
1711int
1712pim6_input(mp, offp, proto)
1713	struct mbuf **mp;
1714	int *offp, proto;
1715{
1716	struct pim *pim; /* pointer to a pim struct */
1717	struct ip6_hdr *ip6;
1718	int pimlen;
1719	struct mbuf *m = *mp;
1720	int minlen;
1721	int off = *offp;
1722
1723	++pim6stat.pim6s_rcv_total;
1724
1725	ip6 = mtod(m, struct ip6_hdr *);
1726	pimlen = m->m_pkthdr.len - *offp;
1727
1728	/*
1729	 * Validate lengths
1730	 */
1731	if (pimlen < PIM_MINLEN) {
1732		++pim6stat.pim6s_rcv_tooshort;
1733#ifdef MRT6DEBUG
1734		if (mrt6debug & DEBUG_PIM)
1735			log(LOG_DEBUG,"pim6_input: PIM packet too short\n");
1736#endif
1737		m_freem(m);
1738		return (IPPROTO_DONE);
1739	}
1740
1741	/*
1742	 * if the packet is at least as big as a REGISTER, go ahead
1743	 * and grab the PIM REGISTER header size, to avoid another
1744	 * possible m_pullup() later.
1745	 *
1746	 * PIM_MINLEN       == pimhdr + u_int32 == 8
1747	 * PIM6_REG_MINLEN   == pimhdr + reghdr + eip6hdr == 4 + 4 + 40
1748	 */
1749	minlen = (pimlen >= PIM6_REG_MINLEN) ? PIM6_REG_MINLEN : PIM_MINLEN;
1750
1751	/*
1752	 * Make sure that the IP6 and PIM headers in contiguous memory, and
1753	 * possibly the PIM REGISTER header
1754	 */
1755#ifndef PULLDOWN_TEST
1756	IP6_EXTHDR_CHECK(m, off, minlen, IPPROTO_DONE);
1757	/* adjust pointer */
1758	ip6 = mtod(m, struct ip6_hdr *);
1759
1760	/* adjust mbuf to point to the PIM header */
1761	pim = (struct pim *)((caddr_t)ip6 + off);
1762#else
1763	IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen);
1764	if (pim == NULL) {
1765		pim6stat.pim6s_rcv_tooshort++;
1766		return (IPPROTO_DONE);
1767	}
1768#endif
1769
1770#define PIM6_CHECKSUM
1771#ifdef PIM6_CHECKSUM
1772	{
1773		int cksumlen;
1774
1775		/*
1776		 * Validate checksum.
1777		 * If PIM REGISTER, exclude the data packet
1778		 */
1779		if (pim->pim_type == PIM_REGISTER)
1780			cksumlen = PIM_MINLEN;
1781		else
1782			cksumlen = pimlen;
1783
1784		if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) {
1785			++pim6stat.pim6s_rcv_badsum;
1786#ifdef MRT6DEBUG
1787			if (mrt6debug & DEBUG_PIM)
1788				log(LOG_DEBUG,
1789				    "pim6_input: invalid checksum\n");
1790#endif
1791			m_freem(m);
1792			return (IPPROTO_DONE);
1793		}
1794	}
1795#endif /* PIM_CHECKSUM */
1796
1797	/* PIM version check */
1798	if (pim->pim_ver != PIM_VERSION) {
1799		++pim6stat.pim6s_rcv_badversion;
1800#ifdef MRT6DEBUG
1801		log(LOG_ERR,
1802		    "pim6_input: incorrect version %d, expecting %d\n",
1803		    pim->pim_ver, PIM_VERSION);
1804#endif
1805		m_freem(m);
1806		return (IPPROTO_DONE);
1807	}
1808
1809	if (pim->pim_type == PIM_REGISTER) {
1810		/*
1811		 * since this is a REGISTER, we'll make a copy of the register
1812		 * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the
1813		 * routing daemon.
1814		 */
1815		static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 };
1816
1817		struct mbuf *mcp;
1818		struct ip6_hdr *eip6;
1819		u_int32_t *reghdr;
1820		int rc;
1821#ifdef MRT6DEBUG
1822		char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
1823#endif
1824
1825		++pim6stat.pim6s_rcv_registers;
1826
1827		if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {
1828#ifdef MRT6DEBUG
1829			if (mrt6debug & DEBUG_PIM)
1830				log(LOG_DEBUG,
1831				    "pim6_input: register mif not set: %d\n",
1832				    reg_mif_num);
1833#endif
1834			m_freem(m);
1835			return (IPPROTO_DONE);
1836		}
1837
1838		reghdr = (u_int32_t *)(pim + 1);
1839
1840		if ((ntohl(*reghdr) & PIM_NULL_REGISTER))
1841			goto pim6_input_to_daemon;
1842
1843		/*
1844		 * Validate length
1845		 */
1846		if (pimlen < PIM6_REG_MINLEN) {
1847			++pim6stat.pim6s_rcv_tooshort;
1848			++pim6stat.pim6s_rcv_badregisters;
1849#ifdef MRT6DEBUG
1850			log(LOG_ERR,
1851			    "pim6_input: register packet size too "
1852			    "small %d from %s\n",
1853			    pimlen, ip6_sprintf(ip6bufs, &ip6->ip6_src));
1854#endif
1855			m_freem(m);
1856			return (IPPROTO_DONE);
1857		}
1858
1859		eip6 = (struct ip6_hdr *) (reghdr + 1);
1860#ifdef MRT6DEBUG
1861		if (mrt6debug & DEBUG_PIM)
1862			log(LOG_DEBUG,
1863			    "pim6_input[register], eip6: %s -> %s, "
1864			    "eip6 plen %d\n",
1865			    ip6_sprintf(ip6bufs, &eip6->ip6_src),
1866			    ip6_sprintf(ip6bufd, &eip6->ip6_dst),
1867			    ntohs(eip6->ip6_plen));
1868#endif
1869
1870		/* verify the version number of the inner packet */
1871		if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
1872			++pim6stat.pim6s_rcv_badregisters;
1873#ifdef MRT6DEBUG
1874			log(LOG_DEBUG, "pim6_input: invalid IP version (%d) "
1875			    "of the inner packet\n",
1876			    (eip6->ip6_vfc & IPV6_VERSION));
1877#endif
1878			m_freem(m);
1879			return (IPPROTO_NONE);
1880		}
1881
1882		/* verify the inner packet is destined to a mcast group */
1883		if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
1884			++pim6stat.pim6s_rcv_badregisters;
1885#ifdef MRT6DEBUG
1886			if (mrt6debug & DEBUG_PIM)
1887				log(LOG_DEBUG,
1888				    "pim6_input: inner packet of register "
1889				    "is not multicast %s\n",
1890				    ip6_sprintf(ip6bufd, &eip6->ip6_dst));
1891#endif
1892			m_freem(m);
1893			return (IPPROTO_DONE);
1894		}
1895
1896		/*
1897		 * make a copy of the whole header to pass to the daemon later.
1898		 */
1899		mcp = m_copy(m, 0, off + PIM6_REG_MINLEN);
1900		if (mcp == NULL) {
1901#ifdef MRT6DEBUG
1902			log(LOG_ERR,
1903			    "pim6_input: pim register: "
1904			    "could not copy register head\n");
1905#endif
1906			m_freem(m);
1907			return (IPPROTO_DONE);
1908		}
1909
1910		/*
1911		 * forward the inner ip6 packet; point m_data at the inner ip6.
1912		 */
1913		m_adj(m, off + PIM_MINLEN);
1914#ifdef MRT6DEBUG
1915		if (mrt6debug & DEBUG_PIM) {
1916			log(LOG_DEBUG,
1917			    "pim6_input: forwarding decapsulated register: "
1918			    "src %s, dst %s, mif %d\n",
1919			    ip6_sprintf(ip6bufs, &eip6->ip6_src),
1920			    ip6_sprintf(ip6bufd, &eip6->ip6_dst),
1921			    reg_mif_num);
1922		}
1923#endif
1924
1925		rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m,
1926				dst.sin6_family, 0);
1927
1928		/* prepare the register head to send to the mrouting daemon */
1929		m = mcp;
1930	}
1931
1932	/*
1933	 * Pass the PIM message up to the daemon; if it is a register message
1934	 * pass the 'head' only up to the daemon. This includes the
1935	 * encapsulator ip6 header, pim header, register header and the
1936	 * encapsulated ip6 header.
1937	 */
1938  pim6_input_to_daemon:
1939	rip6_input(&m, offp, proto);
1940	return (IPPROTO_DONE);
1941}
1942