]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if_llreach.c
xnu-3248.50.21.tar.gz
[apple/xnu.git] / bsd / net / if_llreach.c
index 669beb0f41df49f1bf9ea43f6808df8e7ec24bde..2012d8c056c6cadab30b335fcd0aa6648c7d6887 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #include <sys/mcache.h>
 #include <sys/protosw.h>
 
+#include <dev/random/randomdev.h>
+
 #include <net/if_dl.h>
 #include <net/if.h>
 #include <net/if_var.h>
 #include <net/if_llreach.h>
 #include <net/dlil.h>
+#include <net/kpi_interface.h>
+#include <net/route.h>
 
 #include <kern/assert.h>
 #include <kern/locks.h>
@@ -163,7 +167,7 @@ SYSCTL_NODE(_net_link_generic_system, OID_AUTO, llreach_info,
 #define LL_MIN_RANDOM_FACTOR   512     /* 1024 * 0.5 */
 #define LL_MAX_RANDOM_FACTOR   1536    /* 1024 * 1.5 */
 #define LL_COMPUTE_RTIME(x)                                            \
-       (((LL_MIN_RANDOM_FACTOR * (x >> 10)) + (random() &              \
+       (((LL_MIN_RANDOM_FACTOR * (x >> 10)) + (RandomULong() &         \
        ((LL_MAX_RANDOM_FACTOR - LL_MIN_RANDOM_FACTOR) * (x >> 10)))) / 1000)
 #endif /* !INET6 */
 
@@ -288,7 +292,7 @@ ifnet_llreach_alloc(struct ifnet *ifp, u_int16_t llproto, void *addr,
     unsigned int alen, u_int64_t llreach_base)
 {
        struct if_llreach find, *lr;
-       struct timeval now;
+       struct timeval cnow;
 
        if (llreach_base == 0)
                return (NULL);
@@ -335,14 +339,17 @@ found:
        IFLR_ADDREF_LOCKED(lr);                 /* for caller */
        lr->lr_lastrcvd = net_uptime();         /* current approx. uptime */
        lr->lr_baseup = lr->lr_lastrcvd;        /* base uptime */
-       microtime(&now);
-       lr->lr_basecal = now.tv_sec;            /* base calendar time */
+       getmicrotime(&cnow);
+       lr->lr_basecal = cnow.tv_sec;           /* base calendar time */
        lr->lr_basereachable = llreach_base;
        lr->lr_reachable = LL_COMPUTE_RTIME(lr->lr_basereachable * 1000);
        lr->lr_debug |= IFD_ATTACHED;
        lr->lr_ifp = ifp;
        lr->lr_key.proto = llproto;
        bcopy(addr, &lr->lr_key.addr, IF_LLREACH_MAXLEN);
+       lr->lr_rssi = IFNET_RSSI_UNKNOWN;
+       lr->lr_lqm = IFNET_LQM_THRESH_UNKNOWN;
+       lr->lr_npm = IFNET_NPM_THRESH_UNKNOWN;
        RB_INSERT(ll_reach_tree, &ifp->if_ll_srcs, lr);
        IFLR_UNLOCK(lr);
        lck_rw_done(&ifp->if_llreach_lock);
@@ -386,7 +393,7 @@ ifnet_llreach_free(struct if_llreach *lr)
 }
 
 u_int64_t
-ifnet_llreach_up2cal(struct if_llreach *lr, u_int64_t uptime)
+ifnet_llreach_up2calexp(struct if_llreach *lr, u_int64_t uptime)
 {
        u_int64_t calendar = 0;
 
@@ -411,6 +418,62 @@ ifnet_llreach_up2cal(struct if_llreach *lr, u_int64_t uptime)
        return (calendar);
 }
 
+u_int64_t
+ifnet_llreach_up2upexp(struct if_llreach *lr, u_int64_t uptime)
+{
+       return (lr->lr_reachable + uptime);
+}
+
+int
+ifnet_llreach_get_defrouter(struct ifnet *ifp, int af,
+    struct ifnet_llreach_info *iflri)
+{
+       struct radix_node_head *rnh;
+       struct sockaddr_storage dst_ss, mask_ss;
+       struct rtentry *rt;
+       int error = ESRCH;
+
+       VERIFY(ifp != NULL && iflri != NULL &&
+           (af == AF_INET || af == AF_INET6));
+
+       bzero(iflri, sizeof (*iflri));
+
+       if ((rnh = rt_tables[af]) == NULL)
+               return (error);
+
+       bzero(&dst_ss, sizeof (dst_ss));
+       bzero(&mask_ss, sizeof (mask_ss));
+       dst_ss.ss_family = af;
+       dst_ss.ss_len = (af == AF_INET) ? sizeof (struct sockaddr_in) :
+           sizeof (struct sockaddr_in6);
+
+       lck_mtx_lock(rnh_lock);
+       rt = rt_lookup(TRUE, SA(&dst_ss), SA(&mask_ss), rnh, ifp->if_index);
+       if (rt != NULL) {
+               struct rtentry *gwrt;
+
+               RT_LOCK(rt);
+               if ((rt->rt_flags & RTF_GATEWAY) &&
+                   (gwrt = rt->rt_gwroute) != NULL &&
+                   rt_key(rt)->sa_family == rt_key(gwrt)->sa_family &&
+                   (gwrt->rt_flags & RTF_UP)) {
+                       RT_UNLOCK(rt);
+                       RT_LOCK(gwrt);
+                       if (gwrt->rt_llinfo_get_iflri != NULL) {
+                               (*gwrt->rt_llinfo_get_iflri)(gwrt, iflri);
+                               error = 0;
+                       }
+                       RT_UNLOCK(gwrt);
+               } else {
+                       RT_UNLOCK(rt);
+               }
+               rtfree_locked(rt);
+       }
+       lck_mtx_unlock(rnh_lock);
+
+       return (error);
+}
+
 static struct if_llreach *
 iflr_alloc(int how)
 {
@@ -495,6 +558,44 @@ ifnet_lr2ri(struct if_llreach *lr, struct rt_reach_info *ri)
        ri->ri_refcnt = lri.lri_refcnt;
        ri->ri_probes = lri.lri_probes;
        ri->ri_rcv_expire = lri.lri_expire;
+       ri->ri_rssi = lri.lri_rssi;
+       ri->ri_lqm = lri.lri_lqm;
+       ri->ri_npm = lri.lri_npm;
+}
+
+void
+ifnet_lr2iflri(struct if_llreach *lr, struct ifnet_llreach_info *iflri)
+{
+       IFLR_LOCK_ASSERT_HELD(lr);
+
+       bzero(iflri, sizeof (*iflri));
+       /*
+        * Note here we return request count, not actual memory refcnt.
+        */
+       iflri->iflri_refcnt = lr->lr_reqcnt;
+       iflri->iflri_probes = lr->lr_probes;
+       iflri->iflri_rcv_expire = ifnet_llreach_up2upexp(lr, lr->lr_lastrcvd);
+       iflri->iflri_curtime = net_uptime();
+       switch (lr->lr_key.proto) {
+       case ETHERTYPE_IP:
+               iflri->iflri_netproto = PF_INET;
+               break;
+       case ETHERTYPE_IPV6:
+               iflri->iflri_netproto = PF_INET6;
+               break;
+       default:
+               /*
+                * This shouldn't be possible for the time being,
+                * since link-layer reachability records are only
+                * kept for ARP and ND6.
+                */
+               iflri->iflri_netproto = PF_UNSPEC;
+               break;
+       }
+       bcopy(&lr->lr_key.addr, &iflri->iflri_addr, IF_LLREACH_MAXLEN);
+       iflri->iflri_rssi = lr->lr_rssi;
+       iflri->iflri_lqm = lr->lr_lqm;
+       iflri->iflri_npm = lr->lr_npm;
 }
 
 void
@@ -509,9 +610,12 @@ ifnet_lr2lri(struct if_llreach *lr, struct if_llreach_info *lri)
        lri->lri_refcnt = lr->lr_reqcnt;
        lri->lri_ifindex = lr->lr_ifp->if_index;
        lri->lri_probes = lr->lr_probes;
-       lri->lri_expire = ifnet_llreach_up2cal(lr, lr->lr_lastrcvd);
+       lri->lri_expire = ifnet_llreach_up2calexp(lr, lr->lr_lastrcvd);
        lri->lri_proto = lr->lr_key.proto;
        bcopy(&lr->lr_key.addr, &lri->lri_addr, IF_LLREACH_MAXLEN);
+       lri->lri_rssi = lr->lr_rssi;
+       lri->lri_lqm = lr->lr_lqm;
+       lri->lri_npm = lr->lr_npm;
 }
 
 static int