]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/in6_prefix.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_prefix.c
index a1afb0124a385625a030d68e22c8d51938368bea..891917965d4b9033086be6ccb898fe5ef5a62104 100644 (file)
@@ -1,3 +1,31 @@
+/*
+ * Copyright (c) 2008 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@
+ */
+
 /*     $KAME: in6_prefix.c,v 1.27 2000/03/29 23:13:13 itojun Exp $     */
 
 /*
@@ -65,9 +93,6 @@
  */
 
 #include <sys/param.h>
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
-#include <sys/ioctl.h>
-#endif
 #include <sys/malloc.h>
 #include <sys/kernel.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/systm.h>
 #include <sys/syslog.h>
-#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
 #include <sys/proc.h>
-#endif
 
 #include <net/if.h>
 
 #include <netinet6/in6_prefix.h>
 #include <netinet6/ip6_var.h>
 
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
-static MALLOC_DEFINE(M_IPFW, "ip6rr", "IPv6 Router Renumbering Prefix");
-static MALLOC_DEFINE(M_IPFW, "rp_addr", "IPv6 Router Renumbering Ifid");
+#ifdef __APPLE__
+#define M_IP6RR        M_IP6MISC
+#define M_RR_ADDR      M_IP6MISC
+#else
+static MALLOC_DEFINE(M_IP6RR, "ip6rr", "IPv6 Router Renumbering Prefix");
+static MALLOC_DEFINE(M_RR_ADDR, "rp_addr", "IPv6 Router Renumbering Ifid");
 #endif
 
 struct rr_prhead rr_prefix;
 
 #include <net/net_osdep.h>
 
-static void    add_each_addr __P((struct socket *so, struct rr_prefix *rpp,
-                                  struct rp_addr *rap));
-static int create_ra_entry __P((struct rp_addr **rapp));
-static int add_each_prefix __P((struct socket *so, struct rr_prefix *rpp));
-static void free_rp_entries __P((struct rr_prefix *rpp));
-static int link_stray_ia6s __P((struct rr_prefix *rpp));
-static void    rp_remove __P((struct rr_prefix *rpp));
+static void    add_each_addr(struct socket *so, struct rr_prefix *rpp,
+                                  struct rp_addr *rap);
+static int create_ra_entry(struct rp_addr **rapp);
+static int add_each_prefix(struct socket *so, struct rr_prefix *rpp);
+static void free_rp_entries(struct rr_prefix *rpp);
+static int link_stray_ia6s(struct rr_prefix *rpp);
+static void    rp_remove(struct rr_prefix *rpp);
+extern lck_mtx_t *prefix6_mutex;
 
 /*
  * Copy bits from src to tgt, from off bit for len bits.
@@ -160,16 +187,21 @@ in6_prefixwithifp(struct ifnet *ifp, int plen, struct in6_addr *dst)
        struct ifprefix *ifpr;
 
        /* search matched prefix */
-       for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) {
+       ifnet_lock_shared(ifp);
+       for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
+            ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+       {
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
                if (plen <= in6_matchlen(dst, IFPR_IN6(ifpr)))
                        break;
        }
+       ifnet_lock_done(ifp);
        return (ifpr);
 }
 
+#if 0
 /*
  * Search prefix which matches arg prefix as specified in
  * draft-ietf-ipngwg-router-renum-08.txt
@@ -192,11 +224,8 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
         * which matches the addr
         */
 
-#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
-       for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
-#else
-       for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
-#endif
+       ifnet_lock_shared(ifp);
+       TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
        {
                if (ifa->ifa_addr->sa_family != AF_INET6)
                        continue;
@@ -204,14 +233,20 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
                    in6_matchlen(&ipr->ipr_prefix.sin6_addr, IFA_IN6(ifa)))
                        break;
        }
-       if (ifa == NULL)
+       if (ifa == NULL) {
+               ifnet_lock_done(ifp);
                return NULL;
+       }
 
        rpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr);
-       if (rpp != 0)
+       if (rpp != 0) {
+               ifnet_lock_done(ifp);
                return rpp;
-
-       for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) {
+       }
+       
+       for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
+            ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+       {
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
@@ -219,6 +254,7 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
                                                    IFPR_IN6(ifpr)))
                        break;
        }
