]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/ip6_mroute.c
xnu-1699.22.81.tar.gz
[apple/xnu.git] / bsd / netinet6 / ip6_mroute.c
index 6140af6fee2377ec20017f6c761e4a0614529f89..39f14628426d8d84842995a02e51a2a55a31c077 100644 (file)
@@ -1,4 +1,32 @@
-/*     $KAME: ip6_mroute.c,v 1.15 2000/02/22 14:04:21 itojun Exp $     */
+/*
+ * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*     $FreeBSD: src/sys/netinet6/ip6_mroute.c,v 1.16.2.1 2002/12/18 21:39:40 suz Exp $        */
+/*     $KAME: ip6_mroute.c,v 1.58 2001/12/18 02:36:31 itojun Exp $     */
 
 /*
  * Copyright (C) 1998 WIDE Project.
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*
+ * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
+ * support for mandatory and extensible security protections.  This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
+ */
 
 /*     BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp     */
 
  * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support
  */
 
-#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
-#include "opt_inet.h"
-#endif
-
-#ifndef _KERNEL
-# ifdef KERNEL
-#  define _KERNEL
-# endif
-#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
 #include <sys/malloc.h>
-#endif
 #include <sys/mbuf.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/errno.h>
 #include <sys/time.h>
 #include <sys/kernel.h>
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
-#include <sys/ioctl.h>
-#endif
 #include <sys/syslog.h>
+#include <kern/locks.h>
 
 #include <net/if.h>
 #include <net/route.h>
 #include <net/raw_cb.h>
+#include <net/dlil.h>
+#include <net/net_osdep.h>
 
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 
 #include <netinet/ip6.h>
 #include <netinet6/ip6_var.h>
+#include <netinet6/scope6_var.h>
 #include <netinet6/ip6_mroute.h>
+#include <netinet/icmp6.h>
 #include <netinet6/pim6.h>
 #include <netinet6/pim6_var.h>
 
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#if CONFIG_MACF_NET
+#include <security/mac.h>
+#endif /* MAC_NET */
+
+#ifndef __APPLE__
 static MALLOC_DEFINE(M_MRTABLE, "mf6c", "multicast forwarding cache entry");
 #endif
 
 #define M_HASCL(m) ((m)->m_flags & M_EXT)
 
-static int ip6_mdq __P((struct mbuf *, struct ifnet *, struct mf6c *));
-static void phyint_send __P((struct ip6_hdr *, struct mif6 *, struct mbuf *));
+static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
+static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
 
-static int set_pim6 __P((int *));
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__)
-static int get_pim6 __P((struct mbuf *));
-#endif
-static int socket_send __P((struct socket *, struct mbuf *,
-                           struct sockaddr_in6 *));
-static int register_send __P((struct ip6_hdr *, struct mif6 *,
-                             struct mbuf *));
+static int set_pim6(int *);
+static int socket_send(struct socket *, struct mbuf *,
+                           struct sockaddr_in6 *);
+static int register_send(struct ip6_hdr *, struct mif6 *,
+                             struct mbuf *);
 
 /*
  * Globals.  All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
  * except for netstat or debugging purposes.
  */
 struct socket  *ip6_mrouter  = NULL;
+int            ip6_mrouter_ver = 0;
 int            ip6_mrtproto = IPPROTO_PIM;    /* for netstat only */
+
+#if MROUTING
+
 struct mrt6stat        mrt6stat;
 
 #define NO_RTE_FOUND   0x1
 #define RTE_FOUND      0x2
 
 struct mf6c    *mf6ctable[MF6CTBLSIZ];
-u_char         nexpire[MF6CTBLSIZ];
+u_char         n6expire[MF6CTBLSIZ];
 static struct mif6 mif6table[MAXMIFS];
 #if MRT6DEBUG
 u_int          mrt6debug = 0;    /* debug level        */
@@ -127,7 +157,8 @@ u_int               mrt6debug = 0;    /* debug level        */
 #define         DEBUG_PIM       0x40
 #endif
 
-static void    expire_upcalls __P((void *));
+static void    expire_upcalls(void *);
+
 #define                EXPIRE_TIMEOUT  (hz / 4)        /* 4x / second */
 #define                UPCALL_EXPIRE   6               /* number of timeouts */
 
@@ -137,7 +168,6 @@ extern struct socket *ip_mrouter;
 #endif
 #endif
 
-static u_long  lo_dl_tag = 0;
 /*
  * 'Interfaces' associated with decapsulator (so we can tell
  * packets that went through it from ones that get reflected
@@ -157,15 +187,6 @@ static mifi_t nummifs = 0;
 static mifi_t reg_mif_num = (mifi_t)-1;
 
 static struct pim6stat pim6stat;
-
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-static struct callout_handle expire_upcalls_ch;
-#endif
-
-/*
- * one-back cache used by ipip_input to locate a tunnel's mif
- * given a datagram's src ip address.
- */
 static int pim6;
 
 /*
@@ -181,8 +202,8 @@ static int pim6;
  * Quality of service parameter to be added in the future!!!
  */
 
-#define MF6CFIND(o, g, rt) { \
-       register struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
+#define MF6CFIND(o, g, rt) do { \
+       struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
        rt = NULL; \
        mrt6stat.mrt6s_mfc_lookups++; \
        while (_rt) { \
@@ -197,14 +218,14 @@ static int pim6;
        if (rt == NULL) { \
                mrt6stat.mrt6s_mfc_misses++; \
        } \
-}
+} while (0)
 
 /*
  * Macros to compute elapsed time efficiently
  * Borrowed from Van Jacobson's scheduling code
  */
-#define TV_DELTA(a, b, delta) { \
-           register int xxs; \
+#define TV_DELTA(a, b, delta) do { \
+           int xxs; \
                \
            delta = (a).tv_usec - (b).tv_usec; \
            if ((xxs = (a).tv_sec - (b).tv_sec)) { \
@@ -219,102 +240,98 @@ static int pim6;
                          delta += (1000000 * xxs); \
               } \
            } \
