+ char outbuf[IFNAMSIZ];
+ struct if_clone *ifc;
+ int error = 0;
+
+ *total = if_cloners_count;
+ if (dst == USER_ADDR_NULL) {
+ /* Just asking how many there are. */
+ return (0);
+ }
+
+ if (count < 0)
+ return (EINVAL);
+
+ count = (if_cloners_count < count) ? if_cloners_count : count;
+
+ for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
+ ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
+ strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ);
+ error = copyout(outbuf, dst, IFNAMSIZ);
+ if (error)
+ break;
+ }
+
+ return (error);
+}
+#endif /* IF_CLONE_LIST */
+
+/*
+ * 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)
+{
+ 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) {
+ IFA_LOCK_SPIN(&ia->ia_ifa);
+ if (ia->ia_addr.sin_addr.s_addr == addr &&
+ (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope)) {
+ IFA_ADDREF_LOCKED(&ia->ia_ifa); /* for caller */
+ IFA_UNLOCK(&ia->ia_ifa);
+ break;
+ }
+ IFA_UNLOCK(&ia->ia_ifa);
+ }
+ lck_rw_done(in_ifaddr_rwlock);
+ return (ia);
+}
+
+#if INET6
+/*
+ * Similar to ifa_foraddr, except that this for IPv6.
+ */
+__private_extern__ struct in6_ifaddr *
+ifa_foraddr6(struct in6_addr *addr6)
+{
+ return (ifa_foraddr6_scoped(addr6, IFSCOPE_NONE));
+}
+
+__private_extern__ struct in6_ifaddr *
+ifa_foraddr6_scoped(struct in6_addr *addr6, unsigned int scope)
+{
+ struct in6_ifaddr *ia = NULL;
+
+ lck_rw_lock_shared(&in6_ifaddr_rwlock);
+ for (ia = in6_ifaddrs; ia; ia = ia->ia_next) {
+ IFA_LOCK(&ia->ia_ifa);
+ if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, addr6) &&
+ (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope)) {
+ IFA_ADDREF_LOCKED(&ia->ia_ifa); /* for caller */
+ IFA_UNLOCK(&ia->ia_ifa);
+ break;
+ }
+ IFA_UNLOCK(&ia->ia_ifa);
+ }
+ lck_rw_done(&in6_ifaddr_rwlock);
+
+ return (ia);
+}
+#endif /* INET6 */
+
+/*
+ * Return the first (primary) address of a given family on an interface.
+ */
+__private_extern__ struct ifaddr *
+ifa_ifpgetprimary(struct ifnet *ifp, int family)
+{
+ struct ifaddr *ifa;
+
+ ifnet_lock_shared(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ IFA_LOCK_SPIN(ifa);
+ if (ifa->ifa_addr->sa_family == family) {
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(ifa);
+ break;
+ }
+ IFA_UNLOCK(ifa);
+ }
+ ifnet_lock_done(ifp);
+
+ return (ifa);
+}
+
+/*
+ * Locate an interface based on a complete address.
+ */
+/*ARGSUSED*/
+struct ifaddr *
+ifa_ifwithaddr(const struct sockaddr *addr)
+{
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct ifaddr *result = NULL;
+
+#define equal(a1, a2) \
+ (bcmp((const void*)(a1), (const void*)(a2), \
+ ((const struct sockaddr *)(a1))->sa_len) == 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) {
+ IFA_LOCK_SPIN(ifa);
+ if (ifa->ifa_addr->sa_family != addr->sa_family) {
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+ if (equal(addr, ifa->ifa_addr)) {
+ result = ifa;
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(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;
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(ifa);
+ break;
+ }
+ IFA_UNLOCK(ifa);
+ }
+ ifnet_lock_done(ifp);
+ }
+ ifnet_head_done();
+
+ return (result);
+}
+/*
+ * Locate the point to point interface with a given destination address.
+ */
+/*ARGSUSED*/
+struct ifaddr *
+ifa_ifwithdstaddr(const struct sockaddr *addr)
+{
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct ifaddr *result = NULL;
+
+ ifnet_head_lock_shared();
+ for (ifp = ifnet_head.tqh_first; ifp && !result;
+ ifp = ifp->if_link.tqe_next) {
+ if ((ifp->if_flags & IFF_POINTOPOINT)) {
+ ifnet_lock_shared(ifp);
+ for (ifa = ifp->if_addrhead.tqh_first; ifa;
+ ifa = ifa->ifa_link.tqe_next) {
+ IFA_LOCK_SPIN(ifa);
+ if (ifa->ifa_addr->sa_family !=
+ addr->sa_family) {
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+ if (ifa->ifa_dstaddr &&
+ equal(addr, ifa->ifa_dstaddr)) {
+ result = ifa;
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(ifa);
+ break;
+ }
+ IFA_UNLOCK(ifa);
+ }
+ ifnet_lock_done(ifp);
+ }
+ }
+ ifnet_head_done();
+ 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) {
+ IFA_LOCK_SPIN(ifa);
+ if (ifa->ifa_addr->sa_family != addr->sa_family) {
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+ if (equal(addr, ifa->ifa_addr)) {
+ result = ifa;
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(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;
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(ifa);
+ break;
+ }
+ IFA_UNLOCK(ifa);
+ }
+ 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.
+ */
+static struct ifaddr *
+ifa_ifwithnet_common(const struct sockaddr *addr, unsigned int ifscope)
+{
+ struct ifnet *ifp;
+ struct ifaddr *ifa = NULL;
+ struct ifaddr *ifa_maybe = NULL;
+ u_int af = addr->sa_family;
+ const char *addr_data = addr->sa_data, *cplim;
+
+#if INET6
+ if ((af != AF_INET && af != AF_INET6) ||
+ (af == AF_INET && !ip_doscopedroute) ||
+ (af == AF_INET6 && !ip6_doscopedroute))
+#else
+ if (af != AF_INET || !ip_doscopedroute)
+#endif /* !INET6 */
+ ifscope = IFSCOPE_NONE;
+
+ ifnet_head_lock_shared();
+ /*
+ * AF_LINK addresses can be looked up directly by their index number,
+ * so do that if we can.
+ */
+ if (af == AF_LINK) {
+ const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)addr;
+ if (sdl->sdl_index && sdl->sdl_index <= if_index) {
+ ifa = ifnet_addrs[sdl->sdl_index - 1];
+ if (ifa != NULL)
+ IFA_ADDREF(ifa);
+
+ ifnet_head_done();
+ return (ifa);
+ }
+ }
+
+ /*
+ * Scan though each interface, looking for ones that have
+ * addresses in this address family.
+ */
+ for (ifp = ifnet_head.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
+ ifnet_lock_shared(ifp);
+ for (ifa = ifp->if_addrhead.tqh_first; ifa;
+ ifa = ifa->ifa_link.tqe_next) {
+ const char *cp, *cp2, *cp3;
+
+ IFA_LOCK(ifa);
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != af) {
+next:
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+#ifndef __APPLE__
+/* This breaks tunneling application trying to install a route with
+ * a specific subnet and the local address as the destination
+ * It's breaks binary compatibility with previous version of MacOS X
+ */
+ if (
+#if INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */
+ addr->sa_family != AF_INET6 &&
+#endif
+ ifp->if_flags & IFF_POINTOPOINT) {
+ /*
+ * This is a bit broken as it doesn't
+ * take into account that the remote end may
+ * be a single node in the network we are
+ * looking for.
+ * The trouble is that we don't know the
+ * netmask for the remote end.
+ */
+ if (ifa->ifa_dstaddr != 0 &&
+ equal(addr, ifa->ifa_dstaddr)) {
+ IFA_ADDREF_LOCKED(ifa);
+ IFA_UNLOCK(ifa);
+ break;
+ }
+ IFA_UNLOCK(ifa);
+ } else
+#endif /* __APPLE__*/
+ {
+ /*
+ * If we're looking up with a scope,
+ * find using a matching interface.
+ */
+ if (ifscope != IFSCOPE_NONE &&
+ ifp->if_index != ifscope) {
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+
+ /*
+ * Scan all the bits in the ifa's address.
+ * If a bit dissagrees with what we are
+ * looking for, mask it with the netmask
+ * to see if it really matters.
+ * (A byte at a time)
+ */
+ if (ifa->ifa_netmask == 0) {
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+ cp = addr_data;
+ cp2 = ifa->ifa_addr->sa_data;
+ cp3 = ifa->ifa_netmask->sa_data;
+ cplim = ifa->ifa_netmask->sa_len
+ + (char *)ifa->ifa_netmask;
+ while (cp3 < cplim)
+ if ((*cp++ ^ *cp2++) & *cp3++)
+ goto next; /* next address! */
+ /*
+ * If the netmask of what we just found
+ * is more specific than what we had before
+ * (if we had one) then remember the new one
+ * before continuing to search
+ * for an even better one.
+ */
+ if (ifa_maybe == NULL ||
+ rn_refines((caddr_t)ifa->ifa_netmask,
+ (caddr_t)ifa_maybe->ifa_netmask)) {
+ IFA_ADDREF_LOCKED(ifa); /* ifa_maybe */
+ IFA_UNLOCK(ifa);
+ if (ifa_maybe != NULL)
+ IFA_REMREF(ifa_maybe);
+ ifa_maybe = ifa;
+ } else {
+ IFA_UNLOCK(ifa);
+ }
+ }
+ IFA_LOCK_ASSERT_NOTHELD(ifa);
+ }
+ ifnet_lock_done(ifp);
+
+ if (ifa != NULL)
+ break;
+ }
+ ifnet_head_done();
+
+ if (ifa == NULL)
+ ifa = ifa_maybe;
+ else if (ifa_maybe != NULL)
+ IFA_REMREF(ifa_maybe);
+
+ return (ifa);
+}
+
+/*
+ * Find an interface address specific to an interface best matching
+ * a given address.
+ */
+struct ifaddr *
+ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
+{
+ struct ifaddr *ifa = NULL;
+ const char *cp, *cp2, *cp3;
+ char *cplim;
+ struct ifaddr *ifa_maybe = NULL;
+ struct ifaddr *better_ifa_maybe = NULL;
+ u_int af = addr->sa_family;
+
+ if (af >= AF_MAX)
+ return (NULL);
+
+ ifnet_lock_shared(ifp);
+ for (ifa = ifp->if_addrhead.tqh_first; ifa;
+ ifa = ifa->ifa_link.tqe_next) {
+ IFA_LOCK(ifa);
+ if (ifa->ifa_addr->sa_family != af) {
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+ if (ifa_maybe == NULL) {
+ IFA_ADDREF_LOCKED(ifa); /* for ifa_maybe */
+ ifa_maybe = ifa;
+ }
+ if (ifa->ifa_netmask == 0) {
+ if (equal(addr, ifa->ifa_addr) || (ifa->ifa_dstaddr &&
+ equal(addr, ifa->ifa_dstaddr))) {
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(ifa);
+ break;
+ }
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) {
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(ifa);
+ break;
+ }
+ } else {
+ if (equal(addr, ifa->ifa_addr)) {
+ /* exact match */
+ IFA_ADDREF_LOCKED(ifa); /* for caller */
+ IFA_UNLOCK(ifa);
+ break;
+ }
+ cp = addr->sa_data;
+ cp2 = ifa->ifa_addr->sa_data;
+ cp3 = ifa->ifa_netmask->sa_data;
+ cplim = ifa->ifa_netmask->sa_len +
+ (char *)ifa->ifa_netmask;
+ for (; cp3 < cplim; cp3++)
+ if ((*cp++ ^ *cp2++) & *cp3)
+ break;
+ if (cp3 == cplim) {
+ /* subnet match */
+ if (better_ifa_maybe == NULL) {
+ /* for better_ifa_maybe */
+ IFA_ADDREF_LOCKED(ifa);
+ better_ifa_maybe = ifa;
+ }
+ }
+ }
+ IFA_UNLOCK(ifa);
+ }
+
+ if (ifa == NULL) {
+ if (better_ifa_maybe != NULL) {
+ ifa = better_ifa_maybe;
+ better_ifa_maybe = NULL;
+ } else {
+ ifa = ifa_maybe;
+ ifa_maybe = NULL;
+ }
+ }
+
+ ifnet_lock_done(ifp);
+
+ if (better_ifa_maybe != NULL)
+ IFA_REMREF(better_ifa_maybe);
+ if (ifa_maybe != NULL)
+ IFA_REMREF(ifa_maybe);
+
+ return (ifa);
+}
+
+#include <net/route.h>
+
+/*
+ * Default action when installing a route with a Link Level gateway.
+ * Lookup an appropriate real ifa to point to.
+ * This should be moved to /sys/net/link.c eventually.
+ */
+void
+link_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
+{
+ struct ifaddr *ifa;
+ struct sockaddr *dst;
+ struct ifnet *ifp;
+ void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *);
+
+ 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;
+
+ /* Become a regular mutex, just in case */
+ RT_CONVERT_LOCK(rt);
+
+ ifa = ifaof_ifpforaddr(dst, ifp);
+ if (ifa) {
+ rtsetifa(rt, ifa);
+ IFA_LOCK_SPIN(ifa);
+ ifa_rtrequest = ifa->ifa_rtrequest;
+ IFA_UNLOCK(ifa);
+ if (ifa_rtrequest != NULL && ifa_rtrequest != link_rtrequest)
+ ifa_rtrequest(cmd, rt, sa);
+ IFA_REMREF(ifa);
+ }
+}
+
+/*
+ * if_updown will set the interface up or down. It will
+ * prevent other up/down events from occurring until this
+ * up/down event has completed.
+ *
+ * Caller must lock ifnet. This function will drop the
+ * lock. This allows ifnet_set_flags to set the rest of
+ * the flags after we change the up/down state without
+ * dropping the interface lock between setting the
+ * up/down state and updating the rest of the flags.
+ */
+__private_extern__ void
+if_updown(
+ struct ifnet *ifp,
+ int up)
+{
+ int i;
+ struct ifaddr **ifa;
+ struct timespec tv;
+
+ /* Wait until no one else is changing the up/down state */
+ while ((ifp->if_eflags & IFEF_UPDOWNCHANGE) != 0) {
+ tv.tv_sec = 0;
+ tv.tv_nsec = NSEC_PER_SEC / 10;
+ ifnet_lock_done(ifp);
+ msleep(&ifp->if_eflags, NULL, 0, "if_updown", &tv);
+ ifnet_lock_exclusive(ifp);
+ }
+
+ /* Verify that the interface isn't already in the right state */
+ if ((!up && (ifp->if_flags & IFF_UP) == 0) ||
+ (up && (ifp->if_flags & IFF_UP) == IFF_UP)) {
+ return;
+ }
+
+ /* Indicate that the up/down state is changing */
+ ifp->if_eflags |= IFEF_UPDOWNCHANGE;
+
+ /* Mark interface up or down */
+ if (up) {
+ ifp->if_flags |= IFF_UP;
+ }
+ else {
+ ifp->if_flags &= ~IFF_UP;
+ }
+
+ ifnet_touch_lastchange(ifp);
+
+ /* Drop the lock to notify addresses and route */
+ ifnet_lock_done(ifp);
+ if (ifnet_get_address_list(ifp, &ifa) == 0) {
+ for (i = 0; ifa[i] != 0; i++) {
+ pfctlinput(up ? PRC_IFUP : PRC_IFDOWN, ifa[i]->ifa_addr);
+ }
+ ifnet_free_address_list(ifa);
+ }
+ rt_ifmsg(ifp);
+
+ /* Aquire the lock to clear the changing flag and flush the send queue */
+ ifnet_lock_exclusive(ifp);
+ if (!up)
+ if_qflush(&ifp->if_snd);
+ ifp->if_eflags &= ~IFEF_UPDOWNCHANGE;
+ wakeup(&ifp->if_eflags);
+
+ return;
+}
+
+/*
+ * Mark an interface down and notify protocols of
+ * the transition.
+ */
+void
+if_down(
+ struct ifnet *ifp)
+{
+ ifnet_lock_exclusive(ifp);
+ if_updown(ifp, 0);
+ ifnet_lock_done(ifp);
+}
+
+/*
+ * Mark an interface up and notify protocols of
+ * the transition.
+ */
+void
+if_up(
+ struct ifnet *ifp)
+{
+ ifnet_lock_exclusive(ifp);
+ if_updown(ifp, 1);
+ ifnet_lock_done(ifp);
+}
+
+/*
+ * Flush an interface queue.
+ */
+static void
+if_qflush(struct ifqueue *ifq)
+{
+ struct mbuf *m, *n;