+       ifnet_lock_done(ifp);
        if (ifpr != NULL)
                log(LOG_ERR,  "in6_prefix.c: search_matched_prefix: addr %s"
                    "has no pointer to prefix %s\n", ip6_sprintf(IFA_IN6(ifa)),
@@ -232,14 +268,17 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
  * Return 1 if anything matched, and 0 if nothing matched.
  */
 static int
-mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
+mark_matched_prefixes(u_int32_t cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
 {
        struct ifprefix *ifpr;
        struct ifaddr *ifa;
        int matchlen, matched = 0;
 
        /* search matched prefixes */
-       for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) {
+       ifnet_lock_exclusive(ifp);      /* Should if_prefixhead be protected by IPv6?? */
+       for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
+            ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+       {
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
@@ -259,11 +298,7 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
         * search matched addr, and then search prefixes
         * which matche the addr
         */
-#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
-       for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
-#else
-       for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
-#endif
+       TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
        {
                struct rr_prefix *rpp;
 
@@ -286,6 +321,7 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
                            "ND autoconfigured addr?\n",
                            ip6_sprintf(IFA_IN6(ifa)));
        }
+       ifnet_lock_done(ifp);
        return matched;
 }
 
@@ -293,12 +329,15 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
  * Mark global prefixes as to be deleted.
  */
 static void
-delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr)
+delmark_global_prefixes(struct ifnet *ifp, __unused struct in6_rrenumreq *irr)
 {
        struct ifprefix *ifpr;
 
        /* search matched prefixes */
-       for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) {
+       ifnet_lock_exclusive(ifp);
+       for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
+            ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+       {
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
@@ -307,6 +346,7 @@ delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr)
                    IPV6_ADDR_SCOPE_GLOBAL)
                        ifpr2rp(ifpr)->rp_statef_delmark = 1;
        }
+       ifnet_lock_done(ifp);
 }
 
 /* Unmark prefixes */
@@ -316,7 +356,10 @@ unmark_prefixes(struct ifnet *ifp)
        struct ifprefix *ifpr;
 
        /* unmark all prefix */
-       for (ifpr = ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) {
+       ifnet_lock_exclusive(ifp);
+       for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
+            ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+       {
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
@@ -324,25 +367,27 @@ unmark_prefixes(struct ifnet *ifp)
                ifpr2rp(ifpr)->rp_statef_addmark = 0;
                ifpr2rp(ifpr)->rp_statef_delmark = 0;
        }
+       ifnet_lock_done(ifp);
 }
+#endif
 
 static void
 init_prefix_ltimes(struct rr_prefix *rpp)
 {
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined (__APPLE__)
-       long time_second = time.tv_sec;
-#endif
+       struct timeval timenow;
+
+       getmicrotime(&timenow);
 
        if (rpp->rp_pltime == RR_INFINITE_LIFETIME ||
            rpp->rp_rrf_decrprefd == 0)
                rpp->rp_preferred = 0;
        else
-               rpp->rp_preferred = time_second + rpp->rp_pltime;
+               rpp->rp_preferred = timenow.tv_sec + rpp->rp_pltime;
        if (rpp->rp_vltime == RR_INFINITE_LIFETIME ||
            rpp->rp_rrf_decrvalid == 0)
                rpp->rp_expire = 0;
        else
-               rpp->rp_expire = time_second + rpp->rp_vltime;
+               rpp->rp_expire = timenow.tv_sec + rpp->rp_vltime;
 }
 
 static int
@@ -380,21 +425,23 @@ search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid)
 {
        struct rp_addr *rap;
 
-       for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
-            rap = rap->ra_entry.le_next)
+       lck_mtx_lock(prefix6_mutex);
+       LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
+       {
                if (rr_are_ifid_equal(ifid, &rap->ra_ifid,
                                      (sizeof(struct in6_addr) << 3) -
                                      rpp->rp_plen))
                        break;
+       }
+       lck_mtx_unlock(prefix6_mutex);
        return rap;
 }
 
 static int
-assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
+assign_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
 {
        int error = 0;
        struct rp_addr *rap;
-       int s;
 
        if ((error = create_ra_entry(&rap)) != 0)
                return error;
@@ -405,24 +452,28 @@ assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
                 sizeof(*IA6_IN6(ia)) << 3, rpp->rp_plen, iilen);
        /* link to ia, and put into list */
        rap->ra_addr = ia;
-       rap->ra_addr->ia_ifa.ifa_refcnt++;
+       ifaref(&rap->ra_addr->ia_ifa);
 #if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */
        ia->ia6_ifpr = rp2ifpr(rpp);
 #endif
-       s = splnet();
+       lck_mtx_lock(prefix6_mutex);
        LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
-       splx(s);
+       lck_mtx_unlock(prefix6_mutex);
 
        return 0;
 }
 
+/*
+ * add a link-local address to an interface.  we will add new interface address
+ * (prefix database + new interface id).
+ */
 static int
-in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia)
+in6_prefix_add_llifid(__unused int iilen, struct in6_ifaddr *ia)
 {
        struct rr_prefix *rpp;
        struct rp_addr *rap;
        struct socket so;
-       int error, s;
+       int error;
 
        if ((error = create_ra_entry(&rap)) != 0)
                return(error);
@@ -433,21 +484,26 @@ in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia)
        /* XXX: init dummy so */
        bzero(&so, sizeof(so));
        /* insert into list */
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
+       lck_mtx_lock(prefix6_mutex);
        LIST_FOREACH(rpp, &rr_prefix, rp_entry)
