]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if.c
xnu-1504.9.37.tar.gz
[apple/xnu.git] / bsd / net / if.c
index 31d3cd0825cbe6913958e10c59daf405084cfa84..02b698007897c6f6b6ac4a24534fcc34c338f430 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -82,6 +82,8 @@
 #include <sys/syslog.h>
 #include <sys/sysctl.h>
 
+#include <machine/endian.h>
+
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <net/if_dl.h>
 /*XXX*/
 #include <netinet/in.h>
 #include <netinet/in_var.h>
+#include <netinet/ip_var.h>
 #if INET6
 #include <netinet6/in6_var.h>
 #include <netinet6/in6_ifattach.h>
 #endif
 #endif
 
-extern u_long route_generation;
-extern int use_routegenid;
 extern int dlil_multithreaded_input;
 extern struct dlil_threading_info *dlil_lo_thread_ptr;
 
@@ -118,6 +119,7 @@ extern struct dlil_threading_info *dlil_lo_thread_ptr;
 #include <security/mac_framework.h>
 #endif
 
+
 /*
  * System initialization
  */
@@ -130,10 +132,9 @@ void if_rtproto_del(struct ifnet *ifp, int protocol);
 static int if_rtmtu(struct radix_node *, void *);
 static void if_rtmtu_update(struct ifnet *);
 
-static struct  if_clone *if_clone_lookup(const char *, int *);
-#ifdef IF_CLONE_LIST
+#if IF_CLONE_LIST
 static int     if_clone_list(int count, int * total, user_addr_t dst);
-#endif
+#endif /* IF_CLONE_LIST */
 
 MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
 MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
@@ -144,6 +145,9 @@ struct      ifnethead ifnet_head = TAILQ_HEAD_INITIALIZER(ifnet_head);
 static int     if_cloners_count;
 LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
 
+static struct ifaddr *ifa_ifwithnet_common(const struct sockaddr *,
+    unsigned int);
+
 #if INET6
 /*
  * XXX: declare here to avoid to include many inet6 related files..
@@ -152,7 +156,6 @@ LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
 extern void    nd6_setmtu(struct ifnet *);
 #endif
 
-#define M_CLONE                M_IFADDR
 
 /*
  * Network interface utility routines.
@@ -171,11 +174,11 @@ if_attach_ifa(
        struct ifaddr *ifa)
 {
        ifnet_lock_assert(ifp, LCK_MTX_ASSERT_OWNED);
-       if (ifa->ifa_debug & IFA_ATTACHED) {
+       if (ifa->ifa_debug & IFD_ATTACHED) {
                panic("if_attach_ifa: Attempted to attach address that's already attached!\n");
        }
        ifaref(ifa);
-       ifa->ifa_debug |= IFA_ATTACHED;
+       ifa->ifa_debug |= IFD_ATTACHED;
        TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
 }
 
@@ -187,8 +190,8 @@ if_detach_ifa(
        ifnet_lock_assert(ifp, LCK_MTX_ASSERT_OWNED);
 #if 1
        /* Debugging code */
