FreeBSD kernel IPv6 code
ip6_mroute.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (C) 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $KAME: ip6_mroute.c,v 1.58 2001/12/18 02:36:31 itojun Exp $
32 */
33
34/*-
35 * Copyright (c) 1989 Stephen Deering
36 * Copyright (c) 1992, 1993
37 * The Regents of the University of California. All rights reserved.
38 *
39 * This code is derived from software contributed to Berkeley by
40 * Stephen Deering of Stanford University.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
67 * BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp
68 */
69
70/*
71 * IP multicast forwarding procedures
72 *
73 * Written by David Waitzman, BBN Labs, August 1988.
74 * Modified by Steve Deering, Stanford, February 1989.
75 * Modified by Mark J. Steiglitz, Stanford, May, 1991
76 * Modified by Van Jacobson, LBL, January 1993
77 * Modified by Ajit Thyagarajan, PARC, August 1993
78 * Modified by Bill Fenner, PARC, April 1994
79 *
80 * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support
81 */
82
83#include <sys/cdefs.h>
84__FBSDID("$FreeBSD$");
85
86#include "opt_inet6.h"
87
88#include <sys/param.h>
89#include <sys/callout.h>
90#include <sys/errno.h>
91#include <sys/kernel.h>
92#include <sys/lock.h>
93#include <sys/malloc.h>
94#include <sys/mbuf.h>
95#include <sys/module.h>
96#include <sys/domain.h>
97#include <sys/protosw.h>
98#include <sys/sdt.h>
99#include <sys/signalvar.h>
100#include <sys/socket.h>
101#include <sys/socketvar.h>
102#include <sys/sockio.h>
103#include <sys/sx.h>
104#include <sys/sysctl.h>
105#include <sys/syslog.h>
106#include <sys/systm.h>
107#include <sys/time.h>
108
109#include <net/if.h>
110#include <net/if_var.h>
111#include <net/if_types.h>
112#include <net/vnet.h>
113
114#include <netinet/in.h>
115#include <netinet/in_var.h>
116#include <netinet/icmp6.h>
117#include <netinet/ip_encap.h>
118
119#include <netinet/ip6.h>
120#include <netinet/in_kdtrace.h>
121#include <netinet6/ip6_var.h>
122#include <netinet6/scope6_var.h>
123#include <netinet6/nd6.h>
124#include <netinet6/ip6_mroute.h>
125#include <netinet6/pim6.h>
126#include <netinet6/pim6_var.h>
127
128static MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry");
129
130static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
131static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
132static int register_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
133static int set_pim6(int *);
134static int socket_send(struct socket *, struct mbuf *,
135 struct sockaddr_in6 *);
136
137extern int in6_mcast_loop;
138extern struct domain inet6domain;
139
140static const struct encaptab *pim6_encap_cookie;
141static int pim6_encapcheck(const struct mbuf *, int, int, void *);
142static int pim6_input(struct mbuf *, int, int, void *);
143
144static const struct encap_config ipv6_encap_cfg = {
145 .proto = IPPROTO_PIM,
146 .min_length = sizeof(struct ip6_hdr) + PIM_MINLEN,
147 .exact_match = 8,
148 .check = pim6_encapcheck,
149 .input = pim6_input
150};
151
152VNET_DEFINE_STATIC(int, ip6_mrouter_ver) = 0;
153#define V_ip6_mrouter_ver VNET(ip6_mrouter_ver)
154
155SYSCTL_DECL(_net_inet6);
156SYSCTL_DECL(_net_inet6_ip6);
157static SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim,
158 CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
159 "PIM");
160
161static struct mrt6stat mrt6stat;
162SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW,
164 "Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)");
165
166#define MRT6STAT_INC(name) mrt6stat.name += 1
167#define NO_RTE_FOUND 0x1
168#define RTE_FOUND 0x2
169
170static struct sx mrouter6_mtx;
171#define MROUTER6_LOCKPTR() (&mrouter6_mtx)
172#define MROUTER6_LOCK() sx_xlock(MROUTER6_LOCKPTR())
173#define MROUTER6_UNLOCK() sx_xunlock(MROUTER6_LOCKPTR())
174#define MROUTER6_LOCK_ASSERT() sx_assert(MROUTER6_LOCKPTR(), SA_XLOCKED
175#define MROUTER6_LOCK_INIT() sx_init(MROUTER6_LOCKPTR(), "mrouter6")
176#define MROUTER6_LOCK_DESTROY() sx_destroy(MROUTER6_LOCKPTR())
177
178static struct mf6c *mf6ctable[MF6CTBLSIZ];
179SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mf6ctable, CTLFLAG_RD,
180 &mf6ctable, sizeof(mf6ctable), "S,*mf6ctable[MF6CTBLSIZ]",
181 "IPv6 Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], "
182 "netinet6/ip6_mroute.h)");
183
184static struct mtx mfc6_mtx;
185#define MFC6_LOCKPTR() (&mfc6_mtx)
186#define MFC6_LOCK() mtx_lock(MFC6_LOCKPTR())
187#define MFC6_UNLOCK() mtx_unlock(MFC6_LOCKPTR())
188#define MFC6_LOCK_ASSERT() mtx_assert(MFC6_LOCKPTR(), MA_OWNED)
189#define MFC6_LOCK_INIT() mtx_init(MFC6_LOCKPTR(), \
190 "IPv6 multicast forwarding cache", \
191 NULL, MTX_DEF)
192#define MFC6_LOCK_DESTROY() mtx_destroy(MFC6_LOCKPTR())
193
194static u_char n6expire[MF6CTBLSIZ];
195
196static struct mif6 mif6table[MAXMIFS];
197static int
198sysctl_mif6table(SYSCTL_HANDLER_ARGS)
199{
200 struct mif6_sctl *out;
201 int error;
202
203 out = malloc(sizeof(struct mif6_sctl) * MAXMIFS, M_TEMP,
204 M_WAITOK | M_ZERO);
205 for (int i = 0; i < MAXMIFS; i++) {
206 out[i].m6_flags = mif6table[i].m6_flags;
209 if (mif6table[i].m6_ifp != NULL)
210 out[i].m6_ifp = mif6table[i].m6_ifp->if_index;
211 else
212 out[i].m6_ifp = 0;
213 out[i].m6_pkt_in = mif6table[i].m6_pkt_in;
214 out[i].m6_pkt_out = mif6table[i].m6_pkt_out;
217 }
218 error = SYSCTL_OUT(req, out, sizeof(struct mif6_sctl) * MAXMIFS);
219 free(out, M_TEMP);
220 return (error);
221}
222SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, mif6table,
223 CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
224 NULL, 0, sysctl_mif6table, "S,mif6_sctl[MAXMIFS]",
225 "IPv6 Multicast Interfaces (struct mif6_sctl[MAXMIFS], "
226 "netinet6/ip6_mroute.h)");
227
228static struct mtx mif6_mtx;
229#define MIF6_LOCKPTR() (&mif6_mtx)
230#define MIF6_LOCK() mtx_lock(MIF6_LOCKPTR())
231#define MIF6_UNLOCK() mtx_unlock(MIF6_LOCKPTR())
232#define MIF6_LOCK_ASSERT() mtx_assert(MIF6_LOCKPTR(), MA_OWNED)
233#define MIF6_LOCK_INIT() \
234 mtx_init(MIF6_LOCKPTR(), "IPv6 multicast interfaces", NULL, MTX_DEF)
235#define MIF6_LOCK_DESTROY() mtx_destroy(MIF6_LOCKPTR())
236
237#ifdef MRT6DEBUG
238VNET_DEFINE_STATIC(u_int, mrt6debug) = 0; /* debug level */
239#define V_mrt6debug VNET(mrt6debug)
240#define DEBUG_MFC 0x02
241#define DEBUG_FORWARD 0x04
242#define DEBUG_EXPIRE 0x08
243#define DEBUG_XMIT 0x10
244#define DEBUG_REG 0x20
245#define DEBUG_PIM 0x40
246#define DEBUG_ERR 0x80
247#define DEBUG_ANY 0x7f
248#define MRT6_DLOG(m, fmt, ...) \
249 if (V_mrt6debug & (m)) \
250 log(((m) & DEBUG_ERR) ? LOG_ERR: LOG_DEBUG, \
251 "%s: " fmt "\n", __func__, ##__VA_ARGS__)
252#else
253#define MRT6_DLOG(m, fmt, ...)
254#endif
255
256static void expire_upcalls(void *);
257#define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */
258#define UPCALL_EXPIRE 6 /* number of timeouts */
259
260/*
261 * XXX TODO: maintain a count to if_allmulti() calls in struct ifnet.
262 */
263
264/*
265 * 'Interfaces' associated with decapsulator (so we can tell
266 * packets that went through it from ones that get reflected
267 * by a broken gateway). Different from IPv4 register_if,
268 * these interfaces are linked into the system ifnet list,
269 * because per-interface IPv6 statistics are maintained in
270 * ifp->if_afdata. But it does not have any routes point
271 * to them. I.e., packets can't be sent this way. They
272 * only exist as a placeholder for multicast source
273 * verification.
274 */
275static struct ifnet *multicast_register_if6;
276
277#define ENCAP_HOPS 64
278
279/*
280 * Private variables.
281 */
282static mifi_t nummifs = 0;
284
285static struct pim6stat pim6stat;
286SYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RW,
288 "PIM Statistics (struct pim6stat, netinet6/pim6_var.h)");
289
290#define PIM6STAT_INC(name) pim6stat.name += 1
292#define V_pim6 VNET(pim6)
293
294/*
295 * Hash function for a source, group entry
296 */
297#define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
298 (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
299 (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \
300 (g).s6_addr32[2] ^ (g).s6_addr32[3])
301
302/*
303 * Find a route for a given origin IPv6 address and Multicast group address.
304 */
305#define MF6CFIND(o, g, rt) do { \
306 struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
307 rt = NULL; \
308 while (_rt) { \
309 if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \
310 IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \
311 (_rt->mf6c_stall == NULL)) { \
312 rt = _rt; \
313 break; \
314 } \
315 _rt = _rt->mf6c_next; \
316 } \
317 if (rt == NULL) { \
318 MRT6STAT_INC(mrt6s_mfc_misses); \
319 } \
320} while (/*CONSTCOND*/ 0)
321
322/*
323 * Macros to compute elapsed time efficiently
324 * Borrowed from Van Jacobson's scheduling code
325 * XXX: replace with timersub() ?
326 */
327#define TV_DELTA(a, b, delta) do { \
328 int xxs; \
329 \
330 delta = (a).tv_usec - (b).tv_usec; \
331 if ((xxs = (a).tv_sec - (b).tv_sec)) { \
332 switch (xxs) { \
333 case 2: \
334 delta += 1000000; \
335 /* FALLTHROUGH */ \
336 case 1: \
337 delta += 1000000; \
338 break; \
339 default: \
340 delta += (1000000 * xxs); \
341 } \
342 } \
343} while (/*CONSTCOND*/ 0)
344
345/* XXX: replace with timercmp(a, b, <) ? */
346#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
347 (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
348
349#ifdef UPCALL_TIMING
350#define UPCALL_MAX 50
351static u_long upcall_data[UPCALL_MAX + 1];
352static void collate();
353#endif /* UPCALL_TIMING */
354
355static int ip6_mrouter_init(struct socket *, int, int);
356static int add_m6fc(struct mf6cctl *);
357static int add_m6if(struct mif6ctl *);
358static int del_m6fc(struct mf6cctl *);
359static int del_m6if(mifi_t *);
360static int del_m6if_locked(mifi_t *);
361static int get_mif6_cnt(struct sioc_mif_req6 *);
362static int get_sg_cnt(struct sioc_sg_req6 *);
363
364static struct callout expire_upcalls_ch;
365
366int X_ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
367int X_ip6_mrouter_done(void);
368int X_ip6_mrouter_set(struct socket *, struct sockopt *);
369int X_ip6_mrouter_get(struct socket *, struct sockopt *);
370int X_mrt6_ioctl(u_long, caddr_t);
371
372/*
373 * Handle MRT setsockopt commands to modify the multicast routing tables.
374 */
375int
376X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
377{
378 int error = 0;
379 int optval;
380 struct mif6ctl mifc;
381 struct mf6cctl mfcc;
382 mifi_t mifi;
383
384 if (so != V_ip6_mrouter && sopt->sopt_name != MRT6_INIT)
385 return (EPERM);
386
387 switch (sopt->sopt_name) {
388 case MRT6_INIT:
389#ifdef MRT6_OINIT
390 case MRT6_OINIT:
391#endif
392 error = sooptcopyin(sopt, &optval, sizeof(optval),
393 sizeof(optval));
394 if (error)
395 break;
396 error = ip6_mrouter_init(so, optval, sopt->sopt_name);
397 break;
398 case MRT6_DONE:
399 error = X_ip6_mrouter_done();
400 break;
401 case MRT6_ADD_MIF:
402 error = sooptcopyin(sopt, &mifc, sizeof(mifc), sizeof(mifc));
403 if (error)
404 break;
405 error = add_m6if(&mifc);
406 break;
407 case MRT6_ADD_MFC:
408 error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
409 if (error)
410 break;
411 error = add_m6fc(&mfcc);
412 break;
413 case MRT6_DEL_MFC:
414 error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
415 if (error)
416 break;
417 error = del_m6fc(&mfcc);
418 break;
419 case MRT6_DEL_MIF:
420 error = sooptcopyin(sopt, &mifi, sizeof(mifi), sizeof(mifi));
421 if (error)
422 break;
423 error = del_m6if(&mifi);
424 break;
425 case MRT6_PIM:
426 error = sooptcopyin(sopt, &optval, sizeof(optval),
427 sizeof(optval));
428 if (error)
429 break;
430 error = set_pim6(&optval);
431 break;
432 default:
433 error = EOPNOTSUPP;
434 break;
435 }
436
437 return (error);
438}
439
440/*
441 * Handle MRT getsockopt commands
442 */
443int
444X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
445{
446 int error = 0;
447
448 if (so != V_ip6_mrouter)
449 return (EACCES);
450
451 switch (sopt->sopt_name) {
452 case MRT6_PIM:
453 error = sooptcopyout(sopt, &V_pim6, sizeof(V_pim6));
454 break;
455 }
456 return (error);
457}
458
459/*
460 * Handle ioctl commands to obtain information from the cache
461 */
462int
463X_mrt6_ioctl(u_long cmd, caddr_t data)
464{
465 int ret;
466
467 ret = EINVAL;
468
469 switch (cmd) {
470 case SIOCGETSGCNT_IN6:
471 ret = get_sg_cnt((struct sioc_sg_req6 *)data);
472 break;
473
475 ret = get_mif6_cnt((struct sioc_mif_req6 *)data);
476 break;
477
478 default:
479 break;
480 }
481
482 return (ret);
483}
484
485/*
486 * returns the packet, byte, rpf-failure count for the source group provided
487 */
488static int
490{
491 struct mf6c *rt;
492 int ret;
493
494 ret = 0;
495
496 MFC6_LOCK();
497
498 MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
499 if (rt == NULL) {
500 ret = ESRCH;
501 } else {
502 req->pktcnt = rt->mf6c_pkt_cnt;
503 req->bytecnt = rt->mf6c_byte_cnt;
504 req->wrong_if = rt->mf6c_wrong_if;
505 }
506
507 MFC6_UNLOCK();
508
509 return (ret);
510}
511
512/*
513 * returns the input and output packet and byte counts on the mif provided
514 */
515static int
517{
518 mifi_t mifi;
519 int ret;
520
521 ret = 0;
522 mifi = req->mifi;
523
524 MIF6_LOCK();
525
526 if (mifi >= nummifs) {
527 ret = EINVAL;
528 } else {
529 req->icount = mif6table[mifi].m6_pkt_in;
530 req->ocount = mif6table[mifi].m6_pkt_out;
531 req->ibytes = mif6table[mifi].m6_bytes_in;
532 req->obytes = mif6table[mifi].m6_bytes_out;
533 }
534
535 MIF6_UNLOCK();
536
537 return (ret);
538}
539
540static int
541set_pim6(int *i)
542{
543 if ((*i != 1) && (*i != 0))
544 return (EINVAL);
545
546 V_pim6 = *i;
547
548 return (0);
549}
550
551/*
552 * Enable multicast routing
553 */
554static int
555ip6_mrouter_init(struct socket *so, int v, int cmd)
556{
557
558 MRT6_DLOG(DEBUG_ANY, "so_type = %d, pr_protocol = %d",
559 so->so_type, so->so_proto->pr_protocol);
560
561 if (so->so_type != SOCK_RAW ||
562 so->so_proto->pr_protocol != IPPROTO_ICMPV6)
563 return (EOPNOTSUPP);
564
565 if (v != 1)
566 return (ENOPROTOOPT);
567
569
570 if (V_ip6_mrouter != NULL) {
572 return (EADDRINUSE);
573 }
574
575 V_ip6_mrouter = so;
576 V_ip6_mrouter_ver = cmd;
577
578 bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
579 bzero((caddr_t)n6expire, sizeof(n6expire));
580
581 V_pim6 = 0;/* used for stubbing out/in pim stuff */
582
583 callout_init_mtx(&expire_upcalls_ch, MFC6_LOCKPTR(), 0);
584 callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
585 expire_upcalls, NULL);
586
588
589 MRT6_DLOG(DEBUG_ANY, "finished");
590
591 return (0);
592}
593
594/*
595 * Disable IPv6 multicast forwarding.
596 */
597int
599{
600 mifi_t mifi;
601 u_long i;
602 struct mf6c *rt;
603 struct rtdetq *rte;
604
606
607 if (V_ip6_mrouter == NULL) {
609 return (EINVAL);
610 }
611
612 /*
613 * For each phyint in use, disable promiscuous reception of all IPv6
614 * multicasts.
615 */
616 for (mifi = 0; mifi < nummifs; mifi++) {
617 if (mif6table[mifi].m6_ifp &&
618 !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
619 if_allmulti(mif6table[mifi].m6_ifp, 0);
620 }
621 }
622 bzero((caddr_t)mif6table, sizeof(mif6table));
623 nummifs = 0;
624
625 V_pim6 = 0; /* used to stub out/in pim specific code */
626
627 /*
628 * Free all multicast forwarding cache entries.
629 */
630 MFC6_LOCK();
631 for (i = 0; i < MF6CTBLSIZ; i++) {
632 rt = mf6ctable[i];
633 while (rt) {
634 struct mf6c *frt;
635
636 for (rte = rt->mf6c_stall; rte != NULL; ) {
637 struct rtdetq *n = rte->next;
638
639 m_freem(rte->m);
640 free(rte, M_MRTABLE6);
641 rte = n;
642 }
643 frt = rt;
644 rt = rt->mf6c_next;
645 free(frt, M_MRTABLE6);
646 }
647 }
648 bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
649 MFC6_UNLOCK();
650
651 callout_drain(&expire_upcalls_ch);
652
653 /*
654 * Reset register interface
655 */
656 if (reg_mif_num != (mifi_t)-1 && multicast_register_if6 != NULL) {
657 if_detach(multicast_register_if6);
658 if_free(multicast_register_if6);
659 reg_mif_num = (mifi_t)-1;
661 }
662
663 V_ip6_mrouter = NULL;
665
667 MRT6_DLOG(DEBUG_ANY, "finished");
668
669 return (0);
670}
671
672static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
673
674/*
675 * Add a mif to the mif table
676 */
677static int
678add_m6if(struct mif6ctl *mifcp)
679{
680 struct epoch_tracker et;
681 struct mif6 *mifp;
682 struct ifnet *ifp;
683 int error;
684
685 MIF6_LOCK();
686
687 if (mifcp->mif6c_mifi >= MAXMIFS) {
688 MIF6_UNLOCK();
689 return (EINVAL);
690 }
691 mifp = mif6table + mifcp->mif6c_mifi;
692 if (mifp->m6_ifp != NULL) {
693 MIF6_UNLOCK();
694 return (EADDRINUSE); /* XXX: is it appropriate? */
695 }
696
697 NET_EPOCH_ENTER(et);
698 if ((ifp = ifnet_byindex(mifcp->mif6c_pifi)) == NULL) {
699 NET_EPOCH_EXIT(et);
700 MIF6_UNLOCK();
701 return (ENXIO);
702 }
703 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifp */
704
705 if (mifcp->mif6c_flags & MIFF_REGISTER) {
706 if (reg_mif_num == (mifi_t)-1) {
707 ifp = if_alloc(IFT_OTHER);
708
709 if_initname(ifp, "register_mif", 0);
710 ifp->if_flags |= IFF_LOOPBACK;
711 if_attach(ifp);
713 reg_mif_num = mifcp->mif6c_mifi;
714 /*
715 * it is impossible to guess the ifindex of the
716 * register interface. So mif6c_pifi is automatically
717 * calculated.
718 */
719 mifcp->mif6c_pifi = ifp->if_index;
720 } else {
722 }
723 } else {
724 /* Make sure the interface supports multicast */
725 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
726 MIF6_UNLOCK();
727 return (EOPNOTSUPP);
728 }
729
730 error = if_allmulti(ifp, 1);
731 if (error) {
732 MIF6_UNLOCK();
733 return (error);
734 }
735 }
736
737 mifp->m6_flags = mifcp->mif6c_flags;
738 mifp->m6_ifp = ifp;
739
740 /* initialize per mif pkt counters */
741 mifp->m6_pkt_in = 0;
742 mifp->m6_pkt_out = 0;
743 mifp->m6_bytes_in = 0;
744 mifp->m6_bytes_out = 0;
745
746 /* Adjust nummifs up if the mifi is higher than nummifs */
747 if (nummifs <= mifcp->mif6c_mifi)
748 nummifs = mifcp->mif6c_mifi + 1;
749
750 MIF6_UNLOCK();
751 MRT6_DLOG(DEBUG_ANY, "mif #%d, phyint %s", mifcp->mif6c_mifi,
752 if_name(ifp));
753
754 return (0);
755}
756
757/*
758 * Delete a mif from the mif table
759 */
760static int
762{
763 struct mif6 *mifp = mif6table + *mifip;
764 mifi_t mifi;
765 struct ifnet *ifp;
766
768
769 if (*mifip >= nummifs)
770 return (EINVAL);
771 if (mifp->m6_ifp == NULL)
772 return (EINVAL);
773
774 if (!(mifp->m6_flags & MIFF_REGISTER)) {
775 /* XXX: TODO: Maintain an ALLMULTI refcount in struct ifnet. */
776 ifp = mifp->m6_ifp;
777 if_allmulti(ifp, 0);
778 } else {
779 if (reg_mif_num != (mifi_t)-1 &&
780 multicast_register_if6 != NULL) {
781 if_detach(multicast_register_if6);
782 if_free(multicast_register_if6);
783 reg_mif_num = (mifi_t)-1;
785 }
786 }
787
788 bzero((caddr_t)mifp, sizeof(*mifp));
789
790 /* Adjust nummifs down */
791 for (mifi = nummifs; mifi > 0; mifi--)
792 if (mif6table[mifi - 1].m6_ifp)
793 break;
794 nummifs = mifi;
795 MRT6_DLOG(DEBUG_ANY, "mif %d, nummifs %d", *mifip, nummifs);
796
797 return (0);
798}
799
800static int
802{
803 int cc;
804
805 MIF6_LOCK();
806 cc = del_m6if_locked(mifip);
807 MIF6_UNLOCK();
808
809 return (cc);
810}
811
812/*
813 * Add an mfc entry
814 */
815static int
816add_m6fc(struct mf6cctl *mfccp)
817{
818 struct mf6c *rt;
819 u_long hash;
820 struct rtdetq *rte;
821 u_short nstl;
822 char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
823
824 MFC6_LOCK();
825
827 mfccp->mf6cc_mcastgrp.sin6_addr, rt);
828
829 /* If an entry already exists, just update the fields */
830 if (rt) {
831 MRT6_DLOG(DEBUG_MFC, "no upcall o %s g %s p %x",
832 ip6_sprintf(ip6bufo, &mfccp->mf6cc_origin.sin6_addr),
833 ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr),
834 mfccp->mf6cc_parent);
835
836 rt->mf6c_parent = mfccp->mf6cc_parent;
837 rt->mf6c_ifset = mfccp->mf6cc_ifset;
838
839 MFC6_UNLOCK();
840 return (0);
841 }
842
843 /*
844 * Find the entry for which the upcall was made and update
845 */
846 hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
848 for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
850 &mfccp->mf6cc_origin.sin6_addr) &&
852 &mfccp->mf6cc_mcastgrp.sin6_addr) &&
853 (rt->mf6c_stall != NULL)) {
854 if (nstl++)
855 log(LOG_ERR,
856 "add_m6fc: %s o %s g %s p %x dbx %p\n",
857 "multiple kernel entries",
858 ip6_sprintf(ip6bufo,
859 &mfccp->mf6cc_origin.sin6_addr),
860 ip6_sprintf(ip6bufg,
861 &mfccp->mf6cc_mcastgrp.sin6_addr),
862 mfccp->mf6cc_parent, rt->mf6c_stall);
863
864 MRT6_DLOG(DEBUG_MFC, "o %s g %s p %x dbg %p",
865 ip6_sprintf(ip6bufo,
866 &mfccp->mf6cc_origin.sin6_addr),
867 ip6_sprintf(ip6bufg,
868 &mfccp->mf6cc_mcastgrp.sin6_addr),
869 mfccp->mf6cc_parent, rt->mf6c_stall);
870
871 rt->mf6c_origin = mfccp->mf6cc_origin;
872 rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
873 rt->mf6c_parent = mfccp->mf6cc_parent;
874 rt->mf6c_ifset = mfccp->mf6cc_ifset;
875 /* initialize pkt counters per src-grp */
876 rt->mf6c_pkt_cnt = 0;
877 rt->mf6c_byte_cnt = 0;
878 rt->mf6c_wrong_if = 0;
879
880 rt->mf6c_expire = 0; /* Don't clean this guy up */
881 n6expire[hash]--;
882
883 /* free packets Qed at the end of this entry */
884 for (rte = rt->mf6c_stall; rte != NULL; ) {
885 struct rtdetq *n = rte->next;
886 ip6_mdq(rte->m, rte->ifp, rt);
887 m_freem(rte->m);
888#ifdef UPCALL_TIMING
889 collate(&(rte->t));
890#endif /* UPCALL_TIMING */
891 free(rte, M_MRTABLE6);
892 rte = n;
893 }
894 rt->mf6c_stall = NULL;
895 }
896 }
897
898 /*
899 * It is possible that an entry is being inserted without an upcall
900 */
901 if (nstl == 0) {
902 MRT6_DLOG(DEBUG_MFC, "no upcall h %lu o %s g %s p %x", hash,
903 ip6_sprintf(ip6bufo, &mfccp->mf6cc_origin.sin6_addr),
904 ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr),
905 mfccp->mf6cc_parent);
906
907 for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
909 &mfccp->mf6cc_origin.sin6_addr)&&
911 &mfccp->mf6cc_mcastgrp.sin6_addr)) {
912 rt->mf6c_origin = mfccp->mf6cc_origin;
913 rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
914 rt->mf6c_parent = mfccp->mf6cc_parent;
915 rt->mf6c_ifset = mfccp->mf6cc_ifset;
916 /* initialize pkt counters per src-grp */
917 rt->mf6c_pkt_cnt = 0;
918 rt->mf6c_byte_cnt = 0;
919 rt->mf6c_wrong_if = 0;
920
921 if (rt->mf6c_expire)
922 n6expire[hash]--;
923 rt->mf6c_expire = 0;
924 }
925 }
926 if (rt == NULL) {
927 /* no upcall, so make a new entry */
928 rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6,
929 M_NOWAIT);
930 if (rt == NULL) {
931 MFC6_UNLOCK();
932 return (ENOBUFS);
933 }
934
935 /* insert new entry at head of hash chain */
936 rt->mf6c_origin = mfccp->mf6cc_origin;
937 rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
938 rt->mf6c_parent = mfccp->mf6cc_parent;
939 rt->mf6c_ifset = mfccp->mf6cc_ifset;
940 /* initialize pkt counters per src-grp */
941 rt->mf6c_pkt_cnt = 0;
942 rt->mf6c_byte_cnt = 0;
943 rt->mf6c_wrong_if = 0;
944 rt->mf6c_expire = 0;
945 rt->mf6c_stall = NULL;
946
947 /* link into table */
948 rt->mf6c_next = mf6ctable[hash];
949 mf6ctable[hash] = rt;
950 }
951 }
952
953 MFC6_UNLOCK();
954 return (0);
955}
956
957#ifdef UPCALL_TIMING
958/*
959 * collect delay statistics on the upcalls
960 */
961static void
962collate(struct timeval *t)
963{
964 u_long d;
965 struct timeval tp;
966 u_long delta;
967
968 GET_TIME(tp);
969
970 if (TV_LT(*t, tp))
971 {
972 TV_DELTA(tp, *t, delta);
973
974 d = delta >> 10;
975 if (d > UPCALL_MAX)
976 d = UPCALL_MAX;
977
978 ++upcall_data[d];
979 }
980}
981#endif /* UPCALL_TIMING */
982
983/*
984 * Delete an mfc entry
985 */
986static int
987del_m6fc(struct mf6cctl *mfccp)
988{
989#ifdef MRT6DEBUG
990 char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
991#endif
992 struct sockaddr_in6 origin;
993 struct sockaddr_in6 mcastgrp;
994 struct mf6c *rt;
995 struct mf6c **nptr;
996 u_long hash;
997
998 origin = mfccp->mf6cc_origin;
999 mcastgrp = mfccp->mf6cc_mcastgrp;
1000 hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);
1001
1002 MRT6_DLOG(DEBUG_MFC, "orig %s mcastgrp %s",
1003 ip6_sprintf(ip6bufo, &origin.sin6_addr),
1004 ip6_sprintf(ip6bufg, &mcastgrp.sin6_addr));
1005
1006 MFC6_LOCK();
1007
1008 nptr = &mf6ctable[hash];
1009 while ((rt = *nptr) != NULL) {
1010 if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,
1011 &rt->mf6c_origin.sin6_addr) &&
1012 IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr,
1013 &rt->mf6c_mcastgrp.sin6_addr) &&
1014 rt->mf6c_stall == NULL)
1015 break;
1016
1017 nptr = &rt->mf6c_next;
1018 }
1019 if (rt == NULL) {
1020 MFC6_UNLOCK();
1021 return (EADDRNOTAVAIL);
1022 }
1023
1024 *nptr = rt->mf6c_next;
1025 free(rt, M_MRTABLE6);
1026
1027 MFC6_UNLOCK();
1028
1029 return (0);
1030}
1031
1032static int
1033socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src)
1034{
1035
1036 if (s) {
1037 if (sbappendaddr(&s->so_rcv,
1038 (struct sockaddr *)src,
1039 mm, (struct mbuf *)0) != 0) {
1040 sorwakeup(s);
1041 return (0);
1042 } else
1043 soroverflow(s);
1044 }
1045 m_freem(mm);
1046 return (-1);
1047}
1048
1049/*
1050 * IPv6 multicast forwarding function. This function assumes that the packet
1051 * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
1052 * pointed to by "ifp", and the packet is to be relayed to other networks
1053 * that have members of the packet's destination IPv6 multicast group.
1054 *
1055 * The packet is returned unscathed to the caller, unless it is
1056 * erroneous, in which case a non-zero return value tells the caller to
1057 * discard it.
1058 *
1059 * NOTE: this implementation assumes that m->m_pkthdr.rcvif is NULL iff
1060 * this function is called in the originating context (i.e., not when
1061 * forwarding a packet from other node). ip6_output(), which is currently the
1062 * only function that calls this function is called in the originating context,
1063 * explicitly ensures this condition. It is caller's responsibility to ensure
1064 * that if this function is called from somewhere else in the originating
1065 * context in the future.
1066 */
1067int
1068X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
1069{
1070 struct rtdetq *rte;
1071 struct mbuf *mb0;
1072 struct mf6c *rt;
1073 struct mif6 *mifp;
1074 struct mbuf *mm;
1075 u_long hash;
1076 mifi_t mifi;
1077 char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
1078#ifdef UPCALL_TIMING
1079 struct timeval tp;
1080
1081 GET_TIME(tp);
1082#endif /* UPCALL_TIMING */
1083
1084 MRT6_DLOG(DEBUG_FORWARD, "src %s, dst %s, ifindex %d",
1085 ip6_sprintf(ip6bufs, &ip6->ip6_src),
1086 ip6_sprintf(ip6bufd, &ip6->ip6_dst), ifp->if_index);
1087
1088 /*
1089 * Don't forward a packet with Hop limit of zero or one,
1090 * or a packet destined to a local-only group.
1091 */
1092 if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
1093 IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
1094 return (0);
1095 ip6->ip6_hlim--;
1096
1097 /*
1098 * Source address check: do not forward packets with unspecified
1099 * source. It was discussed in July 2000, on ipngwg mailing list.
1100 * This is rather more serious than unicast cases, because some
1101 * MLD packets can be sent with the unspecified source address
1102 * (although such packets must normally set 1 to the hop limit field).
1103 */
1104 if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1105 IP6STAT_INC(ip6s_cantforward);
1106 if (V_ip6_log_time + V_ip6_log_interval < time_uptime) {
1107 V_ip6_log_time = time_uptime;
1108 log(LOG_DEBUG,
1109 "cannot forward "
1110 "from %s to %s nxt %d received on %s\n",
1111 ip6_sprintf(ip6bufs, &ip6->ip6_src),
1112 ip6_sprintf(ip6bufd, &ip6->ip6_dst),
1113 ip6->ip6_nxt,
1114 if_name(m->m_pkthdr.rcvif));
1115 }
1116 return (0);
1117 }
1118
1119 MFC6_LOCK();
1120
1121 /*
1122 * Determine forwarding mifs from the forwarding cache table
1123 */
1124 MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
1125 MRT6STAT_INC(mrt6s_mfc_lookups);
1126
1127 /* Entry exists, so forward if necessary */
1128 if (rt) {
1129 MFC6_UNLOCK();
1130 return (ip6_mdq(m, ifp, rt));
1131 }
1132
1133 /*
1134 * If we don't have a route for packet's origin,
1135 * Make a copy of the packet & send message to routing daemon.
1136 */
1137 MRT6STAT_INC(mrt6s_no_route);
1138 MRT6_DLOG(DEBUG_FORWARD | DEBUG_MFC, "no rte s %s g %s",
1139 ip6_sprintf(ip6bufs, &ip6->ip6_src),
1140 ip6_sprintf(ip6bufd, &ip6->ip6_dst));
1141
1142 /*
1143 * Allocate mbufs early so that we don't do extra work if we
1144 * are just going to fail anyway.
1145 */
1146 rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE6, M_NOWAIT);
1147 if (rte == NULL) {
1148 MFC6_UNLOCK();
1149 return (ENOBUFS);
1150 }
1151 mb0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
1152 /*
1153 * Pullup packet header if needed before storing it,
1154 * as other references may modify it in the meantime.
1155 */
1156 if (mb0 && (!M_WRITABLE(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))
1157 mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
1158 if (mb0 == NULL) {
1159 free(rte, M_MRTABLE6);
1160 MFC6_UNLOCK();
1161 return (ENOBUFS);
1162 }
1163
1164 /* is there an upcall waiting for this packet? */
1165 hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
1166 for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
1167 if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
1168 &rt->mf6c_origin.sin6_addr) &&
1169 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
1170 &rt->mf6c_mcastgrp.sin6_addr) && (rt->mf6c_stall != NULL))
1171 break;
1172 }
1173
1174 if (rt == NULL) {
1175 struct mrt6msg *im;
1176#ifdef MRT6_OINIT
1177 struct omrt6msg *oim;
1178#endif
1179 /* no upcall, so make a new entry */
1180 rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6, M_NOWAIT);
1181 if (rt == NULL) {
1182 free(rte, M_MRTABLE6);
1183 m_freem(mb0);
1184 MFC6_UNLOCK();
1185 return (ENOBUFS);
1186 }
1187 /*
1188 * Make a copy of the header to send to the user
1189 * level process
1190 */
1191 mm = m_copym(mb0, 0, sizeof(struct ip6_hdr), M_NOWAIT);
1192 if (mm == NULL) {
1193 free(rte, M_MRTABLE6);
1194 m_freem(mb0);
1195 free(rt, M_MRTABLE6);
1196 MFC6_UNLOCK();
1197 return (ENOBUFS);
1198 }
1199
1200 /*
1201 * Send message to routing daemon
1202 */
1203 sin6.sin6_addr = ip6->ip6_src;
1204 im = NULL;
1205#ifdef MRT6_OINIT
1206 oim = NULL;
1207#endif
1208 switch (V_ip6_mrouter_ver) {
1209#ifdef MRT6_OINIT
1210 case MRT6_OINIT:
1211 oim = mtod(mm, struct omrt6msg *);
1213 oim->im6_mbz = 0;
1214 break;
1215#endif
1216 case MRT6_INIT:
1217 im = mtod(mm, struct mrt6msg *);
1219 im->im6_mbz = 0;
1220 break;
1221 default:
1222 free(rte, M_MRTABLE6);
1223 m_freem(mb0);
1224 free(rt, M_MRTABLE6);
1225 MFC6_UNLOCK();
1226 return (EINVAL);
1227 }
1228
1229 MRT6_DLOG(DEBUG_FORWARD, "getting the iif info in the kernel");
1230 for (mifp = mif6table, mifi = 0;
1231 mifi < nummifs && mifp->m6_ifp != ifp; mifp++, mifi++)
1232 ;
1233
1234 switch (V_ip6_mrouter_ver) {
1235#ifdef MRT6_OINIT
1236 case MRT6_OINIT:
1237 oim->im6_mif = mifi;
1238 break;
1239#endif
1240 case MRT6_INIT:
1241 im->im6_mif = mifi;
1242 break;
1243 }
1244
1245 if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
1246 log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
1247 "socket queue full\n");
1248 MRT6STAT_INC(mrt6s_upq_sockfull);
1249 free(rte, M_MRTABLE6);
1250 m_freem(mb0);
1251 free(rt, M_MRTABLE6);
1252 MFC6_UNLOCK();
1253 return (ENOBUFS);
1254 }
1255
1256 MRT6STAT_INC(mrt6s_upcalls);
1257
1258 /* insert new entry at head of hash chain */
1259 bzero(rt, sizeof(*rt));
1260 rt->mf6c_origin.sin6_family = AF_INET6;
1261 rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6);
1262 rt->mf6c_origin.sin6_addr = ip6->ip6_src;
1263 rt->mf6c_mcastgrp.sin6_family = AF_INET6;
1264 rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
1265 rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;
1267 n6expire[hash]++;
1269
1270 /* link into table */
1271 rt->mf6c_next = mf6ctable[hash];
1272 mf6ctable[hash] = rt;
1273 /* Add this entry to the end of the queue */
1274 rt->mf6c_stall = rte;
1275 } else {
1276 /* determine if q has overflowed */
1277 struct rtdetq **p;
1278 int npkts = 0;
1279
1280 for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
1281 if (++npkts > MAX_UPQ6) {
1282 MRT6STAT_INC(mrt6s_upq_ovflw);
1283 free(rte, M_MRTABLE6);
1284 m_freem(mb0);
1285 MFC6_UNLOCK();
1286 return (0);
1287 }
1288
1289 /* Add this entry to the end of the queue */
1290 *p = rte;
1291 }
1292
1293 rte->next = NULL;
1294 rte->m = mb0;
1295 rte->ifp = ifp;
1296#ifdef UPCALL_TIMING
1297 rte->t = tp;
1298#endif /* UPCALL_TIMING */
1299
1300 MFC6_UNLOCK();
1301
1302 return (0);
1303}
1304
1305/*
1306 * Clean up cache entries if upcalls are not serviced
1307 * Call from the Slow Timeout mechanism, every half second.
1308 */
1309static void
1310expire_upcalls(void *unused)
1311{
1312#ifdef MRT6DEBUG
1313 char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
1314#endif
1315 struct rtdetq *rte;
1316 struct mf6c *mfc, **nptr;
1317 u_long i;
1318
1320
1321 for (i = 0; i < MF6CTBLSIZ; i++) {
1322 if (n6expire[i] == 0)
1323 continue;
1324 nptr = &mf6ctable[i];
1325 while ((mfc = *nptr) != NULL) {
1326 rte = mfc->mf6c_stall;
1327 /*
1328 * Skip real cache entries
1329 * Make sure it wasn't marked to not expire (shouldn't happen)
1330 * If it expires now
1331 */
1332 if (rte != NULL &&
1333 mfc->mf6c_expire != 0 &&
1334 --mfc->mf6c_expire == 0) {
1335 MRT6_DLOG(DEBUG_EXPIRE, "expiring (%s %s)",
1336 ip6_sprintf(ip6bufo, &mfc->mf6c_origin.sin6_addr),
1337 ip6_sprintf(ip6bufg, &mfc->mf6c_mcastgrp.sin6_addr));
1338 /*
1339 * drop all the packets
1340 * free the mbuf with the pkt, if, timing info
1341 */
1342 do {
1343 struct rtdetq *n = rte->next;
1344 m_freem(rte->m);
1345 free(rte, M_MRTABLE6);
1346 rte = n;
1347 } while (rte != NULL);
1348 MRT6STAT_INC(mrt6s_cache_cleanups);
1349 n6expire[i]--;
1350
1351 *nptr = mfc->mf6c_next;
1352 free(mfc, M_MRTABLE6);
1353 } else {
1354 nptr = &mfc->mf6c_next;
1355 }
1356 }
1357 }
1358 callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
1359 expire_upcalls, NULL);
1360}
1361
1362/*
1363 * Packet forwarding routine once entry in the cache is made
1364 */
1365static int
1366ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct mf6c *rt)
1367{
1368 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1369 mifi_t mifi, iif;
1370 struct mif6 *mifp;
1371 int plen = m->m_pkthdr.len;
1372 struct in6_addr src0, dst0; /* copies for local work */
1373 u_int32_t iszone, idzone, oszone, odzone;
1374 int error = 0;
1375
1376 /*
1377 * Don't forward if it didn't arrive from the parent mif
1378 * for its origin.
1379 */
1380 mifi = rt->mf6c_parent;
1381 if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) {
1382 /* came in the wrong interface */
1383 MRT6_DLOG(DEBUG_FORWARD,
1384 "wrong if: ifid %d mifi %d mififid %x", ifp->if_index,
1385 mifi, mif6table[mifi].m6_ifp->if_index);
1386 MRT6STAT_INC(mrt6s_wrong_if);
1387 rt->mf6c_wrong_if++;
1388 /*
1389 * If we are doing PIM processing, and we are forwarding
1390 * packets on this interface, send a message to the
1391 * routing daemon.
1392 */
1393 /* have to make sure this is a valid mif */
1394 if (mifi < nummifs && mif6table[mifi].m6_ifp)
1395 if (V_pim6 && (m->m_flags & M_LOOP) == 0) {
1396 /*
1397 * Check the M_LOOP flag to avoid an
1398 * unnecessary PIM assert.
1399 * XXX: M_LOOP is an ad-hoc hack...
1400 */
1401 static struct sockaddr_in6 sin6 =
1402 { sizeof(sin6), AF_INET6 };
1403
1404 struct mbuf *mm;
1405 struct mrt6msg *im;
1406#ifdef MRT6_OINIT
1407 struct omrt6msg *oim;
1408#endif
1409
1410 mm = m_copym(m, 0, sizeof(struct ip6_hdr),
1411 M_NOWAIT);
1412 if (mm &&
1413 (!M_WRITABLE(mm) ||
1414 mm->m_len < sizeof(struct ip6_hdr)))
1415 mm = m_pullup(mm, sizeof(struct ip6_hdr));
1416 if (mm == NULL)
1417 return (ENOBUFS);
1418
1419#ifdef MRT6_OINIT
1420 oim = NULL;
1421#endif
1422 im = NULL;
1423 switch (V_ip6_mrouter_ver) {
1424#ifdef MRT6_OINIT
1425 case MRT6_OINIT:
1426 oim = mtod(mm, struct omrt6msg *);
1428 oim->im6_mbz = 0;
1429 break;
1430#endif
1431 case MRT6_INIT:
1432 im = mtod(mm, struct mrt6msg *);
1434 im->im6_mbz = 0;
1435 break;
1436 default:
1437 m_freem(mm);
1438 return (EINVAL);
1439 }
1440
1441 for (mifp = mif6table, iif = 0;
1442 iif < nummifs && mifp &&
1443 mifp->m6_ifp != ifp;
1444 mifp++, iif++)
1445 ;
1446
1447 switch (V_ip6_mrouter_ver) {
1448#ifdef MRT6_OINIT
1449 case MRT6_OINIT:
1450 oim->im6_mif = iif;
1451 sin6.sin6_addr = oim->im6_src;
1452 break;
1453#endif
1454 case MRT6_INIT:
1455 im->im6_mif = iif;
1456 sin6.sin6_addr = im->im6_src;
1457 break;
1458 }
1459
1460 MRT6STAT_INC(mrt6s_upcalls);
1461
1462 if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
1463 MRT6_DLOG(DEBUG_ANY,
1464 "ip6_mrouter socket queue full");
1465 MRT6STAT_INC(mrt6s_upq_sockfull);
1466 return (ENOBUFS);
1467 } /* if socket Q full */
1468 } /* if PIM */
1469 return (0);
1470 } /* if wrong iif */
1471
1472 /* If I sourced this packet, it counts as output, else it was input. */
1473 if (m->m_pkthdr.rcvif == NULL) {
1474 /* XXX: is rcvif really NULL when output?? */
1475 mif6table[mifi].m6_pkt_out++;
1476 mif6table[mifi].m6_bytes_out += plen;
1477 } else {
1478 mif6table[mifi].m6_pkt_in++;
1479 mif6table[mifi].m6_bytes_in += plen;
1480 }
1481 rt->mf6c_pkt_cnt++;
1482 rt->mf6c_byte_cnt += plen;
1483
1484 /*
1485 * For each mif, forward a copy of the packet if there are group
1486 * members downstream on the interface.
1487 */
1488 src0 = ip6->ip6_src;
1489 dst0 = ip6->ip6_dst;
1490 if ((error = in6_setscope(&src0, ifp, &iszone)) != 0 ||
1491 (error = in6_setscope(&dst0, ifp, &idzone)) != 0) {
1492 IP6STAT_INC(ip6s_badscope);
1493 return (error);
1494 }
1495 for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) {
1496 if (IF_ISSET(mifi, &rt->mf6c_ifset)) {
1497 /*
1498 * check if the outgoing packet is going to break
1499 * a scope boundary.
1500 * XXX For packets through PIM register tunnel
1501 * interface, we believe a routing daemon.
1502 */
1503 if (!(mif6table[rt->mf6c_parent].m6_flags &
1504 MIFF_REGISTER) &&
1505 !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
1506 if (in6_setscope(&src0, mif6table[mifi].m6_ifp,
1507 &oszone) ||
1508 in6_setscope(&dst0, mif6table[mifi].m6_ifp,
1509 &odzone) ||
1510 iszone != oszone ||
1511 idzone != odzone) {
1512 IP6STAT_INC(ip6s_badscope);
1513 continue;
1514 }
1515 }
1516
1517 mifp->m6_pkt_out++;
1518 mifp->m6_bytes_out += plen;
1519 if (mifp->m6_flags & MIFF_REGISTER)
1520 register_send(ip6, mifp, m);
1521 else
1522 phyint_send(ip6, mifp, m);
1523 }
1524 }
1525 return (0);
1526}
1527
1528static void
1529phyint_send(struct ip6_hdr *ip6, struct mif6 *mifp, struct mbuf *m)
1530{
1531#ifdef MRT6DEBUG
1532 char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
1533#endif
1534 struct mbuf *mb_copy;
1535 struct ifnet *ifp = mifp->m6_ifp;
1536 int error = 0;
1537 u_long linkmtu;
1538
1539 /*
1540 * Make a new reference to the packet; make sure that
1541 * the IPv6 header is actually copied, not just referenced,
1542 * so that ip6_output() only scribbles on the copy.
1543 */
1544 mb_copy = m_copym(m, 0, M_COPYALL, M_NOWAIT);
1545 if (mb_copy &&
1546 (!M_WRITABLE(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
1547 mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
1548 if (mb_copy == NULL) {
1549 return;
1550 }
1551 /* set MCAST flag to the outgoing packet */
1552 mb_copy->m_flags |= M_MCAST;
1553
1554 /*
1555 * If we sourced the packet, call ip6_output since we may devide
1556 * the packet into fragments when the packet is too big for the
1557 * outgoing interface.
1558 * Otherwise, we can simply send the packet to the interface
1559 * sending queue.
1560 */
1561 if (m->m_pkthdr.rcvif == NULL) {
1562 struct ip6_moptions im6o;
1563 struct epoch_tracker et;
1564
1565 im6o.im6o_multicast_ifp = ifp;
1566 /* XXX: ip6_output will override ip6->ip6_hlim */
1567 im6o.im6o_multicast_hlim = ip6->ip6_hlim;
1568 im6o.im6o_multicast_loop = 1;
1569 NET_EPOCH_ENTER(et);
1570 error = ip6_output(mb_copy, NULL, NULL, IPV6_FORWARDING, &im6o,
1571 NULL, NULL);
1572 NET_EPOCH_EXIT(et);
1573
1574 MRT6_DLOG(DEBUG_XMIT, "mif %u err %d",
1575 (uint16_t)(mifp - mif6table), error);
1576 return;
1577 }
1578
1579 /*
1580 * If configured to loop back multicasts by default,
1581 * loop back a copy now.
1582 */
1583 if (in6_mcast_loop)
1584 ip6_mloopback(ifp, m);
1585
1586 /*
1587 * Put the packet into the sending queue of the outgoing interface
1588 * if it would fit in the MTU of the interface.
1589 */
1590 linkmtu = IN6_LINKMTU(ifp);
1591 if (mb_copy->m_pkthdr.len <= linkmtu || linkmtu < IPV6_MMTU) {
1592 struct sockaddr_in6 dst6;
1593
1594 bzero(&dst6, sizeof(dst6));
1595 dst6.sin6_len = sizeof(struct sockaddr_in6);
1596 dst6.sin6_family = AF_INET6;
1597 dst6.sin6_addr = ip6->ip6_dst;
1598
1599 IP_PROBE(send, NULL, NULL, ip6, ifp, NULL, ip6);
1600 /*
1601 * We just call if_output instead of nd6_output here, since
1602 * we need no ND for a multicast forwarded packet...right?
1603 */
1604 m_clrprotoflags(m); /* Avoid confusing lower layers. */
1605 error = (*ifp->if_output)(ifp, mb_copy,
1606 (struct sockaddr *)&dst6, NULL);
1607 MRT6_DLOG(DEBUG_XMIT, "mif %u err %d",
1608 (uint16_t)(mifp - mif6table), error);
1609 } else {
1610 /*
1611 * pMTU discovery is intentionally disabled by default, since
1612 * various router may notify pMTU in multicast, which can be
1613 * a DDoS to a router
1614 */
1615 if (V_ip6_mcast_pmtu)
1616 icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, linkmtu);
1617 else {
1618 MRT6_DLOG(DEBUG_XMIT, " packet too big on %s o %s "
1619 "g %s size %d (discarded)", if_name(ifp),
1620 ip6_sprintf(ip6bufs, &ip6->ip6_src),
1621 ip6_sprintf(ip6bufd, &ip6->ip6_dst),
1622 mb_copy->m_pkthdr.len);
1623 m_freem(mb_copy); /* simply discard the packet */
1624 }
1625 }
1626}
1627
1628static int
1629register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
1630{
1631#ifdef MRT6DEBUG
1632 char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
1633#endif
1634 struct mbuf *mm;
1635 int i, len = m->m_pkthdr.len;
1636 static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
1637 struct mrt6msg *im6;
1638
1639 MRT6_DLOG(DEBUG_ANY, "src %s dst %s",
1640 ip6_sprintf(ip6bufs, &ip6->ip6_src),
1641 ip6_sprintf(ip6bufd, &ip6->ip6_dst));
1642 PIM6STAT_INC(pim6s_snd_registers);
1643
1644 /* Make a copy of the packet to send to the user level process. */
1645 mm = m_gethdr(M_NOWAIT, MT_DATA);
1646 if (mm == NULL)
1647 return (ENOBUFS);
1648 mm->m_data += max_linkhdr;
1649 mm->m_len = sizeof(struct ip6_hdr);
1650
1651 if ((mm->m_next = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
1652 m_freem(mm);
1653 return (ENOBUFS);
1654 }
1655 i = MHLEN - M_LEADINGSPACE(mm);
1656 if (i > len)
1657 i = len;
1658 mm = m_pullup(mm, i);
1659 if (mm == NULL)
1660 return (ENOBUFS);
1661/* TODO: check it! */
1662 mm->m_pkthdr.len = len + sizeof(struct ip6_hdr);
1663
1664 /*
1665 * Send message to routing daemon
1666 */
1667 sin6.sin6_addr = ip6->ip6_src;
1668
1669 im6 = mtod(mm, struct mrt6msg *);
1671 im6->im6_mbz = 0;
1672
1673 im6->im6_mif = mif - mif6table;
1674
1675 /* iif info is not given for reg. encap.n */
1676 MRT6STAT_INC(mrt6s_upcalls);
1677
1678 if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) {
1679 MRT6_DLOG(DEBUG_ANY, "ip6_mrouter socket queue full");
1680 MRT6STAT_INC(mrt6s_upq_sockfull);
1681 return (ENOBUFS);
1682 }
1683 return (0);
1684}
1685
1686/*
1687 * pim6_encapcheck() is called by the encap6_input() path at runtime to
1688 * determine if a packet is for PIM; allowing PIM to be dynamically loaded
1689 * into the kernel.
1690 */
1691static int
1692pim6_encapcheck(const struct mbuf *m __unused, int off __unused,
1693 int proto __unused, void *arg __unused)
1694{
1695
1696 KASSERT(proto == IPPROTO_PIM, ("not for IPPROTO_PIM"));
1697 return (8); /* claim the datagram. */
1698}
1699
1700/*
1701 * PIM sparse mode hook
1702 * Receives the pim control messages, and passes them up to the listening
1703 * socket, using rip6_input.
1704 * The only message processed is the REGISTER pim message; the pim header
1705 * is stripped off, and the inner packet is passed to register_mforward.
1706 */
1707static int
1708pim6_input(struct mbuf *m, int off, int proto, void *arg __unused)
1709{
1710 struct pim *pim; /* pointer to a pim struct */
1711 struct ip6_hdr *ip6;
1712 int pimlen;
1713 int minlen;
1714
1715 PIM6STAT_INC(pim6s_rcv_total);
1716
1717 /*
1718 * Validate lengths
1719 */
1720 pimlen = m->m_pkthdr.len - off;
1721 if (pimlen < PIM_MINLEN) {
1722 PIM6STAT_INC(pim6s_rcv_tooshort);
1723 MRT6_DLOG(DEBUG_PIM, "PIM packet too short");
1724 m_freem(m);
1725 return (IPPROTO_DONE);
1726 }
1727
1728 /*
1729 * if the packet is at least as big as a REGISTER, go ahead
1730 * and grab the PIM REGISTER header size, to avoid another
1731 * possible m_pullup() later.
1732 *
1733 * PIM_MINLEN == pimhdr + u_int32 == 8
1734 * PIM6_REG_MINLEN == pimhdr + reghdr + eip6hdr == 4 + 4 + 40
1735 */
1736 minlen = (pimlen >= PIM6_REG_MINLEN) ? PIM6_REG_MINLEN : PIM_MINLEN;
1737
1738 /*
1739 * Make sure that the IP6 and PIM headers in contiguous memory, and
1740 * possibly the PIM REGISTER header
1741 */
1742 if (m->m_len < off + minlen) {
1743 m = m_pullup(m, off + minlen);
1744 if (m == NULL) {
1745 IP6STAT_INC(ip6s_exthdrtoolong);
1746 return (IPPROTO_DONE);
1747 }
1748 }
1749 ip6 = mtod(m, struct ip6_hdr *);
1750 pim = (struct pim *)((caddr_t)ip6 + off);
1751
1752#define PIM6_CHECKSUM
1753#ifdef PIM6_CHECKSUM
1754 {
1755 int cksumlen;
1756
1757 /*
1758 * Validate checksum.
1759 * If PIM REGISTER, exclude the data packet
1760 */
1761 if (pim->pim_type == PIM_REGISTER)
1762 cksumlen = PIM_MINLEN;
1763 else
1764 cksumlen = pimlen;
1765
1766 if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) {
1767 PIM6STAT_INC(pim6s_rcv_badsum);
1768 MRT6_DLOG(DEBUG_PIM, "invalid checksum");
1769 m_freem(m);
1770 return (IPPROTO_DONE);
1771 }
1772 }
1773#endif /* PIM_CHECKSUM */
1774
1775 /* PIM version check */
1776 if (pim->pim_ver != PIM_VERSION) {
1777 PIM6STAT_INC(pim6s_rcv_badversion);
1778 MRT6_DLOG(DEBUG_ANY | DEBUG_ERR,
1779 "incorrect version %d, expecting %d",
1781 m_freem(m);
1782 return (IPPROTO_DONE);
1783 }
1784
1785 if (pim->pim_type == PIM_REGISTER) {
1786 /*
1787 * since this is a REGISTER, we'll make a copy of the register
1788 * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the
1789 * routing daemon.
1790 */
1791 static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 };
1792
1793 struct mbuf *mcp;
1794 struct ip6_hdr *eip6;
1795 u_int32_t *reghdr;
1796 int rc;
1797#ifdef MRT6DEBUG
1798 char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
1799#endif
1800
1801 PIM6STAT_INC(pim6s_rcv_registers);
1802
1803 if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {
1804 MRT6_DLOG(DEBUG_PIM, "register mif not set: %d",
1805 reg_mif_num);
1806 m_freem(m);
1807 return (IPPROTO_DONE);
1808 }
1809
1810 reghdr = (u_int32_t *)(pim + 1);
1811
1812 if ((ntohl(*reghdr) & PIM_NULL_REGISTER))
1813 goto pim6_input_to_daemon;
1814
1815 /*
1816 * Validate length
1817 */
1818 if (pimlen < PIM6_REG_MINLEN) {
1819 PIM6STAT_INC(pim6s_rcv_tooshort);
1820 PIM6STAT_INC(pim6s_rcv_badregisters);
1821 MRT6_DLOG(DEBUG_ANY | DEBUG_ERR, "register packet "
1822 "size too small %d from %s",
1823 pimlen, ip6_sprintf(ip6bufs, &ip6->ip6_src));
1824 m_freem(m);
1825 return (IPPROTO_DONE);
1826 }
1827
1828 eip6 = (struct ip6_hdr *) (reghdr + 1);
1829 MRT6_DLOG(DEBUG_PIM, "eip6: %s -> %s, eip6 plen %d",
1830 ip6_sprintf(ip6bufs, &eip6->ip6_src),
1831 ip6_sprintf(ip6bufd, &eip6->ip6_dst),
1832 ntohs(eip6->ip6_plen));
1833
1834 /* verify the version number of the inner packet */
1835 if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
1836 PIM6STAT_INC(pim6s_rcv_badregisters);
1837 MRT6_DLOG(DEBUG_ANY, "invalid IP version (%d) "
1838 "of the inner packet",
1839 (eip6->ip6_vfc & IPV6_VERSION));
1840 m_freem(m);
1841 return (IPPROTO_DONE);
1842 }
1843
1844 /* verify the inner packet is destined to a mcast group */
1845 if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
1846 PIM6STAT_INC(pim6s_rcv_badregisters);
1847 MRT6_DLOG(DEBUG_PIM, "inner packet of register "
1848 "is not multicast %s",
1849 ip6_sprintf(ip6bufd, &eip6->ip6_dst));
1850 m_freem(m);
1851 return (IPPROTO_DONE);
1852 }
1853
1854 /*
1855 * make a copy of the whole header to pass to the daemon later.
1856 */
1857 mcp = m_copym(m, 0, off + PIM6_REG_MINLEN, M_NOWAIT);
1858 if (mcp == NULL) {
1859 MRT6_DLOG(DEBUG_ANY | DEBUG_ERR, "pim register: "
1860 "could not copy register head");
1861 m_freem(m);
1862 return (IPPROTO_DONE);
1863 }
1864
1865 /*
1866 * forward the inner ip6 packet; point m_data at the inner ip6.
1867 */
1868 m_adj(m, off + PIM_MINLEN);
1869 MRT6_DLOG(DEBUG_PIM, "forwarding decapsulated register: "
1870 "src %s, dst %s, mif %d",
1871 ip6_sprintf(ip6bufs, &eip6->ip6_src),
1872 ip6_sprintf(ip6bufd, &eip6->ip6_dst), reg_mif_num);
1873
1874 rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m,
1875 dst.sin6_family, 0);
1876
1877 /* prepare the register head to send to the mrouting daemon */
1878 m = mcp;
1879 }
1880
1881 /*
1882 * Pass the PIM message up to the daemon; if it is a register message
1883 * pass the 'head' only up to the daemon. This includes the
1884 * encapsulator ip6 header, pim header, register header and the
1885 * encapsulated ip6 header.
1886 */
1887 pim6_input_to_daemon:
1888 return (rip6_input(&m, &off, proto));
1889}
1890
1891static int
1892ip6_mroute_modevent(module_t mod, int type, void *unused)
1893{
1894
1895 switch (type) {
1896 case MOD_LOAD:
1900
1901 pim6_encap_cookie = ip6_encap_attach(&ipv6_encap_cfg,
1902 NULL, M_WAITOK);
1903 if (pim6_encap_cookie == NULL) {
1904 printf("ip6_mroute: unable to attach pim6 encap\n");
1908 return (EINVAL);
1909 }
1910
1916 break;
1917
1918 case MOD_UNLOAD:
1919 if (V_ip6_mrouter != NULL)
1920 return EINVAL;
1921
1922 if (pim6_encap_cookie) {
1923 ip6_encap_detach(pim6_encap_cookie);
1924 pim6_encap_cookie = NULL;
1925 }
1927 ip6_mforward = NULL;
1928 ip6_mrouter_done = NULL;
1929 ip6_mrouter_get = NULL;
1930 ip6_mrouter_set = NULL;
1931 mrt6_ioctl = NULL;
1932
1936 break;
1937
1938 default:
1939 return (EOPNOTSUPP);
1940 }
1941
1942 return (0);
1943}
1944
1945static moduledata_t ip6_mroutemod = {
1946 "ip6_mroute",
1948 0
1949};
1950
1951DECLARE_MODULE(ip6_mroute, ip6_mroutemod, SI_SUB_PROTO_MC, SI_ORDER_ANY);
void icmp6_error(struct mbuf *m, int type, int code, int param)
Definition: icmp6.c:257
char * ip6_sprintf(char *ip6buf, const struct in6_addr *addr)
Definition: in6.c:1637
#define IN6_IS_ADDR_MC_LINKLOCAL(a)
Definition: in6.h:322
#define IN6_IS_ADDR_UNSPECIFIED(a)
Definition: in6.h:239
#define IN6_ARE_ADDR_EQUAL(a, b)
Definition: in6.h:227
#define M_LOOP
Definition: in6.h:657
int in6_cksum(struct mbuf *, u_int8_t, u_int32_t, u_int32_t)
Definition: in6_cksum.c:364
#define IN6_IS_ADDR_MULTICAST(a)
Definition: in6.h:304
#define IN6_IS_ADDR_MC_INTFACELOCAL(a)
Definition: in6.h:319
#define INET6_ADDRSTRLEN
Definition: in6.h:112
#define SIOCGETSGCNT_IN6
Definition: in6_var.h:485
#define SIOCGETMIFCNT_IN6
Definition: in6_var.h:487
SYSCTL_DECL(_net_inet6)
#define MFC6_UNLOCK()
Definition: ip6_mroute.c:187
int X_ip6_mrouter_set(struct socket *, struct sockopt *)
Definition: ip6_mroute.c:376
#define EXPIRE_TIMEOUT
Definition: ip6_mroute.c:257
#define PIM6STAT_INC(name)
Definition: ip6_mroute.c:290
static struct sockaddr_in6 sin6
Definition: ip6_mroute.c:672
static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *)
Definition: ip6_mroute.c:1529
#define MIF6_LOCK_DESTROY()
Definition: ip6_mroute.c:235
static struct ifnet * multicast_register_if6
Definition: ip6_mroute.c:275
#define MFC6_LOCK()
Definition: ip6_mroute.c:186
#define V_ip6_mrouter_ver
Definition: ip6_mroute.c:153
static struct callout expire_upcalls_ch
Definition: ip6_mroute.c:364
static void expire_upcalls(void *)
Definition: ip6_mroute.c:1310
#define TV_DELTA(a, b, delta)
Definition: ip6_mroute.c:327
#define MF6CFIND(o, g, rt)
Definition: ip6_mroute.c:305
static const struct encaptab * pim6_encap_cookie
Definition: ip6_mroute.c:140
#define MF6CHASH(a, g)
Definition: ip6_mroute.c:297
#define MIF6_LOCK_ASSERT()
Definition: ip6_mroute.c:232
static int register_send(struct ip6_hdr *, struct mif6 *, struct mbuf *)
Definition: ip6_mroute.c:1629
static struct sx mrouter6_mtx
Definition: ip6_mroute.c:170
#define MRT6STAT_INC(name)
Definition: ip6_mroute.c:166
static int set_pim6(int *)
Definition: ip6_mroute.c:541
#define MIF6_LOCK_INIT()
Definition: ip6_mroute.c:233
#define MROUTER6_LOCK()
Definition: ip6_mroute.c:172
static struct mtx mif6_mtx
Definition: ip6_mroute.c:228
DECLARE_MODULE(ip6_mroute, ip6_mroutemod, SI_SUB_PROTO_MC, SI_ORDER_ANY)
#define MROUTER6_LOCK_DESTROY()
Definition: ip6_mroute.c:176
int X_ip6_mrouter_get(struct socket *, struct sockopt *)
Definition: ip6_mroute.c:444
static int pim6_input(struct mbuf *, int, int, void *)
#define UPCALL_EXPIRE
Definition: ip6_mroute.c:258
#define TV_LT(a, b)
Definition: ip6_mroute.c:346
SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mf6ctable, CTLFLAG_RD, &mf6ctable, sizeof(mf6ctable), "S,*mf6ctable[MF6CTBLSIZ]", "IPv6 Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], " "netinet6/ip6_mroute.h)")
static int pim6_encapcheck(const struct mbuf *, int, int, void *)
static u_char n6expire[MF6CTBLSIZ]
Definition: ip6_mroute.c:194
static mifi_t reg_mif_num
Definition: ip6_mroute.c:283
static int get_mif6_cnt(struct sioc_mif_req6 *)
Definition: ip6_mroute.c:516
static struct mtx mfc6_mtx
Definition: ip6_mroute.c:184
static int sysctl_mif6table(SYSCTL_HANDLER_ARGS)
Definition: ip6_mroute.c:198
static MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry")
static SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "PIM")
static int ip6_mroute_modevent(module_t mod, int type, void *unused)
Definition: ip6_mroute.c:1892
#define MIF6_UNLOCK()
Definition: ip6_mroute.c:231
static const struct encap_config ipv6_encap_cfg
Definition: ip6_mroute.c:144
__FBSDID("$FreeBSD$")
static int del_m6fc(struct mf6cctl *)
Definition: ip6_mroute.c:987
static int add_m6fc(struct mf6cctl *)
Definition: ip6_mroute.c:816
int X_ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *)
Definition: ip6_mroute.c:1068
static moduledata_t ip6_mroutemod
Definition: ip6_mroute.c:1945
#define MROUTER6_LOCK_INIT()
Definition: ip6_mroute.c:175
#define MROUTER6_UNLOCK()
Definition: ip6_mroute.c:173
#define MRT6_DLOG(m, fmt,...)
Definition: ip6_mroute.c:253
static mifi_t nummifs
Definition: ip6_mroute.c:282
static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *)
Definition: ip6_mroute.c:1366
struct domain inet6domain
Definition: in6_proto.c:334
int in6_mcast_loop
Definition: in6_mcast.c:186
SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, mif6table, CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_NEEDGIANT, NULL, 0, sysctl_mif6table, "S,mif6_sctl[MAXMIFS]", "IPv6 Multicast Interfaces (struct mif6_sctl[MAXMIFS], " "netinet6/ip6_mroute.h)")
int X_mrt6_ioctl(u_long, caddr_t)
Definition: ip6_mroute.c:463
static int socket_send(struct socket *, struct mbuf *, struct sockaddr_in6 *)
Definition: ip6_mroute.c:1033
#define MFC6_LOCK_INIT()
Definition: ip6_mroute.c:189
#define MIF6_LOCK()
Definition: ip6_mroute.c:230
SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW, &mrt6stat, mrt6stat, "Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)")
static int get_sg_cnt(struct sioc_sg_req6 *)
Definition: ip6_mroute.c:489
#define MFC6_LOCK_DESTROY()
Definition: ip6_mroute.c:192
static struct mf6c * mf6ctable[MF6CTBLSIZ]
Definition: ip6_mroute.c:178
#define V_pim6
Definition: ip6_mroute.c:292
static int add_m6if(struct mif6ctl *)
Definition: ip6_mroute.c:678
#define MFC6_LOCK_ASSERT()
Definition: ip6_mroute.c:188
static int del_m6if(mifi_t *)
Definition: ip6_mroute.c:801
#define MFC6_LOCKPTR()
Definition: ip6_mroute.c:185
int X_ip6_mrouter_done(void)
Definition: ip6_mroute.c:598
static int ip6_mrouter_init(struct socket *, int, int)
Definition: ip6_mroute.c:555
VNET_DEFINE_STATIC(int, ip6_mrouter_ver)=0
static struct mif6 mif6table[MAXMIFS]
Definition: ip6_mroute.c:196
static int del_m6if_locked(mifi_t *)
Definition: ip6_mroute.c:761
#define MRT6_PIM
Definition: ip6_mroute.h:63
u_short mifi_t
Definition: ip6_mroute.h:77
#define MRT6MSG_WHOLEPKT
Definition: ip6_mroute.h:168
int(* mrt6_ioctl)(u_long, caddr_t)
Definition: raw_ip6.c:152
#define MRT6MSG_WRONGMIF
Definition: ip6_mroute.h:167
#define GET_TIME(t)
Definition: ip6_mroute.h:71
#define MIFF_REGISTER
Definition: ip6_mroute.h:110
#define MRT6MSG_NOCACHE
Definition: ip6_mroute.h:166
#define MRT6_DONE
Definition: ip6_mroute.h:58
#define MAX_UPQ6
Definition: ip6_mroute.h:273
#define IF_ISSET(n, p)
Definition: ip6_mroute.h:97
#define MAXMIFS
Definition: ip6_mroute.h:78
#define MRT6_OINIT
Definition: ip6_mroute.h:56
#define MRT6_DEL_MFC
Definition: ip6_mroute.h:62
#define MF6C_INCOMPLETE_PARENT
Definition: ip6_mroute.h:250
int(* ip6_mrouter_set)(struct socket *so, struct sockopt *sopt)
Definition: raw_ip6.c:148
int(* ip6_mrouter_done)(void)
Definition: raw_ip6.c:150
#define MF6CTBLSIZ
Definition: ip6_mroute.h:266
int(* ip6_mrouter_get)(struct socket *so, struct sockopt *sopt)
Definition: raw_ip6.c:149
#define MRT6_INIT
Definition: ip6_mroute.h:64
#define MRT6_ADD_MIF
Definition: ip6_mroute.h:59
#define MRT6_DEL_MIF
Definition: ip6_mroute.h:60
#define MRT6_ADD_MFC
Definition: ip6_mroute.h:61
void ip6_mloopback(struct ifnet *ifp, struct mbuf *m)
Definition: ip6_output.c:3297
int ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro, int flags, struct ip6_moptions *im6o, struct ifnet **ifpp, struct inpcb *inp)
Definition: ip6_output.c:409
#define V_ip6_log_time
Definition: ip6_var.h:308
#define V_ip6_mcast_pmtu
Definition: ip6_var.h:285
#define IP6STAT_INC(name)
Definition: ip6_var.h:256
int rip6_input(struct mbuf **, int *, int)
Definition: raw_ip6.c:186
#define V_ip6_mrouter
Definition: ip6_var.h:301
#define IPV6_FORWARDING
Definition: ip6_var.h:263
#define V_ip6_log_interval
Definition: ip6_var.h:307
int(* ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *)
Definition: raw_ip6.c:151
#define IN6_LINKMTU(ifp)
Definition: nd6.h:101
#define PIM_MINLEN
Definition: pim6.h:62
#define PIM_NULL_REGISTER
Definition: pim6.h:71
#define PIM6_REG_MINLEN
Definition: pim6.h:63
#define PIM_VERSION
Definition: pim6.h:45
#define PIM_REGISTER
Definition: pim6.h:68
#define PIM6CTL_STATS
Definition: pim6_var.h:59
int in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
Definition: scope6.c:406
Definition: in6.h:97
u_quad_t mf6c_wrong_if
Definition: ip6_mroute.h:243
struct sockaddr_in6 mf6c_mcastgrp
Definition: ip6_mroute.h:237
struct if_set mf6c_ifset
Definition: ip6_mroute.h:239
int mf6c_expire
Definition: ip6_mroute.h:244
mifi_t mf6c_parent
Definition: ip6_mroute.h:238
u_quad_t mf6c_pkt_cnt
Definition: ip6_mroute.h:241
struct mf6c * mf6c_next
Definition: ip6_mroute.h:247
struct rtdetq * mf6c_stall
Definition: ip6_mroute.h:246
u_quad_t mf6c_byte_cnt
Definition: ip6_mroute.h:242
struct sockaddr_in6 mf6c_origin
Definition: ip6_mroute.h:236
struct sockaddr_in6 mf6cc_origin
Definition: ip6_mroute.h:116
mifi_t mf6cc_parent
Definition: ip6_mroute.h:118
struct if_set mf6cc_ifset
Definition: ip6_mroute.h:119
struct sockaddr_in6 mf6cc_mcastgrp
Definition: ip6_mroute.h:117
u_quad_t m6_pkt_out
Definition: ip6_mroute.h:208
u_quad_t m6_bytes_out
Definition: ip6_mroute.h:210
u_char m6_flags
Definition: ip6_mroute.h:203
uint32_t m6_ifp
Definition: ip6_mroute.h:206
u_quad_t m6_pkt_in
Definition: ip6_mroute.h:207
u_quad_t m6_bytes_in
Definition: ip6_mroute.h:209
struct in6_addr m6_lcl_addr
Definition: ip6_mroute.h:205
u_int m6_rate_limit
Definition: ip6_mroute.h:204
u_quad_t m6_bytes_out
Definition: ip6_mroute.h:225
u_quad_t m6_bytes_in
Definition: ip6_mroute.h:224
u_char m6_flags
Definition: ip6_mroute.h:218
struct ifnet * m6_ifp
Definition: ip6_mroute.h:221
u_quad_t m6_pkt_in
Definition: ip6_mroute.h:222
struct in6_addr m6_lcl_addr
Definition: ip6_mroute.h:220
u_int m6_rate_limit
Definition: ip6_mroute.h:219
u_quad_t m6_pkt_out
Definition: ip6_mroute.h:223
u_short mif6c_pifi
Definition: ip6_mroute.h:107
mifi_t mif6c_mifi
Definition: ip6_mroute.h:105
u_char mif6c_flags
Definition: ip6_mroute.h:106
u_char im6_mbz
Definition: ip6_mroute.h:169
u_int16_t im6_mif
Definition: ip6_mroute.h:171
u_char im6_msgtype
Definition: ip6_mroute.h:170
u_char im6_msgtype
Definition: ip6_mroute.h:149
u_char im6_mbz
Definition: ip6_mroute.h:150
u_char im6_mif
Definition: ip6_mroute.h:151
Definition: pim6.h:46
u_char pim_type
Definition: pim6.h:56
u_char pim_ver
Definition: pim6.h:55
struct ifnet * ifp
Definition: ip6_mroute.h:258
struct mbuf * m
Definition: ip6_mroute.h:257
struct rtdetq * next
Definition: ip6_mroute.h:262
u_quad_t obytes
Definition: ip6_mroute.h:196
u_quad_t ocount
Definition: ip6_mroute.h:194
u_quad_t ibytes
Definition: ip6_mroute.h:195
u_quad_t icount
Definition: ip6_mroute.h:193
u_quad_t pktcnt
Definition: ip6_mroute.h:183
u_quad_t bytecnt
Definition: ip6_mroute.h:184
u_quad_t wrong_if
Definition: ip6_mroute.h:185
struct sockaddr_in6 src
Definition: ip6_mroute.h:181
struct sockaddr_in6 grp
Definition: ip6_mroute.h:182
uint8_t sin6_len
Definition: in6.h:126
struct in6_addr sin6_addr
Definition: in6.h:130
sa_family_t sin6_family
Definition: in6.h:127