-}
+} while (0)
 
 #define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
              (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
 
 #if UPCALL_TIMING
 #define UPCALL_MAX     50
-u_long upcall_data[UPCALL_MAX + 1];
+u_int32_t upcall_data[UPCALL_MAX + 1];
 static void collate();
 #endif /* UPCALL_TIMING */
 
-static int get_sg_cnt __P((struct sioc_sg_req6 *));
-static int get_mif6_cnt __P((struct sioc_mif_req6 *));
-static int ip6_mrouter_init __P((struct socket *, struct mbuf *));
-static int add_m6if __P((struct mif6ctl *));
-static int del_m6if __P((mifi_t *));
-static int add_m6fc __P((struct mf6cctl *));
-static int del_m6fc __P((struct mf6cctl *));
+static int get_sg_cnt(struct sioc_sg_req6 *);
+static int get_mif6_cnt(void *, int);
+static int ip6_mrouter_init(struct socket *, int, int);
+static int add_m6if(struct mif6ctl *);
+static int del_m6if(mifi_t *);
+static int add_m6fc(struct mf6cctl *);
+static int del_m6fc(struct mf6cctl *);
 
 /*
  * Handle MRT setsockopt commands to modify the multicast routing tables.
  */
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
 int
 ip6_mrouter_set(so, sopt)
        struct socket *so;
        struct sockopt *sopt;
 {
-       int     error = 0;
-       struct mbuf *m;
+       int error = 0;
+       int optval;
+       struct mif6ctl mifc;
+       struct mf6cctl mfcc;
+       mifi_t mifi;
 
        if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT)
                return (EACCES);
 
-       if (error = sooptgetm(sopt, &m)) /* XXX */
-               return (error);
-       if (error = sooptmcopyin(sopt, m)) /* XXX */
-               return (error);
-
        switch (sopt->sopt_name) {
-        case MRT6_INIT:
-                error = ip6_mrouter_init(so, m);
-                break;
-        case MRT6_DONE:
-                error = ip6_mrouter_done();
-                break;
-        case MRT6_ADD_MIF:
-                error = add_m6if(mtod(m, struct mif6ctl *));
-                break;
-        case MRT6_DEL_MIF:
-                error = del_m6if(mtod(m, mifi_t *));
-                break;
-        case MRT6_ADD_MFC:
-                error = add_m6fc(mtod(m, struct mf6cctl *));
-                break;
-        case MRT6_DEL_MFC:
-                error = del_m6fc(mtod(m, struct mf6cctl *));
-                break;
-        case MRT6_PIM:
-                error = set_pim6(mtod(m, int *));
-                break;
-        default:
-                error = EOPNOTSUPP;
-                break;
+       case MRT6_INIT:
+#if MRT6_OINIT
+       case MRT6_OINIT:
+#endif
+               error = sooptcopyin(sopt, &optval, sizeof(optval),
+                   sizeof(optval));
+               if (error)
+                       break;
+               error = ip6_mrouter_init(so, optval, sopt->sopt_name);
+               break;
+       case MRT6_DONE:
+               error = ip6_mrouter_done();
+               break;
+       case MRT6_ADD_MIF:
+               error = sooptcopyin(sopt, &mifc, sizeof(mifc), sizeof(mifc));
+               if (error)
+                       break;
+               error = add_m6if(&mifc);
+               break;
+       case MRT6_ADD_MFC:
+               error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
+               if (error)
+                       break;
+               error = add_m6fc(&mfcc);
+               break;
+       case MRT6_DEL_MFC:
+               error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc));
+               if (error)
+                       break;
+               error = del_m6fc(&mfcc);
+               break;
+       case MRT6_DEL_MIF:
+               error = sooptcopyin(sopt, &mifi, sizeof(mifi), sizeof(mifi));
+               if (error)
+                       break;
+               error = del_m6if(&mifi);
+               break;
+       case MRT6_PIM:
+               error = sooptcopyin(sopt, &optval, sizeof(optval),
+                   sizeof(optval));
+               if (error)
+                       break;
+               error = set_pim6(&optval);
+               break;
+       default:
+               error = EOPNOTSUPP;
+               break;
        }
 
-       (void)m_freem(m);
-       return(error);
-}
-#else
-int
-ip6_mrouter_set(cmd, so, m)
-       int cmd;
-       struct socket *so;
-       struct mbuf *m;
-{
-       if (cmd != MRT6_INIT && so != ip6_mrouter)
-               return EACCES;
-
-       switch (cmd) {
-        case MRT6_INIT:      return ip6_mrouter_init(so, m);
-        case MRT6_DONE:      return ip6_mrouter_done();
-        case MRT6_ADD_MIF:   return add_m6if(mtod(m, struct mif6ctl *));
-        case MRT6_DEL_MIF:   return del_m6if(mtod(m, mifi_t *));
-        case MRT6_ADD_MFC:   return add_m6fc(mtod(m, struct mf6cctl *));
-        case MRT6_DEL_MFC:   return del_m6fc(mtod(m, struct mf6cctl *));
-        case MRT6_PIM:       return set_pim6(mtod(m, int *));
-        default:            return EOPNOTSUPP;
-       }
+       return (error);
 }
-#endif
 
 /*
  * Handle MRT getsockopt commands
  */
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
 int
 ip6_mrouter_get(so, sopt)
        struct socket *so;
@@ -331,50 +348,30 @@ ip6_mrouter_get(so, sopt)
        }
        return (error);
 }
-#else
-int
-ip6_mrouter_get(cmd, so, m)
-       int cmd;
-       struct socket *so;
-       struct mbuf **m;
-{
-       struct mbuf *mb;
-
-       if (so != ip6_mrouter) return EACCES;
-
-       *m = mb = m_get(M_WAIT, MT_SOOPTS);
-
-       switch (cmd) {
-        case MRT6_PIM:       return get_pim6(mb);
-        default:
-                m_free(mb);
-                return EOPNOTSUPP;
-       }
-}
-#endif
 
 /*
  * Handle ioctl commands to obtain information from the cache
  */
 int
-mrt6_ioctl(cmd, data)
-       int cmd;
-       caddr_t data;
+mrt6_ioctl(u_long cmd, caddr_t data)
 {
-    int error = 0;
-
-    switch (cmd) {
-     case SIOCGETSGCNT_IN6:
-            return(get_sg_cnt((struct sioc_sg_req6 *)data));
-            break;             /* for safety */
-     case SIOCGETMIFCNT_IN6:
-            return(get_mif6_cnt((struct sioc_mif_req6 *)data));
-            break;             /* for safety */
-     default:
-            return (EINVAL);
-            break;
-    }
-    return error;
+       int error = 0;
+
+       switch (cmd) {
+       case SIOCGETSGCNT_IN6:
+               return (get_sg_cnt((struct sioc_sg_req6 *)data));
+               /* NOTREACHED */
+
+       case SIOCGETMIFCNT_IN6_32:
+       case SIOCGETMIFCNT_IN6_64:
+               return (get_mif6_cnt(data, cmd == SIOCGETMIFCNT_IN6_64));
+               /* NOTREACHED */
+
+       default:
+               error = EINVAL;
+               break;
+       }
+       return (error);
 }
 
 /*
@@ -382,18 +379,11 @@ mrt6_ioctl(cmd, data)
  */
 static int
 get_sg_cnt(req)