-#else
-       for (rpp = LIST_FIRST(&rr_prefix); rpp; rpp = LIST_NEXT(rpp, rp_entry))
-#endif
        {
-               s = splnet();
+               /*
+                * do not attempt to add an address, if ifp does not match
+                */
+               if (rpp->rp_ifp != ia->ia_ifp)
+                       continue;
+
                LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
-               splx(s);
                add_each_addr(&so, rpp, rap);
        }
+       lck_mtx_unlock(prefix6_mutex);
        return 0;
 }
 
-
+/*
+ * add an address to an interface.  if the interface id portion is new,
+ * we will add new interface address (prefix database + new interface id).
+ */
 int
 in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
 {
@@ -462,7 +518,7 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
        if (ifpr == NULL) {
                struct rr_prefix rp;
                struct socket so;
-               int pplen = (plen == 128) ? 64 : plen;
+               int pplen = (plen == 128) ? 64 : plen; /* XXX hardcoded 64 is bad */
 
                /* allocate a prefix for ia, with default properties */
 
@@ -493,9 +549,6 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
 
                /* XXX: init dummy so */
                bzero(&so, sizeof(so));
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__NetBSD__)
-               so.so_state |= SS_PRIV;
-#endif
 
                error = add_each_prefix(&so, &rp);
 
@@ -514,11 +567,11 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
        if (rap != NULL) {
                if (rap->ra_addr == NULL) {
                        rap->ra_addr = ia;
-                       rap->ra_addr->ia_ifa.ifa_refcnt++;
+                       ifaref(&rap->ra_addr->ia_ifa);
                } else if (rap->ra_addr != ia) {
                        /* There may be some inconsistencies between addrs. */
                        log(LOG_ERR, "ip6_prefix.c: addr %s/%d matched prefix"
-                           "has already another ia %x(%s) on its ifid list\n",
+                           " already has another ia %p(%s) on its ifid list\n",
                            ip6_sprintf(IA6_IN6(ia)), plen,
                            rap->ra_addr,
                            ip6_sprintf(IA6_IN6(rap->ra_addr)));
@@ -527,14 +580,14 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
                ia->ia6_ifpr = ifpr;
                return 0;
        }
-       error = assigne_ra_entry(ifpr2rp(ifpr), iilen, ia);
+       error = assign_ra_entry(ifpr2rp(ifpr), iilen, ia);
        if (error == 0)
                ia->ia6_ifpr = ifpr;
        return (error);
 }
 
 void
-in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia)
+in6_prefix_remove_ifid(__unused int iilen, struct in6_ifaddr *ia)
 {
        struct rp_addr *rap;
 
@@ -542,46 +595,36 @@ in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia)
                return;
        rap = search_ifidwithprefix(ifpr2rp(ia->ia6_ifpr), IA6_IN6(ia));
        if (rap != NULL) {
-               int s = splnet();
+               lck_mtx_lock(prefix6_mutex);
                LIST_REMOVE(rap, ra_entry);
-               splx(s);
+               lck_mtx_unlock(prefix6_mutex);
                if (rap->ra_addr)
-                       IFAFREE(&rap->ra_addr->ia_ifa);
-               _FREE(rap, M_IPFW);
+                       ifafree(&rap->ra_addr->ia_ifa);
+               FREE(rap, M_RR_ADDR);
        }
 
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
        if (LIST_EMPTY(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead))
-#else
-       if (LIST_FIRST(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead) == NULL)
-#endif
                rp_remove(ifpr2rp(ia->ia6_ifpr));
 }
 
 void
-in6_purgeprefix(ifp)
-       struct ifnet *ifp;
+in6_purgeprefix(
+       struct ifnet *ifp)
 {
        struct ifprefix *ifpr, *nextifpr;
 
        /* delete prefixes before ifnet goes away */
-#if defined(__FreeBSD__) && __FreeBSD__ >= 4
+       ifnet_lock_exclusive(ifp);
        for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
             ifpr = nextifpr)
-#else
-       for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr)
-#endif
        {
-#if defined(__FreeBSD__) && __FreeBSD__ >= 4
                nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
-#else
-               nextifpr = ifpr->ifpr_next;
-#endif
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
                (void)delete_each_prefix(ifpr2rp(ifpr), PR_ORIG_KERNEL);
        }
+       ifnet_lock_done(ifp);
 }
 
 static void
