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