+/*
+ * 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));
+}
+