-       if ((ifa->ifa_debug & IFA_ATTACHED) == 0) {
-               printf("if_detach_ifa: ifa is not attached to any interface! flags=%lu\n", ifa->ifa_debug);
+       if ((ifa->ifa_debug & IFD_ATTACHED) == 0) {
+               printf("if_detach_ifa: ifa is not attached to any interface! flags=%u\n", ifa->ifa_debug);
                return;
        }
        else {
@@ -203,7 +206,7 @@ if_detach_ifa(
        }
 #endif
        TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
-       ifa->ifa_debug &= ~IFA_ATTACHED;
+       ifa->ifa_debug &= ~IFD_ATTACHED;
        ifafree(ifa);
 }
 
@@ -248,6 +251,11 @@ if_next_index(void)
                /* allocate space for the larger arrays */
                n = (2 * new_if_indexlim + 1) * sizeof(caddr_t);
                new_ifnet_addrs = _MALLOC(n, M_IFADDR, M_WAITOK);
+               if (new_ifnet_addrs == NULL) {
+                       --if_index;
+                       return -1;
+               }
+
                new_ifindex2ifnet = new_ifnet_addrs 
                        + new_if_indexlim * sizeof(caddr_t);
                bzero(new_ifnet_addrs, n);
@@ -277,12 +285,13 @@ if_next_index(void)
  * Create a clone network interface.
  */
 static int
-if_clone_create(char *name, int len)
+if_clone_create(char *name, int len, void *params)
 {
        struct if_clone *ifc;
        char *dp;
-       int wildcard, bytoff, bitoff;
-       int unit;
+       int wildcard;
+       u_int32_t bytoff, bitoff;
+       u_int32_t unit;
        int err;
 
        ifc = if_clone_lookup(name, &unit);
@@ -293,7 +302,7 @@ if_clone_create(char *name, int len)
                return (EEXIST);
 
        bytoff = bitoff = 0;
-       wildcard = (unit < 0);
+       wildcard = (unit == UINT32_MAX);
        /*
         * Find a free unit if none was given.
         */
@@ -311,7 +320,7 @@ if_clone_create(char *name, int len)
        if (unit > ifc->ifc_maxunit)
                return (ENXIO);
 
-       err = (*ifc->ifc_create)(ifc, unit);
+       err = (*ifc->ifc_create)(ifc, unit, params);
        if (err != 0)
                return (err);
 
@@ -354,7 +363,7 @@ if_clone_destroy(const char *name)
        struct if_clone *ifc;
        struct ifnet *ifp;
        int bytoff, bitoff;
-       int unit;
+       u_int32_t unit;
 
        ifc = if_clone_lookup(name, &unit);
        if (ifc == NULL)
@@ -387,8 +396,8 @@ if_clone_destroy(const char *name)
  * Look up a network interface cloner.
  */
 
-static struct if_clone *
-if_clone_lookup(const char *name, int *unitp)
+__private_extern__ struct if_clone *
+if_clone_lookup(const char *name, u_int32_t *unitp)
 {
        struct if_clone *ifc;
        const char *cp;
@@ -409,7 +418,7 @@ if_clone_lookup(const char *name, int *unitp)
 
  found_name:
        if (*cp == '\0') {
-               i = -1;
+               i = 0xffff;
        } else {
                for (i = 0; *cp != '\0'; cp++) {
                        if (*cp < '0' || *cp > '9') {
@@ -428,13 +437,13 @@ if_clone_lookup(const char *name, int *unitp)
 /*
  * Register a network interface cloner.
  */
-void
+int
 if_clone_attach(struct if_clone *ifc)
 {
        int bytoff, bitoff;
        int err;
        int len, maxclone;
-       int unit;
+       u_int32_t unit;
 
        KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit,
            ("%s: %s requested more units then allowed (%d > %d)",
@@ -448,6 +457,8 @@ if_clone_attach(struct if_clone *ifc)
        if ((len << 3) < maxclone)
                len++;
        ifc->ifc_units = _MALLOC(len, M_CLONE, M_WAITOK | M_ZERO);
+       if (ifc->ifc_units == NULL)
+               return ENOBUFS;
        bzero(ifc->ifc_units, len);
        ifc->ifc_bmlen = len;
 
@@ -455,7 +466,7 @@ if_clone_attach(struct if_clone *ifc)
        if_cloners_count++;
 
        for (unit = 0; unit < ifc->ifc_minifs; unit++) {
-               err = (*ifc->ifc_create)(ifc, unit);
+               err = (*ifc->ifc_create)(ifc, unit, NULL);
                KASSERT(err == 0,
                    ("%s: failed to create required interface %s%d",
                    __func__, ifc->ifc_name, unit));
@@ -465,6 +476,8 @@ if_clone_attach(struct if_clone *ifc)
                bitoff = unit - (bytoff << 3);
                ifc->ifc_units[bytoff] |= (1 << bitoff);
        }
+
+       return 0;
 }
 
 /*
@@ -479,7 +492,7 @@ if_clone_detach(struct if_clone *ifc)
        if_cloners_count--;
 }
 
-#ifdef IF_CLONE_LIST
+#if IF_CLONE_LIST
 /*
  * Provide list of interface cloners to userspace.
  */
@@ -511,36 +524,38 @@ if_clone_list(int count, int * total, user_addr_t dst)
 
        return (error);
 }
-#endif IF_CLONE_LIST
+#endif /* IF_CLONE_LIST */
 
-__private_extern__ int
-ifa_foraddr(
-       unsigned int addr)
+/*
+ * Similar to ifa_ifwithaddr, except that this is IPv4 specific
+ * and that it matches only the local (not broadcast) address.
+ */
+__private_extern__ struct in_ifaddr *
+ifa_foraddr(unsigned int addr)
 {
-       struct ifnet *ifp;
-       struct ifaddr *ifa;
-       unsigned int addr2;
-       int     result = 0;
-       
-       ifnet_head_lock_shared();
-       for (ifp = ifnet_head.tqh_first; ifp && !result; ifp = ifp->if_link.tqe_next) {
-               ifnet_lock_shared(ifp);
-           for (ifa = ifp->if_addrhead.tqh_first; ifa;
-                ifa = ifa->ifa_link.tqe_next) {
-                       if (ifa->ifa_addr->sa_family != AF_INET)
-                               continue;
-                       addr2 = IA_SIN(ifa)->sin_addr.s_addr;
-                       
-                       if (addr == addr2) {
-                               result = 1;
-                               break;
-                       }
-               }
-               ifnet_lock_done(ifp);
+       return (ifa_foraddr_scoped(addr, IFSCOPE_NONE));
+}
+
+/*
+ * Similar to ifa_foraddr, except with the added interface scope
+ * constraint (unless the caller passes in IFSCOPE_NONE in which
+ * case there is no scope restriction).
+ */
+__private_extern__ struct in_ifaddr *
+ifa_foraddr_scoped(unsigned int addr, unsigned int scope)
+{
+       struct in_ifaddr *ia = NULL;
+
+       lck_rw_lock_shared(in_ifaddr_rwlock);
+       TAILQ_FOREACH(ia, INADDR_HASH(addr), ia_hash) {
+               if (ia->ia_addr.sin_addr.s_addr == addr &&
+                   (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope))
+                       break;
        }
-       ifnet_head_done();
-       
-       return result;
+       if (ia != NULL)
+               ifaref(&ia->ia_ifa);
+       lck_rw_done(in_ifaddr_rwlock);
+       return (ia);
 }
 
 /*
@@ -641,13 +656,78 @@ ifa_ifwithdstaddr(
        return result;
 }
 
+/*
+ * Locate the source address of an interface based on a complete address.
+ */
+struct ifaddr *
+ifa_ifwithaddr_scoped(const struct sockaddr *addr, unsigned int ifscope)
+{
+       struct ifaddr *result = NULL;
+       struct ifnet *ifp;
+
+       if (ifscope == IFSCOPE_NONE)
+               return (ifa_ifwithaddr(addr));
+
+       ifnet_head_lock_shared();
+       if (ifscope > (unsigned int)if_index) {
+               ifnet_head_done();
+               return (NULL);
+       }
+
+       ifp = ifindex2ifnet[ifscope];
+       if (ifp != NULL) {
+               struct ifaddr *ifa = NULL;
+
+               /*
+                * This is suboptimal; there should be a better way
+                * to search for a given address of an interface
+                * for any given address family.
+                */
+               ifnet_lock_shared(ifp);
+               for (ifa = ifp->if_addrhead.tqh_first; ifa != NULL;
+                   ifa = ifa->ifa_link.tqe_next) {
+                       if (ifa->ifa_addr->sa_family != addr->sa_family)
+                               continue;
+                       if (equal(addr, ifa->ifa_addr)) {
+                               result = ifa;
+                               break;
+                       }
+                       if ((ifp->if_flags & IFF_BROADCAST) &&
+                           ifa->ifa_broadaddr != NULL &&
+                           /* IP6 doesn't have broadcast */
+                           ifa->ifa_broadaddr->sa_len != 0 &&
+                           equal(ifa->ifa_broadaddr, addr)) {
+                               result = ifa;
+                               break;
+                       }
+               }
+               if (result != NULL)
+                       ifaref(result);
+               ifnet_lock_done(ifp);
+       }
+       ifnet_head_done();
+
+       return (result);
+}
+
+struct ifaddr *
+ifa_ifwithnet(const struct sockaddr *addr)
+{
+       return (ifa_ifwithnet_common(addr, IFSCOPE_NONE));
+}
+
+struct ifaddr *
+ifa_ifwithnet_scoped(const struct sockaddr *addr, unsigned int ifscope)
+{
+       return (ifa_ifwithnet_common(addr, ifscope));
+}
+
 /*
  * Find an interface on a specific network.  If many, choice
  * is most specific found.
  */
-struct ifaddr *
-ifa_ifwithnet(
-       const struct sockaddr *addr)
+static struct ifaddr *
+ifa_ifwithnet_common(const struct sockaddr *addr, unsigned int ifscope)
 {
        struct ifnet *ifp;
        struct ifaddr *ifa = NULL;
@@ -655,6 +735,9 @@ ifa_ifwithnet(
        u_int af = addr->sa_family;
        const char *addr_data = addr->sa_data, *cplim;
 
+       if (!ip_doscopedroute || addr->sa_family != AF_INET)
+               ifscope = IFSCOPE_NONE;
+
        ifnet_head_lock_shared();
        /*
         * AF_LINK addresses can be looked up directly by their index number,
@@ -712,16 +795,12 @@ next:                             continue;
 #endif /* __APPLE__*/
                        {
                                /*
-                                * if we have a special address handler,
-                                * then use it instead of the generic one.
+                                * If we're looking up with a scope,
+                                * find using a matching interface.
                                 */
-                               if (ifa->ifa_claim_addr) {
-                                       if (ifa->ifa_claim_addr(ifa, addr)) {
-                                               break;
-                                       } else {
-                                               continue;
-                                       }
-                               }
+                               if (ifscope != IFSCOPE_NONE &&
+                                   ifp->if_index != ifscope)
+                                       continue;
 
                                /*
                                 * Scan all the bits in the ifa's address.
@@ -816,7 +895,7 @@ ifaof_ifpforaddr(
                        continue;
                }
                if (ifp->if_flags & IFF_POINTOPOINT) {
-                       if (equal(addr, ifa->ifa_dstaddr))
+                       if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
                                break;
                } else {
                        if (equal(addr, ifa->ifa_addr)) {
@@ -866,6 +945,9 @@ link_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
        struct sockaddr *dst;
        struct ifnet *ifp;
 
+       lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
+       RT_LOCK_ASSERT_HELD(rt);
+
        if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
            ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
                return;
@@ -1082,41 +1164,49 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
        struct net_event_data ev_data;
 
        switch (cmd) {
-       case SIOCGIFCONF:
-       case OSIOCGIFCONF:
+       case OSIOCGIFCONF32:
+       case SIOCGIFCONF32: {
+               struct ifconf32 *ifc = (struct ifconf32 *)data;
+               return (ifconf(cmd, CAST_USER_ADDR_T(ifc->ifc_req),
+                   &ifc->ifc_len));
+               /* NOTREACHED */
+       }
        case SIOCGIFCONF64:
-           {
-               struct ifconf64 *       ifc = (struct ifconf64 *)data;
-               user_addr_t             user_addr;
-               
-               user_addr = proc_is64bit(p)
-                   ? ifc->ifc_req64 : CAST_USER_ADDR_T(ifc->ifc_req);
-               return (ifconf(cmd, user_addr, &ifc->ifc_len));
-           }
-           break;
+       case OSIOCGIFCONF64: {
+               struct ifconf64 *ifc = (struct ifconf64 *)data;
+               return (ifconf(cmd, ifc->ifc_req, &ifc->ifc_len));
+               /* NOTREACHED */
+       }
        }
        ifr = (struct ifreq *)data;
        switch (cmd) {
        case SIOCIFCREATE:
+       case SIOCIFCREATE2:
+                error = proc_suser(p);
+                if (error)
+                        return (error);
+                return if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name),
+                        cmd == SIOCIFCREATE2 ? ifr->ifr_data : NULL);
        case SIOCIFDESTROY:
                error = proc_suser(p);
                if (error)
                        return (error);
-               return ((cmd == SIOCIFCREATE) ?
-                       if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) :
-                       if_clone_destroy(ifr->ifr_name));
+               return if_clone_destroy(ifr->ifr_name);
 #if IF_CLONE_LIST
-       case SIOCIFGCLONERS:
-       case SIOCIFGCLONERS64:
-           {
-               struct if_clonereq64 *  ifcr = (struct if_clonereq64 *)data;
-               user_addr = proc_is64bit(p)
-                   ? ifcr->ifcr_ifcru.ifcru_buffer64
-                   : CAST_USER_ADDR_T(ifcr->ifcr_ifcru.ifcru_buffer32);
+       case SIOCIFGCLONERS32: {
+               struct if_clonereq32 *ifcr = (struct if_clonereq32 *)data;
                return (if_clone_list(ifcr->ifcr_count, &ifcr->ifcr_total,
-                                     user_data));
+                   CAST_USER_ADDR_T(ifcr->ifcru_buffer)));
+               /* NOTREACHED */
+
+       }
+       case SIOCIFGCLONERS64: {
+               struct if_clonereq64 *ifcr = (struct if_clonereq64 *)data;
+               return (if_clone_list(ifcr->ifcr_count, &ifcr->ifcr_total,
+                   ifcr->ifcru_buffer));
+               /* NOTREACHED */
            }
-#endif IF_CLONE_LIST
+#endif /* IF_CLONE_LIST */
        }
 
        ifp = ifunit(ifr->ifr_name);
@@ -1165,20 +1255,20 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                error = ifnet_ioctl(ifp, so->so_proto->pr_domain->dom_family, 
                                                        cmd, data);
 
-               if (error == 0) {
-                        ev_msg.vendor_code    = KEV_VENDOR_APPLE;
-                        ev_msg.kev_class      = KEV_NETWORK_CLASS;
-                        ev_msg.kev_subclass   = KEV_DL_SUBCLASS;
-
-                        ev_msg.event_code = KEV_DL_SIFFLAGS;
-                        strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
-                        ev_data.if_family = ifp->if_family;
-                        ev_data.if_unit   = (unsigned long) ifp->if_unit;
-                        ev_msg.dv[0].data_length = sizeof(struct net_event_data);
-                        ev_msg.dv[0].data_ptr    = &ev_data;
-                        ev_msg.dv[1].data_length = 0;
-                        kev_post_msg(&ev_msg);
-               }
+               /* Send the event even upon error from the driver because we changed the flags */
+               ev_msg.vendor_code    = KEV_VENDOR_APPLE;
+               ev_msg.kev_class      = KEV_NETWORK_CLASS;
+               ev_msg.kev_subclass   = KEV_DL_SUBCLASS;
+               
+               ev_msg.event_code = KEV_DL_SIFFLAGS;
+               strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
+               ev_data.if_family = ifp->if_family;
+               ev_data.if_unit   = (u_int32_t) ifp->if_unit;
+               ev_msg.dv[0].data_length = sizeof(struct net_event_data);
+               ev_msg.dv[0].data_ptr    = &ev_data;
+               ev_msg.dv[1].data_length = 0;
+               kev_post_msg(&ev_msg);
+
                ifnet_touch_lastchange(ifp);
                break;
 
@@ -1203,7 +1293,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                ev_msg.event_code = KEV_DL_SIFMETRICS;
                strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
                ev_data.if_family = ifp->if_family;
-               ev_data.if_unit   = (unsigned long) ifp->if_unit;
+               ev_data.if_unit   = (u_int32_t) ifp->if_unit;
                ev_msg.dv[0].data_length = sizeof(struct net_event_data);
                ev_msg.dv[0].data_ptr    = &ev_data;
 
@@ -1229,7 +1319,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                        ev_msg.event_code = KEV_DL_SIFPHYS;
                        strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
                        ev_data.if_family = ifp->if_family;
-                       ev_data.if_unit   = (unsigned long) ifp->if_unit;
+                       ev_data.if_unit   = (u_int32_t) ifp->if_unit;
                        ev_msg.dv[0].data_length = sizeof(struct net_event_data);
                        ev_msg.dv[0].data_ptr    = &ev_data;
                        ev_msg.dv[1].data_length = 0;
@@ -1241,7 +1331,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
 
        case SIOCSIFMTU:
        {
-               u_long oldmtu = ifp->if_mtu;
+               u_int32_t oldmtu = ifp->if_mtu;
 
                error = proc_suser(p);
                if (error)
@@ -1262,7 +1352,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                     ev_msg.event_code = KEV_DL_SIFMTU;
                     strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
                     ev_data.if_family = ifp->if_family;
-                    ev_data.if_unit   = (unsigned long) ifp->if_unit;
+                    ev_data.if_unit   = (u_int32_t) ifp->if_unit;
                     ev_msg.dv[0].data_length = sizeof(struct net_event_data);
                     ev_msg.dv[0].data_ptr    = &ev_data;
                     ev_msg.dv[1].data_length = 0;
@@ -1315,7 +1405,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                     strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
        
                     ev_data.if_family = ifp->if_family;
-                    ev_data.if_unit   = (unsigned long) ifp->if_unit;
+                    ev_data.if_unit   = (u_int32_t) ifp->if_unit;
                     ev_msg.dv[0].data_length = sizeof(struct net_event_data);
                     ev_msg.dv[0].data_ptr    = &ev_data;
                     ev_msg.dv[1].data_length = 0;
@@ -1328,7 +1418,8 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
        case SIOCSIFPHYADDR:
        case SIOCDIFPHYADDR:
 #if INET6
-       case SIOCSIFPHYADDR_IN6:
+       case SIOCSIFPHYADDR_IN6_32:
+       case SIOCSIFPHYADDR_IN6_64:
 #endif
        case SIOCSLIFPHYADDR:
        case SIOCSIFMEDIA:
@@ -1355,7 +1446,8 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
        case SIOCGIFPSRCADDR:
        case SIOCGIFPDSTADDR:
        case SIOCGLIFPHYADDR:
-       case SIOCGIFMEDIA:
+       case SIOCGIFMEDIA32:
+       case SIOCGIFMEDIA64:
        case SIOCGIFGENERIC:
        case SIOCGIFDEVMTU:
                return ifnet_ioctl(ifp, so->so_proto->pr_domain->dom_family, 
@@ -1365,6 +1457,22 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
                return ifnet_ioctl(ifp, so->so_proto->pr_domain->dom_family, 
                                                   cmd, data);
 
+       case SIOCGIFWAKEFLAGS:
+               ifnet_lock_shared(ifp);
+               ifr->ifr_wake_flags = ifnet_get_wake_flags(ifp);
+               ifnet_lock_done(ifp);
+               break;
+
+       case SIOCGIFGETRTREFCNT:
+#if IFNET_ROUTE_REFCNT
+               ifnet_lock_shared(ifp);
+               ifr->ifr_route_refcnt = ifp->if_route_refcnt;
+               ifnet_lock_done(ifp);
+               break;
+#else
+               return (EOPNOTSUPP);
+#endif /* IFNET_ROUTE_REFCNT */
+
        default:
                oif_flags = ifp->if_flags;
                if (so->so_proto == 0)
@@ -1550,7 +1658,7 @@ ifconf(u_long cmd, user_addr_t ifrp, int * ret_space)
                                continue;
 #endif
                        addrs++;
-                       if (cmd == OSIOCGIFCONF) {
+                       if (cmd == OSIOCGIFCONF32 || cmd == OSIOCGIFCONF64) {
                                struct osockaddr *osa =
                                         (struct osockaddr *)&ifr.ifr_addr;
                                ifr.ifr_addr = *sa;
@@ -1634,7 +1742,7 @@ void
 ifma_reference(
        struct ifmultiaddr *ifma)
 {
-       if (OSIncrementAtomic((SInt32 *)&ifma->ifma_refcount) <= 0)
+       if (OSIncrementAtomic(&ifma->ifma_refcount) <= 0)
                panic("ifma_reference: ifma already released or invalid\n");
 }
 
@@ -1644,7 +1752,7 @@ ifma_release(
 {
        while (ifma) {
                struct ifmultiaddr *next;
-               int32_t prevValue = OSDecrementAtomic((SInt32 *)&ifma->ifma_refcount);
+               int32_t prevValue = OSDecrementAtomic(&ifma->ifma_refcount);
                if (prevValue < 1)
                        panic("ifma_release: ifma already released or invalid\n");
                if (prevValue != 1)
@@ -2075,48 +2183,53 @@ if_down_all(void)
  *
  */
 static int
-if_rtdel(
-       struct radix_node       *rn,
-       void                    *arg)
+if_rtdel(struct radix_node *rn, void *arg)
 {
        struct rtentry  *rt = (struct rtentry *)rn;
        struct ifnet    *ifp = arg;
        int             err;
 
-       if (rt != NULL && rt->rt_ifp == ifp) {
-               
+       if (rt == NULL)
+               return (0);
+       /*
+        * Checking against RTF_UP protects against walktree
+        * recursion problems with cloned routes.
+        */
+       RT_LOCK(rt);
+       if (rt->rt_ifp == ifp && (rt->rt_flags & RTF_UP)) {
                /*
-                * Protect (sorta) against walktree recursion problems
-                * with cloned routes
+                * Safe to drop rt_lock and use rt_key, rt_gateway,
+                * since holding rnh_lock here prevents another thread
+                * from calling rt_setgate() on this route.
                 */
-               if ((rt->rt_flags & RTF_UP) == 0)
-                       return (0);
-
+               RT_UNLOCK(rt);
                err = rtrequest_locked(RTM_DELETE, rt_key(rt), rt->rt_gateway,
-                               rt_mask(rt), rt->rt_flags,
-                               (struct rtentry **) NULL);
+                   rt_mask(rt), rt->rt_flags, NULL);
                if (err) {
                        log(LOG_WARNING, "if_rtdel: error %d\n", err);
                }
+       } else {
+               RT_UNLOCK(rt);
        }
-
        return (0);
 }
 
 /*
- * Removes routing table reference to a given interfacei
+ * Removes routing table reference to a given interface
  * for a given protocol family
  */
-void if_rtproto_del(struct ifnet *ifp, int protocol)
+void
+if_rtproto_del(struct ifnet *ifp, int protocol)
 {
        struct radix_node_head  *rnh;
-       if (use_routegenid) 
-               route_generation++;
+
+       if (use_routegenid)
+               routegenid_update();
        if ((protocol <= AF_MAX) && (protocol >= 0) &&
                ((rnh = rt_tables[protocol]) != NULL) && (ifp != NULL)) {
-               lck_mtx_lock(rt_mtx);
+               lck_mtx_lock(rnh_lock);
                (void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
-               lck_mtx_unlock(rt_mtx);
+               lck_mtx_unlock(rnh_lock);
        }
 }
 
@@ -2126,6 +2239,7 @@ if_rtmtu(struct radix_node *rn, void *arg)
        struct rtentry *rt = (struct rtentry *)rn;
        struct ifnet *ifp = arg;
 
+       RT_LOCK(rt);
        if (rt->rt_ifp == ifp) {
                /*
                 * Update the MTU of this entry only if the MTU
@@ -2135,6 +2249,7 @@ if_rtmtu(struct radix_node *rn, void *arg)
                if (!(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_rmx.rmx_mtu)
                        rt->rt_rmx.rmx_mtu = ifp->if_mtu;
        }
+       RT_UNLOCK(rt);
 
        return (0);
 }
@@ -2154,13 +2269,13 @@ void if_rtmtu_update(struct ifnet *ifp)
                if ((rnh = rt_tables[p]) == NULL)
                        continue;
 
-               lck_mtx_lock(rt_mtx);
+               lck_mtx_lock(rnh_lock);
                (void) rnh->rnh_walktree(rnh, if_rtmtu, ifp);
-               lck_mtx_unlock(rt_mtx);
+               lck_mtx_unlock(rnh_lock);
        }
 
        if (use_routegenid)
-               route_generation++;
+               routegenid_update();
 }
 
 __private_extern__ void
@@ -2206,7 +2321,8 @@ if_data_internal_to_if_data(
        COPYFIELD32(ifi_noproto);
        COPYFIELD32(ifi_recvtiming);
        COPYFIELD32(ifi_xmittiming);
-       COPYFIELD(ifi_lastchange);
+       if_data->ifi_lastchange.tv_sec = if_data_int->ifi_lastchange.tv_sec;
+       if_data->ifi_lastchange.tv_usec = if_data_int->ifi_lastchange.tv_usec;
        lck_mtx_unlock(thread->input_lck);
        
 #if IF_LASTCHANGEUPTIME
@@ -2258,7 +2374,8 @@ if_data_internal_to_if_data64(
        COPYFIELD(ifi_noproto);
        COPYFIELD(ifi_recvtiming);
        COPYFIELD(ifi_xmittiming);
-       COPYFIELD(ifi_lastchange);
+       if_data64->ifi_lastchange.tv_sec = if_data_int->ifi_lastchange.tv_sec;
+       if_data64->ifi_lastchange.tv_usec = if_data_int->ifi_lastchange.tv_usec;
        lck_mtx_unlock(thread->input_lck);
        
 #if IF_LASTCHANGEUPTIME
@@ -2267,3 +2384,44 @@ if_data_internal_to_if_data64(
 
 #undef COPYFIELD
 }
+
+void
+ifafree(struct ifaddr *ifa)
+{
+       int oldval;
+
+       oldval = OSAddAtomic(-1, &ifa->ifa_refcnt);
+       if (oldval >= 1 && ifa->ifa_trace != NULL)
+               (*ifa->ifa_trace)(ifa, FALSE);
+       if (oldval == 0) {
+               panic("%s: ifa %p negative refcnt\n", __func__, ifa);
+       } else if (oldval == 1) {
+               if  (ifa->ifa_debug & IFD_ATTACHED)
+                       panic("ifa %p attached to ifp is being freed\n", ifa);
+               /*
+                * Some interface addresses are allocated either statically
+                * or carved out of a larger block; e.g. AppleTalk addresses.
+                * Only free it if it was allocated via MALLOC or via the
+                * corresponding per-address family allocator.  Otherwise,
+                * leave it alone.
+                */
+               if (ifa->ifa_debug & IFD_ALLOC) {
+                       if (ifa->ifa_free == NULL)
+                               FREE(ifa, M_IFADDR);
+                       else
+                               (*ifa->ifa_free)(ifa);
+               }
+       }
+}
+
+void
+ifaref(struct ifaddr *ifa)
+{
+       int oldval;
+
+       oldval = OSAddAtomic(1, &ifa->ifa_refcnt);
+       if (oldval < 0)
+               panic("%s: ifa %p negative refcnt\n", __func__, ifa);
+       else if (ifa->ifa_trace != NULL)
+               (*ifa->ifa_trace)(ifa, TRUE);
+}