]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/route.c
xnu-3789.70.16.tar.gz
[apple/xnu.git] / bsd / net / route.c
index 03c66249f98b0f0dad6861353c639e669de62f45..96633f83378c4b03623a9a65257cac16f236f50c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <sys/mbuf.h>
 #include <sys/socket.h>
 #include <sys/domain.h>
+#include <sys/stat.h>
+#include <sys/ubc.h>
+#include <sys/vnode.h>
 #include <sys/syslog.h>
 #include <sys/queue.h>
 #include <sys/mcache.h>
 #include <sys/protosw.h>
 #include <sys/kernel.h>
-#include <kern/lock.h>
+#include <kern/locks.h>
 #include <kern/zalloc.h>
 
 #include <net/dlil.h>
@@ -83,7 +86,6 @@
 
 #include <netinet/in.h>
 #include <netinet/in_var.h>
-#include <netinet/ip_mroute.h>
 #include <netinet/ip_var.h>
 #include <netinet/ip6.h>
 
@@ -238,6 +240,8 @@ static struct zone *rte_zone;                       /* special zone for rtentry */
 #define        RTD_INUSE               0xFEEDFACE      /* entry is in use */
 #define        RTD_FREED               0xDEADBEEF      /* entry is freed */
 
+#define MAX_SCOPE_ADDR_STR_LEN (MAX_IPv6_STR_LEN + 6)
+
 /* For gdb */
 __private_extern__ unsigned int ctrace_stack_size = CTRACE_STACK_SIZE;
 __private_extern__ unsigned int ctrace_hist_size = CTRACE_HIST_SIZE;
@@ -283,8 +287,8 @@ static inline struct rtentry *rte_alloc_debug(void);
 static inline void rte_free_debug(struct rtentry *);
 static inline void rte_lock_debug(struct rtentry_dbg *);
 static inline void rte_unlock_debug(struct rtentry_dbg *);
-static void rt_maskedcopy(struct sockaddr *,
-           struct sockaddr *, struct sockaddr *);
+static void rt_maskedcopy(const struct sockaddr *,
+           struct sockaddr *, const struct sockaddr *);
 static void rtable_init(void **);
 static inline void rtref_audit(struct rtentry_dbg *);
 static inline void rtunref_audit(struct rtentry_dbg *);
@@ -298,8 +302,6 @@ static void rtalloc_ign_common_locked(struct route *, uint32_t, unsigned int);
 static inline void sin6_set_ifscope(struct sockaddr *, unsigned int);
 static inline void sin6_set_embedded_ifscope(struct sockaddr *, unsigned int);
 static inline unsigned int sin6_get_embedded_ifscope(struct sockaddr *);
-static struct sockaddr *sa_copy(struct sockaddr *, struct sockaddr_storage *,
-    unsigned int *);
 static struct sockaddr *ma_copy(int, struct sockaddr *,
     struct sockaddr_storage *, unsigned int);
 static struct sockaddr *sa_trim(struct sockaddr *, int);
@@ -336,7 +338,7 @@ uint32_t route_genid_inet6 = 0;
 #define        ASSERT_SIN6IFSCOPE(sa) {                                        \
        if ((sa)->sa_family != AF_INET6 ||                              \
            (sa)->sa_len < sizeof (struct sockaddr_in6))                \
-               panic("%s: bad sockaddr_in %p\n", __func__, sa);        \
+               panic("%s: bad sockaddr_in6 %p\n", __func__, sa);       \
 }
 
 /*
@@ -379,11 +381,12 @@ static unsigned int primary6_ifscope = IFSCOPE_NONE;
 #define        RN(r)           ((struct radix_node *)r)
 #define        RT_HOST(r)      (RT(r)->rt_flags & RTF_HOST)
 
+unsigned int rt_verbose = 0;
+#if (DEVELOPMENT || DEBUG)
 SYSCTL_DECL(_net_route);
-
-unsigned int rt_verbose;       /* verbosity level (0 to disable) */
 SYSCTL_UINT(_net_route, OID_AUTO, verbose, CTLFLAG_RW | CTLFLAG_LOCKED,
        &rt_verbose, 0, "");
+#endif /* (DEVELOPMENT || DEBUG) */
 
 static void
 rtable_init(void **table)
@@ -561,7 +564,7 @@ sin6_get_embedded_ifscope(struct sockaddr *sa)
  * In any case, the effective scope ID value is returned to the caller via
  * pifscope, if it is non-NULL.
  */
