Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if.c
Show First 20 Lines • Show All 1,042 Lines • ▼ Show 20 Lines | |||||
if_purgemaddrs(struct ifnet *ifp) | if_purgemaddrs(struct ifnet *ifp) | ||||
{ | { | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
IF_ADDR_WLOCK(ifp); | IF_ADDR_WLOCK(ifp); | ||||
while (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) { | while (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) { | ||||
ifma = CK_STAILQ_FIRST(&ifp->if_multiaddrs); | ifma = CK_STAILQ_FIRST(&ifp->if_multiaddrs); | ||||
CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); | CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); | ||||
ifma->ifma_flags &= ~IFMA_F_ENQUEUED; | |||||
MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname); | |||||
if_delmulti_locked(ifp, ifma, 1); | if_delmulti_locked(ifp, ifma, 1); | ||||
} | } | ||||
IF_ADDR_WUNLOCK(ifp); | IF_ADDR_WUNLOCK(ifp); | ||||
} | } | ||||
/* | /* | ||||
* Detach an interface, removing it from the list of "active" interfaces. | * Detach an interface, removing it from the list of "active" interfaces. | ||||
* If vmove flag is set on entry to if_detach_internal(), perform only a | * If vmove flag is set on entry to if_detach_internal(), perform only a | ||||
▲ Show 20 Lines • Show All 2,357 Lines • ▼ Show 20 Lines | if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa, | ||||
if (dupsa == NULL) { | if (dupsa == NULL) { | ||||
free(ifma, M_IFMADDR); | free(ifma, M_IFMADDR); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
bcopy(sa, dupsa, sa->sa_len); | bcopy(sa, dupsa, sa->sa_len); | ||||
ifma->ifma_addr = dupsa; | ifma->ifma_addr = dupsa; | ||||
ifma->ifma_ifp = ifp; | ifma->ifma_ifp = ifp; | ||||
if_ref(ifp); | |||||
ifma->ifma_refcount = 1; | ifma->ifma_refcount = 1; | ||||
ifma->ifma_protospec = NULL; | ifma->ifma_protospec = NULL; | ||||
if (llsa == NULL) { | if (llsa == NULL) { | ||||
ifma->ifma_lladdr = NULL; | ifma->ifma_lladdr = NULL; | ||||
return (ifma); | return (ifma); | ||||
} | } | ||||
Show All 17 Lines | |||||
*/ | */ | ||||
#ifdef MCAST_VERBOSE | #ifdef MCAST_VERBOSE | ||||
extern void kdb_backtrace(void); | extern void kdb_backtrace(void); | ||||
#endif | #endif | ||||
static void | static void | ||||
if_freemulti_internal(struct ifmultiaddr *ifma) | if_freemulti_internal(struct ifmultiaddr *ifma) | ||||
{ | { | ||||
#ifdef MCAST_VERBOSE | |||||
kdb_backtrace(); | |||||
printf("%s freeing ifma: %p\n", __func__, ifma); | |||||
#endif | |||||
KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d", | KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d", | ||||
ifma->ifma_refcount)); | ifma->ifma_refcount)); | ||||
if (ifma->ifma_lladdr != NULL) | if (ifma->ifma_lladdr != NULL) | ||||
free(ifma->ifma_lladdr, M_IFMADDR); | free(ifma->ifma_lladdr, M_IFMADDR); | ||||
#ifdef MCAST_VERBOSE | |||||
kdb_backtrace(); | |||||
printf("%s freeing ifma: %p\n", __func__, ifma); | |||||
#endif | |||||
free(ifma->ifma_addr, M_IFMADDR); | free(ifma->ifma_addr, M_IFMADDR); | ||||
free(ifma, M_IFMADDR); | free(ifma, M_IFMADDR); | ||||
} | } | ||||
static void | static void | ||||
if_destroymulti(epoch_context_t ctx) | if_destroymulti(epoch_context_t ctx) | ||||
{ | { | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | #endif | ||||
* list. | * list. | ||||
*/ | */ | ||||
if (llsa != NULL) { | if (llsa != NULL) { | ||||
ll_ifma = if_findmulti(ifp, llsa); | ll_ifma = if_findmulti(ifp, llsa); | ||||
if (ll_ifma == NULL) { | if (ll_ifma == NULL) { | ||||
ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT); | ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT); | ||||
if (ll_ifma == NULL) { | if (ll_ifma == NULL) { | ||||
--ifma->ifma_refcount; | --ifma->ifma_refcount; | ||||
if (ifma->ifma_refcount == 0) | |||||
if_freemulti(ifma); | if_freemulti(ifma); | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto free_llsa_out; | goto free_llsa_out; | ||||
} | } | ||||
ll_ifma->ifma_flags |= IFMA_F_ENQUEUED; | ll_ifma->ifma_flags |= IFMA_F_ENQUEUED; | ||||
CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma, | CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma, | ||||
ifma_link); | ifma_link); | ||||
} else | } else | ||||
ll_ifma->ifma_refcount++; | ll_ifma->ifma_refcount++; | ||||
ifma->ifma_llifma = ll_ifma; | ifma->ifma_llifma = ll_ifma; | ||||
} | } | ||||
/* | /* | ||||
* We now have a new multicast address, ifma, and possibly a new or | * We now have a new multicast address, ifma, and possibly a new or | ||||
* referenced link layer address. Add the primary address to the | * referenced link layer address. Add the primary address to the | ||||
* ifnet address list. | * ifnet address list. | ||||
*/ | */ | ||||
ifma->ifma_flags |= IFMA_F_ENQUEUED; | ifma->ifma_flags |= IFMA_F_ENQUEUED; | ||||
MCDPRINTF("insert ifma: %p in %s\n", ifma, ifp->if_xname); | |||||
CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); | CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); | ||||
if (retifma != NULL) | if (retifma != NULL) | ||||
*retifma = ifma; | *retifma = ifma; | ||||
/* | /* | ||||
* Must generate the message while holding the lock so that 'ifma' | * Must generate the message while holding the lock so that 'ifma' | ||||
* pointer is still valid. | * pointer is still valid. | ||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | |||||
* Return 0 if the reference count was decremented. | * Return 0 if the reference count was decremented. | ||||
* Return 1 if the final reference was released, indicating that the | * Return 1 if the final reference was released, indicating that the | ||||
* hardware hash filter should be reprogrammed. | * hardware hash filter should be reprogrammed. | ||||
*/ | */ | ||||
static int | static int | ||||
if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching) | if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching) | ||||
{ | { | ||||
struct ifmultiaddr *ll_ifma; | struct ifmultiaddr *ll_ifma; | ||||
struct ifmultiaddr *ifmatmp; | |||||
if (ifp != NULL && ifma->ifma_ifp != NULL) { | if (ifp != NULL && ifma->ifma_ifp != NULL) { | ||||
KASSERT(ifma->ifma_ifp == ifp, | KASSERT(ifma->ifma_ifp == ifp, | ||||
("%s: inconsistent ifp %p", __func__, ifp)); | ("%s: inconsistent ifp %p", __func__, ifp)); | ||||
IF_ADDR_WLOCK_ASSERT(ifp); | IF_ADDR_WLOCK_ASSERT(ifp); | ||||
} | } | ||||
ifp = ifma->ifma_ifp; | MPASS(ifma->ifma_ifp == NULL || ifma->ifma_ifp == ifp); | ||||
MCDPRINTF("%s freeing %p from %s \n", __func__, ifma, ifp ? ifp->if_xname : ""); | MCDPRINTF("%s freeing %p from %s \n", __func__, ifma, ifp ? ifp->if_xname : ""); | ||||
if (ifp) { | |||||
if (ifma->ifma_flags & IFMA_F_ENQUEUED) { | |||||
MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname); | |||||
CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); | |||||
ifma->ifma_flags &= ~IFMA_F_ENQUEUED; | |||||
} | |||||
/* | /* | ||||
* If the ifnet is detaching, null out references to ifnet, | * If this is a link level interface, we need to ensure that we've cleared any | ||||
* so that upper protocol layers will notice, and not attempt | * dangling references | ||||
* to obtain locks for an ifnet which no longer exists. The | |||||
* routing socket announcement must happen before the ifnet | |||||
* instance is detached from the system. | |||||
*/ | */ | ||||
if (detaching) { | CK_STAILQ_FOREACH(ifmatmp, &ifp->if_multiaddrs, ifma_link) { | ||||
#ifdef DIAGNOSTIC | if (ifmatmp->ifma_llifma == ifma) | ||||
printf("%s: detaching ifnet instance %p\n", __func__, ifp); | ifmatmp->ifma_llifma = NULL; | ||||
#endif | } | ||||
/* | |||||
* ifp may already be nulled out if we are being reentered | |||||
* to delete the ll_ifma. | |||||
*/ | |||||
if (ifp != NULL) { | |||||
rt_newmaddrmsg(RTM_DELMADDR, ifma); | rt_newmaddrmsg(RTM_DELMADDR, ifma); | ||||
if_rele(ifp); | |||||
ifma->ifma_ifp = NULL; | ifma->ifma_ifp = NULL; | ||||
} | } | ||||
} | ifma->ifma_llifma = NULL; | ||||
if (--ifma->ifma_refcount > 0) | if (--ifma->ifma_refcount > 0) | ||||
return 0; | return 0; | ||||
if (ifp != NULL && detaching == 0 && (ifma->ifma_flags & IFMA_F_ENQUEUED)) { | |||||
CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); | |||||
ifma->ifma_flags &= ~IFMA_F_ENQUEUED; | |||||
} | |||||
/* | /* | ||||
* If this ifma is a network-layer ifma, a link-layer ifma may | * If this ifma is a network-layer ifma, a link-layer ifma may | ||||
* have been associated with it. Release it first if so. | * have been associated with it. Release it first if so. | ||||
*/ | */ | ||||
ll_ifma = ifma->ifma_llifma; | ll_ifma = ifma->ifma_llifma; | ||||
if (ll_ifma != NULL) { | if (ifp && ll_ifma != NULL) { | ||||
KASSERT(ifma->ifma_lladdr != NULL, | ifp = ll_ifma->ifma_ifp; | ||||
("%s: llifma w/o lladdr", __func__)); | |||||
if (detaching) | |||||
ll_ifma->ifma_ifp = NULL; /* XXX */ | |||||
if (--ll_ifma->ifma_refcount == 0) { | |||||
if (ifp != NULL) { | |||||
if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) { | if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) { | ||||
CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, | CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, | ||||
ifma_link); | ifma_link); | ||||
ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED; | ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED; | ||||
} | } | ||||
KASSERT(ifma->ifma_lladdr != NULL, | |||||
("%s: llifma w/o lladdr", __func__)); | |||||
ifma->ifma_llifma = NULL; | |||||
if (ifp) { | |||||
if_rele(ifp); | |||||
ll_ifma->ifma_ifp = NULL; /* XXX */ | |||||
} | } | ||||
if (ll_ifma->ifma_refcount == 0) | |||||
if_freemulti(ll_ifma); | if_freemulti(ll_ifma); | ||||
} | } | ||||
} | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if (ifp) { | if (ifp) { | ||||
struct ifmultiaddr *ifmatmp; | |||||
CK_STAILQ_FOREACH(ifmatmp, &ifp->if_multiaddrs, ifma_link) | CK_STAILQ_FOREACH(ifmatmp, &ifp->if_multiaddrs, ifma_link) | ||||
MPASS(ifma != ifmatmp); | MPASS(ifma != ifmatmp); | ||||
} | } | ||||
#endif | #endif | ||||
if_freemulti(ifma); | if_freemulti(ifma); | ||||
/* | /* | ||||
* The last reference to this instance of struct ifmultiaddr | * The last reference to this instance of struct ifmultiaddr | ||||
▲ Show 20 Lines • Show All 789 Lines • Show Last 20 Lines |