-       register struct sioc_sg_req6 *req;
+       struct sioc_sg_req6 *req;
 {
-       register struct mf6c *rt;
-       int s;
+       struct mf6c *rt;
 
-#if __NetBSD__
-       s = splsoftnet();
-#else
-       s = splnet();
-#endif
        MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
-       splx(s);
        if (rt != NULL) {
                req->pktcnt = rt->mf6c_pkt_cnt;
                req->bytecnt = rt->mf6c_byte_cnt;
@@ -411,39 +401,35 @@ get_sg_cnt(req)
  * returns the input and output packet and byte counts on the mif provided
  */
 static int
-get_mif6_cnt(req)
-       register struct sioc_mif_req6 *req;
+get_mif6_cnt(void *data, int p64)
 {
-       register mifi_t mifi = req->mifi;
+       if (p64) {
+               struct sioc_mif_req6_64 *req = data;
 
-       if (mifi >= nummifs)
-               return EINVAL;
+               mifi_t mifi = req->mifi;
 
-       req->icount = mif6table[mifi].m6_pkt_in;
-       req->ocount = mif6table[mifi].m6_pkt_out;
-       req->ibytes = mif6table[mifi].m6_bytes_in;
-       req->obytes = mif6table[mifi].m6_bytes_out;
+               if (mifi >= nummifs)
+                       return (EINVAL);
 
-       return 0;
-}
-
-#if !(defined(__FreeBSD__) && __FreeBSD__ >=3) || !defined(__APPLE__)
-/*
- * Get PIM processiong global
- */
-static int
-get_pim6(m)
-       struct mbuf *m;
-{
-       int *i;
+               req->icount = mif6table[mifi].m6_pkt_in;
+               req->ocount = mif6table[mifi].m6_pkt_out;
+               req->ibytes = mif6table[mifi].m6_bytes_in;
+               req->obytes = mif6table[mifi].m6_bytes_out;
+       } else {
+               struct sioc_mif_req6_32 *req = data;
 
-       i = mtod(m, int *);
+               mifi_t mifi = req->mifi;
 
-       *i = pim6;
+               if (mifi >= nummifs)
+                       return (EINVAL);
 
-       return 0;
+               req->icount = mif6table[mifi].m6_pkt_in;
+               req->ocount = mif6table[mifi].m6_pkt_out;
+               req->ibytes = mif6table[mifi].m6_bytes_in;
+               req->obytes = mif6table[mifi].m6_bytes_out;
+       }
+       return (0);
 }
-#endif
 
 static int
 set_pim6(i)
@@ -461,12 +447,11 @@ set_pim6(i)
  * Enable multicast routing
  */
 static int
-ip6_mrouter_init(so, m)
+ip6_mrouter_init(so, v, cmd)
        struct socket *so;
-       struct mbuf *m;
+       int v;
+       int cmd;
 {
-       int *v;
-
 #if MRT6DEBUG
        if (mrt6debug)
                log(LOG_DEBUG,
@@ -478,25 +463,19 @@ ip6_mrouter_init(so, m)
            so->so_proto->pr_protocol != IPPROTO_ICMPV6)
                return EOPNOTSUPP;
 
-       if (!m || (m->m_len != sizeof(int *)))
-               return ENOPROTOOPT;
-
-       v = mtod(m, int *);
-       if (*v != 1)
-               return ENOPROTOOPT;
+       if (v != 1)
+               return (ENOPROTOOPT);
 
        if (ip6_mrouter != NULL) return EADDRINUSE;
 
        ip6_mrouter = so;
+       ip6_mrouter_ver = cmd;
 
        bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
-       bzero((caddr_t)nexpire, sizeof(nexpire));
+       bzero((caddr_t)n6expire, sizeof(n6expire));
 
        pim6 = 0;/* used for stubbing out/in pim stuff */
 
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-       expire_upcalls_ch =
-#endif
        timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
 
 #if MRT6DEBUG
@@ -515,17 +494,9 @@ ip6_mrouter_done()
 {
        mifi_t mifi;
        int i;
-       struct ifnet *ifp;
-       struct in6_ifreq ifr;
        struct mf6c *rt;
        struct rtdetq *rte;
-       int s;
 
-#if __NetBSD__
-       s = splsoftnet();
-#else
-       s = splnet();
-#endif
 
        /*
         * For each phyint in use, disable promiscuous reception of all IPv6
@@ -546,36 +517,32 @@ ip6_mrouter_done()
                for (mifi = 0; mifi < nummifs; mifi++) {
                        if (mif6table[mifi].m6_ifp &&
                            !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
-                               ifr.ifr_addr.sin6_family = AF_INET6;
-                               ifr.ifr_addr.sin6_addr= in6addr_any;
-                               ifp = mif6table[mifi].m6_ifp;
 #ifdef __APPLE__
-                               dlil_ioctl(0, ifp, SIOCDELMULTI,
-                                                (caddr_t)&ifr);
+                               if_allmulti(mif6table[mifi].m6_ifp, 0);
 #else
-                               (*ifp->if_ioctl)(ifp, SIOCDELMULTI,
-                                                (caddr_t)&ifr);
+                               {
+                                       struct ifnet *ifp;
+                                       struct in6_ifreq ifr;
+                       
+                                       ifr.ifr_addr.sin6_family = AF_INET6;
+                                       ifr.ifr_addr.sin6_addr= in6addr_any;
+                                       ifp = mif6table[mifi].m6_ifp;
+                                       ifnet_ioctl(ifp, 0, SIOCDELMULTI, &ifr);
+                               }
 #endif
                        }
                }
        }
-#if notyet
-       bzero((caddr_t)qtable, sizeof(qtable));
-       bzero((caddr_t)tbftable, sizeof(tbftable));
-#endif
        bzero((caddr_t)mif6table, sizeof(mif6table));
        nummifs = 0;
 
        pim6 = 0; /* used to stub out/in pim specific code */
 
-       untimeout(expire_upcalls, (caddr_t)NULL
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-                 , expire_upcalls_ch
-#endif
-                 );
+       untimeout(expire_upcalls, (caddr_t)NULL);
 
        /*
         * Free all multicast forwarding cache entries.
+        *###LD 5/27 needs locking
         */
        for (i = 0; i < MF6CTBLSIZ; i++) {
                rt = mf6ctable[i];
@@ -586,12 +553,12 @@ ip6_mrouter_done()
                                struct rtdetq *n = rte->next;
 
                                m_free(rte->m);
-                               _FREE(rte, M_MRTABLE);
+                               FREE(rte, M_MRTABLE);
                                rte = n;
                        }
                        frt = rt;
                        rt = rt->mf6c_next;
-                       _FREE(frt, M_MRTABLE);
+                       FREE(frt, M_MRTABLE);
                }
        }
 
@@ -603,8 +570,8 @@ ip6_mrouter_done()
        reg_mif_num = -1;
 
        ip6_mrouter = NULL;
+       ip6_mrouter_ver = 0;
 
-       splx(s);
 
 #if MRT6DEBUG
        if (mrt6debug)
@@ -614,21 +581,19 @@ ip6_mrouter_done()
        return 0;
 }
 
-static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
+static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 ,
+                                     0, 0, IN6ADDR_ANY_INIT, 0};
 
 /*
  * Add a mif to the mif table
  */
 static int
 add_m6if(mifcp)
-       register struct mif6ctl *mifcp;
+       struct mif6ctl *mifcp;
 {
-       register struct mif6 *mifp;
+       struct mif6 *mifp;
        struct ifnet *ifp;
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__)
-       struct in6_ifreq ifr;
-#endif
-       int error, s;
+       int error;
 #if notyet
        struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi;
 #endif
@@ -637,19 +602,24 @@ add_m6if(mifcp)
                return EINVAL;
        mifp = mif6table + mifcp->mif6c_mifi;
        if (mifp->m6_ifp)
-               return EADDRINUSE; /* XXX: is it appropriate? */
+               return (EADDRINUSE); /* XXX: is it appropriate? */
        if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > if_index)
+               return (ENXIO);
+
+       ifnet_head_lock_shared();
+       if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > if_index) {
+               ifnet_head_done();
                return ENXIO;
+       }
        ifp = ifindex2ifnet[mifcp->mif6c_pifi];
+       ifnet_head_done();
 