-static struct sockaddr *
+struct sockaddr *
 sa_copy(struct sockaddr *src, struct sockaddr_storage *dst,
     unsigned int *pifscope)
 {
@@ -590,7 +593,13 @@ sa_copy(struct sockaddr *src, struct sockaddr_storage *dst,
                        eifscope = sin6_get_embedded_ifscope(SA(dst));
                        if (eifscope != IFSCOPE_NONE && ifscope == IFSCOPE_NONE)
                                ifscope = eifscope;
-                       sin6_set_ifscope(SA(dst), ifscope);
+                       if (ifscope != IFSCOPE_NONE) {
+                               /* Set ifscope from pifscope or eifscope */
+                               sin6_set_ifscope(SA(dst), ifscope);
+                       } else {
+                               /* If sin6_scope_id has a value, use that one */
+                               ifscope = sin6_get_ifscope(SA(dst));
+                       }
                        /*
                         * If sin6_scope_id is set but the address doesn't
                         * contain the equivalent embedded value, set it.
@@ -690,7 +699,7 @@ sa_trim(struct sockaddr *sa, int skip)
  */
 struct sockaddr *
 rtm_scrub(int type, int idx, struct sockaddr *hint, struct sockaddr *sa,
-    void *buf, uint32_t buflen, kauth_cred_t *credp)
+    void *buf, uint32_t buflen, kauth_cred_t *credp, uint32_t rtm_hint_flags)
 {
        struct sockaddr_storage *ss = (struct sockaddr_storage *)buf;
        struct sockaddr *ret = sa;
@@ -761,8 +770,20 @@ rtm_scrub(int type, int idx, struct sockaddr *hint, struct sockaddr *sa,
                }
                break;
        }
+       case RTAX_GATEWAY: {
+               /*
+                * Break if the gateway is not AF_LINK type (indirect routes)
+                *
+                * Else, if is, check if it is resolved. If not yet resolved
+                * simply break else scrub the link layer address.
+                */
+               if ((sa->sa_family != AF_LINK) || (SDL(sa)->sdl_alen == 0))
+                       break;
+               /* fallthrough */
+       }
        case RTAX_IFP: {
-               if (sa->sa_family == AF_LINK && credp) {
+               if (sa->sa_family == AF_LINK && credp &&
+                   (rtm_hint_flags & RTMF_HIDE_LLADDR)) {
                        struct sockaddr_dl *sdl = SDL(buf);
                        const void *bytes;
                        size_t size;
@@ -900,11 +921,7 @@ rtalloc1_scoped_locked(struct sockaddr *dst, int report, uint32_t ignflags,
        return (rtalloc1_common_locked(dst, report, ignflags, ifscope));
 }
 
-/*
- * Look up the route that matches the address given
- * Or, at least try.. Create a cloned route if needed.
- */
-static struct rtentry *
+struct rtentry *
 rtalloc1_common_locked(struct sockaddr *dst, int report, uint32_t ignflags,
     unsigned int ifscope)
 {
@@ -953,6 +970,38 @@ rtalloc1_common_locked(struct sockaddr *dst, int report, uint32_t ignflags,
                 * reference held during rtrequest.
                 */
                rtfree_locked(rt);
+
+               /*
+                * If the newly created cloned route is a direct host route
+                * then also check if it is to a router or not.
+                * If it is, then set the RTF_ROUTER flag on the host route
+                * for the gateway.
+                *
+                * XXX It is possible for the default route to be created post
+                * cloned route creation of router's IP.
+                * We can handle that corner case by special handing for RTM_ADD
+                * of default route.
+                */
+               if ((newrt->rt_flags & (RTF_HOST | RTF_LLINFO)) ==
+                   (RTF_HOST | RTF_LLINFO)) {
+                       struct rtentry *defrt = NULL;
+                       struct sockaddr_storage def_key;
+
+                       bzero(&def_key, sizeof(def_key));
+                       def_key.ss_len = rt_key(newrt)->sa_len;
+                       def_key.ss_family = rt_key(newrt)->sa_family;
+
+                       defrt = rtalloc1_scoped_locked((struct sockaddr *)&def_key,
+                                       0, 0, newrt->rt_ifp->if_index);
+
+                       if (defrt) {
+                               if (equal(rt_key(newrt), defrt->rt_gateway)) {
+                                       newrt->rt_flags |= RTF_ROUTER;
+                               }
+                               rtfree_locked(defrt);
+                       }
+               }
+
                if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
                        /*
                         * If the new route specifies it be
@@ -970,6 +1019,7 @@ unreachable:
         * Which basically means "cant get there from here"
         */
        rtstat.rts_unreach++;
+
 miss:
        if (report) {
                /*
@@ -1321,10 +1371,9 @@ rtredirect(struct ifnet *ifp, struct sockaddr *dst, struct sockaddr *gateway,
         * comparison against rt_gateway below.
         */
 #if INET6
-       if ((af == AF_INET && ip_doscopedroute) ||
-           (af == AF_INET6 && ip6_doscopedroute))
+       if ((af == AF_INET) || (af == AF_INET6))
 #else
-       if (af == AF_INET && ip_doscopedroute)
+       if (af == AF_INET)
 #endif /* !INET6 */
                src = sa_copy(src, &ss, &ifscope);
 
@@ -1458,14 +1507,8 @@ out:
 int
 rtioctl(unsigned long req, caddr_t data, struct proc *p)
 {
-#pragma unused(p)
-#if INET && MROUTING
-       return (mrt_ioctl(req, data));
-#else
-#pragma unused(req)
-#pragma unused(data)
+#pragma unused(p, req, data)
        return (ENXIO);
-#endif
 }
 
 struct ifaddr *
@@ -1520,19 +1563,19 @@ ifa_ifwithroute_common_locked(int flags, const struct sockaddr *dst,
         */
 #if INET6
        if (dst != NULL &&
-           ((dst->sa_family == AF_INET && ip_doscopedroute) ||
-           (dst->sa_family == AF_INET6 && ip6_doscopedroute)))
+           ((dst->sa_family == AF_INET) ||
+           (dst->sa_family == AF_INET6)))
 #else
-       if (dst != NULL && dst->sa_family == AF_INET && ip_doscopedroute)
+       if (dst != NULL && dst->sa_family == AF_INET)
 #endif /* !INET6 */
                dst = sa_copy(SA((uintptr_t)dst), &dst_ss, NULL);
 
 #if INET6
        if (gw != NULL &&
-           ((gw->sa_family == AF_INET && ip_doscopedroute) ||
-           (gw->sa_family == AF_INET6 && ip6_doscopedroute)))
+           ((gw->sa_family == AF_INET) ||
+           (gw->sa_family == AF_INET6)))
 #else
-       if (gw != NULL && gw->sa_family == AF_INET && ip_doscopedroute)
+       if (gw != NULL && gw->sa_family == AF_INET)
 #endif /* !INET6 */
                gw = sa_copy(SA((uintptr_t)gw), &gw_ss, NULL);
 
@@ -1718,11 +1761,9 @@ rtrequest_common_locked(int req, struct sockaddr *dst0,
         * routing socket request.
         */
 #if INET6
-       if (req != RTM_RESOLVE &&
-           ((af == AF_INET && ip_doscopedroute) ||
-           (af == AF_INET6 && ip6_doscopedroute))) {
+       if (req != RTM_RESOLVE && ((af == AF_INET) || (af == AF_INET6))) {
 #else
-       if (req != RTM_RESOLVE && af == AF_INET && ip_doscopedroute) {
+       if (req != RTM_RESOLVE && af == AF_INET) {
 #endif /* !INET6 */
                /* Transform dst into the internal routing table form */
                dst = sa_copy(dst, &ss, &ifscope);
@@ -1733,17 +1774,9 @@ rtrequest_common_locked(int req, struct sockaddr *dst0,
 
                if (ifscope != IFSCOPE_NONE)
                        flags |= RTF_IFSCOPE;
-       } else {
-               if ((flags & RTF_IFSCOPE) && (af != AF_INET && af != AF_INET6))
-                       senderr(EINVAL);
-
-#if INET6
-               if ((af == AF_INET && !ip_doscopedroute) ||
-                   (af == AF_INET6 && !ip6_doscopedroute))
-#else
-               if (af == AF_INET && !ip_doscopedroute)
-#endif /* !INET6 */
-                       ifscope = IFSCOPE_NONE;
+       } else if ((flags & RTF_IFSCOPE) &&
+           (af != AF_INET && af != AF_INET6)) {
+               senderr(EINVAL);
        }
 
        if (ifscope == IFSCOPE_NONE)
@@ -1879,6 +1912,19 @@ rtrequest_common_locked(int req, struct sockaddr *dst0,
        case RTM_RESOLVE:
                if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)
                        senderr(EINVAL);
+               /*
+                * According to the UNIX conformance tests, we need to return
+                * ENETUNREACH when the parent route is RTF_REJECT.
+                * However, there isn't any point in cloning RTF_REJECT
+                * routes, so we immediately return an error.
+                */
+               if (rt->rt_flags & RTF_REJECT) {
+                       if (rt->rt_flags & RTF_HOST) {
+                               senderr(EHOSTUNREACH);
+                       } else {
+                               senderr(ENETUNREACH);
+                       }
+               }
                /*
                 * If cloning, we have the parent route given by the caller
                 * and will use its rt_gateway, rt_rmx as part of the cloning
@@ -1899,11 +1945,9 @@ rtrequest_common_locked(int req, struct sockaddr *dst0,
                        flags |= RTF_HOST;
 
 #if INET6
-               if ((af != AF_INET && af != AF_INET6) ||
-                   (af == AF_INET && !ip_doscopedroute) ||
-                   (af == AF_INET6 && !ip6_doscopedroute))
+               if (af != AF_INET && af != AF_INET6)
 #else
-               if (af != AF_INET || !ip_doscopedroute)
+               if (af != AF_INET)
 #endif /* !INET6 */
                        goto makeroute;
 
@@ -2342,9 +2386,14 @@ int
 rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate)
 {
        int dlen = SA_SIZE(dst->sa_len), glen = SA_SIZE(gate->sa_len);
-       struct radix_node_head *rnh = rt_tables[dst->sa_family];
+       struct radix_node_head *rnh = NULL;
        boolean_t loop = FALSE;
 
+       if (dst->sa_family != AF_INET && dst->sa_family != AF_INET6) {
+               return (EINVAL);
+       }
+
+       rnh = rt_tables[dst->sa_family];
        lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
        RT_LOCK_ASSERT_HELD(rt);
 
@@ -2352,8 +2401,9 @@ rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate)
         * If this is for a route that is on its way of being removed,
         * or is temporarily frozen, reject the modification request.
         */
-       if (rt->rt_flags & RTF_CONDEMNED)
+       if (rt->rt_flags & RTF_CONDEMNED) {
                return (EBUSY);
+       }
 
        /* Add an extra ref for ourselves */
        RT_ADDREF_LOCKED(rt);
@@ -2647,23 +2697,23 @@ rt_set_gwroute(struct rtentry *rt, struct sockaddr *dst, struct rtentry *gwrt)
 }
 
 static void
-rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst,
-    struct sockaddr *netmask)
+rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,
+    const struct sockaddr *netmask)
 {
-       u_char *cp1 = (u_char *)src;
-       u_char *cp2 = (u_char *)dst;
-       u_char *cp3 = (u_char *)netmask;
-       u_char *cplim = cp2 + *cp3;
-       u_char *cplim2 = cp2 + *cp1;
+       const char *netmaskp = &netmask->sa_data[0];
+       const char *srcp = &src->sa_data[0];
+       char *dstp = &dst->sa_data[0];
+       const char *maskend = (char *)dst
+                                   + MIN(netmask->sa_len, src->sa_len);
+       const char *srcend = (char *)dst + src->sa_len;
+
+       dst->sa_len = src->sa_len;
+       dst->sa_family = src->sa_family;
 
-       *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
-       cp3 += 2;
-       if (cplim > cplim2)
-               cplim = cplim2;
-       while (cp2 < cplim)
-               *cp2++ = *cp1++ & *cp3++;
-       if (cp2 < cplim2)
-               bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
+       while (dstp < maskend)
+               *dstp++ = *srcp++ & *netmaskp++;
+       if (dstp < srcend)
+               memset(dstp, 0, (size_t)(srcend - dstp));
 }
 
 /*
@@ -2722,6 +2772,29 @@ node_lookup_default(int af)
            rnh->rnh_lookup(&sin6_def, NULL, rnh));
 }
 
+boolean_t
+rt_ifa_is_dst(struct sockaddr *dst, struct ifaddr *ifa)
+{
+       boolean_t result = FALSE;
+
+       if (ifa == NULL || ifa->ifa_addr == NULL)
+               return (result);
+
+       IFA_LOCK_SPIN(ifa);
+
+       if (dst->sa_family == ifa->ifa_addr->sa_family &&
+           ((dst->sa_family == AF_INET &&
+           SIN(dst)->sin_addr.s_addr ==
+           SIN(ifa->ifa_addr)->sin_addr.s_addr) ||
+           (dst->sa_family == AF_INET6 &&
+           SA6_ARE_ADDR_EQUAL(SIN6(dst), SIN6(ifa->ifa_addr)))))
+               result = TRUE;
+
+       IFA_UNLOCK(ifa);
+
+       return (result);
+}
+
 /*
  * Common routine to lookup/match a route.  It invokes the lookup/matchaddr
  * callback which could be address family-specific.  The main difference
@@ -2749,11 +2822,15 @@ static struct rtentry *
 rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
     struct sockaddr *netmask, struct radix_node_head *rnh, unsigned int ifscope)
 {
-       struct radix_node *rn0, *rn;
-       boolean_t dontcare;
+       struct radix_node *rn0, *rn = NULL;
        int af = dst->sa_family;
-       struct sockaddr_storage dst_ss, mask_ss;
-
+       struct sockaddr_storage dst_ss;
+       struct sockaddr_storage mask_ss;
+       boolean_t dontcare;
+#if (DEVELOPMENT || DEBUG)
+       char dbuf[MAX_SCOPE_ADDR_STR_LEN], gbuf[MAX_IPv6_STR_LEN];
+       char s_dst[MAX_IPv6_STR_LEN], s_netmask[MAX_IPv6_STR_LEN];
+#endif
        VERIFY(!coarse || ifscope == IFSCOPE_NONE);
 
        lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
@@ -2772,11 +2849,9 @@ rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
         * Non-scoped route lookup.
         */
 #if INET6
-       if ((af != AF_INET && af != AF_INET6) ||
-           (af == AF_INET && !ip_doscopedroute) ||
-           (af == AF_INET6 && !ip6_doscopedroute)) {
+       if (af != AF_INET && af != AF_INET6) {
 #else
-       if (af != AF_INET || !ip_doscopedroute) {
+       if (af != AF_INET) {
 #endif /* !INET6 */
                rn = rnh->rnh_matchaddr(dst, rnh);
 
@@ -2806,6 +2881,28 @@ rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
                netmask = ma_copy(af, netmask, &mask_ss, ifscope);
        dontcare = (ifscope == IFSCOPE_NONE);
 
+#if (DEVELOPMENT || DEBUG)
+       if (rt_verbose) {
+               if (af == AF_INET)
+                       (void) inet_ntop(af, &SIN(dst)->sin_addr.s_addr,
+                           s_dst, sizeof (s_dst));
+               else
+                       (void) inet_ntop(af, &SIN6(dst)->sin6_addr,
+                           s_dst, sizeof (s_dst));
+
+               if (netmask != NULL && af == AF_INET)
+                       (void) inet_ntop(af, &SIN(netmask)->sin_addr.s_addr,
+                           s_netmask, sizeof (s_netmask));
+               if (netmask != NULL && af == AF_INET6)
+                       (void) inet_ntop(af, &SIN6(netmask)->sin6_addr,
+                           s_netmask, sizeof (s_netmask));
+               else
+                       *s_netmask = '\0';
+               printf("%s (%d, %d, %s, %s, %u)\n",
+                   __func__, lookup_only, coarse, s_dst, s_netmask, ifscope);
+       }
+#endif
+
        /*
         * Scoped route lookup:
         *
@@ -2840,7 +2937,19 @@ rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
         */
        if (rn != NULL) {
                struct rtentry *rt = RT(rn);
-               if (!(rt->rt_ifp->if_flags & IFF_LOOPBACK)) {
+#if (DEVELOPMENT || DEBUG)
+               if (rt_verbose) {
+                       rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
+                       printf("%s unscoped search %p to %s->%s->%s ifa_ifp %s\n",
+                           __func__, rt,
+                           dbuf, gbuf,
+                           (rt->rt_ifp != NULL) ? rt->rt_ifp->if_xname : "",
+                           (rt->rt_ifa->ifa_ifp != NULL) ?
+                           rt->rt_ifa->ifa_ifp->if_xname : "");
+               }
+#endif
+               if (!(rt->rt_ifp->if_flags & IFF_LOOPBACK) ||
+                   (rt->rt_flags & RTF_GATEWAY)) {
                        if (rt->rt_ifp->if_index != ifscope) {
                                /*
                                 * Wrong interface; keep the original result
@@ -2848,11 +2957,15 @@ rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
                                 * and do a more specific scoped search using
                                 * the scope of the found route.  Otherwise,
                                 * start again from scratch.
+                                *
+                                * For loopback scope we keep the unscoped
+                                * route for local addresses
                                 */
                                rn = NULL;
                                if (dontcare)
                                        ifscope = rt->rt_ifp->if_index;
-                               else
+                               else if (ifscope != lo_ifp->if_index ||
+                                   rt_ifa_is_dst(dst, rt->rt_ifa) == FALSE)
                                        rn0 = NULL;
                        } else if (!(rt->rt_flags & RTF_IFSCOPE)) {
                                /*
@@ -2872,9 +2985,22 @@ rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
         * interface scope as the one requested.  The following will result
         * in searching for the longest prefix scoped match.
         */
-       if (rn == NULL)
+       if (rn == NULL) {
                rn = node_lookup(dst, netmask, ifscope);
+#if (DEVELOPMENT || DEBUG)
+               if (rt_verbose && rn != NULL) {
+                       struct rtentry *rt = RT(rn);
 
+                       rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
+                       printf("%s scoped search %p to %s->%s->%s ifa %s\n",
+                           __func__, rt,
+                           dbuf, gbuf,
+                           (rt->rt_ifp != NULL) ? rt->rt_ifp->if_xname : "",
+                           (rt->rt_ifa->ifa_ifp != NULL) ?
+                           rt->rt_ifa->ifa_ifp->if_xname : "");
+               }
+#endif
+       }
        /*
         * Use the original result if either of the following is true:
         *
@@ -2897,8 +3023,9 @@ rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
         * route as long as the interface portion satistifes the scope.
         */
        if (rn == NULL && (rn = node_lookup_default(af)) != NULL &&
-           RT(rn)->rt_ifp->if_index != ifscope)
+           RT(rn)->rt_ifp->if_index != ifscope) {
                rn = NULL;
+       }
 
        if (rn != NULL) {
                /*
@@ -2917,7 +3044,24 @@ rt_lookup_common(boolean_t lookup_only, boolean_t coarse, struct sockaddr *dst,
                        rn = NULL;
                }
        }
+#if (DEVELOPMENT || DEBUG)
+       if (rt_verbose) {
+               if (rn == NULL)
+                       printf("%s %u return NULL\n", __func__, ifscope);
+               else {
+                       struct rtentry *rt = RT(rn);
+
+                       rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
 
+                       printf("%s %u return %p to %s->%s->%s ifa_ifp %s\n",
+                           __func__, ifscope, rt,
+                           dbuf, gbuf,
+                           (rt->rt_ifp != NULL) ? rt->rt_ifp->if_xname : "",
+                           (rt->rt_ifa->ifa_ifp != NULL) ?
+                           rt->rt_ifa->ifa_ifp->if_xname : "");
+               }
+       }
+#endif
        return (RT(rn));
 }
 
@@ -2979,8 +3123,10 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
 {
        struct radix_node_head *rnh;
        uint8_t nbuf[128];      /* long enough for IPv6 */
+#if (DEVELOPMENT || DEBUG)
        char dbuf[MAX_IPv6_STR_LEN], gbuf[MAX_IPv6_STR_LEN];
        char abuf[MAX_IPv6_STR_LEN];
+#endif
        struct rtentry *rt = NULL;
        struct sockaddr *dst;
        struct sockaddr *netmask;
@@ -3014,6 +3160,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                goto done;
        }
 
+#if (DEVELOPMENT || DEBUG)
        if (dst->sa_family == AF_INET) {
                (void) inet_ntop(AF_INET, &SIN(dst)->sin_addr.s_addr,
                    abuf, sizeof (abuf));
@@ -3024,6 +3171,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                    abuf, sizeof (abuf));
        }
 #endif /* INET6 */
+#endif /* (DEVELOPMENT || DEBUG) */    
 
        if ((rnh = rt_tables[dst->sa_family]) == NULL) {
                error = EINVAL;
@@ -3055,7 +3203,9 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                 */
                rt = rt_lookup_coarse(TRUE, dst, NULL, rnh);
                if (rt != NULL) {
+#if (DEVELOPMENT || DEBUG)
                        rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
+#endif                 
                        /*
                         * Ok so we found the rtentry. it has an extra reference
                         * for us at this stage. we won't need that so
@@ -3070,6 +3220,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                                 * an error.  This seems to be the only point
                                 * of this whole RTM_DELETE clause.
                                 */
+#if (DEVELOPMENT || DEBUG)
                                if (rt_verbose) {
                                        log(LOG_DEBUG, "%s: not removing "
                                            "route to %s->%s->%s, flags %b, "
@@ -3082,6 +3233,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                                            rt->rt_ifa),
                                            (uint64_t)VM_KERNEL_ADDRPERM(ifa));
                                }
+#endif /* (DEVELOPMENT || DEBUG) */
                                RT_REMREF_LOCKED(rt);
                                RT_UNLOCK(rt);
                                rt = NULL;
@@ -3093,6 +3245,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                                 * Don't remove the subnet/prefix route if
                                 * this was manually added from above.
                                 */
+#if (DEVELOPMENT || DEBUG)
                                if (rt_verbose) {
                                        log(LOG_DEBUG, "%s: not removing "
                                            "static route to %s->%s->%s, "
@@ -3101,12 +3254,14 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                                            rt->rt_ifp->if_xname : ""),
                                            rt->rt_flags, RTF_BITS, abuf);
                                }
+#endif /* (DEVELOPMENT || DEBUG) */
                                RT_REMREF_LOCKED(rt);
                                RT_UNLOCK(rt);
                                rt = NULL;
                                error = EBUSY;
                                goto done;
                        }
+#if (DEVELOPMENT || DEBUG)
                        if (rt_verbose) {
                                log(LOG_DEBUG, "%s: removing route to "
                                    "%s->%s->%s, flags %b, ifaddr %s\n",
@@ -3115,6 +3270,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                                    rt->rt_ifp->if_xname : ""),
                                    rt->rt_flags, RTF_BITS, abuf);
                        }
+#endif /* (DEVELOPMENT || DEBUG) */
                        RT_REMREF_LOCKED(rt);
                        RT_UNLOCK(rt);
                        rt = NULL;
@@ -3128,9 +3284,9 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                goto done;
 
        VERIFY(rt != NULL);
-
+#if (DEVELOPMENT || DEBUG)
        rt_str(rt, dbuf, sizeof (dbuf), gbuf, sizeof (gbuf));
-
+#endif /* (DEVELOPMENT || DEBUG) */
        switch (cmd) {
        case RTM_DELETE:
                /*
@@ -3141,12 +3297,14 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                RT_LOCK(rt);
                rt_newaddrmsg(cmd, ifa, error, rt);
                RT_UNLOCK(rt);
+#if (DEVELOPMENT || DEBUG)
                if (rt_verbose) {
                        log(LOG_DEBUG, "%s: removed route to %s->%s->%s, "
                            "flags %b, ifaddr %s\n", __func__, dbuf, gbuf,
                            ((rt->rt_ifp != NULL) ? rt->rt_ifp->if_xname : ""),
                            rt->rt_flags, RTF_BITS, abuf);
                }
+#endif /* (DEVELOPMENT || DEBUG) */
                rtfree_locked(rt);
                break;
 
@@ -3161,20 +3319,20 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                if (rt->rt_ifa != ifa) {
                        void (*ifa_rtrequest)
                            (int, struct rtentry *, struct sockaddr *);
-
-                       if (!(rt->rt_ifa->ifa_ifp->if_flags &
-                           (IFF_POINTOPOINT|IFF_LOOPBACK))) {
-                               log(LOG_ERR, "%s: %s route to %s->%s->%s, "
-                                   "flags %b, ifaddr %s, rt_ifa 0x%llx != "
-                                   "ifa 0x%llx\n", __func__, rtm2str(cmd),
-                                   dbuf, gbuf, ((rt->rt_ifp != NULL) ?
-                                   rt->rt_ifp->if_xname : ""), rt->rt_flags,
-                                   RTF_BITS, abuf,
-                                   (uint64_t)VM_KERNEL_ADDRPERM(rt->rt_ifa),
-                                   (uint64_t)VM_KERNEL_ADDRPERM(ifa));
-                       }
-
+#if (DEVELOPMENT || DEBUG)
                        if (rt_verbose) {
+                               if (!(rt->rt_ifa->ifa_ifp->if_flags &
+                                   (IFF_POINTOPOINT|IFF_LOOPBACK))) {
+                                       log(LOG_ERR, "%s: %s route to %s->%s->%s, "
+                                           "flags %b, ifaddr %s, rt_ifa 0x%llx != "
+                                           "ifa 0x%llx\n", __func__, rtm2str(cmd),
+                                           dbuf, gbuf, ((rt->rt_ifp != NULL) ?
+                                               rt->rt_ifp->if_xname : ""), rt->rt_flags,
+                                           RTF_BITS, abuf,
+                                           (uint64_t)VM_KERNEL_ADDRPERM(rt->rt_ifa),
+                                           (uint64_t)VM_KERNEL_ADDRPERM(ifa));
+                               }
+
                                log(LOG_DEBUG, "%s: %s route to %s->%s->%s, "
                                    "flags %b, ifaddr %s, rt_ifa was 0x%llx "
                                    "now 0x%llx\n", __func__, rtm2str(cmd),
@@ -3184,6 +3342,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                                    (uint64_t)VM_KERNEL_ADDRPERM(rt->rt_ifa),
                                    (uint64_t)VM_KERNEL_ADDRPERM(ifa));
                        }
+#endif /* (DEVELOPMENT || DEBUG) */
 
                        /*
                         * Ask that the protocol in question
@@ -3233,6 +3392,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                        if (ifa_rtrequest != NULL)
                                ifa_rtrequest(RTM_ADD, rt, NULL);
                } else {
+#if (DEVELOPMENT || DEBUG)
                        if (rt_verbose) {
                                log(LOG_DEBUG, "%s: added route to %s->%s->%s, "
                                    "flags %b, ifaddr %s\n", __func__, dbuf,
@@ -3240,6 +3400,7 @@ rtinit_locked(struct ifaddr *ifa, int cmd, int flags)
                                    rt->rt_ifp->if_xname : ""), rt->rt_flags,
                                    RTF_BITS, abuf);
                        }
+#endif /* (DEVELOPMENT || DEBUG) */
                }
                /*
                 * notify any listenning routing agents of the change
@@ -3406,6 +3567,7 @@ rte_free(struct rtentry *p)
                panic("rte_free: rte=%p refcnt=%d non-zero\n", p, p->rt_refcnt);
                /* NOTREACHED */
        }
+
        zfree(rte_zone, p);
 }
 
@@ -3453,7 +3615,7 @@ rte_if_ref(struct ifnet *ifp, int cnt)
                ev_msg.dv[0].data_length = sizeof (struct net_event_data);
                ev_msg.dv[0].data_ptr   = &ev_data;
 
-               kev_post_msg(&ev_msg);
+               dlil_post_complete_msg(NULL, &ev_msg);
        }
 }
 
@@ -3787,7 +3949,6 @@ bad:
 void
 rt_revalidate_gwroute(struct rtentry *rt, struct rtentry *gwrt)
 {
-       VERIFY(rt->rt_flags & (RTF_CLONING | RTF_PRCLONING));
        VERIFY(gwrt != NULL);
 
        RT_LOCK_SPIN(rt);
@@ -3796,6 +3957,7 @@ rt_revalidate_gwroute(struct rtentry *rt, struct rtentry *gwrt)
            rt_key(gwrt)->sa_family && (rt->rt_gwroute == NULL ||
            !(rt->rt_gwroute->rt_flags & RTF_UP))) {
                boolean_t isequal;
+               VERIFY(rt->rt_flags & (RTF_CLONING | RTF_PRCLONING));
 
                if (rt->rt_gateway->sa_family == AF_INET ||
                    rt->rt_gateway->sa_family == AF_INET6) {
@@ -3833,9 +3995,20 @@ rt_str4(struct rtentry *rt, char *ds, uint32_t dslen, char *gs, uint32_t gslen)
 {
        VERIFY(rt_key(rt)->sa_family == AF_INET);
 
-       if (ds != NULL)
+       if (ds != NULL) {
                (void) inet_ntop(AF_INET,
                    &SIN(rt_key(rt))->sin_addr.s_addr, ds, dslen);
+               if (dslen >= MAX_SCOPE_ADDR_STR_LEN &&
+                   SINIFSCOPE(rt_key(rt))->sin_scope_id != IFSCOPE_NONE) {
+                       char scpstr[16];
+
+                       snprintf(scpstr, sizeof(scpstr), "@%u",
+                           SINIFSCOPE(rt_key(rt))->sin_scope_id);
+
+                       strlcat(ds, scpstr, dslen);
+               }
+       }
+
        if (gs != NULL) {
                if (rt->rt_flags & RTF_GATEWAY) {
                        (void) inet_ntop(AF_INET,
@@ -3854,9 +4027,20 @@ rt_str6(struct rtentry *rt, char *ds, uint32_t dslen, char *gs, uint32_t gslen)
 {
        VERIFY(rt_key(rt)->sa_family == AF_INET6);
 
-       if (ds != NULL)
+       if (ds != NULL) {
                (void) inet_ntop(AF_INET6,
                    &SIN6(rt_key(rt))->sin6_addr, ds, dslen);
+               if (dslen >= MAX_SCOPE_ADDR_STR_LEN &&
+                   SIN6IFSCOPE(rt_key(rt))->sin6_scope_id != IFSCOPE_NONE) {
+                       char scpstr[16];
+
+                       snprintf(scpstr, sizeof(scpstr), "@%u",
+                           SIN6IFSCOPE(rt_key(rt))->sin6_scope_id);
+
+                       strlcat(ds, scpstr, dslen);
+               }
+       }
+
        if (gs != NULL) {
                if (rt->rt_flags & RTF_GATEWAY) {
                        (void) inet_ntop(AF_INET6,