@@ -589,7 +632,8 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
 {
        struct in6_ifaddr *ia6;
        struct in6_aliasreq ifra;
-       int error;
+       struct proc *p = current_proc();
+       int error, p64 = proc_is64bit(p);
 
        /* init ifra */
        bzero(&ifra, sizeof(ifra));
@@ -611,20 +655,30 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
        in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, rpp->rp_plen);
        /* don't care ifra_flags for now */
 
+       /*
+        * XXX: if we did this with finite lifetime values, the lifetimes would
+        *      decrese in time and never incremented.
+        *      we should need more clarifications on the prefix mechanism...
+        */
+       ifra.ifra_lifetime.ia6t_vltime = rpp->rp_vltime;
+       ifra.ifra_lifetime.ia6t_pltime = rpp->rp_pltime;
+
        ia6 = in6ifa_ifpwithaddr(rpp->rp_ifp, &ifra.ifra_addr.sin6_addr);
        if (ia6 != NULL) {
                if (ia6->ia6_ifpr == NULL) {
                        /* link this addr and the prefix each other */
-                       IFAFREE(&rap->ra_addr->ia_ifa);
+                       if (rap->ra_addr)
+                               ifafree(&rap->ra_addr->ia_ifa);
+                       /* Reference held in in6ifa_ifpwithaddr() */
                        rap->ra_addr = ia6;
-                       rap->ra_addr->ia_ifa.ifa_refcnt++;
                        ia6->ia6_ifpr = rp2ifpr(rpp);
                        return;
                }
                if (ia6->ia6_ifpr == rp2ifpr(rpp)) {
-                       IFAFREE(&rap->ra_addr->ia_ifa);
+                       if (rap->ra_addr)
+                               ifafree(&rap->ra_addr->ia_ifa);
+                       /* Reference held in in6ifa_ifpwithaddr() */
                        rap->ra_addr = ia6;
-                       rap->ra_addr->ia_ifa.ifa_refcnt++;
                        return;
                }
                /*
@@ -637,27 +691,56 @@ add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
                 *      Or, completely duplicated prefixes?
                 * log it and return.
                 */
-               log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr"
-                   "%s/%d failed because there is already another addr %s/%d\n",
+               log(LOG_ERR,
+                   "in6_prefix.c: add_each_addr: addition of an addr %s/%d "
+                   "failed because there is already another addr %s/%d\n",
                    ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
                    ip6_sprintf(IA6_IN6(ia6)),
-                   in6_mask2len(&ia6->ia_prefixmask.sin6_addr));
+                   in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL));
+               ifafree(&ia6->ia_ifa);
                return;
        }
        /* propagate ANYCAST flag if it is set for ancestor addr */
        if (rap->ra_flags.anycast != 0)
                ifra.ifra_flags |= IN6_IFF_ANYCAST;
-       error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp
-#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined(__APPLE__)
-                           , current_proc()
-#endif
-                           );
-       if (error != 0)
+
+       if (!p64) {
+#if defined(__LP64__)
+               struct in6_aliasreq_32 ifra_32;
+               /*
+                * Use 32-bit ioctl and structure for 32-bit process.
+                */
+               in6_aliasreq_64_to_32((struct in6_aliasreq_64 *)&ifra,
+                   &ifra_32);
+               error = in6_control(so, SIOCAIFADDR_IN6_32, (caddr_t)&ifra_32,
+                   rpp->rp_ifp, p);
+#else
+               error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra,
+                   rpp->rp_ifp, p);
+#endif /* __LP64__ */
+       } else {
+#if defined(__LP64__)
+               error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra,
+                   rpp->rp_ifp, p);
+#else
+               struct in6_aliasreq_64 ifra_64;
+               /*
+                * Use 32-bit ioctl and structure for 32-bit process.
+                */
+               in6_aliasreq_32_to_64((struct in6_aliasreq_32 *)&ifra,
+                   &ifra_64);
+               error = in6_control(so, SIOCAIFADDR_IN6_64, (caddr_t)&ifra_64,
+                   rpp->rp_ifp, p);
+#endif /* __LP64__ */
+       }
+
+       if (error != 0) {
                log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr"
                    "%s/%d failed because in6_control failed for error %d\n",
                    ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
                    error);
                return;
+       }
 
        /*
         * link beween this addr and the prefix will be done
@@ -671,10 +754,12 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
        struct rr_prefix *rpp;
        struct ifprefix *ifpr;
        struct rp_addr *rap;
-       int s;
 
        /* search existing prefix */