+       if (ifp == NULL) {
+               return ENXIO;
+       }
        if (mifcp->mif6c_flags & MIFF_REGISTER) {
                if (reg_mif_num == (mifi_t)-1) {
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-                       strcpy(multicast_register_if.if_xname,
-                              "register_mif"); /* XXX */
-#else
                        multicast_register_if.if_name = "register_mif";
-#endif
                        multicast_register_if.if_flags |= IFF_LOOPBACK;
                        multicast_register_if.if_index = mifcp->mif6c_mifi;
                        reg_mif_num = mifcp->mif6c_mifi;
@@ -663,44 +633,19 @@ add_m6if(mifcp)
                if ((ifp->if_flags & IFF_MULTICAST) == 0)
                        return EOPNOTSUPP;
 
-#if __NetBSD__
-               s = splsoftnet();
-#else
-               s = splnet();
-#endif
-#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
                error = if_allmulti(ifp, 1);
-#else
-               /*
-                * Enable promiscuous reception of all IPv6 multicasts
-                * from the interface.
-                */
-               ifr.ifr_addr.sin6_family = AF_INET6;
-               ifr.ifr_addr.sin6_addr = in6addr_any;
-               error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
-#endif
-               splx(s);
                if (error)
                        return error;
        }
 
-#if __NetBSD__
-       s = splsoftnet();
-#else
-       s = splnet();
-#endif
        mifp->m6_flags     = mifcp->mif6c_flags;
        mifp->m6_ifp       = ifp;
-#if notyet
-       /* scaling up here allows division by 1024 in critical code */
-       mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
-#endif
+
        /* initialize per mif pkt counters */
        mifp->m6_pkt_in    = 0;
        mifp->m6_pkt_out   = 0;
        mifp->m6_bytes_in  = 0;
        mifp->m6_bytes_out = 0;
-       splx(s);
 
        /* Adjust nummifs up if the mifi is higher than nummifs */
        if (nummifs <= mifcp->mif6c_mifi)
@@ -724,24 +669,15 @@ static int
 del_m6if(mifip)
        mifi_t *mifip;
 {
-       register struct mif6 *mifp = mif6table + *mifip;
-       register mifi_t mifi;
+       struct mif6 *mifp = mif6table + *mifip;
+       mifi_t mifi;
        struct ifnet *ifp;
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__)
-       struct in6_ifreq ifr;
-#endif
-       int s;
 
        if (*mifip >= nummifs)
                return EINVAL;
        if (mifp->m6_ifp == NULL)
                return EINVAL;
 
-#if __NetBSD__
-       s = splsoftnet();
-#else
-       s = splnet();
-#endif
 
        if (!(mifp->m6_flags & MIFF_REGISTER)) {
                /*
@@ -750,20 +686,10 @@ del_m6if(mifip)
                 */
                ifp = mifp->m6_ifp;
 
-#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
                if_allmulti(ifp, 0);
-#else
-               ifr.ifr_addr.sin6_family = AF_INET6;
-               ifr.ifr_addr.sin6_addr = in6addr_any;
-               (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
-#endif
        }
 
-#if notyet
-       bzero((caddr_t)qtable[*mifip], sizeof(qtable[*mifip]));
-       bzero((caddr_t)mifp->m6_tbf, sizeof(*(mifp->m6_tbf)));
-#endif
-       bzero((caddr_t)mifp, sizeof (*mifp));
+       bzero((caddr_t)mifp, sizeof(*mifp));
 
        /* Adjust nummifs down */
        for (mifi = nummifs; mifi > 0; mifi--)
@@ -771,7 +697,6 @@ del_m6if(mifip)
                        break;
        nummifs = mifi;
 
-       splx(s);
 
 #if MRT6DEBUG
        if (mrt6debug)
@@ -789,10 +714,9 @@ add_m6fc(mfccp)
        struct mf6cctl *mfccp;
 {
        struct mf6c *rt;
-       u_long hash;
+       u_int32_t hash;
        struct rtdetq *rte;
-       register u_short nstl;
-       int s;
+       u_short nstl;
 
        MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
                 mfccp->mf6cc_mcastgrp.sin6_addr, rt);
@@ -801,31 +725,21 @@ add_m6fc(mfccp)
        if (rt) {
 #if MRT6DEBUG
                if (mrt6debug & DEBUG_MFC)
-                       log(LOG_DEBUG,"add_m6fc update o %s g %s p %x\n",
+                       log(LOG_DEBUG,
+                           "add_m6fc no upcall h %d o %s g %s p %x\n",
                            ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
                            ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
                            mfccp->mf6cc_parent);
 #endif
 
-#if __NetBSD__
-               s = splsoftnet();
-#else
-               s = splnet();
-#endif
                rt->mf6c_parent = mfccp->mf6cc_parent;
                rt->mf6c_ifset = mfccp->mf6cc_ifset;
-               splx(s);
                return 0;
        }
 
        /*
         * Find the entry for which the upcall was made and update
         */
-#if __NetBSD__
-       s = splsoftnet();
-#else
-       s = splnet();
-#endif
        hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
                        mfccp->mf6cc_mcastgrp.sin6_addr);
        for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
@@ -862,7 +776,7 @@ add_m6fc(mfccp)
                        rt->mf6c_wrong_if   = 0;
 
                        rt->mf6c_expire = 0;    /* Don't clean this guy up */
-                       nexpire[hash]--;
+                       n6expire[hash]--;
 
                        /* free packets Qed at the end of this entry */
                        for (rte = rt->mf6c_stall; rte != NULL; ) {
@@ -872,7 +786,7 @@ add_m6fc(mfccp)
 #if UPCALL_TIMING
                                collate(&(rte->t));
 #endif /* UPCALL_TIMING */
-                               _FREE(rte, M_MRTABLE);
+                               FREE(rte, M_MRTABLE);
                                rte = n;
                        }
                        rt->mf6c_stall = NULL;
@@ -902,13 +816,14 @@ add_m6fc(mfccp)
                                rt->mf6c_origin     = mfccp->mf6cc_origin;
                                rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
                                rt->mf6c_parent     = mfccp->mf6cc_parent;
+                               rt->mf6c_ifset      = mfccp->mf6cc_ifset;
                                /* initialize pkt counters per src-grp */
                                rt->mf6c_pkt_cnt    = 0;
                                rt->mf6c_byte_cnt   = 0;
                                rt->mf6c_wrong_if   = 0;
 
                                if (rt->mf6c_expire)
-                                       nexpire[hash]--;
+                                       n6expire[hash]--;
                                rt->mf6c_expire    = 0;
                        }
                }
@@ -917,7 +832,6 @@ add_m6fc(mfccp)
                        rt = (struct mf6c *)_MALLOC(sizeof(*rt), M_MRTABLE,
                                                  M_NOWAIT);
                        if (rt == NULL) {
-                               splx(s);
                                return ENOBUFS;
                        }
        
@@ -925,6 +839,7 @@ add_m6fc(mfccp)
                        rt->mf6c_origin     = mfccp->mf6cc_origin;
                        rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
                        rt->mf6c_parent     = mfccp->mf6cc_parent;
+                       rt->mf6c_ifset      = mfccp->mf6cc_ifset;
                        /* initialize pkt counters per src-grp */
                        rt->mf6c_pkt_cnt    = 0;
                        rt->mf6c_byte_cnt   = 0;
@@ -937,7 +852,6 @@ add_m6fc(mfccp)
                        mf6ctable[hash] = rt;
                }
        }
-       splx(s);
        return 0;
 }
 
@@ -947,11 +861,11 @@ add_m6fc(mfccp)
  */
 static void
 collate(t)
-       register struct timeval *t;
+       struct timeval *t;
 {
-       register u_long d;
-       register struct timeval tp;
-       register u_long delta;
+       u_int32_t d;
+       struct timeval tp;
+       u_int32_t delta;
 
        GET_TIME(tp);
 
@@ -979,8 +893,7 @@ del_m6fc(mfccp)
        struct sockaddr_in6     mcastgrp;
        struct mf6c             *rt;
        struct mf6c             **nptr;
-       u_long          hash;
-       int s;
+       u_int32_t               hash;
 
        origin = mfccp->mf6cc_origin;
        mcastgrp = mfccp->mf6cc_mcastgrp;
@@ -993,11 +906,6 @@ del_m6fc(mfccp)
                    ip6_sprintf(&mcastgrp.sin6_addr));
 #endif
 
-#if __NetBSD__
-       s = splsoftnet();
-#else
-       s = splnet();
-#endif
 
        nptr = &mf6ctable[hash];
        while ((rt = *nptr) != NULL) {
@@ -1011,14 +919,12 @@ del_m6fc(mfccp)
                nptr = &rt->mf6c_next;
        }
        if (rt == NULL) {
-               splx(s);
                return EADDRNOTAVAIL;
        }
 
        *nptr = rt->mf6c_next;
-       _FREE(rt, M_MRTABLE);
+       FREE(rt, M_MRTABLE);
 
-       splx(s);
 
        return 0;
 }
@@ -1029,15 +935,16 @@ socket_send(s, mm, src)
        struct mbuf *mm;
        struct sockaddr_in6 *src;
 {
+//### LD 5/27/04 needs locking!
+//
        if (s) {
                if (sbappendaddr(&s->so_rcv,
                                 (struct sockaddr *)src,
-                                mm, (struct mbuf *)0) != 0) {
+                                mm, (struct mbuf *)0, NULL) != 0) {
                        sorwakeup(s);
                        return 0;
                }
        }
-       m_freem(mm);
        return -1;
 }
 
@@ -1054,15 +961,15 @@ socket_send(s, mm, src)
 
 int
 ip6_mforward(ip6, ifp, m)
