[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/ip6_mroute.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (C) 1998 WIDE Project.
  3  * All rights reserved.
  4  *
  5  * Redistribution and use in source and binary forms, with or without
  6  * modification, are permitted provided that the following conditions
  7  * are met:
  8  * 1. Redistributions of source code must retain the above copyright
  9  *    notice, this list of conditions and the following disclaimer.
 10  * 2. Redistributions in binary form must reproduce the above copyright
 11  *    notice, this list of conditions and the following disclaimer in the
 12  *    documentation and/or other materials provided with the distribution.
 13  * 3. Neither the name of the project nor the names of its contributors
 14  *    may be used to endorse or promote products derived from this software
 15  *    without specific prior written permission.
 16  *
 17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 27  * SUCH DAMAGE.
 28  *
 29  *      $KAME: ip6_mroute.c,v 1.58 2001/12/18 02:36:31 itojun Exp $
 30  */
 31 
 32 /*-
 33  * Copyright (c) 1989 Stephen Deering
 34  * Copyright (c) 1992, 1993
 35  *      The Regents of the University of California.  All rights reserved.
 36  *
 37  * This code is derived from software contributed to Berkeley by
 38  * Stephen Deering of Stanford University.
 39  *
 40  * Redistribution and use in source and binary forms, with or without
 41  * modification, are permitted provided that the following conditions
 42  * are met:
 43  * 1. Redistributions of source code must retain the above copyright
 44  *    notice, this list of conditions and the following disclaimer.
 45  * 2. Redistributions in binary form must reproduce the above copyright
 46  *    notice, this list of conditions and the following disclaimer in the
 47  *    documentation and/or other materials provided with the distribution.
 48  * 4. Neither the name of the University nor the names of its contributors
 49  *    may be used to endorse or promote products derived from this software
 50  *    without specific prior written permission.
 51  *
 52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 62  * SUCH DAMAGE.
 63  *
 64  *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
 65  *      BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp
 66  */
 67 
 68 /*
 69  * IP multicast forwarding procedures
 70  *
 71  * Written by David Waitzman, BBN Labs, August 1988.
 72  * Modified by Steve Deering, Stanford, February 1989.
 73  * Modified by Mark J. Steiglitz, Stanford, May, 1991
 74  * Modified by Van Jacobson, LBL, January 1993
 75  * Modified by Ajit Thyagarajan, PARC, August 1993
 76  * Modified by Bill Fenner, PARC, April 1994
 77  *
 78  * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support
 79  */
 80 
 81 #include <sys/cdefs.h>
 82 __FBSDID("$FreeBSD: src/sys/netinet6/ip6_mroute.c,v 1.52 2008/12/02 21:37:28 bz Exp $");
 83 
 84 #include "opt_inet.h"
 85 #include "opt_inet6.h"
 86 
 87 #include <sys/param.h>
 88 #include <sys/callout.h>
 89 #include <sys/errno.h>
 90 #include <sys/kernel.h>
 91 #include <sys/lock.h>
 92 #include <sys/malloc.h>
 93 #include <sys/mbuf.h>
 94 #include <sys/protosw.h>
 95 #include <sys/signalvar.h>
 96 #include <sys/socket.h>
 97 #include <sys/socketvar.h>
 98 #include <sys/sockio.h>
 99 #include <sys/sx.h>
100 #include <sys/sysctl.h>
101 #include <sys/syslog.h>
102 #include <sys/systm.h>
103 #include <sys/time.h>
104 #include <sys/vimage.h>
105 
106 #include <net/if.h>
107 #include <net/if_types.h>
108 #include <net/raw_cb.h>
109 #include <net/route.h>
110 #include <net/vnet.h>
111 
112 #include <netinet/in.h>
113 #include <netinet/in_var.h>
114 #include <netinet/icmp6.h>
115 #include <netinet/vinet.h>
116 
117 #include <netinet/ip6.h>
118 #include <netinet6/ip6_var.h>
119 #include <netinet6/scope6_var.h>
120 #include <netinet6/nd6.h>
121 #include <netinet6/ip6_mroute.h>
122 #include <netinet6/ip6protosw.h>
123 #include <netinet6/pim6.h>
124 #include <netinet6/pim6_var.h>
125 #include <netinet6/vinet6.h>
126 
127 static MALLOC_DEFINE(M_MRTABLE6, "mf6c", "multicast forwarding cache entry");
128 
129 /* XXX: this is a very common idiom; move to <sys/mbuf.h> ? */
130 #define M_HASCL(m) ((m)->m_flags & M_EXT)
131 
132 static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
133 static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
134 
135 static void pim6_init(void);
136 static int set_pim6(int *);
137 static int socket_send __P((struct socket *, struct mbuf *,
138             struct sockaddr_in6 *));
139 static int register_send __P((struct ip6_hdr *, struct mif6 *,
140             struct mbuf *));
141 
142 extern struct domain inet6domain;
143 
144 /* XXX: referenced from ip_mroute.c for dynamically loading this code. */
145 struct ip6protosw in6_pim_protosw = {
146         .pr_type =              SOCK_RAW,
147         .pr_domain =            &inet6domain,
148         .pr_protocol =          IPPROTO_PIM,
149         .pr_flags =             PR_ATOMIC|PR_ADDR|PR_LASTHDR,
150         .pr_input =             pim6_input,
151         .pr_output =            rip6_output,
152         .pr_ctloutput =         rip6_ctloutput,
153         .pr_init =              pim6_init,
154         .pr_usrreqs =           &rip6_usrreqs
155 };
156 
157 #ifdef VIMAGE_GLOBALS
158 static int ip6_mrouter_ver;
159 #endif
160 
161 SYSCTL_DECL(_net_inet6);
162 SYSCTL_DECL(_net_inet6_ip6);
163 SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM");
164 
165 static struct mrt6stat mrt6stat;
166 SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW,
167     &mrt6stat, mrt6stat,
168     "Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)");
169 
170 #define NO_RTE_FOUND    0x1
171 #define RTE_FOUND       0x2
172 
173 static struct mf6c *mf6ctable[MF6CTBLSIZ];
174 SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mf6ctable, CTLFLAG_RD,
175     &mf6ctable, sizeof(mf6ctable), "S,*mf6ctable[MF6CTBLSIZ]",
176     "Multicast Forwarding Table (struct *mf6ctable[MF6CTBLSIZ], "
177     "netinet6/ip6_mroute.h)");
178 
179 static u_char n6expire[MF6CTBLSIZ];
180 
181 static struct mif6 mif6table[MAXMIFS];
182 SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mif6table, CTLFLAG_RD,
183     &mif6table, sizeof(mif6table), "S,vif[MAXMIFS]",
184     "Multicast Interfaces (struct mif[MAXMIFS], netinet6/ip6_mroute.h)");
185 
186 #ifdef MRT6DEBUG
187 #ifdef VIMAGE_GLOBALS
188 static u_int mrt6debug = 0;             /* debug level */
189 #endif
190 #define DEBUG_MFC       0x02
191 #define DEBUG_FORWARD   0x04
192 #define DEBUG_EXPIRE    0x08
193 #define DEBUG_XMIT      0x10
194 #define DEBUG_REG       0x20
195 #define DEBUG_PIM       0x40
196 #endif
197 
198 static void     expire_upcalls(void *);
199 #define EXPIRE_TIMEOUT  (hz / 4)        /* 4x / second */
200 #define UPCALL_EXPIRE   6               /* number of timeouts */
201 
202 #ifdef INET
203 #ifdef MROUTING
204 extern struct socket *ip_mrouter;
205 #endif
206 #endif
207 
208 /*
209  * 'Interfaces' associated with decapsulator (so we can tell
210  * packets that went through it from ones that get reflected
211  * by a broken gateway).  Different from IPv4 register_if,
212  * these interfaces are linked into the system ifnet list,
213  * because per-interface IPv6 statistics are maintained in
214  * ifp->if_afdata.  But it does not have any routes point
215  * to them.  I.e., packets can't be sent this way.  They
216  * only exist as a placeholder for multicast source
217  * verification.
218  */
219 static struct ifnet *multicast_register_if6;
220 
221 #define ENCAP_HOPS 64
222 
223 /*
224  * Private variables.
225  */
226 static mifi_t nummifs = 0;
227 static mifi_t reg_mif_num = (mifi_t)-1;
228 
229 static struct pim6stat pim6stat;
230 SYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RD,
231     &pim6stat, pim6stat,
232     "PIM Statistics (struct pim6stat, netinet6/pim_var.h)");
233 
234 #ifdef VIMAGE_GLOBALS
235 static int pim6;
236 #endif
237 
238 /*
239  * Hash function for a source, group entry
240  */
241 #define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
242                                    (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
243                                    (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \
244                                    (g).s6_addr32[2] ^ (g).s6_addr32[3])
245 
246 /*
247  * Find a route for a given origin IPv6 address and Multicast group address.
248  */
249 #define MF6CFIND(o, g, rt) do { \
250         struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
251         rt = NULL; \
252         mrt6stat.mrt6s_mfc_lookups++; \
253         while (_rt) { \
254                 if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \
255                     IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \
256                     (_rt->mf6c_stall == NULL)) { \
257                         rt = _rt; \
258                         break; \
259                 } \
260                 _rt = _rt->mf6c_next; \
261         } \
262         if (rt == NULL) { \
263                 mrt6stat.mrt6s_mfc_misses++; \
264         } \
265 } while (/*CONSTCOND*/ 0)
266 
267 /*
268  * Macros to compute elapsed time efficiently
269  * Borrowed from Van Jacobson's scheduling code
270  * XXX: replace with timersub() ?
271  */
272 #define TV_DELTA(a, b, delta) do { \
273             int xxs; \
274                 \
275             delta = (a).tv_usec - (b).tv_usec; \
276             if ((xxs = (a).tv_sec - (b).tv_sec)) { \
277                switch (xxs) { \
278                       case 2: \
279                           delta += 1000000; \
280                               /* FALLTHROUGH */ \
281                       case 1: \
282                           delta += 1000000; \
283                           break; \
284                       default: \
285                           delta += (1000000 * xxs); \
286                } \
287             } \
288 } while (/*CONSTCOND*/ 0)
289 
290 /* XXX: replace with timercmp(a, b, <) ? */
291 #define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
292               (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
293 
294 #ifdef UPCALL_TIMING
295 #define UPCALL_MAX      50
296 static u_long upcall_data[UPCALL_MAX + 1];
297 static void collate();
298 #endif /* UPCALL_TIMING */
299 
300 static int get_sg_cnt(struct sioc_sg_req6 *);
301 static int get_mif6_cnt(struct sioc_mif_req6 *);
302 static int ip6_mrouter_init(struct socket *, int, int);
303 static int add_m6if(struct mif6ctl *);
304 static int del_m6if(mifi_t *);
305 static int add_m6fc(struct mf6cctl *);
306 static int del_m6fc(struct mf6cctl *);
307 
308 static struct callout expire_upcalls_ch;
309 
310 int X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m);
311 int X_ip6_mrouter_done(void);
312 int X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt);
313 int X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt);
314 int X_mrt6_ioctl(int cmd, caddr_t data);
315 
316 static void
317 pim6_init(void)
318 {
319         INIT_VNET_INET6(curvnet);
320 
321         V_ip6_mrouter_ver = 0;
322 #ifdef MRT6DEBUG
323         V_mrt6debug = 0;        /* debug level */
324 #endif
325 }
326 
327 /*
328  * Handle MRT setsockopt commands to modify the multicast routing tables.
329  */
330 int
331 X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
332 {
333         int error = 0;
334         int optval;
335         struct mif6ctl mifc;
336         struct mf6cctl mfcc;
337         mifi_t mifi;
338 
339         if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT)
340                 return (EACCES);
341 
342         switch (sopt->sopt_name) {
343         case MRT6_INIT:
344 #ifdef MRT6_OINIT
345         case MRT6_OINIT:
346 #endif
347                 error = sooptcopyin(sopt, &optval, sizeof(optval),
348                     sizeof(optval));
349                 if (error)
350                         break;
351                 error = ip6_mrouter_init(so, optval, sopt->sopt_name);
352                 break;
353         case MRT6_DONE:
354                 error = X_ip6_mrouter_done();
355                 break;
356         case MRT6_ADD_MIF:
357                 error = sooptcopyin(sopt, &mifc, sizeof(mifc), sizeof(mifc));
358                 if (error)
359                         break;
360                 error = add_m6if(&mifc);
361                 break;
362         case MRT6_ADD_MFC:
363                 error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
364                 if (error)
365                         break;
366                 error = add_m6fc(&mfcc);
367                 break;
368         case MRT6_DEL_MFC:
369                 error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
370                 if (error)
371                         break;
372                 error = del_m6fc(&mfcc);
373                 break;
374         case MRT6_DEL_MIF:
375                 error = sooptcopyin(sopt, &mifi, sizeof(mifi), sizeof(mifi));
376                 if (error)
377                         break;
378                 error = del_m6if(&mifi);
379                 break;
380         case MRT6_PIM:
381                 error = sooptcopyin(sopt, &optval, sizeof(optval),
382                     sizeof(optval));
383                 if (error)
384                         break;
385                 error = set_pim6(&optval);
386                 break;
387         default:
388                 error = EOPNOTSUPP;
389                 break;
390         }
391 
392         return (error);
393 }
394 
395 /*
396  * Handle MRT getsockopt commands
397  */
398 int
399 X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
400 {
401         INIT_VNET_INET6(curvnet);
402         int error = 0;
403 
404         if (so != ip6_mrouter)
405                 return (EACCES);
406 
407         switch (sopt->sopt_name) {
408                 case MRT6_PIM:
409                         error = sooptcopyout(sopt, &V_pim6, sizeof(V_pim6));
410                         break;
411         }
412         return (error);
413 }
414 
415 /*
416  * Handle ioctl commands to obtain information from the cache
417  */
418 int
419 X_mrt6_ioctl(int cmd, caddr_t data)
420 {
421         switch (cmd) {
422         case SIOCGETSGCNT_IN6:
423                 return (get_sg_cnt((struct sioc_sg_req6 *)data));
424         case SIOCGETMIFCNT_IN6:
425                 return (get_mif6_cnt((struct sioc_mif_req6 *)data));
426         default:
427                 return (EINVAL);
428         }
429 }
430 
431 /*
432  * returns the packet, byte, rpf-failure count for the source group provided
433  */
434 static int
435 get_sg_cnt(struct sioc_sg_req6 *req)
436 {
437         struct mf6c *rt;
438         int s;
439 
440         s = splnet();
441         MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
442         splx(s);
443         if (rt != NULL) {
444                 req->pktcnt = rt->mf6c_pkt_cnt;
445                 req->bytecnt = rt->mf6c_byte_cnt;
446                 req->wrong_if = rt->mf6c_wrong_if;
447         } else
448                 return (ESRCH);
449 #if 0
450                 req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
451 #endif
452 
453         return (0);
454 }
455 
456 /*
457  * returns the input and output packet and byte counts on the mif provided
458  */
459 static int
460 get_mif6_cnt(struct sioc_mif_req6 *req)
461 {
462         mifi_t mifi = req->mifi;
463 
464         if (mifi >= nummifs)
465                 return (EINVAL);
466 
467         req->icount = mif6table[mifi].m6_pkt_in;
468         req->ocount = mif6table[mifi].m6_pkt_out;
469         req->ibytes = mif6table[mifi].m6_bytes_in;
470         req->obytes = mif6table[mifi].m6_bytes_out;
471 
472         return (0);
473 }
474 
475 static int
476 set_pim6(int *i)
477 {
478         INIT_VNET_INET6(curvnet);
479         if ((*i != 1) && (*i != 0))
480                 return (EINVAL);
481 
482         V_pim6 = *i;
483 
484         return (0);
485 }
486 
487 /*
488  * Enable multicast routing
489  */
490 static int
491 ip6_mrouter_init(struct socket *so, int v, int cmd)
492 {
493         INIT_VNET_INET6(curvnet);
494 
495 #ifdef MRT6DEBUG
496         if (V_mrt6debug)
497                 log(LOG_DEBUG,
498                     "ip6_mrouter_init: so_type = %d, pr_protocol = %d\n",
499                     so->so_type, so->so_proto->pr_protocol);
500 #endif
501 
502         if (so->so_type != SOCK_RAW ||
503             so->so_proto->pr_protocol != IPPROTO_ICMPV6)
504                 return (EOPNOTSUPP);
505 
506         if (v != 1)
507                 return (ENOPROTOOPT);
508 
509         if (ip6_mrouter != NULL)
510                 return (EADDRINUSE);
511 
512         ip6_mrouter = so;
513         V_ip6_mrouter_ver = cmd;
514 
515         bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
516         bzero((caddr_t)n6expire, sizeof(n6expire));
517 
518         V_pim6 = 0;/* used for stubbing out/in pim stuff */
519 
520         callout_init(&expire_upcalls_ch, 0);
521         callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
522             expire_upcalls, NULL);
523 
524 #ifdef MRT6DEBUG
525         if (V_mrt6debug)
526                 log(LOG_DEBUG, "ip6_mrouter_init\n");
527 #endif
528 
529         return (0);
530 }
531 
532 /*
533  * Disable multicast routing
534  */
535 int
536 X_ip6_mrouter_done(void)
537 {
538         INIT_VNET_INET6(curvnet);
539         mifi_t mifi;
540         int i;
541         struct mf6c *rt;
542         struct rtdetq *rte;
543         int s;
544 
545         s = splnet();
546 
547         /*
548          * For each phyint in use, disable promiscuous reception of all IPv6
549          * multicasts.
550          */
551 #ifdef INET
552 #ifdef MROUTING
553         /*
554          * If there is still IPv4 multicast routing daemon,
555          * we remain interfaces to receive all muliticasted packets.
556          * XXX: there may be an interface in which the IPv4 multicast
557          * daemon is not interested...
558          */
559         if (!V_ip_mrouter)
560 #endif
561 #endif
562         {
563                 for (mifi = 0; mifi < nummifs; mifi++) {
564                         if (mif6table[mifi].m6_ifp &&
565                             !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
566                                 if_allmulti(mif6table[mifi].m6_ifp, 0);
567                         }
568                 }
569         }
570         bzero((caddr_t)mif6table, sizeof(mif6table));
571         nummifs = 0;
572 
573         V_pim6 = 0; /* used to stub out/in pim specific code */
574 
575         callout_stop(&expire_upcalls_ch);
576 
577         /*
578          * Free all multicast forwarding cache entries.
579          */
580         for (i = 0; i < MF6CTBLSIZ; i++) {
581                 rt = mf6ctable[i];
582                 while (rt) {
583                         struct mf6c *frt;
584 
585                         for (rte = rt->mf6c_stall; rte != NULL; ) {
586                                 struct rtdetq *n = rte->next;
587 
588                                 m_free(rte->m);
589                                 free(rte, M_MRTABLE6);
590                                 rte = n;
591                         }
592                         frt = rt;
593                         rt = rt->mf6c_next;
594                         free(frt, M_MRTABLE6);
595                 }
596         }
597 
598         bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
599 
600         /*
601          * Reset register interface
602          */
603         if (reg_mif_num != (mifi_t)-1 && multicast_register_if6 != NULL) {
604                 if_detach(multicast_register_if6);
605                 if_free(multicast_register_if6);
606                 reg_mif_num = (mifi_t)-1;
607                 multicast_register_if6 = NULL;
608         }
609 
610         ip6_mrouter = NULL;
611         V_ip6_mrouter_ver = 0;
612 
613         splx(s);
614 
615 #ifdef MRT6DEBUG
616         if (V_mrt6debug)
617                 log(LOG_DEBUG, "ip6_mrouter_done\n");
618 #endif
619 
620         return (0);
621 }
622 
623 static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
624 
625 /*
626  * Add a mif to the mif table
627  */
628 static int
629 add_m6if(struct mif6ctl *mifcp)
630 {
631         INIT_VNET_NET(curvnet);
632         struct mif6 *mifp;
633         struct ifnet *ifp;
634         int error, s;
635 
636         if (mifcp->mif6c_mifi >= MAXMIFS)
637                 return (EINVAL);
638         mifp = mif6table + mifcp->mif6c_mifi;
639         if (mifp->m6_ifp)
640                 return (EADDRINUSE); /* XXX: is it appropriate? */
641         if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index)
642                 return (ENXIO);
643         ifp = ifnet_byindex(mifcp->mif6c_pifi);
644 
645         if (mifcp->mif6c_flags & MIFF_REGISTER) {
646                 if (reg_mif_num == (mifi_t)-1) {
647                         ifp = if_alloc(IFT_OTHER);
648 
649                         if_initname(ifp, "register_mif", 0);
650                         ifp->if_flags |= IFF_LOOPBACK;
651                         if_attach(ifp);
652                         multicast_register_if6 = ifp;
653                         reg_mif_num = mifcp->mif6c_mifi;
654                         /*
655                          * it is impossible to guess the ifindex of the
656                          * register interface.  So mif6c_pifi is automatically
657                          * calculated.
658                          */
659                         mifcp->mif6c_pifi = ifp->if_index;
660                 } else {
661                         ifp = multicast_register_if6;
662                 }
663 
664         } /* if REGISTER */
665         else {
666                 /* Make sure the interface supports multicast */
667                 if ((ifp->if_flags & IFF_MULTICAST) == 0)
668                         return (EOPNOTSUPP);
669 
670                 s = splnet();
671                 error = if_allmulti(ifp, 1);
672                 splx(s);
673                 if (error)
674                         return (error);
675         }
676 
677         s = splnet();
678         mifp->m6_flags     = mifcp->mif6c_flags;
679         mifp->m6_ifp       = ifp;
680 
681         /* initialize per mif pkt counters */
682         mifp->m6_pkt_in    = 0;
683         mifp->m6_pkt_out   = 0;
684         mifp->m6_bytes_in  = 0;
685         mifp->m6_bytes_out = 0;
686         splx(s);
687 
688         /* Adjust nummifs up if the mifi is higher than nummifs */
689         if (nummifs <= mifcp->mif6c_mifi)
690                 nummifs = mifcp->mif6c_mifi + 1;
691 
692 #ifdef MRT6DEBUG
693         if (V_mrt6debug)
694                 log(LOG_DEBUG,
695                     "add_mif #%d, phyint %s\n",
696                     mifcp->mif6c_mifi,
697                     ifp->if_xname);
698 #endif
699 
700         return (0);
701 }
702 
703 /*
704  * Delete a mif from the mif table
705  */
706 static int
707 del_m6if(mifi_t *mifip)
708 {
709         struct mif6 *mifp = mif6table + *mifip;
710         mifi_t mifi;
711         struct ifnet *ifp;
712         int s;
713 
714         if (*mifip >= nummifs)
715                 return (EINVAL);
716         if (mifp->m6_ifp == NULL)
717                 return (EINVAL);
718 
719         s = splnet();
720 
721         if (!(mifp->m6_flags & MIFF_REGISTER)) {
722                 /*
723                  * XXX: what if there is yet IPv4 multicast daemon
724                  *      using the interface?
725                  */
726                 ifp = mifp->m6_ifp;
727 
728                 if_allmulti(ifp, 0);
729         } else {
730                 if (reg_mif_num != (mifi_t)-1 &&
731                     multicast_register_if6 != NULL) {
732                         if_detach(multicast_register_if6);
733                         if_free(multicast_register_if6);
734                         reg_mif_num = (mifi_t)-1;
735                         multicast_register_if6 = NULL;
736                 }
737         }
738 
739         bzero((caddr_t)mifp, sizeof(*mifp));
740 
741         /* Adjust nummifs down */
742         for (mifi = nummifs; mifi > 0; mifi--)
743                 if (mif6table[mifi - 1].m6_ifp)
744                         break;
745         nummifs = mifi;
746 
747         splx(s);
748 
749 #ifdef MRT6DEBUG
750         if (V_mrt6debug)
751                 log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs);
752 #endif
753 
754         return (0);
755 }
756 
757 /*
758  * Add an mfc entry
759  */
760 static int
761 add_m6fc(struct mf6cctl *mfccp)
762 {
763         struct mf6c *rt;
764         u_long hash;
765         struct rtdetq *rte;
766         u_short nstl;
767         int s;
768         char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
769 
770         MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
771                  mfccp->mf6cc_mcastgrp.sin6_addr, rt);
772 
773         /* If an entry already exists, just update the fields */
774         if (rt) {
775 #ifdef MRT6DEBUG
776                 if (V_mrt6debug & DEBUG_MFC) {
777                     log(LOG_DEBUG,
778                         "add_m6fc no upcall h %d o %s g %s p %x\n",
779                         ip6_sprintf(ip6bufo, &mfccp->mf6cc_origin.sin6_addr),
780                         ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr),
781                         mfccp->mf6cc_parent);
782                 }
783 #endif
784 
785                 s = splnet();
786                 rt->mf6c_parent = mfccp->mf6cc_parent;
787                 rt->mf6c_ifset = mfccp->mf6cc_ifset;
788                 splx(s);
789                 return (0);
790         }
791 
792         /*
793          * Find the entry for which the upcall was made and update
794          */
795         s = splnet();
796         hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
797                         mfccp->mf6cc_mcastgrp.sin6_addr);
798         for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
799                 if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
800                                        &mfccp->mf6cc_origin.sin6_addr) &&
801                     IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
802                                        &mfccp->mf6cc_mcastgrp.sin6_addr) &&
803                     (rt->mf6c_stall != NULL)) {
804 
805                         if (nstl++)
806                                 log(LOG_ERR,
807                                     "add_m6fc: %s o %s g %s p %x dbx %p\n",
808                                     "multiple kernel entries",
809                                     ip6_sprintf(ip6bufo,
810                                             &mfccp->mf6cc_origin.sin6_addr),
811                                     ip6_sprintf(ip6bufg,
812                                             &mfccp->mf6cc_mcastgrp.sin6_addr),
813                                     mfccp->mf6cc_parent, rt->mf6c_stall);
814 
815 #ifdef MRT6DEBUG
816                         if (V_mrt6debug & DEBUG_MFC)
817                                 log(LOG_DEBUG,
818                                     "add_m6fc o %s g %s p %x dbg %x\n",
819                                     ip6_sprintf(ip6bufo,
820                                             &mfccp->mf6cc_origin.sin6_addr),
821                                     ip6_sprintf(ip6bufg,
822                                             &mfccp->mf6cc_mcastgrp.sin6_addr),
823                                     mfccp->mf6cc_parent, rt->mf6c_stall);
824 #endif
825 
826                         rt->mf6c_origin     = mfccp->mf6cc_origin;
827                         rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
828                         rt->mf6c_parent     = mfccp->mf6cc_parent;
829                         rt->mf6c_ifset      = mfccp->mf6cc_ifset;
830                         /* initialize pkt counters per src-grp */
831                         rt->mf6c_pkt_cnt    = 0;
832                         rt->mf6c_byte_cnt   = 0;
833                         rt->mf6c_wrong_if   = 0;
834 
835                         rt->mf6c_expire = 0;    /* Don't clean this guy up */
836                         n6expire[hash]--;
837 
838                         /* free packets Qed at the end of this entry */
839                         for (rte = rt->mf6c_stall; rte != NULL; ) {
840                                 struct rtdetq *n = rte->next;
841                                 ip6_mdq(rte->m, rte->ifp, rt);
842                                 m_freem(rte->m);
843 #ifdef UPCALL_TIMING
844                                 collate(&(rte->t));
845 #endif /* UPCALL_TIMING */
846                                 free(rte, M_MRTABLE6);
847                                 rte = n;
848                         }
849                         rt->mf6c_stall = NULL;
850                 }
851         }
852 
853         /*
854          * It is possible that an entry is being inserted without an upcall
855          */
856         if (nstl == 0) {
857 #ifdef MRT6DEBUG
858                 if (V_mrt6debug & DEBUG_MFC)
859                     log(LOG_DEBUG,
860                         "add_mfc no upcall h %d o %s g %s p %x\n",
861                         hash,
862                         ip6_sprintf(ip6bufo, &mfccp->mf6cc_origin.sin6_addr),
863                         ip6_sprintf(ip6bufg, &mfccp->mf6cc_mcastgrp.sin6_addr),
864                         mfccp->mf6cc_parent);
865 #endif
866 
867                 for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
868 
869                         if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
870                                                &mfccp->mf6cc_origin.sin6_addr)&&
871                             IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
872                                                &mfccp->mf6cc_mcastgrp.sin6_addr)) {
873 
874                                 rt->mf6c_origin     = mfccp->mf6cc_origin;
875                                 rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
876                                 rt->mf6c_parent     = mfccp->mf6cc_parent;
877                                 rt->mf6c_ifset      = mfccp->mf6cc_ifset;
878                                 /* initialize pkt counters per src-grp */
879                                 rt->mf6c_pkt_cnt    = 0;
880                                 rt->mf6c_byte_cnt   = 0;
881                                 rt->mf6c_wrong_if   = 0;
882 
883                                 if (rt->mf6c_expire)
884                                         n6expire[hash]--;
885                                 rt->mf6c_expire    = 0;
886                         }
887                 }
888                 if (rt == NULL) {
889                         /* no upcall, so make a new entry */
890                         rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE6,
891                                                   M_NOWAIT);
892                         if (rt == NULL) {
893                                 splx(s);
894                                 return (ENOBUFS);
895                         }
896 
897                         /* insert new entry at head of hash chain */
898                         rt->mf6c_origin     = mfccp->mf6cc_origin;
899                         rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
900                         rt->mf6c_parent     = mfccp->mf6cc_parent;
901                         rt->mf6c_ifset      = mfccp->mf6cc_ifset;
902                         /* initialize pkt counters per src-grp */
903                         rt->mf6c_pkt_cnt    = 0;
904                         rt->mf6c_byte_cnt   = 0;
905                         rt->mf6c_wrong_if   = 0;
906                         rt->mf6c_expire     = 0;
907                         rt->mf6c_stall = NULL;
908 
909                         /* link into table */
910                         rt->mf6c_next  = mf6ctable[hash];
911                         mf6ctable[hash] = rt;
912                 }
913         }
914         splx(s);
915         return (0);
916 }
917 
918 #ifdef UPCALL_TIMING
919 /*
920  * collect delay statistics on the upcalls
921  */
922 static void
923 collate(struct timeval *t)
924 {
925         u_long d;
926         struct timeval tp;
927         u_long delta;
928 
929         GET_TIME(tp);
930 
931         if (TV_LT(*t, tp))
932         {
933                 TV_DELTA(tp, *t, delta);
934 
935                 d = delta >> 10;
936                 if (d > UPCALL_MAX)
937                         d = UPCALL_MAX;
938 
939                 ++upcall_data[d];
940         }
941 }
942 #endif /* UPCALL_TIMING */
943 
944 /*
945  * Delete an mfc entry
946  */
947 static int
948 del_m6fc(struct mf6cctl *mfccp)
949 {
950         struct sockaddr_in6     origin;
951         struct sockaddr_in6     mcastgrp;
952         struct mf6c             *rt;
953         struct mf6c             **nptr;
954         u_long          hash;
955         int s;
956 
957         origin = mfccp->mf6cc_origin;
958         mcastgrp = mfccp->mf6cc_mcastgrp;
959         hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);
960 
961 #ifdef MRT6DEBUG
962         if (V_mrt6debug & DEBUG_MFC) {
963                 char ip6bufo[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
964                 log(LOG_DEBUG,"del_m6fc orig %s mcastgrp %s\n",
965                     ip6_sprintf(ip6bufo, &origin.sin6_addr),
966                     ip6_sprintf(ip6bufg, &mcastgrp.sin6_addr));
967         }
968 #endif
969 
970         s = splnet();
971 
972         nptr = &mf6ctable[hash];
973         while ((rt = *nptr) != NULL) {
974                 if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,
975                                        &rt->mf6c_origin.sin6_addr) &&
976                     IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr,
977                                        &rt->mf6c_mcastgrp.sin6_addr) &&
978                     rt->mf6c_stall == NULL)
979                         break;
980 
981                 nptr = &rt->mf6c_next;
982         }
983         if (rt == NULL) {
984                 splx(s);
985                 return (EADDRNOTAVAIL);
986         }
987 
988         *nptr = rt->mf6c_next;
989         free(rt, M_MRTABLE6);
990 
991         splx(s);
992 
993         return (0);
994 }
995 
996 static int
997 socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src)
998 {
999 
1000         if (s) {
1001                 if (sbappendaddr(&s->so_rcv,
1002                                  (struct sockaddr *)src,
1003                                  mm, (struct mbuf *)0) != 0) {
1004                         sorwakeup(s);
1005                         return (0);
1006                 }
1007         }
1008         m_freem(mm);
1009         return (-1);
1010 }
1011 
1012 /*
1013  * IPv6 multicast forwarding function. This function assumes that the packet
1014  * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
1015  * pointed to by "ifp", and the packet is to be relayed to other networks
1016  * that have members of the packet's destination IPv6 multicast group.
1017  *
1018  * The packet is returned unscathed to the caller, unless it is
1019  * erroneous, in which case a non-zero return value tells the caller to
1020  * discard it.
1021  *
1022  * NOTE: this implementation assumes that m->m_pkthdr.rcvif is NULL iff
1023  * this function is called in the originating context (i.e., not when
1024  * forwarding a packet from other node).  ip6_output(), which is currently the
1025  * only function that calls this function is called in the originating context,
1026  * explicitly ensures this condition.  It is caller's responsibility to ensure
1027  * that if this function is called from somewhere else in the originating
1028  * context in the future.
1029  */
1030 int
1031