-       for (ifpr = new->rp_ifp->if_prefixlist; ifpr; ifpr = ifpr->ifpr_next) {
+       ifnet_lock_exclusive(new->rp_ifp);
+       for (ifpr = TAILQ_FIRST(&new->rp_ifp->if_prefixhead); ifpr;
+            ifpr = TAILQ_NEXT(ifpr, ifpr_list))
+       {
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
@@ -692,8 +777,10 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
                 * If the origin of the already-installed prefix is more
                 * preferable than the new one, ignore installation request.
                 */
-               if (rpp->rp_origin > new->rp_origin)
+               if (rpp->rp_origin > new->rp_origin) {
+                       ifnet_lock_done(new->rp_ifp);
                        return(EPERM);
+               }
 
                /* update prefix information */
                rpp->rp_flags.prf_ra = new->rp_flags.prf_ra;
@@ -709,73 +796,70 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
                 *  add rp_addr entries in new into rpp, if they have not
                 *  been already included in rpp.
                 */
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__)
+               lck_mtx_lock(prefix6_mutex);
                while (!LIST_EMPTY(&new->rp_addrhead))
-#else
-               while (new->rp_addrhead.lh_first != NULL)
-#endif
                {
                        rap = LIST_FIRST(&new->rp_addrhead);
                        LIST_REMOVE(rap, ra_entry);
                        if (search_ifidwithprefix(rpp, &rap->ra_ifid)
                            != NULL) {
                                if (rap->ra_addr)
-                                       IFAFREE(&rap->ra_addr->ia_ifa);
-                               _FREE(rap, M_IPFW);
+                                       ifafree(&rap->ra_addr->ia_ifa);
+                               FREE(rap, M_RR_ADDR);
                                continue;
                        }
-                       s = splnet();
                        LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
-                       splx(s);
                }
+               lck_mtx_unlock(prefix6_mutex);
        } else {
                /*
                 * We got a fresh prefix.
                 */
                /* create new prefix */
-               rpp = (struct rr_prefix *)_MALLOC(sizeof(*rpp), M_IPFW,
+               rpp = (struct rr_prefix *)_MALLOC(sizeof(*rpp), M_IP6RR,
                                                 M_NOWAIT);
                if (rpp == NULL) {
                        log(LOG_ERR, "in6_prefix.c: rrpr_update:%d"
                            ": ENOBUFS for rr_prefix\n", __LINE__);
+                       ifnet_lock_done(new->rp_ifp);
                        return(ENOBUFS);
                }
                /* initilization */
+               lck_mtx_lock(prefix6_mutex);
                *rpp = *new;
                LIST_INIT(&rpp->rp_addrhead);
                /*  move rp_addr entries of new to rpp */
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__)
                while (!LIST_EMPTY(&new->rp_addrhead))
-#else
-               while (new->rp_addrhead.lh_first != NULL)
-#endif
                {
                        rap = LIST_FIRST(&new->rp_addrhead);
                        LIST_REMOVE(rap, ra_entry);
                        LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
                }
+               lck_mtx_unlock(prefix6_mutex);
 
                /* let rp_ifpr.ifpr_prefix point rr_prefix. */
                rpp->rp_ifpr.ifpr_prefix = (struct sockaddr *)&rpp->rp_prefix;
                /* link rr_prefix entry to if_prefixlist */
                {
                        struct ifnet *ifp = rpp->rp_ifp;
-                       struct ifprefix *ifpr;
 
-                       if ((ifpr = ifp->if_prefixlist) != NULL) {
-                               for ( ; ifpr->ifpr_next;
-                                     ifpr = ifpr->ifpr_next)
+                       if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead))
+                           != NULL) {
+                               for ( ; TAILQ_NEXT(ifpr, ifpr_list);
+                                     ifpr = TAILQ_NEXT(ifpr, ifpr_list))
                                        continue;
-                               ifpr->ifpr_next = rp2ifpr(rpp);
+                               TAILQ_NEXT(ifpr, ifpr_list) = rp2ifpr(rpp);
                        } else
-                               ifp->if_prefixlist = rp2ifpr(rpp);
+                               TAILQ_FIRST(&ifp->if_prefixhead) =
+                                       rp2ifpr(rpp);
                        rp2ifpr(rpp)->ifpr_type = IN6_PREFIX_RR;
                }
                /* link rr_prefix entry to rr_prefix list */
-               s = splnet();
+               lck_mtx_lock(prefix6_mutex);
                LIST_INSERT_HEAD(&rr_prefix, rpp, rp_entry);
-               splx(s);
+               lck_mtx_unlock(prefix6_mutex);
        }
+       ifnet_lock_done(new->rp_ifp);
 
        if (!new->rp_raf_auto)
                return 0;
@@ -785,8 +869,9 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
         * If it existed but not pointing to the prefix yet,
         * init the prefix pointer.
         */
-       for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
-            rap = rap->ra_entry.le_next) {
+       lck_mtx_lock(prefix6_mutex);
+       LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
+       {
                if (rap->ra_addr != NULL) {
                        if (rap->ra_addr->ia6_ifpr == NULL)
                                rap->ra_addr->ia6_ifpr = rp2ifpr(rpp);
@@ -794,6 +879,7 @@ rrpr_update(struct socket *so, struct rr_prefix *new)
                }
                add_each_addr(so, rpp, rap);
        }
+       lck_mtx_unlock(prefix6_mutex);
        return 0;
 }
 