-       register struct ip6_hdr *ip6;
+       struct ip6_hdr *ip6;
        struct ifnet *ifp;
        struct mbuf *m;
 {
-       register struct mf6c *rt;
-       register struct mif6 *mifp;
-       register struct mbuf *mm;
-       int s;
+       struct mf6c *rt;
+       struct mif6 *mifp;
+       struct mbuf *mm;
        mifi_t mifi;
+       struct timeval timenow;
 
 #if MRT6DEBUG
        if (mrt6debug & DEBUG_FORWARD)
@@ -1080,19 +987,36 @@ ip6_mforward(ip6, ifp, m)
                return 0;
        ip6->ip6_hlim--;
 
+       /*
+        * Source address check: do not forward packets with unspecified
+        * source. It was discussed in July 2000, on ipngwg mailing list.
+        * This is rather more serious than unicast cases, because some
+        * MLD packets can be sent with the unspecified source address
+        * (although such packets must normally set 1 to the hop limit field).
+        */
+       getmicrotime(&timenow);
+       if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
+               ip6stat.ip6s_cantforward++;
+               if (ip6_log_time + ip6_log_interval < timenow.tv_sec) {
+                       ip6_log_time = timenow.tv_sec;
+                       log(LOG_DEBUG,
+                           "cannot forward "
+                           "from %s to %s nxt %d received on %s\n",
+                           ip6_sprintf(&ip6->ip6_src),
+                           ip6_sprintf(&ip6->ip6_dst),
+                           ip6->ip6_nxt,
+                           if_name(m->m_pkthdr.rcvif));
+               }
+               return 0;
+       }
+
        /*
         * Determine forwarding mifs from the forwarding cache table
         */
-#if __NetBSD__
-       s = splsoftnet();
-#else
-       s = splnet();
-#endif
        MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
 
        /* Entry exists, so forward if necessary */
        if (rt) {
-               splx(s);
                return (ip6_mdq(m, ifp, rt));
        } else {
                /*
@@ -1101,10 +1025,10 @@ ip6_mforward(ip6, ifp, m)
                 * send message to routing daemon
                 */
 
-               register struct mbuf *mb0;
-               register struct rtdetq *rte;
-               register u_long hash;
-/*     register int i, npkts;*/
+               struct mbuf *mb0;
+               struct rtdetq *rte;
+               u_int32_t hash;
+/*             int i, npkts;*/
 #if UPCALL_TIMING
                struct timeval tp;
 
@@ -1126,7 +1050,6 @@ ip6_mforward(ip6, ifp, m)
                rte = (struct rtdetq *)_MALLOC(sizeof(*rte), M_MRTABLE,
                                              M_NOWAIT);
                if (rte == NULL) {
-                       splx(s);
                        return ENOBUFS;
                }
                mb0 = m_copy(m, 0, M_COPYALL);
@@ -1138,8 +1061,7 @@ ip6_mforward(ip6, ifp, m)
                    (M_HASCL(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))
                        mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
                if (mb0 == NULL) {
-                       _FREE(rte, M_MRTABLE);
-                       splx(s);
+                       FREE(rte, M_MRTABLE);
                        return ENOBUFS;
                }
        
@@ -1156,14 +1078,16 @@ ip6_mforward(ip6, ifp, m)
 
                if (rt == NULL) {
                        struct mrt6msg *im;
+#if MRT6_OINIT
+                       struct omrt6msg *oim;
+#endif
 
                        /* no upcall, so make a new entry */
                        rt = (struct mf6c *)_MALLOC(sizeof(*rt), M_MRTABLE,
                                                  M_NOWAIT);
                        if (rt == NULL) {
-                               _FREE(rte, M_MRTABLE);
+                               FREE(rte, M_MRTABLE);
                                m_freem(mb0);
-                               splx(s);
                                return ENOBUFS;
                        }
                        /*
@@ -1173,10 +1097,9 @@ ip6_mforward(ip6, ifp, m)
                        mm = m_copy(mb0, 0, sizeof(struct ip6_hdr));
 
                        if (mm == NULL) {
-                               _FREE(rte, M_MRTABLE);
+                               FREE(rte, M_MRTABLE);
                                m_freem(mb0);
-                               _FREE(rt, M_MRTABLE);
-                               splx(s);
+                               FREE(rt, M_MRTABLE);
                                return ENOBUFS;
                        }
 
@@ -1185,9 +1108,29 @@ ip6_mforward(ip6, ifp, m)
                         */
                        sin6.sin6_addr = ip6->ip6_src;
        
-                       im = mtod(mm, struct mrt6msg *);
-                       im->im6_msgtype = MRT6MSG_NOCACHE;
-                       im->im6_mbz             = 0;
+                       im = NULL;
+#if MRT6_OINIT
+                       oim = NULL;
+#endif
+                       switch (ip6_mrouter_ver) {
+#if MRT6_OINIT
+                       case MRT6_OINIT:
+                               oim = mtod(mm, struct omrt6msg *);
+                               oim->im6_msgtype = MRT6MSG_NOCACHE;
+                               oim->im6_mbz = 0;
+                               break;
+#endif
+                       case MRT6_INIT:
+                               im = mtod(mm, struct mrt6msg *);
+                               im->im6_msgtype = MRT6MSG_NOCACHE;
+                               im->im6_mbz = 0;
+                               break;
+                       default:
+                               FREE(rte, M_MRTABLE);
+                               m_freem(mb0);
+                               FREE(rt, M_MRTABLE);
+                               return EINVAL;
+                       }
 
 #if MRT6DEBUG
                        if (mrt6debug & DEBUG_FORWARD)
@@ -1200,16 +1143,24 @@ ip6_mforward(ip6, ifp, m)
                             mifp++, mifi++)
                                ;
 
-                       im->im6_mif = mifi;
+                       switch (ip6_mrouter_ver) {
+#if MRT6_OINIT
+                       case MRT6_OINIT:
+                               oim->im6_mif = mifi;
+                               break;
+#endif
+                       case MRT6_INIT:
+                               im->im6_mif = mifi;
+                               break;
+                       }
 
                        if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
                                log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
                                    "socket queue full\n");
                                mrt6stat.mrt6s_upq_sockfull++;
-                               _FREE(rte, M_MRTABLE);
+                               FREE(rte, M_MRTABLE);
                                m_freem(mb0);
-                               _FREE(rt, M_MRTABLE);
-                               splx(s);
+                               FREE(rt, M_MRTABLE);
                                return ENOBUFS;
                        }
 
@@ -1224,7 +1175,7 @@ ip6_mforward(ip6, ifp, m)
                        rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
                        rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;
                        rt->mf6c_expire = UPCALL_EXPIRE;
-                       nexpire[hash]++;
+                       n6expire[hash]++;
                        rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;
 
                        /* link into table */
@@ -1235,14 +1186,13 @@ ip6_mforward(ip6, ifp, m)
                } else {
                        /* determine if q has overflowed */
                        struct rtdetq **p;
-                       register int npkts = 0;
+                       int npkts = 0;
 
                        for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
                                if (++npkts > MAX_UPQ6) {
                                        mrt6stat.mrt6s_upq_ovflw++;
-                                       _FREE(rte, M_MRTABLE);
+                                       FREE(rte, M_MRTABLE);
                                        m_freem(mb0);
-                                       splx(s);
                                        return 0;
                                }
 
@@ -1257,7 +1207,6 @@ ip6_mforward(ip6, ifp, m)
                rte->t = tp;
 #endif /* UPCALL_TIMING */
 
-               splx(s);
 
                return 0;
        }
@@ -1268,35 +1217,15 @@ ip6_mforward(ip6, ifp, m)
  * Call from the Slow Timeout mechanism, every half second.
  */
 static void
