ip6_mroute.c revision 183550
1229997Sken/*- 2229997Sken * Copyright (C) 1998 WIDE Project. 3229997Sken * All rights reserved. 4232604Strasz * 5229997Sken * Redistribution and use in source and binary forms, with or without 6229997Sken * modification, are permitted provided that the following conditions 7232604Strasz * are met: 8232604Strasz * 1. Redistributions of source code must retain the above copyright 9232604Strasz * notice, this list of conditions and the following disclaimer. 10229997Sken * 2. Redistributions in binary form must reproduce the above copyright 11229997Sken * notice, this list of conditions and the following disclaimer in the 12229997Sken * documentation and/or other materials provided with the distribution. 13229997Sken * 3. Neither the name of the project nor the names of its contributors 14229997Sken * may be used to endorse or promote products derived from this software 15229997Sken * without specific prior written permission. 16229997Sken * 17229997Sken * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18229997Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19229997Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20229997Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21229997Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25229997Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26229997Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27229997Sken * SUCH DAMAGE. 28229997Sken * 29229997Sken * $KAME: ip6_mroute.c,v 1.58 2001/12/18 02:36:31 itojun Exp $ 30229997Sken */ 31229997Sken 32229997Sken/*- 33229997Sken * Copyright (c) 1989 Stephen Deering 34229997Sken * Copyright (c) 1992, 1993 35229997Sken * The Regents of the University of California. All rights reserved. 36229997Sken * 37229997Sken * This code is derived from software contributed to Berkeley by 38229997Sken * Stephen Deering of Stanford University. 39229997Sken * 40229997Sken * Redistribution and use in source and binary forms, with or without 41229997Sken * modification, are permitted provided that the following conditions 42229997Sken * are met: 43229997Sken * 1. Redistributions of source code must retain the above copyright 44229997Sken * notice, this list of conditions and the following disclaimer. 45229997Sken * 2. Redistributions in binary form must reproduce the above copyright 46229997Sken * notice, this list of conditions and the following disclaimer in the 47229997Sken * documentation and/or other materials provided with the distribution. 48229997Sken * 4. Neither the name of the University nor the names of its contributors 49229997Sken * may be used to endorse or promote products derived from this software 50249328Strasz * without specific prior written permission. 51229997Sken * 52229997Sken * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53229997Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54229997Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55229997Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56229997Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60229997Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61229997Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62229997Sken * SUCH DAMAGE. 63229997Sken * 64229997Sken * @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93 65229997Sken * BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp 66229997Sken */ 67229997Sken 68229997Sken/* 69229997Sken * IP multicast forwarding procedures 70229997Sken * 71229997Sken * Written by David Waitzman, BBN Labs, August 1988. 72229997Sken * Modified by Steve Deering, Stanford, February 1989. 73229997Sken * Modified by Mark J. Steiglitz, Stanford, May, 1991 74229997Sken * Modified by Van Jacobson, LBL, January 1993 75232604Strasz * Modified by Ajit Thyagarajan, PARC, August 1993 76229997Sken * Modified by Bill Fenner, PARC, April 1994 77229997Sken * 78229997Sken * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support 79229997Sken */ 80229997Sken 81229997Sken#include <sys/cdefs.h> 82229997Sken__FBSDID("$FreeBSD: head/sys/netinet6/ip6_mroute.c 183550 2008-10-02 15:37:58Z zec $"); 83229997Sken 84229997Sken#include "opt_inet.h" 85229997Sken#include "opt_inet6.h" 86229997Sken 87229997Sken#include <sys/param.h> 88229997Sken#include <sys/callout.h> 89229997Sken#include <sys/errno.h> 90229997Sken#include <sys/kernel.h> 91229997Sken#include <sys/lock.h> 92229997Sken#include <sys/malloc.h> 93229997Sken#include <sys/mbuf.h> 94229997Sken#include <sys/protosw.h> 95229997Sken#include <sys/signalvar.h> 96229997Sken#include <sys/socket.h> 97268679Smav#include <sys/socketvar.h> 98229997Sken#include <sys/sockio.h> 99229997Sken#include <sys/sx.h> 100229997Sken#include <sys/sysctl.h> 101229997Sken#include <sys/syslog.h> 102229997Sken#include <sys/systm.h> 103229997Sken#include <sys/time.h> 104229997Sken#include <sys/vimage.h> 105229997Sken 106229997Sken#include <net/if.h> 107229997Sken#include <net/if_types.h> 108229997Sken#include <net/raw_cb.h> 109229997Sken#include <net/route.h> 110229997Sken 111229997Sken#include <netinet/in.h> 112229997Sken#include <netinet/in_var.h> 113229997Sken#include <netinet/icmp6.h> 114229997Sken 115229997Sken#include <netinet/ip6.h> 116232604Strasz#include <netinet6/ip6_var.h> 117255570Strasz#include <netinet6/scope6_var.h> 118255570Strasz#include <netinet6/nd6.h> 119255570Strasz#include <netinet6/ip6_mroute.h> 120279002Smav#include <netinet6/ip6protosw.h> 121279002Smav#include <netinet6/pim6.h> 122229997Sken#include <netinet6/pim6_var.h> 123229997Sken 124229997Skenstatic MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry"); 125229997Sken 126229997Sken/* XXX: this is a very common idiom; move to <sys/mbuf.h> ? */ 127229997Sken#define M_HASCL(m) ((m)->m_flags & M_EXT) 128229997Sken 129229997Skenstatic int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *); 130229997Skenstatic void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *); 131229997Sken 132229997Skenstatic int set_pim6(int *); 133229997Skenstatic int socket_send __P((struct socket *, struct mbuf *, 134229997Sken struct sockaddr_in6 *)); 135229997Skenstatic int register_send __P((struct ip6_hdr *, struct mif6 *, 136229997Sken struct mbuf *)); 137229997Sken 138229997Skenextern struct domain inet6domain; 139229997Sken 140229997Sken/* XXX: referenced from ip_mroute.c for dynamically loading this code. */ 141229997Skenstruct ip6protosw in6_pim_protosw = { 142229997Sken .pr_type = SOCK_RAW, 143229997Sken .pr_domain = &inet6domain, 144229997Sken .pr_protocol = IPPROTO_PIM, 145229997Sken .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 146229997Sken .pr_input = pim6_input, 147229997Sken .pr_output = rip6_output, 148274870Strasz .pr_ctloutput = rip6_ctloutput, 149229997Sken .pr_usrreqs = &rip6_usrreqs 150229997Sken}; 151229997Sken 152229997Skenstatic int ip6_mrouter_ver = 0; 153229997Sken 154229997SkenSYSCTL_DECL(_net_inet6); 155229997SkenSYSCTL_DECL(_net_inet6_ip6); 156229997SkenSYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM"); 157229997Sken 158229997Skenstatic struct mrt6stat mrt6stat; 159229997SkenSYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW, 160229997Sken &mrt6stat, mrt6stat, 161229997Sken "Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)"); 162229997Sken 163229997Sken#define NO_RTE_FOUND 0x1 164229997Sken#define RTE_FOUND 0x2 165229997Sken 166229997Skenstatic struct mf6c *mf6ctable[MF6CTBLSIZ]; 167229997SkenSYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mf6ctable, CTLFLAG_RD, 168229997Sken &mf6ctable, sizeof(mf6ctable), "S,*mf6ctable[MF6CTBLSIZ]", 169241737Sed "Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], " 170229997Sken "netinet6/ip6_mroute.h)"); 171229997Sken 172229997Skenstatic u_char n6expire[MF6CTBLSIZ]; 173229997Sken 174229997Skenstatic struct mif6 mif6table[MAXMIFS]; 175229997SkenSYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mif6table, CTLFLAG_RD, 176229997Sken &mif6table, sizeof(mif6table), "S,vif[MAXMIFS]", 177229997Sken "Multicast Interfaces (struct mif[MAXMIFS], netinet6/ip6_mroute.h)"); 178229997Sken 179229997Sken#ifdef MRT6DEBUG 180229997Skenstatic u_int mrt6debug = 0; /* debug level */ 181255570Strasz#define DEBUG_MFC 0x02 182257540Strasz#define DEBUG_FORWARD 0x04 183257540Strasz#define DEBUG_EXPIRE 0x08 184229997Sken#define DEBUG_XMIT 0x10 185279002Smav#define DEBUG_REG 0x20 186229997Sken#define DEBUG_PIM 0x40 187232604Strasz#endif 188229997Sken 189279002Smavstatic void expire_upcalls(void *); 190229997Sken#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */ 191229997Sken#define UPCALL_EXPIRE 6 /* number of timeouts */ 192229997Sken 193229997Sken#ifdef INET 194229997Sken#ifdef MROUTING 195229997Skenextern struct socket *ip_mrouter; 196229997Sken#endif 197229997Sken#endif 198229997Sken 199229997Sken/* 200229997Sken * 'Interfaces' associated with decapsulator (so we can tell 201229997Sken * packets that went through it from ones that get reflected 202229997Sken * by a broken gateway). Different from IPv4 register_if, 203229997Sken * these interfaces are linked into the system ifnet list, 204229997Sken * because per-interface IPv6 statistics are maintained in 205229997Sken * ifp->if_afdata. But it does not have any routes point 206229997Sken * to them. I.e., packets can't be sent this way. They 207229997Sken * only exist as a placeholder for multicast source 208229997Sken * verification. 209229997Sken */ 210229997Skenstatic struct ifnet *multicast_register_if6; 211229997Sken 212229997Sken#define ENCAP_HOPS 64 213229997Sken 214229997Sken/* 215229997Sken * Private variables. 216229997Sken */ 217229997Skenstatic mifi_t nummifs = 0; 218229997Skenstatic mifi_t reg_mif_num = (mifi_t)-1; 219229997Sken 220229997Skenstatic struct pim6stat pim6stat; 221229997SkenSYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RD, 222229997Sken &pim6stat, pim6stat, 223229997Sken "PIM Statistics (struct pim6stat, netinet6/pim_var.h)"); 224229997Sken 225229997Skenstatic int pim6; 226229997Sken 227229997Sken/* 228229997Sken * Hash function for a source, group entry 229229997Sken */ 230274870Strasz#define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \ 231229997Sken (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \ 232229997Sken (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \ 233229997Sken (g).s6_addr32[2] ^ (g).s6_addr32[3]) 234229997Sken 235229997Sken/* 236229997Sken * Find a route for a given origin IPv6 address and Multicast group address. 237229997Sken */ 238229997Sken#define MF6CFIND(o, g, rt) do { \ 239229997Sken struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \ 240229997Sken rt = NULL; \ 241229997Sken mrt6stat.mrt6s_mfc_lookups++; \ 242229997Sken while (_rt) { \ 243229997Sken if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \ 244229997Sken IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \ 245229997Sken (_rt->mf6c_stall == NULL)) { \ 246229997Sken rt = _rt; \ 247229997Sken break; \ 248229997Sken } \ 249229997Sken _rt = _rt->mf6c_next; \ 250229997Sken } \ 251274870Strasz if (rt == NULL) { \ 252229997Sken mrt6stat.mrt6s_mfc_misses++; \ 253229997Sken } \ 254229997Sken} while (/*CONSTCOND*/ 0) 255229997Sken 256229997Sken/* 257229997Sken * Macros to compute elapsed time efficiently 258232604Strasz * Borrowed from Van Jacobson's scheduling code 259229997Sken * XXX: replace with timersub() ? 260229997Sken */ 261229997Sken#define TV_DELTA(a, b, delta) do { \ 262229997Sken int xxs; \ 263229997Sken \ 264229997Sken delta = (a).tv_usec - (b).tv_usec; \ 265229997Sken if ((xxs = (a).tv_sec - (b).tv_sec)) { \ 266229997Sken switch (xxs) { \ 267229997Sken case 2: \ 268229997Sken delta += 1000000; \ 269229997Sken /* FALLTHROUGH */ \ 270229997Sken case 1: \ 271229997Sken delta += 1000000; \ 272229997Sken break; \ 273229997Sken default: \ 274229997Sken delta += (1000000 * xxs); \ 275229997Sken } \ 276229997Sken } \ 277229997Sken} while (/*CONSTCOND*/ 0) 278229997Sken 279229997Sken/* XXX: replace with timercmp(a, b, <) ? */ 280229997Sken#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \ 281229997Sken (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec) 282229997Sken 283229997Sken#ifdef UPCALL_TIMING 284229997Sken#define UPCALL_MAX 50 285229997Skenstatic u_long upcall_data[UPCALL_MAX + 1]; 286229997Skenstatic void collate(); 287229997Sken#endif /* UPCALL_TIMING */ 288229997Sken 289229997Skenstatic int get_sg_cnt(struct sioc_sg_req6 *); 290229997Skenstatic int get_mif6_cnt(struct sioc_mif_req6 *); 291229997Skenstatic int ip6_mrouter_init(struct socket *, int, int); 292229997Skenstatic int add_m6if(struct mif6ctl *); 293229997Skenstatic int del_m6if(mifi_t *); 294229997Skenstatic int add_m6fc(struct mf6cctl *); 295229997Skenstatic int del_m6fc(struct mf6cctl *); 296229997Sken 297229997Skenstatic struct callout expire_upcalls_ch; 298229997Sken 299229997Skenint X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m); 300229997Skenint X_ip6_mrouter_done(void); 301229997Skenint X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt); 302229997Skenint X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt); 303229997Skenint X_mrt6_ioctl(int cmd, caddr_t data); 304229997Sken 305229997Sken/* 306229997Sken * Handle MRT setsockopt commands to modify the multicast routing tables. 307229997Sken */ 308229997Skenint 309229997SkenX_ip6_mrouter_set(struct socket *so, struct sockopt *sopt) 310229997Sken{ 311229997Sken int error = 0; 312229997Sken int optval; 313229997Sken struct mif6ctl mifc; 314229997Sken struct mf6cctl mfcc; 315229997Sken mifi_t mifi; 316229997Sken 317229997Sken if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT) 318229997Sken return (EACCES); 319229997Sken 320229997Sken switch (sopt->sopt_name) { 321229997Sken case MRT6_INIT: 322229997Sken#ifdef MRT6_OINIT 323229997Sken case MRT6_OINIT: 324229997Sken#endif 325229997Sken error = sooptcopyin(sopt, &optval, sizeof(optval), 326229997Sken sizeof(optval)); 327229997Sken if (error) 328229997Sken break; 329229997Sken error = ip6_mrouter_init(so, optval, sopt->sopt_name); 330229997Sken break; 331229997Sken case MRT6_DONE: 332229997Sken error = X_ip6_mrouter_done(); 333229997Sken break; 334229997Sken case MRT6_ADD_MIF: 335229997Sken error = sooptcopyin(sopt, &mifc, sizeof(mifc), sizeof(mifc)); 336229997Sken if (error) 337229997Sken break; 338229997Sken error = add_m6if(&mifc); 339229997Sken break; 340229997Sken case MRT6_ADD_MFC: 341229997Sken error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc)); 342229997Sken if (error) 343229997Sken break; 344229997Sken error = add_m6fc(&mfcc); 345229997Sken break; 346229997Sken case MRT6_DEL_MFC: 347229997Sken error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc)); 348229997Sken if (error) 349229997Sken break; 350229997Sken error = del_m6fc(&mfcc); 351229997Sken break; 352229997Sken case MRT6_DEL_MIF: 353229997Sken error = sooptcopyin(sopt, &mifi, sizeof(mifi), sizeof(mifi)); 354229997Sken if (error) 355229997Sken break; 356229997Sken error = del_m6if(&mifi); 357229997Sken break; 358229997Sken case MRT6_PIM: 359229997Sken error = sooptcopyin(sopt, &optval, sizeof(optval), 360229997Sken sizeof(optval)); 361229997Sken if (error) 362229997Sken break; 363229997Sken error = set_pim6(&optval); 364229997Sken break; 365229997Sken default: 366229997Sken error = EOPNOTSUPP; 367229997Sken break; 368229997Sken } 369229997Sken 370229997Sken return (error); 371229997Sken} 372229997Sken 373229997Sken/* 374229997Sken * Handle MRT getsockopt commands 375229997Sken */ 376229997Skenint 377229997SkenX_ip6_mrouter_get(struct socket *so, struct sockopt *sopt) 378229997Sken{ 379229997Sken INIT_VNET_INET6(curvnet); 380229997Sken int error = 0; 381229997Sken 382229997Sken if (so != ip6_mrouter) 383229997Sken return (EACCES); 384229997Sken 385229997Sken switch (sopt->sopt_name) { 386229997Sken case MRT6_PIM: 387274870Strasz error = sooptcopyout(sopt, &V_pim6, sizeof(V_pim6)); 388229997Sken break; 389229997Sken } 390229997Sken return (error); 391229997Sken} 392229997Sken 393229997Sken/* 394229997Sken * Handle ioctl commands to obtain information from the cache 395229997Sken */ 396229997Skenint 397229997SkenX_mrt6_ioctl(int cmd, caddr_t data) 398229997Sken{ 399229997Sken switch (cmd) { 400229997Sken case SIOCGETSGCNT_IN6: 401229997Sken return (get_sg_cnt((struct sioc_sg_req6 *)data)); 402229997Sken case SIOCGETMIFCNT_IN6: 403229997Sken return (get_mif6_cnt((struct sioc_mif_req6 *)data)); 404229997Sken default: 405229997Sken return (EINVAL); 406229997Sken } 407229997Sken} 408229997Sken 409229997Sken/* 410229997Sken * returns the packet, byte, rpf-failure count for the source group provided 411229997Sken */ 412229997Skenstatic int 413229997Skenget_sg_cnt(struct sioc_sg_req6 *req) 414229997Sken{ 415229997Sken struct mf6c *rt; 416229997Sken int s; 417229997Sken 418229997Sken s = splnet(); 419229997Sken MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt); 420229997Sken splx(s); 421229997Sken if (rt != NULL) { 422229997Sken req->pktcnt = rt->mf6c_pkt_cnt; 423229997Sken req->bytecnt = rt->mf6c_byte_cnt; 424229997Sken req->wrong_if = rt->mf6c_wrong_if; 425229997Sken } else 426229997Sken return (ESRCH); 427229997Sken#if 0 428229997Sken req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; 429229997Sken#endif 430229997Sken 431229997Sken return (0); 432229997Sken} 433229997Sken 434229997Sken/* 435229997Sken * returns the input and output packet and byte counts on the mif provided 436229997Sken */ 437229997Skenstatic int 438229997Skenget_mif6_cnt(struct sioc_mif_req6 *req) 439229997Sken{ 440229997Sken mifi_t mifi = req->mifi; 441229997Sken 442229997Sken if (mifi >= nummifs) 443229997Sken return (EINVAL); 444229997Sken 445229997Sken req->icount = mif6table[mifi].m6_pkt_in; 446229997Sken req->ocount = mif6table[mifi].m6_pkt_out; 447229997Sken req->ibytes = mif6table[mifi].m6_bytes_in; 448229997Sken req->obytes = mif6table[mifi].m6_bytes_out; 449229997Sken 450229997Sken return (0); 451229997Sken} 452229997Sken 453229997Skenstatic int 454229997Skenset_pim6(int *i) 455229997Sken{ 456229997Sken INIT_VNET_INET6(curvnet); 457229997Sken if ((*i != 1) && (*i != 0)) 458229997Sken return (EINVAL); 459229997Sken 460229997Sken V_pim6 = *i; 461229997Sken 462229997Sken return (0); 463229997Sken} 464229997Sken 465229997Sken/* 466229997Sken * Enable multicast routing 467229997Sken */ 468229997Skenstatic int 469229997Skenip6_mrouter_init(struct socket *so, int v, int cmd) 470229997Sken{ 471229997Sken INIT_VNET_INET6(curvnet); 472229997Sken 473229997Sken#ifdef MRT6DEBUG 474229997Sken if (V_mrt6debug) 475229997Sken log(LOG_DEBUG, 476229997Sken "ip6_mrouter_init: so_type = %d, pr_protocol = %d\n", 477229997Sken so->so_type, so->so_proto->pr_protocol); 478229997Sken#endif 479229997Sken 480229997Sken if (so->so_type != SOCK_RAW || 481229997Sken so->so_proto->pr_protocol != IPPROTO_ICMPV6) 482229997Sken return (EOPNOTSUPP); 483229997Sken 484229997Sken if (v != 1) 485229997Sken return (ENOPROTOOPT); 486229997Sken 487229997Sken if (ip6_mrouter != NULL) 488229997Sken return (EADDRINUSE); 489229997Sken 490255570Strasz ip6_mrouter = so; 491255570Strasz V_ip6_mrouter_ver = cmd; 492255570Strasz 493268694Smav bzero((caddr_t)mf6ctable, sizeof(mf6ctable)); 494268694Smav bzero((caddr_t)n6expire, sizeof(n6expire)); 495268694Smav 496229997Sken V_pim6 = 0;/* used for stubbing out/in pim stuff */ 497229997Sken 498229997Sken callout_init(&expire_upcalls_ch, 0); 499229997Sken callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, 500229997Sken expire_upcalls, NULL); 501229997Sken 502229997Sken#ifdef MRT6DEBUG 503229997Sken if (V_mrt6debug) 504229997Sken log(LOG_DEBUG, "ip6_mrouter_init\n"); 505229997Sken#endif 506229997Sken 507229997Sken return (0); 508229997Sken} 509229997Sken 510229997Sken/* 511229997Sken * Disable multicast routing 512229997Sken */ 513229997Skenint 514229997SkenX_ip6_mrouter_done(void) 515229997Sken{ 516229997Sken INIT_VNET_INET6(curvnet); 517229997Sken mifi_t mifi; 518229997Sken int i; 519229997Sken struct mf6c *rt; 520229997Sken struct rtdetq *rte; 521229997Sken int s; 522229997Sken 523229997Sken s = splnet(); 524229997Sken 525229997Sken /* 526229997Sken * For each phyint in use, disable promiscuous reception of all IPv6 527229997Sken * multicasts. 528229997Sken */ 529229997Sken#ifdef INET 530229997Sken#ifdef MROUTING 531229997Sken /* 532229997Sken * If there is still IPv4 multicast routing daemon, 533229997Sken * we remain interfaces to receive all muliticasted packets. 534229997Sken * XXX: there may be an interface in which the IPv4 multicast 535229997Sken * daemon is not interested... 536229997Sken */ 537229997Sken if (!V_ip_mrouter) 538229997Sken#endif 539229997Sken#endif 540229997Sken { 541229997Sken for (mifi = 0; mifi < nummifs; mifi++) { 542229997Sken if (mif6table[mifi].m6_ifp && 543229997Sken !(mif6table[mifi].m6_flags & MIFF_REGISTER)) { 544229997Sken if_allmulti(mif6table[mifi].m6_ifp, 0); 545229997Sken } 546229997Sken } 547229997Sken } 548229997Sken bzero((caddr_t)mif6table, sizeof(mif6table)); 549229997Sken nummifs = 0; 550229997Sken 551229997Sken V_pim6 = 0; /* used to stub out/in pim specific code */ 552229997Sken 553250443Sjh callout_stop(&expire_upcalls_ch); 554250443Sjh 555229997Sken /* 556229997Sken * Free all multicast forwarding cache entries. 557229997Sken */ 558229997Sken for (i = 0; i < MF6CTBLSIZ; i++) { 559229997Sken rt = mf6ctable[i]; 560229997Sken while (rt) { 561229997Sken struct mf6c *frt; 562229997Sken 563229997Sken for (rte = rt->mf6c_stall; rte != NULL; ) { 564229997Sken struct rtdetq *n = rte->next; 565229997Sken 566229997Sken m_free(rte->m); 567229997Sken free(rte, M_MRTABLE6); 568229997Sken rte = n; 569229997Sken } 570229997Sken frt = rt; 571229997Sken rt = rt->mf6c_next; 572229997Sken free(frt, M_MRTABLE6); 573229997Sken } 574229997Sken } 575229997Sken 576229997Sken bzero((caddr_t)mf6ctable, sizeof(mf6ctable)); 577229997Sken 578229997Sken /* 579229997Sken * Reset register interface 580229997Sken */ 581241737Sed if (reg_mif_num != (mifi_t)-1 && multicast_register_if6 != NULL) { 582229997Sken if_detach(multicast_register_if6); 583229997Sken if_free(multicast_register_if6); 584229997Sken reg_mif_num = (mifi_t)-1; 585255570Strasz multicast_register_if6 = NULL; 586268694Smav } 587229997Sken 588229997Sken ip6_mrouter = NULL; 589229997Sken V_ip6_mrouter_ver = 0; 590229997Sken 591229997Sken splx(s); 592229997Sken 593229997Sken#ifdef MRT6DEBUG 594229997Sken if (V_mrt6debug) 595229997Sken log(LOG_DEBUG, "ip6_mrouter_done\n"); 596229997Sken#endif 597229997Sken 598229997Sken return (0); 599229997Sken} 600229997Sken 601229997Skenstatic struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 }; 602229997Sken 603229997Sken/* 604229997Sken * Add a mif to the mif table 605229997Sken */ 606229997Skenstatic int 607229997Skenadd_m6if(struct mif6ctl *mifcp) 608229997Sken{ 609229997Sken INIT_VNET_NET(curvnet); 610229997Sken struct mif6 *mifp; 611229997Sken struct ifnet *ifp; 612229997Sken int error, s; 613229997Sken 614229997Sken if (mifcp->mif6c_mifi >= MAXMIFS) 615274870Strasz return (EINVAL); 616229997Sken mifp = mif6table + mifcp->mif6c_mifi; 617229997Sken if (mifp->m6_ifp) 618229997Sken return (EADDRINUSE); /* XXX: is it appropriate? */ 619229997Sken if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index) 620229997Sken return (ENXIO); 621229997Sken ifp = ifnet_byindex(mifcp->mif6c_pifi); 622229997Sken 623229997Sken if (mifcp->mif6c_flags & MIFF_REGISTER) { 624229997Sken if (reg_mif_num == (mifi_t)-1) { 625229997Sken ifp = if_alloc(IFT_OTHER); 626229997Sken 627229997Sken if_initname(ifp, "register_mif", 0); 628229997Sken ifp->if_flags |= IFF_LOOPBACK; 629229997Sken if_attach(ifp); 630229997Sken multicast_register_if6 = ifp; 631229997Sken reg_mif_num = mifcp->mif6c_mifi; 632229997Sken /* 633229997Sken * it is impossible to guess the ifindex of the 634229997Sken * register interface. So mif6c_pifi is automatically 635229997Sken * calculated. 636229997Sken */ 637229997Sken mifcp->mif6c_pifi = ifp->if_index; 638229997Sken } else { 639229997Sken ifp = multicast_register_if6; 640229997Sken } 641229997Sken 642229997Sken } /* if REGISTER */ 643229997Sken else { 644229997Sken /* Make sure the interface supports multicast */ 645229997Sken if ((ifp->if_flags & IFF_MULTICAST) == 0) 646229997Sken return (EOPNOTSUPP); 647229997Sken 648229997Sken s = splnet(); 649229997Sken error = if_allmulti(ifp, 1); 650229997Sken splx(s); 651229997Sken if (error) 652229997Sken return (error); 653229997Sken } 654229997Sken 655229997Sken s = splnet(); 656229997Sken mifp->m6_flags = mifcp->mif6c_flags; 657229997Sken mifp->m6_ifp = ifp; 658229997Sken 659229997Sken /* initialize per mif pkt counters */ 660229997Sken mifp->m6_pkt_in = 0; 661229997Sken mifp->m6_pkt_out = 0; 662229997Sken mifp->m6_bytes_in = 0; 663229997Sken mifp->m6_bytes_out = 0; 664229997Sken splx(s); 665229997Sken 666229997Sken /* Adjust nummifs up if the mifi is higher than nummifs */ 667229997Sken if (nummifs <= mifcp->mif6c_mifi) 668229997Sken nummifs = mifcp->mif6c_mifi + 1; 669229997Sken 670229997Sken#ifdef MRT6DEBUG 671229997Sken if (V_mrt6debug) 672229997Sken log(LOG_DEBUG, 673229997Sken "add_mif #%d, phyint %s\n", 674229997Sken mifcp->mif6c_mifi, 675229997Sken ifp->if_xname); 676229997Sken#endif 677229997Sken 678229997Sken return (0); 679229997Sken} 680229997Sken 681229997Sken/* 682229997Sken * Delete a mif from the mif table 683229997Sken */ 684229997Skenstatic int 685229997Skendel_m6if(mifi_t *mifip) 686229997Sken{ 687229997Sken struct mif6 *mifp = mif6table + *mifip; 688229997Sken mifi_t mifi; 689229997Sken struct ifnet *ifp; 690229997Sken int s; 691229997Sken 692229997Sken if (*mifip >= nummifs) 693229997Sken return (EINVAL); 694229997Sken if (mifp->m6_ifp == NULL) 695229997Sken return (EINVAL); 696229997Sken 697229997Sken s = splnet(); 698229997Sken 699256190Strasz if (!(mifp->m6_flags & MIFF_REGISTER)) { 700229997Sken /* 701229997Sken * XXX: what if there is yet IPv4 multicast daemon 702229997Sken * using the interface? 703229997Sken */ 704229997Sken ifp = mifp->m6_ifp; 705229997Sken 706229997Sken if_allmulti(ifp, 0); 707229997Sken } else { 708229997Sken if (reg_mif_num != (mifi_t)-1 && 709229997Sken multicast_register_if6 != NULL) { 710229997Sken if_detach(multicast_register_if6); 711229997Sken if_free(multicast_register_if6); 712229997Sken reg_mif_num = (mifi_t)-1; 713229997Sken multicast_register_if6 = NULL; 714229997Sken } 715229997Sken } 716229997Sken 717229997Sken bzero((caddr_t)mifp, sizeof(*mifp)); 718229997Sken 719229997Sken /* Adjust nummifs down */ 720229997Sken for (mifi = nummifs; mifi > 0; mifi--) 721229997Sken if (mif6table[mifi - 1].m6_ifp) 722229997Sken break; 723229997Sken nummifs = mifi; 724229997Sken 725229997Sken splx(s); 726229997Sken 727229997Sken#ifdef MRT6DEBUG 728229997Sken if (V_mrt6debug) 729229997Sken log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs); 730229997Sken#endif 731229997Sken 732229997Sken return (0); 733229997Sken} 734229997Sken 735229997Sken/* 736229997Sken * Add an mfc entry 737229997Sken */ 738229997Skenstatic int 739229997Skenadd_m6fc(struct mf6cctl *mfccp) 740229997Sken{ 741229997Sken struct mf6c *rt; 742229997Sken u_long hash; 743229997Sken struct rtdetq *rte; 744229997Sken u_short nstl; 745229997Sken int s; 746229997Sken char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN]; 747229997Sken 748229997Sken MF6CFIND(mfccp->mf6cc_origin.sin6_addr, 749229997Sken mfccp->mf6cc_mcastgrp.sin6_addr, rt); 750229997Sken 751229997Sken /* If an entry already exists, just update the fields */ 752229997Sken if (rt) { 753229997Sken#ifdef MRT6DEBUG 754229997Sken if (V_mrt6debug & DEBUG_MFC) { 755229997Sken log(LOG_DEBUG, 756229997Sken "add_m6fc no upcall h %d o %s g %s p %x\n", 757229997Sken ip6_sprintf(ip6bufo, &mfccp->mf6cc_origin.sin6_addr), 758229997Sken ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr), 759229997Sken mfccp->mf6cc_parent); 760229997Sken } 761229997Sken#endif 762229997Sken 763229997Sken s = splnet(); 764229997Sken rt->mf6c_parent = mfccp->mf6cc_parent; 765229997Sken rt->mf6c_ifset = mfccp->mf6cc_ifset; 766229997Sken splx(s); 767229997Sken return (0); 768229997Sken } 769229997Sken 770229997Sken /* 771229997Sken * Find the entry for which the upcall was made and update 772229997Sken */ 773229997Sken s = splnet(); 774229997Sken hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr, 775229997Sken mfccp->mf6cc_mcastgrp.sin6_addr); 776229997Sken for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) { 777229997Sken if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr, 778229997Sken &mfccp->mf6cc_origin.sin6_addr) && 779229997Sken IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr, 780229997Sken &mfccp->mf6cc_mcastgrp.sin6_addr) && 781229997Sken (rt->mf6c_stall != NULL)) { 782229997Sken 783229997Sken if (nstl++) 784229997Sken log(LOG_ERR, 785229997Sken "add_m6fc: %s o %s g %s p %x dbx %p\n", 786229997Sken "multiple kernel entries", 787229997Sken ip6_sprintf(ip6bufo, 788229997Sken &mfccp->mf6cc_origin.sin6_addr), 789229997Sken ip6_sprintf(ip6bufg, 790229997Sken &mfccp->mf6cc_mcastgrp.sin6_addr), 791229997Sken mfccp->mf6cc_parent, rt->mf6c_stall); 792229997Sken 793229997Sken#ifdef MRT6DEBUG 794229997Sken if (V_mrt6debug & DEBUG_MFC) 795229997Sken log(LOG_DEBUG, 796229997Sken "add_m6fc o %s g %s p %x dbg %x\n", 797229997Sken ip6_sprintf(ip6bufo, 798229997Sken &mfccp->mf6cc_origin.sin6_addr), 799229997Sken ip6_sprintf(ip6bufg, 800229997Sken &mfccp->mf6cc_mcastgrp.sin6_addr), 801229997Sken mfccp->mf6cc_parent, rt->mf6c_stall); 802229997Sken#endif 803229997Sken 804229997Sken rt->mf6c_origin = mfccp->mf6cc_origin; 805229997Sken rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp; 806229997Sken rt->mf6c_parent = mfccp->mf6cc_parent; 807229997Sken rt->mf6c_ifset = mfccp->mf6cc_ifset; 808229997Sken /* initialize pkt counters per src-grp */ 809229997Sken rt->mf6c_pkt_cnt = 0; 810229997Sken rt->mf6c_byte_cnt = 0; 811229997Sken rt->mf6c_wrong_if = 0; 812229997Sken 813229997Sken rt->mf6c_expire = 0; /* Don't clean this guy up */ 814229997Sken n6expire[hash]--; 815229997Sken 816229997Sken /* free packets Qed at the end of this entry */ 817229997Sken for (rte = rt->mf6c_stall; rte != NULL; ) { 818229997Sken struct rtdetq *n = rte->next; 819229997Sken ip6_mdq(rte->m, rte->ifp, rt); 820229997Sken m_freem(rte->m); 821229997Sken#ifdef UPCALL_TIMING 822229997Sken collate(&(rte->t)); 823229997Sken#endif /* UPCALL_TIMING */ 824229997Sken free(rte, M_MRTABLE6); 825229997Sken rte = n; 826229997Sken } 827229997Sken rt->mf6c_stall = NULL; 828229997Sken } 829229997Sken } 830229997Sken 831229997Sken /* 832229997Sken * It is possible that an entry is being inserted without an upcall 833229997Sken */ 834229997Sken if (nstl == 0) { 835229997Sken#ifdef MRT6DEBUG 836229997Sken if (V_mrt6debug & DEBUG_MFC) 837229997Sken log(LOG_DEBUG, 838229997Sken "add_mfc no upcall h %d o %s g %s p %x\n", 839229997Sken hash, 840229997Sken ip6_sprintf(ip6bufo, &mfccp->mf6cc_origin.sin6_addr), 841229997Sken ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr), 842229997Sken mfccp->mf6cc_parent); 843229997Sken#endif 844229997Sken 845229997Sken for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) { 846229997Sken 847229997Sken if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr, 848229997Sken &mfccp->mf6cc_origin.sin6_addr)&& 849229997Sken IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr, 850229997Sken &mfccp->mf6cc_mcastgrp.sin6_addr)) { 851229997Sken 852229997Sken rt->mf6c_origin = mfccp->mf6cc_origin; 853229997Sken rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp; 854229997Sken rt->mf6c_parent = mfccp->mf6cc_parent; 855229997Sken rt->mf6c_ifset = mfccp->mf6cc_ifset; 856229997Sken /* initialize pkt counters per src-grp */ 857229997Sken rt->mf6c_pkt_cnt = 0; 858229997Sken rt->mf6c_byte_cnt = 0; 859229997Sken rt->mf6c_wrong_if = 0; 860229997Sken 861229997Sken if (rt->mf6c_expire) 862229997Sken n6expire[hash]--; 863229997Sken rt->mf6c_expire = 0; 864229997Sken } 865229997Sken } 866229997Sken if (rt == NULL) { 867229997Sken /* no upcall, so make a new entry */ 868229997Sken rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6, 869229997Sken M_NOWAIT); 870229997Sken if (rt == NULL) { 871229997Sken splx(s); 872229997Sken return (ENOBUFS); 873229997Sken } 874229997Sken 875229997Sken /* insert new entry at head of hash chain */ 876229997Sken rt->mf6c_origin = mfccp->mf6cc_origin; 877229997Sken rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp; 878229997Sken rt->mf6c_parent = mfccp->mf6cc_parent; 879229997Sken rt->mf6c_ifset = mfccp->mf6cc_ifset; 880229997Sken /* initialize pkt counters per src-grp */ 881229997Sken rt->mf6c_pkt_cnt = 0; 882229997Sken rt->mf6c_byte_cnt = 0; 883229997Sken rt->mf6c_wrong_if = 0; 884229997Sken rt->mf6c_expire = 0; 885229997Sken rt->mf6c_stall = NULL; 886229997Sken 887229997Sken /* link into table */ 888229997Sken rt->mf6c_next = mf6ctable[hash]; 889229997Sken mf6ctable[hash] = rt; 890229997Sken } 891229997Sken } 892229997Sken splx(s); 893229997Sken return (0); 894229997Sken} 895229997Sken 896229997Sken#ifdef UPCALL_TIMING 897229997Sken/* 898229997Sken * collect delay statistics on the upcalls 899229997Sken */ 900229997Skenstatic void 901229997Skencollate(struct timeval *t) 902229997Sken{ 903229997Sken u_long d; 904229997Sken struct timeval tp; 905229997Sken u_long delta; 906229997Sken 907229997Sken GET_TIME(tp); 908229997Sken 909229997Sken if (TV_LT(*t, tp)) 910229997Sken { 911229997Sken TV_DELTA(tp, *t, delta); 912229997Sken 913229997Sken d = delta >> 10; 914229997Sken if (d > UPCALL_MAX) 915229997Sken d = UPCALL_MAX; 916229997Sken 917229997Sken ++upcall_data[d]; 918229997Sken } 919229997Sken} 920229997Sken#endif /* UPCALL_TIMING */ 921229997Sken 922229997Sken/* 923229997Sken * Delete an mfc entry 924229997Sken */ 925229997Skenstatic int 926229997Skendel_m6fc(struct mf6cctl *mfccp) 927229997Sken{ 928229997Sken struct sockaddr_in6 origin; 929229997Sken struct sockaddr_in6 mcastgrp; 930229997Sken struct mf6c *rt; 931229997Sken struct mf6c **nptr; 932229997Sken u_long hash; 933229997Sken int s; 934229997Sken 935229997Sken origin = mfccp->mf6cc_origin; 936229997Sken mcastgrp = mfccp->mf6cc_mcastgrp; 937229997Sken hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr); 938229997Sken 939229997Sken#ifdef MRT6DEBUG 940229997Sken if (V_mrt6debug & DEBUG_MFC) { 941229997Sken char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN]; 942229997Sken log(LOG_DEBUG,"del_m6fc orig %s mcastgrp %s\n", 943229997Sken ip6_sprintf(ip6bufo, &origin.sin6_addr), 944229997Sken ip6_sprintf(ip6bufg, &mcastgrp.sin6_addr)); 945229997Sken } 946229997Sken#endif 947229997Sken 948229997Sken s = splnet(); 949229997Sken 950229997Sken nptr = &mf6ctable[hash]; 951229997Sken while ((rt = *nptr) != NULL) { 952229997Sken if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr, 953229997Sken &rt->mf6c_origin.sin6_addr) && 954229997Sken IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr, 955229997Sken &rt->mf6c_mcastgrp.sin6_addr) && 956229997Sken rt->mf6c_stall == NULL) 957229997Sken break; 958229997Sken 959229997Sken nptr = &rt->mf6c_next; 960229997Sken } 961229997Sken if (rt == NULL) { 962229997Sken splx(s); 963229997Sken return (EADDRNOTAVAIL); 964229997Sken } 965229997Sken 966229997Sken *nptr = rt->mf6c_next; 967229997Sken free(rt, M_MRTABLE6); 968229997Sken 969229997Sken splx(s); 970229997Sken 971229997Sken return (0); 972229997Sken} 973229997Sken 974229997Skenstatic int 975229997Skensocket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src) 976229997Sken{ 977229997Sken 978229997Sken if (s) { 979229997Sken if (sbappendaddr(&s->so_rcv, 980229997Sken (struct sockaddr *)src, 981229997Sken mm, (struct mbuf *)0) != 0) { 982229997Sken sorwakeup(s); 983229997Sken return (0); 984229997Sken } 985229997Sken } 986229997Sken m_freem(mm); 987229997Sken return (-1); 988229997Sken} 989229997Sken 990229997Sken/* 991229997Sken * IPv6 multicast forwarding function. This function assumes that the packet 992229997Sken * pointed to by "ip6" has arrived on (or is about to be sent to) the interface 993229997Sken * pointed to by "ifp", and the packet is to be relayed to other networks 994229997Sken * that have members of the packet's destination IPv6 multicast group. 995229997Sken * 996229997Sken * The packet is returned unscathed to the caller, unless it is 997229997Sken * erroneous, in which case a non-zero return value tells the caller to 998229997Sken * discard it. 999229997Sken * 1000229997Sken * NOTE: this implementation assumes that m->m_pkthdr.rcvif is NULL iff 1001229997Sken * this function is called in the originating context (i.e., not when 1002229997Sken * forwarding a packet from other node). ip6_output(), which is currently the 1003229997Sken * only function that calls this function is called in the originating context, 1004229997Sken * explicitly ensures this condition. It is caller's responsibility to ensure 1005229997Sken * that if this function is called from somewhere else in the originating 1006229997Sken * context in the future. 1007229997Sken */ 1008229997Skenint 1009229997SkenX_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m) 1010241737Sed{ 1011229997Sken INIT_VNET_INET6(curvnet); 1012229997Sken struct mf6c *rt; 1013229997Sken struct mif6 *mifp; 1014229997Sken struct mbuf *mm; 1015229997Sken int s; 1016229997Sken mifi_t mifi; 1017229997Sken char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 1018229997Sken 1019241737Sed#ifdef MRT6DEBUG 1020229997Sken if (V_mrt6debug & DEBUG_FORWARD) 1021229997Sken log(LOG_DEBUG, "ip6_mforward: src %s, dst %s, ifindex %d\n", 1022229997Sken ip6_sprintf(ip6bufs, &ip6->ip6_src), 1023229997Sken ip6_sprintf(ip6bufd, &ip6->ip6_dst), 1024229997Sken ifp->if_index); 1025229997Sken#endif 1026229997Sken 1027229997Sken /* 1028229997Sken * Don't forward a packet with Hop limit of zero or one, 1029229997Sken * or a packet destined to a local-only group. 1030229997Sken */ 1031229997Sken if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) || 1032229997Sken IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) 1033229997Sken return (0); 1034274870Strasz ip6->ip6_hlim--; 1035229997Sken 1036229997Sken /* 1037239074Sdim * Source address check: do not forward packets with unspecified 1038229997Sken * source. It was discussed in July 2000, on ipngwg mailing list. 1039229997Sken * This is rather more serious than unicast cases, because some 1040229997Sken * MLD packets can be sent with the unspecified source address 1041229997Sken * (although such packets must normally set 1 to the hop limit field). 1042229997Sken */ 1043229997Sken if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { 1044229997Sken V_ip6stat.ip6s_cantforward++; 1045229997Sken if (V_ip6_log_time + V_ip6_log_interval < time_second) { 1046229997Sken V_ip6_log_time = time_second; 1047229997Sken log(LOG_DEBUG, 1048229997Sken "cannot forward " 1049229997Sken "from %s to %s nxt %d received on %s\n", 1050229997Sken ip6_sprintf(ip6bufs, &ip6->ip6_src), 1051229997Sken ip6_sprintf(ip6bufd, &ip6->ip6_dst), 1052229997Sken ip6->ip6_nxt, 1053229997Sken if_name(m->m_pkthdr.rcvif)); 1054229997Sken } 1055229997Sken return (0); 1056229997Sken } 1057229997Sken 1058229997Sken /* 1059229997Sken * Determine forwarding mifs from the forwarding cache table 1060229997Sken */ 1061229997Sken s = splnet(); 1062229997Sken MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt); 1063229997Sken 1064229997Sken /* Entry exists, so forward if necessary */ 1065229997Sken if (rt) { 1066229997Sken splx(s); 1067229997Sken return (ip6_mdq(m, ifp, rt)); 1068229997Sken } else { 1069229997Sken /* 1070229997Sken * If we don't have a route for packet's origin, 1071229997Sken * Make a copy of the packet & 1072229997Sken * send message to routing daemon 1073229997Sken */ 1074229997Sken 1075229997Sken struct mbuf *mb0; 1076229997Sken struct rtdetq *rte; 1077229997Sken u_long hash; 1078229997Sken/* int i, npkts;*/ 1079229997Sken#ifdef UPCALL_TIMING 1080229997Sken struct timeval tp; 1081229997Sken 1082229997Sken GET_TIME(tp); 1083229997Sken#endif /* UPCALL_TIMING */ 1084229997Sken 1085229997Sken mrt6stat.mrt6s_no_route++; 1086229997Sken#ifdef MRT6DEBUG 1087229997Sken if (V_mrt6debug & (DEBUG_FORWARD | DEBUG_MFC)) 1088229997Sken log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n", 1089229997Sken ip6_sprintf(ip6bufs, &ip6->ip6_src), 1090229997Sken ip6_sprintf(ip6bufd, &ip6->ip6_dst)); 1091229997Sken#endif 1092229997Sken 1093229997Sken /* 1094229997Sken * Allocate mbufs early so that we don't do extra work if we 1095229997Sken * are just going to fail anyway. 1096229997Sken */ 1097229997Sken rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE6, 1098229997Sken M_NOWAIT); 1099229997Sken if (rte == NULL) { 1100229997Sken splx(s); 1101229997Sken return (ENOBUFS); 1102229997Sken } 1103229997Sken mb0 = m_copy(m, 0, M_COPYALL); 1104229997Sken /* 1105229997Sken * Pullup packet header if needed before storing it, 1106229997Sken * as other references may modify it in the meantime. 1107229997Sken */ 1108229997Sken if (mb0 && 1109229997Sken (M_HASCL(mb0) || mb0->m_len < sizeof(struct ip6_hdr))) 1110229997Sken mb0 = m_pullup(mb0, sizeof(struct ip6_hdr)); 1111229997Sken if (mb0 == NULL) { 1112229997Sken free(rte, M_MRTABLE6); 1113229997Sken splx(s); 1114229997Sken return (ENOBUFS); 1115229997Sken } 1116229997Sken 1117229997Sken /* is there an upcall waiting for this packet? */ 1118229997Sken hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst); 1119229997Sken for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) { 1120229997Sken if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, 1121229997Sken &rt->mf6c_origin.sin6_addr) && 1122229997Sken IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, 1123229997Sken &rt->mf6c_mcastgrp.sin6_addr) && 1124229997Sken (rt->mf6c_stall != NULL)) 1125229997Sken break; 1126229997Sken } 1127229997Sken 1128229997Sken if (rt == NULL) { 1129229997Sken struct mrt6msg *im; 1130229997Sken#ifdef MRT6_OINIT 1131229997Sken struct omrt6msg *oim; 1132229997Sken#endif 1133229997Sken 1134229997Sken /* no upcall, so make a new entry */ 1135229997Sken rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6, 1136229997Sken M_NOWAIT); 1137229997Sken if (rt == NULL) { 1138229997Sken free(rte, M_MRTABLE6); 1139229997Sken m_freem(mb0); 1140229997Sken splx(s); 1141229997Sken return (ENOBUFS); 1142229997Sken } 1143229997Sken /* 1144229997Sken * Make a copy of the header to send to the user 1145229997Sken * level process 1146229997Sken */ 1147229997Sken mm = m_copy(mb0, 0, sizeof(struct ip6_hdr)); 1148229997Sken 1149229997Sken if (mm == NULL) { 1150229997Sken free(rte, M_MRTABLE6); 1151229997Sken m_freem(mb0); 1152229997Sken free(rt, M_MRTABLE6); 1153229997Sken splx(s); 1154229997Sken return (ENOBUFS); 1155229997Sken } 1156229997Sken 1157229997Sken /* 1158229997Sken * Send message to routing daemon 1159229997Sken */ 1160229997Sken sin6.sin6_addr = ip6->ip6_src; 1161229997Sken 1162229997Sken im = NULL; 1163229997Sken#ifdef MRT6_OINIT 1164229997Sken oim = NULL; 1165229997Sken#endif 1166229997Sken switch (V_ip6_mrouter_ver) { 1167229997Sken#ifdef MRT6_OINIT 1168229997Sken case MRT6_OINIT: 1169229997Sken oim = mtod(mm, struct omrt6msg *); 1170229997Sken oim->im6_msgtype = MRT6MSG_NOCACHE; 1171229997Sken oim->im6_mbz = 0; 1172229997Sken break; 1173229997Sken#endif 1174229997Sken case MRT6_INIT: 1175229997Sken im = mtod(mm, struct mrt6msg *); 1176229997Sken im->im6_msgtype = MRT6MSG_NOCACHE; 1177229997Sken im->im6_mbz = 0; 1178229997Sken break; 1179229997Sken default: 1180229997Sken free(rte, M_MRTABLE6); 1181229997Sken m_freem(mb0); 1182229997Sken free(rt, M_MRTABLE6); 1183229997Sken splx(s); 1184229997Sken return (EINVAL); 1185229997Sken } 1186229997Sken 1187229997Sken#ifdef MRT6DEBUG 1188229997Sken if (V_mrt6debug & DEBUG_FORWARD) 1189229997Sken log(LOG_DEBUG, 1190229997Sken "getting the iif info in the kernel\n"); 1191229997Sken#endif 1192229997Sken 1193229997Sken for (mifp = mif6table, mifi = 0; 1194229997Sken mifi < nummifs && mifp->m6_ifp != ifp; 1195229997Sken mifp++, mifi++) 1196229997Sken ; 1197229997Sken 1198229997Sken switch (V_ip6_mrouter_ver) { 1199274870Strasz#ifdef MRT6_OINIT 1200229997Sken case MRT6_OINIT: 1201229997Sken oim->im6_mif = mifi; 1202229997Sken break; 1203229997Sken#endif 1204274870Strasz case MRT6_INIT: 1205229997Sken im->im6_mif = mifi; 1206229997Sken break; 1207229997Sken } 1208229997Sken 1209229997Sken if (socket_send(ip6_mrouter, mm, &sin6) < 0) { 1210229997Sken log(LOG_WARNING, "ip6_mforward: ip6_mrouter " 1211229997Sken "socket queue full\n"); 1212229997Sken mrt6stat.mrt6s_upq_sockfull++; 1213229997Sken free(rte, M_MRTABLE6); 1214229997Sken m_freem(mb0); 1215229997Sken free(rt, M_MRTABLE6); 1216229997Sken splx(s); 1217229997Sken return (ENOBUFS); 1218229997Sken } 1219229997Sken 1220229997Sken mrt6stat.mrt6s_upcalls++; 1221229997Sken 1222229997Sken /* insert new entry at head of hash chain */ 1223229997Sken bzero(rt, sizeof(*rt)); 1224229997Sken rt->mf6c_origin.sin6_family = AF_INET6; 1225229997Sken rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6); 1226229997Sken rt->mf6c_origin.sin6_addr = ip6->ip6_src; 1227229997Sken rt->mf6c_mcastgrp.sin6_family = AF_INET6; 1228229997Sken rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6); 1229229997Sken rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst; 1230229997Sken rt->mf6c_expire = UPCALL_EXPIRE; 1231229997Sken n6expire[hash]++; 1232229997Sken rt->mf6c_parent = MF6C_INCOMPLETE_PARENT; 1233229997Sken 1234229997Sken /* link into table */ 1235229997Sken rt->mf6c_next = mf6ctable[hash]; 1236229997Sken mf6ctable[hash] = rt; 1237229997Sken /* Add this entry to the end of the queue */ 1238229997Sken rt->mf6c_stall = rte; 1239229997Sken } else { 1240229997Sken /* determine if q has overflowed */ 1241229997Sken struct rtdetq **p; 1242229997Sken int npkts = 0; 1243229997Sken 1244229997Sken for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next) 1245229997Sken if (++npkts > MAX_UPQ6) { 1246229997Sken mrt6stat.mrt6s_upq_ovflw++; 1247229997Sken free(rte, M_MRTABLE6); 1248229997Sken m_freem(mb0); 1249229997Sken splx(s); 1250229997Sken return (0); 1251229997Sken } 1252229997Sken 1253229997Sken /* Add this entry to the end of the queue */ 1254229997Sken *p = rte; 1255229997Sken } 1256229997Sken 1257229997Sken rte->next = NULL; 1258229997Sken rte->m = mb0; 1259229997Sken rte->ifp = ifp; 1260229997Sken#ifdef UPCALL_TIMING 1261229997Sken rte->t = tp; 1262229997Sken#endif /* UPCALL_TIMING */ 1263229997Sken 1264229997Sken splx(s); 1265229997Sken 1266229997Sken return (0); 1267229997Sken } 1268229997Sken} 1269229997Sken 1270229997Sken/* 1271229997Sken * Clean up cache entries if upcalls are not serviced 1272229997Sken * Call from the Slow Timeout mechanism, every half second. 1273229997Sken */ 1274229997Skenstatic void 1275229997Skenexpire_upcalls(void *unused) 1276229997Sken{ 1277229997Sken struct rtdetq *rte; 1278229997Sken struct mf6c *mfc, **nptr; 1279229997Sken int i; 1280229997Sken int s; 1281229997Sken 1282229997Sken s = splnet(); 1283229997Sken for (i = 0; i < MF6CTBLSIZ; i++) { 1284229997Sken if (n6expire[i] == 0) 1285229997Sken continue; 1286229997Sken nptr = &mf6ctable[i]; 1287229997Sken while ((mfc = *nptr) != NULL) { 1288229997Sken rte = mfc->mf6c_stall; 1289229997Sken /* 1290229997Sken * Skip real cache entries 1291229997Sken * Make sure it wasn't marked to not expire (shouldn't happen) 1292229997Sken * If it expires now 1293229997Sken */ 1294229997Sken if (rte != NULL && 1295229997Sken mfc->mf6c_expire != 0 && 1296229997Sken --mfc->mf6c_expire == 0) { 1297229997Sken#ifdef MRT6DEBUG 1298229997Sken if (V_mrt6debug & DEBUG_EXPIRE) { 1299229997Sken char ip6bufo[INET6_ADDRSTRLEN]; 1300229997Sken char ip6bufg[INET6_ADDRSTRLEN]; 1301229997Sken log(LOG_DEBUG, "expire_upcalls: expiring (%s %s)\n", 1302229997Sken ip6_sprintf(ip6bufo, &mfc->mf6c_origin.sin6_addr), 1303229997Sken ip6_sprintf(ip6bufg, &mfc->mf6c_mcastgrp.sin6_addr)); 1304229997Sken } 1305229997Sken#endif 1306229997Sken /* 1307229997Sken * drop all the packets 1308229997Sken * free the mbuf with the pkt, if, timing info 1309229997Sken */ 1310229997Sken do { 1311229997Sken struct rtdetq *n = rte->next; 1312229997Sken m_freem(rte->m); 1313229997Sken free(rte, M_MRTABLE6); 1314229997Sken rte = n; 1315229997Sken } while (rte != NULL); 1316229997Sken mrt6stat.mrt6s_cache_cleanups++; 1317229997Sken n6expire[i]--; 1318229997Sken 1319229997Sken *nptr = mfc->mf6c_next; 1320229997Sken free(mfc, M_MRTABLE6); 1321229997Sken } else { 1322229997Sken nptr = &mfc->mf6c_next; 1323229997Sken } 1324229997Sken } 1325229997Sken } 1326229997Sken splx(s); 1327229997Sken callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, 1328229997Sken expire_upcalls, NULL); 1329229997Sken} 1330229997Sken 1331229997Sken/* 1332229997Sken * Packet forwarding routine once entry in the cache is made 1333229997Sken */ 1334229997Skenstatic int 1335229997Skenip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt) 1336229997Sken{ 1337229997Sken INIT_VNET_INET6(curvnet); 1338229997Sken struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1339229997Sken mifi_t mifi, iif; 1340229997Sken struct mif6 *mifp; 1341229997Sken int plen = m->m_pkthdr.len; 1342229997Sken struct in6_addr src0, dst0; /* copies for local work */ 1343229997Sken u_int32_t iszone, idzone, oszone, odzone; 1344229997Sken int error = 0; 1345229997Sken 1346229997Sken/* 1347229997Sken * Macro to send packet on mif. Since RSVP packets don't get counted on 1348229997Sken * input, they shouldn't get counted on output, so statistics keeping is 1349229997Sken * separate. 1350229997Sken */ 1351229997Sken 1352229997Sken#define MC6_SEND(ip6, mifp, m) do { \ 1353229997Sken if ((mifp)->m6_flags & MIFF_REGISTER) \ 1354229997Sken register_send((ip6), (mifp), (m)); \ 1355229997Sken else \ 1356229997Sken phyint_send((ip6), (mifp), (m)); \ 1357229997Sken} while (/*CONSTCOND*/ 0) 1358229997Sken 1359229997Sken /* 1360229997Sken * Don't forward if it didn't arrive from the parent mif 1361229997Sken * for its origin. 1362229997Sken */ 1363229997Sken mifi = rt->mf6c_parent; 1364229997Sken if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) { 1365229997Sken /* came in the wrong interface */ 1366229997Sken#ifdef MRT6DEBUG 1367229997Sken if (V_mrt6debug & DEBUG_FORWARD) 1368229997Sken log(LOG_DEBUG, 1369229997Sken "wrong if: ifid %d mifi %d mififid %x\n", 1370229997Sken ifp->if_index, mifi, 1371229997Sken mif6table[mifi].m6_ifp->if_index); 1372229997Sken#endif 1373229997Sken mrt6stat.mrt6s_wrong_if++; 1374229997Sken rt->mf6c_wrong_if++; 1375229997Sken /* 1376229997Sken * If we are doing PIM processing, and we are forwarding 1377229997Sken * packets on this interface, send a message to the 1378229997Sken * routing daemon. 1379229997Sken */ 1380229997Sken /* have to make sure this is a valid mif */ 1381229997Sken if (mifi < nummifs && mif6table[mifi].m6_ifp) 1382229997Sken if (V_pim6 && (m->m_flags & M_LOOP) == 0) { 1383229997Sken /* 1384229997Sken * Check the M_LOOP flag to avoid an 1385229997Sken * unnecessary PIM assert. 1386229997Sken * XXX: M_LOOP is an ad-hoc hack... 1387229997Sken */ 1388229997Sken static struct sockaddr_in6 sin6 = 1389229997Sken { sizeof(sin6), AF_INET6 }; 1390229997Sken 1391229997Sken struct mbuf *mm; 1392229997Sken struct mrt6msg *im; 1393229997Sken#ifdef MRT6_OINIT 1394229997Sken struct omrt6msg *oim; 1395229997Sken#endif 1396229997Sken 1397229997Sken mm = m_copy(m, 0, sizeof(struct ip6_hdr)); 1398229997Sken if (mm && 1399229997Sken (M_HASCL(mm) || 1400229997Sken mm->m_len < sizeof(struct ip6_hdr))) 1401229997Sken mm = m_pullup(mm, sizeof(struct ip6_hdr)); 1402229997Sken if (mm == NULL) 1403229997Sken return (ENOBUFS); 1404229997Sken 1405229997Sken#ifdef MRT6_OINIT 1406229997Sken oim = NULL; 1407229997Sken#endif 1408229997Sken im = NULL; 1409229997Sken switch (V_ip6_mrouter_ver) { 1410229997Sken#ifdef MRT6_OINIT 1411229997Sken case MRT6_OINIT: 1412229997Sken oim = mtod(mm, struct omrt6msg *); 1413229997Sken oim->im6_msgtype = MRT6MSG_WRONGMIF; 1414229997Sken oim->im6_mbz = 0; 1415229997Sken break; 1416229997Sken#endif 1417229997Sken case MRT6_INIT: 1418229997Sken im = mtod(mm, struct mrt6msg *); 1419229997Sken im->im6_msgtype = MRT6MSG_WRONGMIF; 1420229997Sken im->im6_mbz = 0; 1421229997Sken break; 1422229997Sken default: 1423229997Sken m_freem(mm); 1424229997Sken return (EINVAL); 1425229997Sken } 1426229997Sken 1427229997Sken for (mifp = mif6table, iif = 0; 1428229997Sken iif < nummifs && mifp && 1429229997Sken mifp->m6_ifp != ifp; 1430229997Sken mifp++, iif++) 1431229997Sken ; 1432229997Sken 1433229997Sken switch (V_ip6_mrouter_ver) { 1434229997Sken#ifdef MRT6_OINIT 1435229997Sken case MRT6_OINIT: 1436274870Strasz oim->im6_mif = iif; 1437229997Sken sin6.sin6_addr = oim->im6_src; 1438229997Sken break; 1439229997Sken#endif 1440229997Sken case MRT6_INIT: 1441229997Sken im->im6_mif = iif; 1442229997Sken sin6.sin6_addr = im->im6_src; 1443229997Sken break; 1444229997Sken } 1445229997Sken 1446229997Sken mrt6stat.mrt6s_upcalls++; 1447229997Sken 1448274870Strasz if (socket_send(ip6_mrouter, mm, &sin6) < 0) { 1449229997Sken#ifdef MRT6DEBUG 1450229997Sken if (V_mrt6debug) 1451229997Sken log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n"); 1452229997Sken#endif 1453229997Sken ++mrt6stat.mrt6s_upq_sockfull; 1454229997Sken return (ENOBUFS); 1455229997Sken } /* if socket Q full */ 1456229997Sken } /* if PIM */ 1457229997Sken return (0); 1458229997Sken } /* if wrong iif */ 1459229997Sken 1460229997Sken /* If I sourced this packet, it counts as output, else it was input. */ 1461229997Sken if (m->m_pkthdr.rcvif == NULL) { 1462229997Sken /* XXX: is rcvif really NULL when output?? */ 1463229997Sken mif6table[mifi].m6_pkt_out++; 1464229997Sken mif6table[mifi].m6_bytes_out += plen; 1465229997Sken } else { 1466229997Sken mif6table[mifi].m6_pkt_in++; 1467229997Sken mif6table[mifi].m6_bytes_in += plen; 1468229997Sken } 1469229997Sken rt->mf6c_pkt_cnt++; 1470229997Sken rt->mf6c_byte_cnt += plen; 1471229997Sken 1472229997Sken /* 1473229997Sken * For each mif, forward a copy of the packet if there are group 1474229997Sken * members downstream on the interface. 1475229997Sken */ 1476229997Sken src0 = ip6->ip6_src; 1477229997Sken dst0 = ip6->ip6_dst; 1478229997Sken if ((error = in6_setscope(&src0, ifp, &iszone)) != 0 || 1479229997Sken (error = in6_setscope(&dst0, ifp, &idzone)) != 0) { 1480229997Sken V_ip6stat.ip6s_badscope++; 1481229997Sken return (error); 1482229997Sken } 1483229997Sken for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) { 1484229997Sken if (IF_ISSET(mifi, &rt->mf6c_ifset)) { 1485229997Sken /* 1486229997Sken * check if the outgoing packet is going to break 1487229997Sken * a scope boundary. 1488229997Sken * XXX For packets through PIM register tunnel 1489229997Sken * interface, we believe a routing daemon. 1490229997Sken */ 1491229997Sken if (!(mif6table[rt->mf6c_parent].m6_flags & 1492229997Sken MIFF_REGISTER) && 1493229997Sken !(mif6table[mifi].m6_flags & MIFF_REGISTER)) { 1494229997Sken if (in6_setscope(&src0, mif6table[mifi].m6_ifp, 1495229997Sken &oszone) || 1496229997Sken in6_setscope(&dst0, mif6table[mifi].m6_ifp, 1497229997Sken &odzone) || 1498229997Sken iszone != oszone || 1499229997Sken idzone != odzone) { 1500229997Sken V_ip6stat.ip6s_badscope++; 1501274870Strasz continue; 1502229997Sken } 1503229997Sken } 1504229997Sken 1505229997Sken mifp->m6_pkt_out++; 1506229997Sken mifp->m6_bytes_out += plen; 1507229997Sken MC6_SEND(ip6, mifp, m); 1508229997Sken } 1509229997Sken } 1510229997Sken return (0); 1511229997Sken} 1512229997Sken 1513229997Skenstatic void 1514229997Skenphyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m) 1515229997Sken{ 1516229997Sken INIT_VNET_INET6(curvnet); 1517229997Sken struct mbuf *mb_copy; 1518229997Sken struct ifnet *ifp = mifp->m6_ifp; 1519229997Sken int error = 0; 1520229997Sken int s = splnet(); /* needs to protect static "ro" below. */ 1521229997Sken static struct route_in6 ro; 1522229997Sken struct in6_multi *in6m; 1523229997Sken struct sockaddr_in6 *dst6; 1524229997Sken u_long linkmtu; 1525229997Sken 1526229997Sken /* 1527229997Sken * Make a new reference to the packet; make sure that 1528229997Sken * the IPv6 header is actually copied, not just referenced, 1529229997Sken * so that ip6_output() only scribbles on the copy. 1530229997Sken */ 1531229997Sken mb_copy = m_copy(m, 0, M_COPYALL); 1532229997Sken if (mb_copy && 1533229997Sken (M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr))) 1534229997Sken mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr)); 1535229997Sken if (mb_copy == NULL) { 1536229997Sken splx(s); 1537229997Sken return; 1538229997Sken } 1539229997Sken /* set MCAST flag to the outgoing packet */ 1540229997Sken mb_copy->m_flags |= M_MCAST; 1541229997Sken 1542229997Sken /* 1543229997Sken * If we sourced the packet, call ip6_output since we may devide 1544229997Sken * the packet into fragments when the packet is too big for the 1545229997Sken * outgoing interface. 1546229997Sken * Otherwise, we can simply send the packet to the interface 1547229997Sken * sending queue. 1548229997Sken */ 1549229997Sken if (m->m_pkthdr.rcvif == NULL) { 1550229997Sken struct ip6_moptions im6o; 1551229997Sken 1552229997Sken im6o.im6o_multicast_ifp = ifp; 1553229997Sken /* XXX: ip6_output will override ip6->ip6_hlim */ 1554229997Sken im6o.im6o_multicast_hlim = ip6->ip6_hlim; 1555229997Sken im6o.im6o_multicast_loop = 1; 1556229997Sken error = ip6_output(mb_copy, NULL, &ro, 1557229997Sken IPV6_FORWARDING, &im6o, NULL, NULL); 1558229997Sken 1559229997Sken#ifdef MRT6DEBUG 1560229997Sken if (V_mrt6debug & DEBUG_XMIT) 1561229997Sken log(LOG_DEBUG, "phyint_send on mif %d err %d\n", 1562229997Sken mifp - mif6table, error); 1563229997Sken#endif 1564229997Sken splx(s); 1565229997Sken return; 1566229997Sken } 1567229997Sken 1568229997Sken /* 1569229997Sken * If we belong to the destination multicast group 1570229997Sken * on the outgoing interface, loop back a copy. 1571229997Sken */ 1572229997Sken dst6 = (struct sockaddr_in6 *)&ro.ro_dst; 1573229997Sken IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m); 1574229997Sken if (in6m != NULL) { 1575229997Sken dst6->sin6_len = sizeof(struct sockaddr_in6); 1576229997Sken dst6->sin6_family = AF_INET6; 1577229997Sken dst6->sin6_addr = ip6->ip6_dst; 1578229997Sken ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst); 1579229997Sken } 1580229997Sken /* 1581229997Sken * Put the packet into the sending queue of the outgoing interface 1582229997Sken * if it would fit in the MTU of the interface. 1583229997Sken */ 1584229997Sken linkmtu = IN6_LINKMTU(ifp); 1585229997Sken if (mb_copy->m_pkthdr.len <= linkmtu || linkmtu < IPV6_MMTU) { 1586229997Sken dst6->sin6_len = sizeof(struct sockaddr_in6); 1587229997Sken dst6->sin6_family = AF_INET6; 1588229997Sken dst6->sin6_addr = ip6->ip6_dst; 1589229997Sken /* 1590229997Sken * We just call if_output instead of nd6_output here, since 1591229997Sken * we need no ND for a multicast forwarded packet...right? 1592229997Sken */ 1593229997Sken error = (*ifp->if_output)(ifp, mb_copy, 1594229997Sken (struct sockaddr *)&ro.ro_dst, NULL); 1595229997Sken#ifdef MRT6DEBUG 1596229997Sken if (V_mrt6debug & DEBUG_XMIT) 1597229997Sken log(LOG_DEBUG, "phyint_send on mif %d err %d\n", 1598229997Sken mifp - mif6table, error); 1599229997Sken#endif 1600229997Sken } else { 1601229997Sken /* 1602229997Sken * pMTU discovery is intentionally disabled by default, since 1603229997Sken * various router may notify pMTU in multicast, which can be 1604229997Sken * a DDoS to a router 1605229997Sken */ 1606229997Sken if (V_ip6_mcast_pmtu) 1607229997Sken icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, linkmtu); 1608229997Sken else { 1609229997Sken#ifdef MRT6DEBUG 1610229997Sken if (V_mrt6debug & DEBUG_XMIT) { 1611229997Sken char ip6bufs[INET6_ADDRSTRLEN]; 1612229997Sken char ip6bufd[INET6_ADDRSTRLEN]; 1613229997Sken log(LOG_DEBUG, 1614229997Sken "phyint_send: packet too big on %s o %s " 1615229997Sken "g %s size %d(discarded)\n", 1616229997Sken if_name(ifp), 1617229997Sken ip6_sprintf(ip6bufs, &ip6->ip6_src), 1618229997Sken ip6_sprintf(ip6bufd, &ip6->ip6_dst), 1619229997Sken mb_copy->m_pkthdr.len); 1620229997Sken } 1621229997Sken#endif /* MRT6DEBUG */ 1622229997Sken m_freem(mb_copy); /* simply discard the packet */ 1623229997Sken } 1624229997Sken } 1625229997Sken 1626229997Sken splx(s); 1627229997Sken} 1628229997Sken 1629229997Skenstatic int 1630229997Skenregister_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m) 1631229997Sken{ 1632229997Sken struct mbuf *mm; 1633229997Sken int i, len = m->m_pkthdr.len; 1634229997Sken static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 }; 1635229997Sken struct mrt6msg *im6; 1636229997Sken 1637229997Sken#ifdef MRT6DEBUG 1638229997Sken if (V_mrt6debug) { 1639229997Sken char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 1640229997Sken log(LOG_DEBUG, "** IPv6 register_send **\n src %s dst %s\n", 1641229997Sken ip6_sprintf(ip6bufs, &ip6->ip6_src), 1642229997Sken ip6_sprintf(ip6bufd, &ip6->ip6_dst)); 1643229997Sken } 1644229997Sken#endif 1645229997Sken ++pim6stat.pim6s_snd_registers; 1646229997Sken 1647229997Sken /* Make a copy of the packet to send to the user level process */ 1648229997Sken MGETHDR(mm, M_DONTWAIT, MT_HEADER); 1649274870Strasz if (mm == NULL) 1650229997Sken return (ENOBUFS); 1651229997Sken mm->m_pkthdr.rcvif = NULL; 1652229997Sken mm->m_data += max_linkhdr; 1653229997Sken mm->m_len = sizeof(struct ip6_hdr); 1654229997Sken 1655229997Sken if ((mm->m_next = m_copy(m, 0, M_COPYALL)) == NULL) { 1656229997Sken m_freem(mm); 1657229997Sken return (ENOBUFS); 1658229997Sken } 1659229997Sken i = MHLEN - M_LEADINGSPACE(mm); 1660229997Sken if (i > len) 1661229997Sken i = len; 1662229997Sken mm = m_pullup(mm, i); 1663229997Sken if (mm == NULL) 1664229997Sken return (ENOBUFS); 1665229997Sken/* TODO: check it! */ 1666229997Sken mm->m_pkthdr.len = len + sizeof(struct ip6_hdr); 1667229997Sken 1668229997Sken /* 1669229997Sken * Send message to routing daemon 1670229997Sken */ 1671229997Sken sin6.sin6_addr = ip6->ip6_src; 1672229997Sken 1673229997Sken im6 = mtod(mm, struct mrt6msg *); 1674229997Sken im6->im6_msgtype = MRT6MSG_WHOLEPKT; 1675229997Sken im6->im6_mbz = 0; 1676229997Sken 1677229997Sken im6->im6_mif = mif - mif6table; 1678229997Sken 1679229997Sken /* iif info is not given for reg. encap.n */ 1680229997Sken mrt6stat.mrt6s_upcalls++; 1681229997Sken 1682229997Sken if (socket_send(ip6_mrouter, mm, &sin6) < 0) { 1683229997Sken#ifdef MRT6DEBUG 1684229997Sken if (V_mrt6debug) 1685229997Sken log(LOG_WARNING, 1686229997Sken "register_send: ip6_mrouter socket queue full\n"); 1687229997Sken#endif 1688229997Sken ++mrt6stat.mrt6s_upq_sockfull; 1689229997Sken return (ENOBUFS); 1690229997Sken } 1691229997Sken return (0); 1692229997Sken} 1693229997Sken 1694229997Sken/* 1695229997Sken * PIM sparse mode hook 1696229997Sken * Receives the pim control messages, and passes them up to the listening 1697229997Sken * socket, using rip6_input. 1698229997Sken * The only message processed is the REGISTER pim message; the pim header 1699229997Sken * is stripped off, and the inner packet is passed to register_mforward. 1700229997Sken */ 1701229997Skenint 1702229997Skenpim6_input(struct mbuf **mp, int *offp, int proto) 1703229997Sken{ 1704229997Sken INIT_VNET_INET6(curvnet); 1705229997Sken struct pim *pim; /* pointer to a pim struct */ 1706229997Sken struct ip6_hdr *ip6; 1707229997Sken int pimlen; 1708229997Sken struct mbuf *m = *mp; 1709229997Sken int minlen; 1710229997Sken int off = *offp; 1711229997Sken 1712229997Sken ++pim6stat.pim6s_rcv_total; 1713229997Sken 1714229997Sken ip6 = mtod(m, struct ip6_hdr *); 1715229997Sken pimlen = m->m_pkthdr.len - *offp; 1716229997Sken 1717229997Sken /* 1718229997Sken * Validate lengths 1719229997Sken */ 1720229997Sken if (pimlen < PIM_MINLEN) { 1721229997Sken ++pim6stat.pim6s_rcv_tooshort; 1722229997Sken#ifdef MRT6DEBUG 1723229997Sken if (V_mrt6debug & DEBUG_PIM) 1724229997Sken log(LOG_DEBUG,"pim6_input: PIM packet too short\n"); 1725229997Sken#endif 1726229997Sken m_freem(m); 1727229997Sken return (IPPROTO_DONE); 1728229997Sken } 1729229997Sken 1730229997Sken /* 1731229997Sken * if the packet is at least as big as a REGISTER, go ahead 1732229997Sken * and grab the PIM REGISTER header size, to avoid another 1733229997Sken * possible m_pullup() later. 1734229997Sken * 1735229997Sken * PIM_MINLEN == pimhdr + u_int32 == 8 1736229997Sken * PIM6_REG_MINLEN == pimhdr + reghdr + eip6hdr == 4 + 4 + 40 1737229997Sken */ 1738229997Sken minlen = (pimlen >= PIM6_REG_MINLEN) ? PIM6_REG_MINLEN : PIM_MINLEN; 1739229997Sken 1740229997Sken /* 1741229997Sken * Make sure that the IP6 and PIM headers in contiguous memory, and 1742229997Sken * possibly the PIM REGISTER header 1743229997Sken */ 1744229997Sken#ifndef PULLDOWN_TEST 1745229997Sken IP6_EXTHDR_CHECK(m, off, minlen, IPPROTO_DONE); 1746229997Sken /* adjust pointer */ 1747229997Sken ip6 = mtod(m, struct ip6_hdr *); 1748229997Sken 1749229997Sken /* adjust mbuf to point to the PIM header */ 1750229997Sken pim = (struct pim *)((caddr_t)ip6 + off); 1751229997Sken#else 1752229997Sken IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen); 1753229997Sken if (pim == NULL) { 1754229997Sken pim6stat.pim6s_rcv_tooshort++; 1755229997Sken return (IPPROTO_DONE); 1756229997Sken } 1757229997Sken#endif 1758229997Sken 1759229997Sken#define PIM6_CHECKSUM 1760229997Sken#ifdef PIM6_CHECKSUM 1761229997Sken { 1762229997Sken int cksumlen; 1763229997Sken 1764229997Sken /* 1765229997Sken * Validate checksum. 1766229997Sken * If PIM REGISTER, exclude the data packet 1767229997Sken */ 1768229997Sken if (pim->pim_type == PIM_REGISTER) 1769229997Sken cksumlen = PIM_MINLEN; 1770229997Sken else 1771229997Sken cksumlen = pimlen; 1772229997Sken 1773229997Sken if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) { 1774229997Sken ++pim6stat.pim6s_rcv_badsum; 1775229997Sken#ifdef MRT6DEBUG 1776229997Sken if (V_mrt6debug & DEBUG_PIM) 1777229997Sken log(LOG_DEBUG, 1778229997Sken "pim6_input: invalid checksum\n"); 1779229997Sken#endif 1780229997Sken m_freem(m); 1781229997Sken return (IPPROTO_DONE); 1782229997Sken } 1783229997Sken } 1784229997Sken#endif /* PIM_CHECKSUM */ 1785229997Sken 1786229997Sken /* PIM version check */ 1787229997Sken if (pim->pim_ver != PIM_VERSION) { 1788229997Sken ++pim6stat.pim6s_rcv_badversion; 1789229997Sken#ifdef MRT6DEBUG 1790229997Sken log(LOG_ERR, 1791229997Sken "pim6_input: incorrect version %d, expecting %d\n", 1792229997Sken pim->pim_ver, PIM_VERSION); 1793229997Sken#endif 1794229997Sken m_freem(m); 1795229997Sken return (IPPROTO_DONE); 1796229997Sken } 1797229997Sken 1798229997Sken if (pim->pim_type == PIM_REGISTER) { 1799229997Sken /* 1800229997Sken * since this is a REGISTER, we'll make a copy of the register 1801229997Sken * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the 1802229997Sken * routing daemon. 1803229997Sken */ 1804229997Sken static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 }; 1805229997Sken 1806229997Sken struct mbuf *mcp; 1807229997Sken struct ip6_hdr *eip6; 1808229997Sken u_int32_t *reghdr; 1809229997Sken int rc; 1810229997Sken#ifdef MRT6DEBUG 1811229997Sken char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 1812229997Sken#endif 1813229997Sken 1814229997Sken ++pim6stat.pim6s_rcv_registers; 1815229997Sken 1816229997Sken if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) { 1817229997Sken#ifdef MRT6DEBUG 1818229997Sken if (V_mrt6debug & DEBUG_PIM) 1819229997Sken log(LOG_DEBUG, 1820229997Sken "pim6_input: register mif not set: %d\n", 1821229997Sken reg_mif_num); 1822229997Sken#endif 1823229997Sken m_freem(m); 1824229997Sken return (IPPROTO_DONE); 1825229997Sken } 1826229997Sken 1827229997Sken reghdr = (u_int32_t *)(pim + 1); 1828229997Sken 1829229997Sken if ((ntohl(*reghdr) & PIM_NULL_REGISTER)) 1830229997Sken goto pim6_input_to_daemon; 1831229997Sken 1832229997Sken /* 1833229997Sken * Validate length 1834229997Sken */ 1835229997Sken if (pimlen < PIM6_REG_MINLEN) { 1836229997Sken ++pim6stat.pim6s_rcv_tooshort; 1837229997Sken ++pim6stat.pim6s_rcv_badregisters; 1838229997Sken#ifdef MRT6DEBUG 1839229997Sken log(LOG_ERR, 1840229997Sken "pim6_input: register packet size too " 1841229997Sken "small %d from %s\n", 1842229997Sken pimlen, ip6_sprintf(ip6bufs, &ip6->ip6_src)); 1843229997Sken#endif 1844229997Sken m_freem(m); 1845229997Sken return (IPPROTO_DONE); 1846229997Sken } 1847229997Sken 1848229997Sken eip6 = (struct ip6_hdr *) (reghdr + 1); 1849229997Sken#ifdef MRT6DEBUG 1850229997Sken if (V_mrt6debug & DEBUG_PIM) 1851229997Sken log(LOG_DEBUG, 1852229997Sken "pim6_input[register], eip6: %s -> %s, " 1853229997Sken "eip6 plen %d\n", 1854229997Sken ip6_sprintf(ip6bufs, &eip6->ip6_src), 1855229997Sken ip6_sprintf(ip6bufd, &eip6->ip6_dst), 1856229997Sken ntohs(eip6->ip6_plen)); 1857229997Sken#endif 1858229997Sken 1859229997Sken /* verify the version number of the inner packet */ 1860229997Sken if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { 1861229997Sken ++pim6stat.pim6s_rcv_badregisters; 1862229997Sken#ifdef MRT6DEBUG 1863229997Sken log(LOG_DEBUG, "pim6_input: invalid IP version (%d) " 1864229997Sken "of the inner packet\n", 1865229997Sken (eip6->ip6_vfc & IPV6_VERSION)); 1866229997Sken#endif 1867274870Strasz m_freem(m); 1868274870Strasz return (IPPROTO_NONE); 1869229997Sken } 1870229997Sken 1871229997Sken /* verify the inner packet is destined to a mcast group */ 1872229997Sken if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) { 1873229997Sken ++pim6stat.pim6s_rcv_badregisters; 1874229997Sken#ifdef MRT6DEBUG 1875229997Sken if (V_mrt6debug & DEBUG_PIM) 1876229997Sken log(LOG_DEBUG, 1877229997Sken "pim6_input: inner packet of register " 1878229997Sken "is not multicast %s\n", 1879229997Sken ip6_sprintf(ip6bufd, &eip6->ip6_dst)); 1880229997Sken#endif 1881229997Sken m_freem(m); 1882229997Sken return (IPPROTO_DONE); 1883229997Sken } 1884229997Sken 1885229997Sken /* 1886229997Sken * make a copy of the whole header to pass to the daemon later. 1887229997Sken */ 1888229997Sken mcp = m_copy(m, 0, off + PIM6_REG_MINLEN); 1889229997Sken if (mcp == NULL) { 1890229997Sken#ifdef MRT6DEBUG 1891229997Sken log(LOG_ERR, 1892229997Sken "pim6_input: pim register: " 1893229997Sken "could not copy register head\n"); 1894229997Sken#endif 1895229997Sken m_freem(m); 1896229997Sken return (IPPROTO_DONE); 1897229997Sken } 1898229997Sken 1899229997Sken /* 1900229997Sken * forward the inner ip6 packet; point m_data at the inner ip6. 1901229997Sken */ 1902229997Sken m_adj(m, off + PIM_MINLEN); 1903229997Sken#ifdef MRT6DEBUG 1904229997Sken if (V_mrt6debug & DEBUG_PIM) { 1905229997Sken log(LOG_DEBUG, 1906229997Sken "pim6_input: forwarding decapsulated register: " 1907229997Sken "src %s, dst %s, mif %d\n", 1908229997Sken ip6_sprintf(ip6bufs, &eip6->ip6_src), 1909229997Sken ip6_sprintf(ip6bufd, &eip6->ip6_dst), 1910229997Sken reg_mif_num); 1911229997Sken } 1912229997Sken#endif 1913229997Sken 1914229997Sken rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m, 1915229997Sken dst.sin6_family, 0); 1916229997Sken 1917229997Sken /* prepare the register head to send to the mrouting daemon */ 1918229997Sken m = mcp; 1919229997Sken } 1920229997Sken 1921229997Sken /* 1922229997Sken * Pass the PIM message up to the daemon; if it is a register message 1923229997Sken * pass the 'head' only up to the daemon. This includes the 1924229997Sken * encapsulator ip6 header, pim header, register header and the 1925229997Sken * encapsulated ip6 header. 1926229997Sken */ 1927229997Sken pim6_input_to_daemon: 1928229997Sken rip6_input(&m, offp, proto); 1929229997Sken return (IPPROTO_DONE); 1930229997Sken} 1931229997Sken