Index: sys/net/if.c =================================================================== --- sys/net/if.c +++ sys/net/if.c @@ -425,12 +425,12 @@ ifaddr_byindex(u_short idx) { struct ifnet *ifp; - struct ifaddr *ifa = NULL; + struct ifaddr *ifa; IFNET_RLOCK_NOSLEEP(); ifp = ifnet_byindex_locked(idx); - if (ifp != NULL && (ifa = ifp->if_addr) != NULL) - ifa_ref(ifa); + if (ifp == NULL || (ifa = ifp->if_addr) == NULL || ifa_ref(ifa) == 0) + ifa = NULL; /* failure */ IFNET_RUNLOCK_NOSLEEP(); return (ifa); } @@ -964,12 +964,17 @@ void if_purgeaddrs(struct ifnet *ifp) { - struct ifaddr *ifa, *next; + struct ifaddr *ifa; +top:; NET_EPOCH_ENTER(); - CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { - if (ifa->ifa_addr->sa_family == AF_LINK) - continue; + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_LINK && ifa_ref(ifa) != 0) + break; + } + NET_EPOCH_EXIT(); + + if (ifa != NULL) { #ifdef INET /* XXX: Ugly!! ad hoc just for INET */ if (ifa->ifa_addr->sa_family == AF_INET) { @@ -981,7 +986,7 @@ ifr.ifra_broadaddr = *ifa->ifa_dstaddr; if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, NULL) == 0) - continue; + goto skip; } #endif /* INET */ #ifdef INET6 @@ -988,7 +993,7 @@ if (ifa->ifa_addr->sa_family == AF_INET6) { in6_purgeaddr(ifa); /* ifp_addrhead is already updated */ - continue; + goto skip; } #endif /* INET6 */ IF_ADDR_WLOCK(ifp); @@ -995,8 +1000,10 @@ CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(ifa); +skip: + ifa_free(ifa); + goto top; } - NET_EPOCH_EXIT(); } /* @@ -1829,11 +1836,11 @@ return (NULL); } -void +bool ifa_ref(struct ifaddr *ifa) { - refcount_acquire(&ifa->ifa_refcnt); + return (refcount_acquire_unless_zero(&ifa->ifa_refcnt)); } static void @@ -2200,12 +2207,9 @@ return; NET_EPOCH_ENTER(); ifa = ifaof_ifpforaddr(dst, ifp); - if (ifa) { + if (ifa != NULL && ifa_ref(ifa) != 0) { oifa = rt->rt_ifa; - if (oifa != ifa) { - ifa_free(oifa); - ifa_ref(ifa); - } + ifa_free(oifa); rt->rt_ifa = ifa; if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) ifa->ifa_rtrequest(cmd, rt, info); Index: sys/net/if_var.h =================================================================== --- sys/net/if_var.h +++ sys/net/if_var.h @@ -543,7 +543,7 @@ struct ifaddr * ifa_alloc(size_t size, int flags); void ifa_free(struct ifaddr *ifa); -void ifa_ref(struct ifaddr *ifa); +bool ifa_ref(struct ifaddr *ifa) __result_use_check; /* * Multicast address structure. This is analogous to the ifaddr Index: sys/netinet/if_ether.c =================================================================== --- sys/netinet/if_ether.c +++ sys/netinet/if_ether.c @@ -843,8 +843,8 @@ ia->ia_ifp == ifp) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr && (ia->ia_ifa.ifa_carp == NULL || - (*carp_iamatch_p)(&ia->ia_ifa, &enaddr))) { - ifa_ref(&ia->ia_ifa); + (*carp_iamatch_p)(&ia->ia_ifa, &enaddr)) && + ifa_ref(&ia->ia_ifa) != 0) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); goto match; } @@ -852,8 +852,8 @@ LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) if (((bridged && ia->ia_ifp->if_bridge == ifp->if_bridge) || ia->ia_ifp == ifp) && - isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { - ifa_ref(&ia->ia_ifa); + isaddr.s_addr == ia->ia_addr.sin_addr.s_addr && + ifa_ref(&ia->ia_ifa) != 0) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); goto match; } @@ -870,8 +870,8 @@ */ if (is_bridge) { LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { - if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia)) { - ifa_ref(&ia->ia_ifa); + if (BDG_MEMBER_MATCHES_ARP(itaddr.s_addr, ifp, ia) && + ifa_ref(&ia->ia_ifa) != 0) { ifp = ia->ia_ifp; IN_IFADDR_RUNLOCK(&in_ifa_tracker); goto match; @@ -889,9 +889,9 @@ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET && (ifa->ifa_carp == NULL || - (*carp_iamatch_p)(ifa, &enaddr))) { + (*carp_iamatch_p)(ifa, &enaddr)) && + ifa_ref(ifa) != 0) { ia = ifatoia(ifa); - ifa_ref(ifa); IF_ADDR_RUNLOCK(ifp); goto match; } @@ -901,11 +901,11 @@ * If bridging, fall back to using any inet address. */ IN_IFADDR_RLOCK(&in_ifa_tracker); - if (!bridged || (ia = CK_STAILQ_FIRST(&V_in_ifaddrhead)) == NULL) { + if (!bridged || (ia = CK_STAILQ_FIRST(&V_in_ifaddrhead)) == NULL || + ifa_ref(&ia->ia_ifa) == 0) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); goto drop; } - ifa_ref(&ia->ia_ifa); IN_IFADDR_RUNLOCK(&in_ifa_tracker); match: if (!enaddr) @@ -1399,9 +1399,10 @@ IF_ADDR_WLOCK(ia->ia_ifa.ifa_ifp); ia->ia_garp_count = 0; - if (callout_reset(&ia->ia_garp_timer, (1 << ia->ia_garp_count) * hz, - garp_rexmit, ia) == 0) { - ifa_ref(ifa); + if (ifa_ref(ifa) != 0 && + callout_reset(&ia->ia_garp_timer, (1 << ia->ia_garp_count) * hz, + garp_rexmit, ia) != 0) { + ifa_free(ifa); } IF_ADDR_WUNLOCK(ia->ia_ifa.ifa_ifp); } Index: sys/netinet/in.c =================================================================== --- sys/netinet/in.c +++ sys/netinet/in.c @@ -170,8 +170,8 @@ IN_IFADDR_RLOCK(&in_ifa_tracker); LIST_FOREACH(it, INADDR_HASH(in), ia_hash) { - if (it != ia && IA_SIN(it)->sin_addr.s_addr == in) { - ifa_ref(&it->ia_ifa); + if (it != ia && IA_SIN(it)->sin_addr.s_addr == in && + ifa_ref(&it->ia_ifa) != 0) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); return (it); } @@ -458,11 +458,12 @@ CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); IF_ADDR_WUNLOCK(ifp); - ifa_ref(ifa); /* in_ifaddrhead */ - IN_IFADDR_WLOCK(); - CK_STAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); - LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash); - IN_IFADDR_WUNLOCK(); + if (ifa_ref(ifa) != 0) { + IN_IFADDR_WLOCK(); + CK_STAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); + LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash); + IN_IFADDR_WUNLOCK(); + } /* * Give the interface a chance to initialize @@ -859,8 +860,8 @@ * the route itself to it. Make sure that routing daemons * get a heads-up. */ - if ((ia->ia_flags & IFA_ROUTE) == 0) { - ifa_ref(&ia->ia_ifa); + if ((ia->ia_flags & IFA_ROUTE) == 0 && + ifa_ref(&ia->ia_ifa) != 0) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); error = rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); Index: sys/netinet/ip_carp.c =================================================================== --- sys/netinet/ip_carp.c +++ sys/netinet/ip_carp.c @@ -669,8 +669,8 @@ error = ELOOP; } ifa = error ? NULL : match; - if (ifa != NULL) - ifa_ref(ifa); + if (ifa != NULL && ifa_ref(ifa) == 0) + ifa = NULL; IF_ADDR_RUNLOCK(ifp); if (ifa == NULL) { @@ -891,8 +891,8 @@ best = ifa; } IF_ADDR_RUNLOCK(ifp); - if (best != NULL) - ifa_ref(best); + if (best != NULL && ifa_ref(best) == 0) + best = NULL; return (best); } @@ -1176,10 +1176,10 @@ continue; if (!IN6_ARE_ADDR_EQUAL(taddr, IFA_IN6(ifa))) continue; - if (ifa->ifa_carp && ifa->ifa_carp->sc_state != MASTER) + if ((ifa->ifa_carp && ifa->ifa_carp->sc_state != MASTER) || + ifa_ref(ifa) == 0) { ifa = NULL; - else - ifa_ref(ifa); + } break; } IF_ADDR_RUNLOCK(ifp); @@ -1890,6 +1890,9 @@ KASSERT(ifa->ifa_carp == NULL, ("%s: ifa %p attached", __func__, ifa)); + if (ifa_ref(ifa) == 0) + return (ENXIO); + switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: @@ -1899,13 +1902,14 @@ #endif break; default: - return (EPROTOTYPE); + error = EPROTOTYPE; + goto err; } sx_xlock(&carp_sx); if (ifp->if_carp == NULL) { - sx_xunlock(&carp_sx); - return (ENOPROTOOPT); + error = ENOPROTOOPT; + goto err_unlock; } IFNET_FOREACH_CARP(ifp, sc) @@ -1912,15 +1916,14 @@ if (sc->sc_vhid == vhid) break; if (sc == NULL) { - sx_xunlock(&carp_sx); - return (ENOENT); + error = ENOENT; + goto err_unlock; } error = carp_multicast_setup(cif, ifa->ifa_addr->sa_family); if (error) { CIF_FREE(cif); - sx_xunlock(&carp_sx); - return (error); + goto err_unlock; } index = sc->sc_naddrs + sc->sc_naddrs6 + 1; @@ -1942,8 +1945,6 @@ #endif } - ifa_ref(ifa); - CARP_LOCK(sc); sc->sc_ifas[index - 1] = ifa; ifa->ifa_carp = sc; @@ -1954,6 +1955,12 @@ sx_xunlock(&carp_sx); return (0); + +err_unlock: + sx_xunlock(&carp_sx); +err: + ifa_free(ifa); + return (error); } void Index: sys/netinet/raw_ip.c =================================================================== --- sys/netinet/raw_ip.c +++ sys/netinet/raw_ip.c @@ -758,8 +758,8 @@ IN_IFADDR_RLOCK(&in_ifa_tracker); CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (ia->ia_ifa.ifa_addr == sa - && (ia->ia_flags & IFA_ROUTE)) { - ifa_ref(&ia->ia_ifa); + && (ia->ia_flags & IFA_ROUTE) && + ifa_ref(&ia->ia_ifa) != 0) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); /* * in_scrubprefix() kills the interface route. @@ -786,11 +786,11 @@ if (ia->ia_ifa.ifa_addr == sa) break; } - if (ia == NULL || (ia->ia_flags & IFA_ROUTE)) { + if (ia == NULL || (ia->ia_flags & IFA_ROUTE) || + ifa_ref(&ia->ia_ifa) == 0) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); return; } - ifa_ref(&ia->ia_ifa); IN_IFADDR_RUNLOCK(&in_ifa_tracker); flags = RTF_UP; ifp = ia->ia_ifa.ifa_ifp; Index: sys/netinet6/in6.c =================================================================== --- sys/netinet6/in6.c +++ sys/netinet6/in6.c @@ -1117,17 +1117,17 @@ } ia->ia_ifp = ifp; - ifa_ref(&ia->ia_ifa); /* if_addrhead */ - IF_ADDR_WLOCK(ifp); - CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); - IF_ADDR_WUNLOCK(ifp); - - ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ - IN6_IFADDR_WLOCK(); - CK_STAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); - CK_LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash); - IN6_IFADDR_WUNLOCK(); - + if (ifa_ref(&ia->ia_ifa) != 0) { + IF_ADDR_WLOCK(ifp); + CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); + IF_ADDR_WUNLOCK(ifp); + } + if (ifa_ref(&ia->ia_ifa) != 0) { + IN6_IFADDR_WLOCK(); + CK_STAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); + CK_LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash); + IN6_IFADDR_WUNLOCK(); + } return (ia); } @@ -1476,10 +1476,8 @@ continue; if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { if ((((struct in6_ifaddr *)ifa)->ia6_flags & - ignoreflags) != 0) - continue; - ifa_ref(ifa); - break; + ignoreflags) == 0 && ifa_ref(ifa) != 0) + break; } } IF_ADDR_RUNLOCK(ifp); @@ -1504,8 +1502,8 @@ if (zoneid != 0 && zoneid != ia->ia_addr.sin6_scope_id) continue; - ifa_ref(&ia->ia_ifa); - break; + if (ifa_ref(&ia->ia_ifa) != 0) + break; } } IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); @@ -1525,10 +1523,9 @@ CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; - if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) { - ifa_ref(ifa); + if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)) && + ifa_ref(ifa) != 0) break; - } } IF_ADDR_RUNLOCK(ifp); @@ -1860,8 +1857,7 @@ besta = (struct in6_ifaddr *)ifa; } } - if (besta) { - ifa_ref(&besta->ia_ifa); + if (besta && ifa_ref(&besta->ia_ifa) != 0) { IF_ADDR_RUNLOCK(ifp); return (besta); } @@ -1880,21 +1876,18 @@ dep[1] = (struct in6_ifaddr *)ifa; continue; } - - if (ifa != NULL) - ifa_ref(ifa); + if (ifa_ref(ifa) == 0) + continue; IF_ADDR_RUNLOCK(ifp); return (struct in6_ifaddr *)ifa; } /* use the last-resort values, that are, deprecated addresses */ - if (dep[0]) { - ifa_ref((struct ifaddr *)dep[0]); + if (dep[0] && ifa_ref((struct ifaddr *)dep[0]) != 0) { IF_ADDR_RUNLOCK(ifp); return dep[0]; } - if (dep[1]) { - ifa_ref((struct ifaddr *)dep[1]); + if (dep[1] && ifa_ref((struct ifaddr *)dep[1]) != 0) { IF_ADDR_RUNLOCK(ifp); return dep[1]; } Index: sys/netinet6/nd6.c =================================================================== --- sys/netinet6/nd6.c +++ sys/netinet6/nd6.c @@ -1106,8 +1106,9 @@ if (!IFA6_IS_DEPRECATED(it6)) public_ifa6 = it6; } - if (public_ifa6 != NULL) - ifa_ref(&public_ifa6->ia_ifa); + if (public_ifa6 != NULL && + ifa_ref(&public_ifa6->ia_ifa) == 0) + public_ifa6 = NULL; IF_ADDR_RUNLOCK(ifp); if (public_ifa6 != NULL) { Index: sys/netinet6/nd6_nbr.c =================================================================== --- sys/netinet6/nd6_nbr.c +++ sys/netinet6/nd6_nbr.c @@ -1261,6 +1261,9 @@ return; } + if (ifa_ref(ifa) == 0) + return; /* Network address has been freed */ + dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT | M_ZERO); if (dp == NULL) { log(LOG_ERR, "nd6_dad_start: memory allocation failed for " @@ -1267,6 +1270,7 @@ "%s(%s)\n", ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); + ifa_free(ifa); return; } callout_init(&dp->dad_timer_ch, 0); @@ -1283,7 +1287,6 @@ * (re)initialization. */ dp->dad_ifa = ifa; - ifa_ref(dp->dad_ifa); dp->dad_count = V_ip6_dad_count; dp->dad_ns_icount = dp->dad_na_icount = 0; dp->dad_ns_ocount = dp->dad_ns_tcount = 0; Index: sys/netinet6/nd6_rtr.c =================================================================== --- sys/netinet6/nd6_rtr.c +++ sys/netinet6/nd6_rtr.c @@ -480,7 +480,8 @@ IF_ADDR_RLOCK(ifp); ifa = CK_STAILQ_FIRST(&ifp->if_addrhead); info.rti_info[RTAX_IFP] = ifa->ifa_addr; - ifa_ref(ifa); + if (ifa_ref(ifa) == 0) + ifa = NULL; IF_ADDR_RUNLOCK(ifp); info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; } else @@ -1909,8 +1910,8 @@ /* XXX: freebsd does not have ifa_ifwithaf */ IF_ADDR_RLOCK(ifp); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family == AF_INET6) { - ifa_ref(ifa); + if (ifa->ifa_addr->sa_family == AF_INET6 && + ifa_ref(ifa) != 0) { break; } }