-expire_upcalls_funneled(unused)
-       void *unused;
-{
-#ifdef __APPLE__
-       boolean_t   funnel_state;
-       funnel_state = thread_funnel_set(network_flock, TRUE);
-#endif
-       expire_upcalls(unused);
-#ifdef __APPLE__
-        (void) thread_funnel_set(network_flock, FALSE);
-#endif
-}
-
-static void
-expire_upcalls(unused)
-       void *unused;
+expire_upcalls(
+       __unused void *unused)
 {
        struct rtdetq *rte;
        struct mf6c *mfc, **nptr;
        int i;
-       int s;
 
-#if __NetBSD__
-       s = splsoftnet();
-#else
-       s = splnet();
-#endif
        for (i = 0; i < MF6CTBLSIZ; i++) {
-               if (nexpire[i] == 0)
+               if (n6expire[i] == 0)
                        continue;
                nptr = &mf6ctable[i];
                while ((mfc = *nptr) != NULL) {
@@ -1322,24 +1251,21 @@ expire_upcalls(unused)
                                do {
                                        struct rtdetq *n = rte->next;
                                        m_freem(rte->m);
-                                       _FREE(rte, M_MRTABLE);
+                                       FREE(rte, M_MRTABLE);
                                        rte = n;
                                } while (rte != NULL);
                                mrt6stat.mrt6s_cache_cleanups++;
-                               nexpire[i]--;
+                               n6expire[i]--;
 
                                *nptr = mfc->mf6c_next;
-                               _FREE(mfc, M_MRTABLE);
+                               FREE(mfc, M_MRTABLE);
                        } else {
                                nptr = &mfc->mf6c_next;
                        }
                }
        }
-       splx(s);
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-       expire_upcalls_ch =
-#endif
-       timeout(expire_upcalls_funneled, (caddr_t)NULL, EXPIRE_TIMEOUT);
+
+       timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
 }
 
 /*
@@ -1347,27 +1273,30 @@ expire_upcalls(unused)
  */
 static int
 ip6_mdq(m, ifp, rt)
-       register struct mbuf *m;
-       register struct ifnet *ifp;
-       register struct mf6c *rt;
+       struct mbuf *m;
+       struct ifnet *ifp;
+       struct mf6c *rt;
 {
-       register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
-       register mifi_t mifi, iif;
-       register struct mif6 *mifp;
-       register int plen = m->m_pkthdr.len;
+       struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+       mifi_t mifi, iif;
+       struct mif6 *mifp;
+       int plen = m->m_pkthdr.len;
+       struct in6_addr src0, dst0; /* copies for local work */
+       u_int32_t iszone, idzone, oszone, odzone;
+       int error = 0;
 
 /*
  * Macro to send packet on mif.  Since RSVP packets don't get counted on
  * input, they shouldn't get counted on output, so statistics keeping is
- * seperate.
+ * separate.
  */
 
-#define MC6_SEND(ip6,mifp,m) {                                 \
-               if ((mifp)->m6_flags & MIFF_REGISTER)           \
-                   register_send((ip6), (mifp), (m));          \
-                else                                           \
-                    phyint_send((ip6), (mifp), (m));           \
-}
+#define MC6_SEND(ip6, mifp, m) do {                            \
+               if ((mifp)->m6_flags & MIFF_REGISTER)           \
+                   register_send((ip6), (mifp), (m));          \
+               else                                            \
+                   phyint_send((ip6), (mifp), (m));            \
+} while (0)
 
        /*
         * Don't forward if it didn't arrive from the parent mif
@@ -1390,55 +1319,83 @@ ip6_mdq(m, ifp, rt)
                 * packets on this interface, send a message to the
                 * routing daemon.
                 */
-               if(mifi < nummifs) /* have to make sure this is a valid mif */
-                       if(mif6table[mifi].m6_ifp)
-
-                               if (pim6 && (m->m_flags & M_LOOP) == 0) {
-                                       /*
-                                        * Check the M_LOOP flag to avoid an
-                                        * unnecessary PIM assert.
-                                        * XXX: M_LOOP is an ad-hoc hack...
-                                        */
-                                       static struct sockaddr_in6 sin6 =
-                                       { sizeof(sin6), AF_INET6 };
-
-                                       register struct mbuf *mm;
-                                       struct mrt6msg *im;
-
-                                       mm = m_copy(m, 0,
-                                                   sizeof(struct ip6_hdr));
-                                       if (mm &&
-                                           (M_HASCL(mm) ||
-                                            mm->m_len < sizeof(struct ip6_hdr)))
-                                               mm = m_pullup(mm, sizeof(struct ip6_hdr));
-                                       if (mm == NULL)
-                                               return ENOBUFS;
-               
+               /* have to make sure this is a valid mif */
+               if (mifi < nummifs && mif6table[mifi].m6_ifp)
+                       if (pim6 && (m->m_flags & M_LOOP) == 0) {
+                               /*
+                                * Check the M_LOOP flag to avoid an
+                                * unnecessary PIM assert.
+                                * XXX: M_LOOP is an ad-hoc hack...
+                                */
+                               static struct sockaddr_in6 addr =
+                               { sizeof(addr), AF_INET6 , 0, 0, IN6ADDR_ANY_INIT, 0};
+
+                               struct mbuf *mm;
+                               struct mrt6msg *im;
+#if MRT6_OINIT
+                               struct omrt6msg *oim;
+#endif
+
+                               mm = m_copy(m, 0, sizeof(struct ip6_hdr));
+                               if (mm &&
+                                   (M_HASCL(mm) ||
+                                    mm->m_len < sizeof(struct ip6_hdr)))
+                                       mm = m_pullup(mm, sizeof(struct ip6_hdr));
+                               if (mm == NULL)
+                                       return ENOBUFS;
+       
+#if MRT6_OINIT
+                               oim = NULL;
+#endif
+                               im = NULL;
+                               switch (ip6_mrouter_ver) {
+#if MRT6_OINIT
+                               case MRT6_OINIT:
+                                       oim = mtod(mm, struct omrt6msg *);
+                                       oim->im6_msgtype = MRT6MSG_WRONGMIF;
+                                       oim->im6_mbz = 0;
+                                       break;
+#endif
+                               case MRT6_INIT:
                                        im = mtod(mm, struct mrt6msg *);
-                                       im->im6_msgtype = MRT6MSG_WRONGMIF;
-                                       im->im6_mbz     = 0;
-
-                                       for (mifp = mif6table, iif = 0;
-                                            iif < nummifs && mifp &&
-                                                    mifp->m6_ifp != ifp;
-                                            mifp++, iif++);
-
-                                       im->im6_mif     = iif;
+                                       im->im6_msgtype = MRT6MSG_WRONGMIF;
+                                       im->im6_mbz = 0;
+                                       break;
+                               default:
+                                       m_freem(mm);
+                                       return EINVAL;
+                               }
 
-                                       sin6.sin6_addr = im->im6_src;
+                               for (mifp = mif6table, iif = 0;
+                                    iif < nummifs && mifp &&
+                                            mifp->m6_ifp != ifp;
+                                    mifp++, iif++)
+                                       ;
+
+                               switch (ip6_mrouter_ver) {
+#if MRT6_OINIT
+                               case MRT6_OINIT:
+                                       oim->im6_mif = iif;
+                                       addr.sin6_addr = oim->im6_src;
+                                       break;
+#endif
+                               case MRT6_INIT:
+                                       im->im6_mif = iif;
+                                       addr.sin6_addr = im->im6_src;
+                                       break;
+                               }
 
-                                       mrt6stat.mrt6s_upcalls++;
+                               mrt6stat.mrt6s_upcalls++;
 
-                                       if (socket_send(ip6_mrouter, mm,
-                                                       &sin6) < 0) {
+                               if (socket_send(ip6_mrouter, mm, &addr) < 0) {
 #if MRT6DEBUG
-                                               if (mrt6debug)
-                                                       log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
+                                       if (mrt6debug)
+                                               log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
 #endif
-                                               ++mrt6stat.mrt6s_upq_sockfull;
-                                               return ENOBUFS;
-                                       }       /* if socket Q full */
-                               }               /* if PIM */
+                                       ++mrt6stat.mrt6s_upq_sockfull;
+                                       return ENOBUFS;
+                               }       /* if socket Q full */
+                       }               /* if PIM */
                return 0;
        }                       /* if wrong iif */
 
