Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet/in_pcb.c
Show First 20 Lines • Show All 1,322 Lines • ▼ Show 20 Lines | |||||
* work, including removal from global lists, is done in this context, where | * work, including removal from global lists, is done in this context, where | ||||
* the pcbinfo lock is held. | * the pcbinfo lock is held. | ||||
*/ | */ | ||||
void | void | ||||
in_pcbfree(struct inpcb *inp) | in_pcbfree(struct inpcb *inp) | ||||
{ | { | ||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | ||||
#ifdef INET6 | |||||
struct ip6_moptions *im6o = NULL; | |||||
#endif | |||||
#ifdef INET | |||||
struct ip_moptions *imo = NULL; | |||||
#endif | |||||
KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__)); | KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__)); | ||||
KASSERT((inp->inp_flags2 & INP_FREED) == 0, | KASSERT((inp->inp_flags2 & INP_FREED) == 0, | ||||
("%s: called twice for pcb %p", __func__, inp)); | ("%s: called twice for pcb %p", __func__, inp)); | ||||
if (inp->inp_flags2 & INP_FREED) { | if (inp->inp_flags2 & INP_FREED) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
return; | return; | ||||
} | } | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if (pcbinfo == &V_tcbinfo) { | if (pcbinfo == &V_tcbinfo) { | ||||
INP_INFO_LOCK_ASSERT(pcbinfo); | INP_INFO_LOCK_ASSERT(pcbinfo); | ||||
} else { | } else { | ||||
INP_INFO_WLOCK_ASSERT(pcbinfo); | INP_INFO_WLOCK_ASSERT(pcbinfo); | ||||
} | } | ||||
#endif | #endif | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
#ifdef INET | |||||
imo = inp->inp_moptions; | |||||
inp->inp_moptions = NULL; | |||||
#endif | |||||
/* XXXRW: Do as much as possible here. */ | /* XXXRW: Do as much as possible here. */ | ||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
if (inp->inp_sp != NULL) | if (inp->inp_sp != NULL) | ||||
ipsec_delete_pcbpolicy(inp); | ipsec_delete_pcbpolicy(inp); | ||||
#endif | #endif | ||||
INP_LIST_WLOCK(pcbinfo); | INP_LIST_WLOCK(pcbinfo); | ||||
inp->inp_gencnt = ++pcbinfo->ipi_gencnt; | inp->inp_gencnt = ++pcbinfo->ipi_gencnt; | ||||
in_pcbremlists(inp); | in_pcbremlists(inp); | ||||
INP_LIST_WUNLOCK(pcbinfo); | INP_LIST_WUNLOCK(pcbinfo); | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (inp->inp_vflag & INP_IPV6PROTO) { | if (inp->inp_vflag & INP_IPV6PROTO) { | ||||
ip6_freepcbopts(inp->in6p_outputopts); | ip6_freepcbopts(inp->in6p_outputopts); | ||||
if (inp->in6p_moptions != NULL) | im6o = inp->in6p_moptions; | ||||
ip6_freemoptions(inp->in6p_moptions); | inp->in6p_moptions = NULL; | ||||
} | } | ||||
#endif | #endif | ||||
if (inp->inp_options) | if (inp->inp_options) | ||||
(void)m_free(inp->inp_options); | (void)m_free(inp->inp_options); | ||||
#ifdef INET | |||||
if (inp->inp_moptions != NULL) | |||||
inp_freemoptions(inp->inp_moptions); | |||||
#endif | |||||
RO_INVALIDATE_CACHE(&inp->inp_route); | RO_INVALIDATE_CACHE(&inp->inp_route); | ||||
inp->inp_vflag = 0; | inp->inp_vflag = 0; | ||||
inp->inp_flags2 |= INP_FREED; | inp->inp_flags2 |= INP_FREED; | ||||
crfree(inp->inp_cred); | crfree(inp->inp_cred); | ||||
#ifdef MAC | #ifdef MAC | ||||
mac_inpcb_destroy(inp); | mac_inpcb_destroy(inp); | ||||
#endif | #endif | ||||
if (!in_pcbrele_wlocked(inp)) | if (!in_pcbrele_wlocked(inp)) | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
#if defined(INET) && defined(INET6) | |||||
if (imo == NULL && im6o == NULL) | |||||
return; | |||||
#endif | |||||
INP_INFO_WUNLOCK(pcbinfo); | |||||
#ifdef INET6 | |||||
ip6_freemoptions(im6o); | |||||
#endif | |||||
#ifdef INET | |||||
inp_freemoptions(imo); | |||||
#endif | |||||
INP_INFO_WLOCK(pcbinfo); | |||||
} | } | ||||
/* | /* | ||||
* in_pcbdrop() removes an inpcb from hashed lists, releasing its address and | * in_pcbdrop() removes an inpcb from hashed lists, releasing its address and | ||||
* port reservation, and preventing it from being returned by inpcb lookups. | * port reservation, and preventing it from being returned by inpcb lookups. | ||||
* | * | ||||
* It is used by TCP to mark an inpcb as unused and avoid future packet | * It is used by TCP to mark an inpcb as unused and avoid future packet | ||||
* delivery or event notification when a socket remains open but TCP has | * delivery or event notification when a socket remains open but TCP has | ||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | if ((inp->inp_vflag & INP_IPV4) && | ||||
/* | /* | ||||
* Drop multicast group membership if we joined | * Drop multicast group membership if we joined | ||||
* through the interface being detached. | * through the interface being detached. | ||||
*/ | */ | ||||
for (i = 0, gap = 0; i < imo->imo_num_memberships; | for (i = 0, gap = 0; i < imo->imo_num_memberships; | ||||
i++) { | i++) { | ||||
if (imo->imo_membership[i]->inm_ifp == ifp) { | if (imo->imo_membership[i]->inm_ifp == ifp) { | ||||
in_delmulti(imo->imo_membership[i]); | IN_MULTI_LOCK_ASSERT(); | ||||
in_leavegroup_locked(imo->imo_membership[i], NULL); | |||||
gap++; | gap++; | ||||
} else if (gap != 0) | } else if (gap != 0) | ||||
imo->imo_membership[i - gap] = | imo->imo_membership[i - gap] = | ||||
imo->imo_membership[i]; | imo->imo_membership[i]; | ||||
} | } | ||||
imo->imo_num_memberships -= gap; | imo->imo_num_memberships -= gap; | ||||
} | } | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
▲ Show 20 Lines • Show All 1,549 Lines • Show Last 20 Lines |