@@ -807,39 +893,42 @@ add_each_prefix(struct socket *so, struct rr_prefix *rpp)
 static void
 rp_remove(struct rr_prefix *rpp)
 {
-       int s;
 
-       s = splnet();
        /* unlink rp_entry from if_prefixlist */
+       lck_mtx_lock(prefix6_mutex);
        {
                struct ifnet *ifp = rpp->rp_ifp;
                struct ifprefix *ifpr;
 
-               if ((ifpr = ifp->if_prefixlist) == rp2ifpr(rpp))
-                       ifp->if_prefixlist = ifpr->ifpr_next;
+               ifnet_lock_exclusive(ifp);
+               if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead)) == rp2ifpr(rpp))
+                       TAILQ_FIRST(&ifp->if_prefixhead) =
+                               TAILQ_NEXT(ifpr, ifpr_list);
                else {
-                       while (ifpr->ifpr_next &&
-                              (ifpr->ifpr_next != rp2ifpr(rpp)))
-                               ifpr = ifpr->ifpr_next;
-                       if (ifpr->ifpr_next)
-                               ifpr->ifpr_next = rp2ifpr(rpp)->ifpr_next;
-                       else
-                               printf("Couldn't unlink rr_prefix from ifp\n");
+                       while (TAILQ_NEXT(ifpr, ifpr_list) != NULL &&
+                              (TAILQ_NEXT(ifpr, ifpr_list) != rp2ifpr(rpp)))
+                               ifpr = TAILQ_NEXT(ifpr, ifpr_list);
+                       if (TAILQ_NEXT(ifpr, ifpr_list))
+                               TAILQ_NEXT(ifpr, ifpr_list) =
+                                       TAILQ_NEXT(rp2ifpr(rpp), ifpr_list);
+                       else
+                               printf("Couldn't unlink rr_prefix from ifp\n");
                }
+               ifnet_lock_done(ifp);
        }
        /* unlink rp_entry from rr_prefix list */
        LIST_REMOVE(rpp, rp_entry);
-       splx(s);
-       _FREE(rpp, M_IPFW);
+       lck_mtx_unlock(prefix6_mutex);
+       FREE(rpp, M_IP6RR);
 }
 
 static int
 create_ra_entry(struct rp_addr **rapp)
 {
-       *rapp = (struct rp_addr *)_MALLOC(sizeof(struct rp_addr), M_IPFW,
+       *rapp = (struct rp_addr *)_MALLOC(sizeof(struct rp_addr), M_RR_ADDR,
                                         M_NOWAIT);
        if (*rapp == NULL) {
-               log(LOG_ERR, "in6_prefix.c: init_newprefix:%d: ENOBUFS"
+               log(LOG_ERR, "in6_prefix.c:%d: ENOBUFS"
                    "for rp_addr\n", __LINE__);
                return ENOBUFS;
        }
@@ -848,6 +937,7 @@ create_ra_entry(struct rp_addr **rapp)
        return 0;
 }
 
+#if 0
 static int
 init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr,
               struct rr_prefix *rpp)
@@ -872,8 +962,9 @@ init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr,
                         irr->irr_u_uselen,
                         min(ifpr->ifpr_plen - irr->irr_u_uselen,
                             irr->irr_u_keeplen));
-       for (orap = (ifpr2rp(ifpr)->rp_addrhead).lh_first; orap != NULL;
-            orap = orap->ra_entry.le_next) {
+       lck_mtx_lock(prefix6_mutex);
+       LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry)
+       {
                struct rp_addr *rap;
                int error = 0;
 
@@ -894,9 +985,11 @@ init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr,
        /* Is some FlagMasks for rrf necessary? */
        rpp->rp_rrf = irr->irr_rrf;
        rpp->rp_origin = irr->irr_origin;
+       lck_mtx_unlock(prefix6_mutex);
 
        return 0;
 }
+#endif
 
 static void
 free_rp_entries(struct rr_prefix *rpp)
@@ -905,22 +998,21 @@ free_rp_entries(struct rr_prefix *rpp)
         * This func is only called with rpp on stack(not on list).
         * So no splnet() here
         */
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__)
+       lck_mtx_lock(prefix6_mutex);
        while (!LIST_EMPTY(&rpp->rp_addrhead))
-#else
-       while (rpp->rp_addrhead.lh_first != NULL)
-#endif
        {
                struct rp_addr *rap;
 
                rap = LIST_FIRST(&rpp->rp_addrhead);
                LIST_REMOVE(rap, ra_entry);
                if (rap->ra_addr)
-                       IFAFREE(&rap->ra_addr->ia_ifa);
-               _FREE(rap, M_IPFW);
+                       ifafree(&rap->ra_addr->ia_ifa);
+               FREE(rap, M_RR_ADDR);
        }