@@ -1458,12 +1415,40 @@ ip6_mdq(m, ifp, rt)
         * For each mif, forward a copy of the packet if there are group
         * members downstream on the interface.
         */
-       for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++)
+       src0 = ip6->ip6_src;
+       dst0 = ip6->ip6_dst;
+       if ((error = in6_setscope(&src0, ifp, &iszone)) != 0 ||
+           (error = in6_setscope(&dst0, ifp, &idzone)) != 0) {
+               ip6stat.ip6s_badscope++;
+               return (error);
+       }
+       for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) {
                if (IF_ISSET(mifi, &rt->mf6c_ifset)) {
+                       /*
+                        * check if the outgoing packet is going to break
+                        * a scope boundary.
+                        * XXX For packets through PIM register tunnel
+                        * interface, we believe a routing daemon.
+                        */
+                       if (!(mif6table[rt->mf6c_parent].m6_flags &
+                             MIFF_REGISTER) &&
+                           !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
+                               if (in6_setscope(&src0, mif6table[mifi].m6_ifp,
+                                   &oszone) ||
+                                   in6_setscope(&dst0, mif6table[mifi].m6_ifp,
+                                   &odzone) ||
+                                   iszone != oszone ||
+                                   idzone != odzone) {
+                                       ip6stat.ip6s_badscope++;
+                                       continue;
+                               }
+                       }
+
                        mifp->m6_pkt_out++;
                        mifp->m6_bytes_out += plen;
                        MC6_SEND(ip6, mifp, m);
                }
+       }
        return 0;
 }
 
@@ -1473,16 +1458,12 @@ phyint_send(ip6, mifp, m)
     struct mif6 *mifp;
     struct mbuf *m;
 {
-       register struct mbuf *mb_copy;
+       struct mbuf *mb_copy;
        struct ifnet *ifp = mifp->m6_ifp;
        int error = 0;
-#if __NetBSD__
-       int s = splsoftnet();
-#else
-       int s = splnet();
-#endif
-       static struct route_in6 ro6;
+       static struct route_in6 ro;
        struct  in6_multi *in6m;
+       struct sockaddr_in6 *dst6;
 
        /*
         * Make a new reference to the packet; make sure that
@@ -1493,8 +1474,9 @@ phyint_send(ip6, mifp, m)
        if (mb_copy &&
            (M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
                mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
-       if (mb_copy == NULL)
+       if (mb_copy == NULL) {
                return;
+       }
        /* set MCAST flag to the outgoing packet */
        mb_copy->m_flags |= M_MCAST;
 
@@ -1506,21 +1488,27 @@ phyint_send(ip6, mifp, m)
         * sending queue.
         */
        if (m->m_pkthdr.rcvif == NULL) {
-               struct ip6_moptions im6o;
+               struct ip6_moptions *im6o;
+
+               im6o = ip6_allocmoptions(M_DONTWAIT);
+               if (im6o == NULL) {
+                       m_freem(mb_copy);
+                       return;
+               }
 
-               im6o.im6o_multicast_ifp = ifp;
+               im6o->im6o_multicast_ifp = ifp;
                /* XXX: ip6_output will override ip6->ip6_hlim */
-               im6o.im6o_multicast_hlim = ip6->ip6_hlim;
-               im6o.im6o_multicast_loop = 1;
-               error = ip6_output(mb_copy, NULL, &ro6,
-                                  IPV6_FORWARDING, &im6o, NULL);
+               im6o->im6o_multicast_hlim = ip6->ip6_hlim;
+               im6o->im6o_multicast_loop = 1;
+               error = ip6_output(mb_copy, NULL, &ro, IPV6_FORWARDING,
+                   im6o, NULL, NULL);
 
+               IM6O_REMREF(im6o);
 #if MRT6DEBUG
                if (mrt6debug & DEBUG_XMIT)
                        log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
                            mifp - mif6table, error);
 #endif
-               splx(s);
                return;
        }
 
@@ -1528,31 +1516,41 @@ phyint_send(ip6, mifp, m)
         * If we belong to the destination multicast group
         * on the outgoing interface, loop back a copy.
         */
+       dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
+       in6_multihead_lock_shared();
        IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
+       in6_multihead_lock_done();
        if (in6m != NULL) {
-               ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
-               ro6.ro_dst.sin6_family = AF_INET6;
-               ro6.ro_dst.sin6_addr = ip6->ip6_dst;
-               ip6_mloopback(ifp, m, &ro6.ro_dst);
+               IN6M_REMREF(in6m);
+               dst6->sin6_len = sizeof(struct sockaddr_in6);
+               dst6->sin6_family = AF_INET6;
+               dst6->sin6_addr = ip6->ip6_dst;
+               ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst);
        }
        /*
         * Put the packet into the sending queue of the outgoing interface
         * if it would fit in the MTU of the interface.
         */
