/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
/*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>
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..
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.
+ */
+ 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;
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,
} else
#endif /* __APPLE__*/
{
+ /*
+ * If we're looking up with a scope,
+ * find using a matching interface.
+ */
+ if (ifscope != IFSCOPE_NONE &&
+ ifp->if_index != ifscope)
+ continue;
+
/*
* if we have a special address handler,
* then use it instead of the generic one.