+       lck_mtx_unlock(prefix6_mutex);
 }
 
+#if 0
 static int
 add_useprefixes(struct socket *so, struct ifnet *ifp,
                struct in6_rrenumreq *irr)
@@ -930,8 +1022,10 @@ add_useprefixes(struct socket *so, struct ifnet *ifp,
        int error = 0;
 
        /* add prefixes to each of marked prefix */
-       for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) {
-               nextifpr = ifpr->ifpr_next;
+       ifnet_lock_exclusive(ifp);
+       for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr)
+       {
+               nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
@@ -941,27 +1035,32 @@ add_useprefixes(struct socket *so, struct ifnet *ifp,
                        error = add_each_prefix(so, &rp);
                }
        }
+       ifnet_lock_done(ifp);
        /* free each rp_addr entry */
        free_rp_entries(&rp);
 
        return error;
 }
+#endif
 
 static void
 unprefer_prefix(struct rr_prefix *rpp)
 {
        struct rp_addr *rap;
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__)
-       long time_second = time.tv_sec;
-#endif
+       struct timeval timenow;
+
+       getmicrotime(&timenow);
 
+       lck_mtx_lock(prefix6_mutex);
        for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
             rap = rap->ra_entry.le_next) {
                if (rap->ra_addr == NULL)
                        continue;
-               rap->ra_addr->ia6_lifetime.ia6t_preferred = time_second;
+               rap->ra_addr->ia6_lifetime.ia6t_preferred = timenow.tv_sec;
                rap->ra_addr->ia6_lifetime.ia6t_pltime = 0;
        }
+       lck_mtx_unlock(prefix6_mutex);
+
 }
 
 int
@@ -972,58 +1071,59 @@ delete_each_prefix(struct rr_prefix *rpp, u_char origin)
        if (rpp->rp_origin > origin)
                return(EPERM);
 
+       lck_mtx_lock(prefix6_mutex);
        while (rpp->rp_addrhead.lh_first != NULL) {
                struct rp_addr *rap;
-               int s;
 
-               s = splnet();
                rap = LIST_FIRST(&rpp->rp_addrhead);
-               if (rap == NULL)
+               if (rap == NULL) {
                        break;
+               }
                LIST_REMOVE(rap, ra_entry);
-               splx(s);
                if (rap->ra_addr == NULL) {
-                       _FREE(rap, M_IPFW);
+                       FREE(rap, M_RR_ADDR);
                        continue;
                }
                rap->ra_addr->ia6_ifpr = NULL;
 
-               in6_purgeaddr(&rap->ra_addr->ia_ifa, rpp->rp_ifp);
-               IFAFREE(&rap->ra_addr->ia_ifa);
-               _FREE(rap, M_IPFW);
+               in6_purgeaddr(&rap->ra_addr->ia_ifa, 0);
+               ifafree(&rap->ra_addr->ia_ifa);
+               FREE(rap, M_RR_ADDR);
        }
        rp_remove(rpp);
+       lck_mtx_unlock(prefix6_mutex);
 
        return error;
 }
 
+#if 0
 static void
 delete_prefixes(struct ifnet *ifp, u_char origin)
 {
        struct ifprefix *ifpr, *nextifpr;
 
        /* delete prefixes marked as tobe deleted */
-       for (ifpr = ifp->if_prefixlist; ifpr; ifpr = nextifpr) {
-               nextifpr = ifpr->ifpr_next;
+       ifnet_lock_exclusive(ifp);
+       for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr)
+       {
+               nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
                if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
                    ifpr->ifpr_type != IN6_PREFIX_RR)
                        continue;
                if (ifpr2rp(ifpr)->rp_statef_delmark)
                        (void)delete_each_prefix(ifpr2rp(ifpr), origin);
        }
+       ifnet_lock_done(ifp);
 }
+#endif
 
 static int
 link_stray_ia6s(struct rr_prefix *rpp)
 {
        struct ifaddr *ifa;
 
-#if (defined(__FreeBSD__) && __FreeBSD__ < 3) || defined(__bsdi__)
-       for (ifa = rpp->rp_ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
-#else
        for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa;
             ifa = ifa->ifa_list.tqe_next)
-#endif
        {
                struct rp_addr *rap;
                struct rr_prefix *orpp;
@@ -1046,7 +1146,7 @@ link_stray_ia6s(struct rr_prefix *rpp)
                                    rpp->rp_plen);
                        continue;
                }
