diff options
Diffstat (limited to 'sys/netinet/ip_carp.c')
-rw-r--r-- | sys/netinet/ip_carp.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index edeec2a..8c7bd0c 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1500,6 +1500,7 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) /* we have to do it by hands to check we won't match on us */ ia_if = NULL; own = 0; + IN_IFADDR_RLOCK(); TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { /* and, yeah, we need a multicast-capable iface too */ if (ia->ia_ifp != SC2IFP(sc) && @@ -1513,20 +1514,30 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) } } - if (!ia_if) + if (!ia_if) { + IN_IFADDR_RUNLOCK(); return (EADDRNOTAVAIL); + } ia = ia_if; + ifa_ref(&ia->ia_ifa); + IN_IFADDR_RUNLOCK(); + ifp = ia->ia_ifp; if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 || - (imo->imo_multicast_ifp && imo->imo_multicast_ifp != ifp)) + (imo->imo_multicast_ifp && imo->imo_multicast_ifp != ifp)) { + ifa_free(&ia->ia_ifa); return (EADDRNOTAVAIL); + } if (imo->imo_num_memberships == 0) { addr.s_addr = htonl(INADDR_CARP_GROUP); - if ((imo->imo_membership[0] = in_addmulti(&addr, ifp)) == NULL) + if ((imo->imo_membership[0] = in_addmulti(&addr, ifp)) == + NULL) { + ifa_free(&ia->ia_ifa); return (ENOBUFS); + } imo->imo_num_memberships++; imo->imo_multicast_ifp = ifp; imo->imo_multicast_ttl = CARP_DFLTTL; @@ -1601,11 +1612,13 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin) carp_setrun(sc, 0); CARP_UNLOCK(cif); + ifa_free(&ia->ia_ifa); /* XXXRW: should hold reference for softc. */ return (0); cleanup: in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); + ifa_free(&ia->ia_ifa); return (error); } |