-       if (mb_copy->m_pkthdr.len < ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {
-               ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
-               ro6.ro_dst.sin6_family = AF_INET6;
-               ro6.ro_dst.sin6_addr = ip6->ip6_dst;
+       if (mb_copy->m_pkthdr.len <= ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {
+               dst6->sin6_len = sizeof(struct sockaddr_in6);
+               dst6->sin6_family = AF_INET6;
+               dst6->sin6_addr = ip6->ip6_dst;
                /*
                 * We just call if_output instead of nd6_output here, since
                 * we need no ND for a multicast forwarded packet...right?
                 */
 #ifdef __APPLE__
-               error = dlil_output(ifptodlt(ifp, PF_INET6), mb_copy,
-                               NULL, (struct sockaddr *)&ro6.ro_dst, 0);
+               /* Make sure the HW checksum flags are cleaned before sending the packet */
+
+               mb_copy->m_pkthdr.rcvif = 0;
+               mb_copy->m_pkthdr.csum_data = 0;
+               mb_copy->m_pkthdr.csum_flags = 0;
+
+               error = dlil_output(ifp, PF_INET6, mb_copy,
+                               NULL, (struct sockaddr *)&ro.ro_dst, 0);
 #else
                error = (*ifp->if_output)(ifp, mb_copy,
-                                         (struct sockaddr *)&ro6.ro_dst,
+                                         (struct sockaddr *)&ro.ro_dst,
                                          NULL);
 #endif
 #if MRT6DEBUG
@@ -1560,48 +1558,42 @@ phyint_send(ip6, mifp, m)
                        log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
                            mifp - mif6table, error);
 #endif
-       }
-       else {
-#if MULTICAST_PMTUD
-               icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
-               return;
-#else
+       } else {
+               /*
+                * pMTU discovery is intentionally disabled by default, since
+                * various router may notify pMTU in multicast, which can be
+                * a DDoS to a router
+                */
+               if (ip6_mcast_pmtu)
+                       icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
 #if MRT6DEBUG
-#if __NetBSD__
-               if (mrt6debug & DEBUG_DEBUG_XMIT)
-                       log(LOG_DEBUG,
-                           "phyint_send: packet too big on %s o %s g %s"
-                           " size %d(discarded)\n",
-                           ifp->if_xname,
-                           ip6_sprintf(&ip6->ip6_src),
-                           ip6_sprintf(&ip6->ip6_dst),
-                           mb_copy->m_pkthdr.len);
-#else
-               if (mrt6debug & DEBUG_XMIT)
-                       log(LOG_DEBUG,
-                           "phyint_send: packet too big on %s%u o %s g %s"
-                           " size %d(discarded)\n",
-                           ifp->if_name, ifp->if_unit,
-                           ip6_sprintf(&ip6->ip6_src),
-                           ip6_sprintf(&ip6->ip6_dst),
-                           mb_copy->m_pkthdr.len);
-#endif /* __NetBSD__ */
+               else {
+                       if (mrt6debug & DEBUG_XMIT) {
+                               log(LOG_DEBUG,
+                                   "phyint_send: packet too big on %s o %s "
+                                   "g %s size %d(discarded)\n",
+                                   if_name(ifp),
+                                   ip6_sprintf(&ip6->ip6_src),
+                                   ip6_sprintf(&ip6->ip6_dst),
+                                   mb_copy->m_pkthdr.len);
+                       }
+               }
 #endif /* MRT6DEBUG */
                m_freem(mb_copy); /* simply discard the packet */
-               return;
-#endif
+               
        }
 }
 
 static int
 register_send(ip6, mif, m)
-       register struct ip6_hdr *ip6;
+       struct ip6_hdr *ip6;
        struct mif6 *mif;
-       register struct mbuf *m;
+       struct mbuf *m;
 {
-       register struct mbuf *mm;
-       register int i, len = m->m_pkthdr.len;
-       static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
+       struct mbuf *mm;
+       int i, len = m->m_pkthdr.len;
+       static struct sockaddr_in6 addr = { sizeof(addr), AF_INET6 ,
+                                     0, 0, IN6ADDR_ANY_INIT, 0};
        struct mrt6msg *im6;
 
 #if MRT6DEBUG
@@ -1615,6 +1607,12 @@ register_send(ip6, mif, m)
        MGETHDR(mm, M_DONTWAIT, MT_HEADER);
        if (mm == NULL)
                return ENOBUFS;
+#ifdef __darwin8_notyet
+#if CONFIG_MACF_NET
+       mac_create_mbuf_multicast_encap(m, mif->m6_ifp, mm);
+#endif
+#endif
+       mm->m_pkthdr.rcvif = NULL;
        mm->m_data += max_linkhdr;
        mm->m_len = sizeof(struct ip6_hdr);
 
@@ -1636,7 +1634,7 @@ register_send(ip6, mif, m)
        /*
         * Send message to routing daemon
         */
-       sin6.sin6_addr = ip6->ip6_src;
+       addr.sin6_addr = ip6->ip6_src;
 
        im6 = mtod(mm, struct mrt6msg *);
        im6->im6_msgtype      = MRT6MSG_WHOLEPKT;
@@ -1647,14 +1645,14 @@ register_send(ip6, mif, m)
        /* iif info is not given for reg. encap.n */
        mrt6stat.mrt6s_upcalls++;
 
-       if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
+       if (socket_send(ip6_mrouter, mm, &addr) < 0) {
 #if MRT6DEBUG
                if (mrt6debug)
                        log(LOG_WARNING,
-                           "register_send: ip_mrouter socket queue full\n");
+                           "register_send: ip6_mrouter socket queue full\n");
 #endif
-                ++mrt6stat.mrt6s_upq_sockfull;
-                return ENOBUFS;
+               ++mrt6stat.mrt6s_upq_sockfull;
+               return ENOBUFS;
        }
        return 0;
 }
@@ -1667,25 +1665,23 @@ register_send(ip6, mif, m)
  * is stripped off, and the inner packet is passed to register_mforward.
  */
 int
-pim6_input(mp, offp, proto)
-       struct mbuf **mp;
-       int *offp, proto;
+pim6_input(struct mbuf **mp, int *offp, int proto)
 {
-        register struct pim *pim; /* pointer to a pim struct */
-        register struct ip6_hdr *ip6;
-        register int pimlen;
+       struct pim *pim; /* pointer to a pim struct */
+       struct ip6_hdr *ip6;
+       int pimlen;
        struct mbuf *m = *mp;
-        int minlen;
+       int minlen;
        int off = *offp;
 
        ++pim6stat.pim6s_rcv_total;
 
-        ip6 = mtod(m, struct ip6_hdr *);
-        pimlen = m->m_pkthdr.len - *offp;
+       ip6 = mtod(m, struct ip6_hdr *);
+       pimlen = m->m_pkthdr.len - *offp;
 
-        /*
-         * Validate lengths
-         */
+       /*
+        * Validate lengths
+        */
        if (pimlen < PIM_MINLEN) {
                ++pim6stat.pim6s_rcv_tooshort;
 #if MRT6DEBUG
@@ -1711,7 +1707,7 @@ pim6_input(mp, offp, proto)
         * possibly the PIM REGISTER header
         */
 #ifndef PULLDOWN_TEST
-       IP6_EXTHDR_CHECK(m, off, minlen, IPPROTO_DONE);
+       IP6_EXTHDR_CHECK(m, off, minlen, return IPPROTO_DONE);
        /* adjust pointer */
        ip6 = mtod(m, struct ip6_hdr *);
 
@@ -1725,9 +1721,8 @@ pim6_input(mp, offp, proto)
        }
 #endif
 
-
-#define PIM6_CHECKSUM 1
-#if PIM6_CHECKSUM
+#define PIM6_CHECKSUM
+#ifdef PIM6_CHECKSUM
        {
                int cksumlen;
 
@@ -1771,12 +1766,12 @@ pim6_input(mp, offp, proto)
                 * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the
                 * routing daemon.
                 */
-               static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 };
+               static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 , 
+                                                                                       0, 0, IN6ADDR_ANY_INIT, 0 };
 
                struct mbuf *mcp;
                struct ip6_hdr *eip6;
                u_int32_t *reghdr;
-               int rc;
        
                ++pim6stat.pim6s_rcv_registers;
 
@@ -1822,6 +1817,18 @@ pim6_input(mp, offp, proto)
                            ip6_sprintf(&eip6->ip6_dst),
                            ntohs(eip6->ip6_plen));
 #endif
+
+               /* verify the version number of the inner packet */
+               if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
+                       ++pim6stat.pim6s_rcv_badregisters;
+#if MRT6DEBUG
+                       log(LOG_DEBUG, "pim6_input: invalid IP version (%d) "
+                           "of the inner packet\n",
+                           (eip6->ip6_vfc & IPV6_VERSION));
+#endif
+                       m_freem(m);
+                       return(IPPROTO_NONE);
+               }
        
                /* verify the inner packet is destined to a mcast group */
                if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
@@ -1866,25 +1873,18 @@ pim6_input(mp, offp, proto)
                }
 #endif
 
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-               rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m,
-                             (struct sockaddr *) &dst, NULL);
-#else
-#if defined (__APPLE__)
-                if (lo_dl_tag == 0)
-                    dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET6, &lo_dl_tag);
-                if (lo_dl_tag)
-                    dlil_output(lo_dl_tag, m, 0, (struct sockaddr *) &dst, 0);
+#ifdef __APPLE__
+
+                if (lo_ifp) {
+                    dlil_output(lo_ifp, PF_INET6, m, 0, (struct sockaddr *)&dst, 0);
+               }
                 else {
                     printf("Warning: pim6_input call to dlil_find_dltag failed!\n");
                     m_freem(m);
                 }
 #else
-               rc = looutput(mif6table[reg_mif_num].m6_ifp, m,
-                             (struct sockaddr *) &dst,
-                             (struct rtentry *) NULL);
-#endif
+               (void) if_simloop(mif6table[reg_mif_num].m6_ifp, m,
+                               dst.sin6_family, NULL);
 #endif
        
                /* prepare the register head to send to the mrouting daemon */
@@ -1898,6 +1898,7 @@ pim6_input(mp, offp, proto)
         * encapsulated ip6 header.
         */
   pim6_input_to_daemon:
-       rip6_input(&m, offp, proto);
+       rip6_input(&m, offp);
        return(IPPROTO_DONE);
 }
+#endif