-               if ((error = assigne_ra_entry(rpp,
+               if ((error = assign_ra_entry(rpp,
                                              (sizeof(rap->ra_ifid) << 3) -
                                              rpp->rp_plen,
                                              (struct in6_ifaddr *)ifa)) != 0)
@@ -1055,6 +1155,7 @@ link_stray_ia6s(struct rr_prefix *rpp)
        return 0;
 }
 
+#if 0
 /* XXX assumes that permission is already checked by the caller */
 int
 in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
@@ -1068,7 +1169,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
        int error = 0;
 
        /*
-        * Failsafe for errneous address config program.
+        * Failsafe for erroneous address config program.
         * Let's hope rrenumd don't make a mistakes.
         */
        if (ipr->ipr_origin <= PR_ORIG_RA)
@@ -1085,7 +1186,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
                        log(LOG_NOTICE,
                            "in6_prefix_ioctl: preferred lifetime"
                            "(%ld) is greater than valid lifetime(%ld)\n",
-                           (u_long)irr->irr_pltime, (u_long)irr->irr_vltime);
+                           (u_int32_t)irr->irr_pltime, (u_int32_t)irr->irr_vltime);
                        error = EINVAL;
                        break;
                }
@@ -1120,7 +1221,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
                        log(LOG_NOTICE,
                            "in6_prefix_ioctl: preferred lifetime"
                            "(%ld) is greater than valid lifetime(%ld)\n",
-                           (u_long)ipr->ipr_pltime, (u_long)ipr->ipr_vltime);
+                           (u_int32_t)ipr->ipr_pltime, (u_int32_t)ipr->ipr_vltime);
                        error = EINVAL;
                        break;
                }
@@ -1140,13 +1241,10 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
                        free_rp_entries(&rp_tmp);
                        break;
                }
-#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
-               for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
-#else
+               ifnet_lock_exclusive(ifp);
                for (ifa = ifp->if_addrlist.tqh_first;
                     ifa;
                     ifa = ifa->ifa_list.tqe_next)
-#endif
                {
                        if (ifa->ifa_addr == NULL)
                                continue;       /* just for safety */
@@ -1167,8 +1265,11 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
                                 rp_tmp.rp_plen,
                                 (sizeof(rap->ra_ifid) << 3) - rp_tmp.rp_plen);
                        /* insert into list */
+                       lck_mtx_lock(prefix6_mutex);
                        LIST_INSERT_HEAD(&rp_tmp.rp_addrhead, rap, ra_entry);
+                       lck_mtx_unlock(prefix6_mutex);
                }
+               ifnet_lock_done(ifp);
 
                error = add_each_prefix(so, &rp_tmp);
 
@@ -1181,42 +1282,29 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
                if (rpp == NULL || ifp != rpp->rp_ifp)
                        return (EADDRNOTAVAIL);
 
+               ifnet_lock_exclusive(ifp);
                error = delete_each_prefix(rpp, ipr->ipr_origin);
+               ifnet_lock_done(ifp);
                break;
        }
  bad:
        return error;
 }
-
-void
-in6_rr_timer_funneled(void *ignored_arg)
-{
-#ifdef __APPLE__
-       boolean_t   funnel_state;
-       funnel_state = thread_funnel_set(network_flock, TRUE);
-#endif
-       in6_rr_timer(ignored_arg);
-#ifdef __APPLE__
-        (void) thread_funnel_set(network_flock, FALSE);
 #endif
-}
 
 void
-in6_rr_timer(void *ignored_arg)
+in6_rr_timer(__unused void *ignored_arg)
 {
-       int s;
        struct rr_prefix *rpp;
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__)
-       long time_second = time.tv_sec;
-#endif
+       struct timeval timenow;
 
-       timeout(in6_rr_timer_funneled, (caddr_t)0, ip6_rr_prune * hz);
+       getmicrotime(&timenow);
 
-       s = splnet();
        /* expire */
+       lck_mtx_lock(prefix6_mutex);
        rpp = LIST_FIRST(&rr_prefix);
        while (rpp) {
-               if (rpp->rp_expire && rpp->rp_expire < time_second) {
+               if (rpp->rp_expire && rpp->rp_expire < timenow.tv_sec) {
                        struct rr_prefix *next_rpp;
 
                        next_rpp = LIST_NEXT(rpp, rp_entry);
@@ -1224,9 +1312,10 @@ in6_rr_timer(void *ignored_arg)
                        rpp = next_rpp;
                        continue;
                }
-               if (rpp->rp_preferred && rpp->rp_preferred < time_second)
+               if (rpp->rp_preferred && rpp->rp_preferred < timenow.tv_sec)
                        unprefer_prefix(rpp);
                rpp = LIST_NEXT(rpp, rp_entry);
        }
-       splx(s);
+       lck_mtx_unlock(prefix6_mutex);
+       timeout(in6_rr_timer, (caddr_t)0, ip6_rr_prune * hz);
 }