Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/in_pcb.c
Show First 20 Lines • Show All 450 Lines • ▼ Show 20 Lines | in_pcbinfo_init(struct inpcbinfo *pcbinfo, const char *name, | ||||
INP_INFO_LOCK_INIT(pcbinfo, name); | INP_INFO_LOCK_INIT(pcbinfo, name); | ||||
INP_HASH_LOCK_INIT(pcbinfo, "pcbinfohash"); /* XXXRW: argument? */ | INP_HASH_LOCK_INIT(pcbinfo, "pcbinfohash"); /* XXXRW: argument? */ | ||||
INP_LIST_LOCK_INIT(pcbinfo, "pcbinfolist"); | INP_LIST_LOCK_INIT(pcbinfo, "pcbinfolist"); | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
pcbinfo->ipi_vnet = curvnet; | pcbinfo->ipi_vnet = curvnet; | ||||
#endif | #endif | ||||
pcbinfo->ipi_listhead = listhead; | pcbinfo->ipi_listhead = listhead; | ||||
LIST_INIT(pcbinfo->ipi_listhead); | CK_LIST_INIT(pcbinfo->ipi_listhead); | ||||
pcbinfo->ipi_count = 0; | pcbinfo->ipi_count = 0; | ||||
pcbinfo->ipi_hashbase = hashinit(hash_nelements, M_PCB, | pcbinfo->ipi_hashbase = hashinit(hash_nelements, M_PCB, | ||||
&pcbinfo->ipi_hashmask); | &pcbinfo->ipi_hashmask); | ||||
pcbinfo->ipi_porthashbase = hashinit(porthash_nelements, M_PCB, | pcbinfo->ipi_porthashbase = hashinit(porthash_nelements, M_PCB, | ||||
&pcbinfo->ipi_porthashmask); | &pcbinfo->ipi_porthashmask); | ||||
pcbinfo->ipi_lbgrouphashbase = hashinit(hash_nelements, M_PCB, | pcbinfo->ipi_lbgrouphashbase = hashinit(hash_nelements, M_PCB, | ||||
&pcbinfo->ipi_lbgrouphashmask); | &pcbinfo->ipi_lbgrouphashmask); | ||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | #ifdef INET6 | ||||
if (INP_SOCKAF(so) == AF_INET6) { | if (INP_SOCKAF(so) == AF_INET6) { | ||||
inp->inp_vflag |= INP_IPV6PROTO; | inp->inp_vflag |= INP_IPV6PROTO; | ||||
if (V_ip6_v6only) | if (V_ip6_v6only) | ||||
inp->inp_flags |= IN6P_IPV6_V6ONLY; | inp->inp_flags |= IN6P_IPV6_V6ONLY; | ||||
} | } | ||||
#endif | #endif | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
INP_LIST_WLOCK(pcbinfo); | INP_LIST_WLOCK(pcbinfo); | ||||
LIST_INSERT_HEAD(pcbinfo->ipi_listhead, inp, inp_list); | CK_LIST_INSERT_HEAD(pcbinfo->ipi_listhead, inp, inp_list); | ||||
pcbinfo->ipi_count++; | pcbinfo->ipi_count++; | ||||
so->so_pcb = (caddr_t)inp; | so->so_pcb = (caddr_t)inp; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (V_ip6_auto_flowlabel) | if (V_ip6_auto_flowlabel) | ||||
inp->inp_flags |= IN6P_AUTOFLOWLABEL; | inp->inp_flags |= IN6P_AUTOFLOWLABEL; | ||||
#endif | #endif | ||||
inp->inp_gencnt = ++pcbinfo->ipi_gencnt; | inp->inp_gencnt = ++pcbinfo->ipi_gencnt; | ||||
refcount_init(&inp->inp_refcount, 1); /* Reference from inpcbinfo */ | refcount_init(&inp->inp_refcount, 1); /* Reference from inpcbinfo */ | ||||
▲ Show 20 Lines • Show All 1,003 Lines • ▼ Show 20 Lines | for (i = 0; i < n; i++) { | ||||
INP_RLOCK(inp); | INP_RLOCK(inp); | ||||
if (!in_pcbrele_rlocked(inp)) | if (!in_pcbrele_rlocked(inp)) | ||||
INP_RUNLOCK(inp); | INP_RUNLOCK(inp); | ||||
} | } | ||||
INP_INFO_WUNLOCK(pcbinfo); | INP_INFO_WUNLOCK(pcbinfo); | ||||
free(il, M_TEMP); | free(il, M_TEMP); | ||||
} | } | ||||
static void | |||||
inpcbport_free(epoch_context_t ctx) | |||||
{ | |||||
struct inpcbport *phd; | |||||
phd = __containerof(ctx, struct inpcbport, phd_epoch_ctx); | |||||
free(phd, M_PCB); | |||||
} | |||||
static void | |||||
in_pcbfree_deferred(epoch_context_t ctx) | |||||
{ | |||||
struct inpcb *inp; | |||||
struct inpcbinfo *pcbinfo; | |||||
int released __unused; | |||||
inp = __containerof(ctx, struct inpcb, inp_epoch_ctx); | |||||
pcbinfo = inp->inp_pcbinfo; | |||||
INP_WLOCK(inp); | |||||
#ifdef INET | |||||
inp_freemoptions(inp->inp_moptions); | |||||
inp->inp_moptions = NULL; | |||||
#endif | |||||
/* XXXRW: Do as much as possible here. */ | |||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | |||||
if (inp->inp_sp != NULL) | |||||
ipsec_delete_pcbpolicy(inp); | |||||
#endif | |||||
#ifdef INET6 | |||||
if (inp->inp_vflag & INP_IPV6PROTO) { | |||||
ip6_freepcbopts(inp->in6p_outputopts); | |||||
ip6_freemoptions(inp->in6p_moptions); | |||||
inp->in6p_moptions = NULL; | |||||
} | |||||
#endif | |||||
if (inp->inp_options) | |||||
(void)m_free(inp->inp_options); | |||||
inp->inp_vflag = 0; | |||||
crfree(inp->inp_cred); | |||||
#ifdef MAC | |||||
mac_inpcb_destroy(inp); | |||||
#endif | |||||
released = in_pcbrele_wlocked(inp); | |||||
MPASS(released); | |||||
} | |||||
/* | /* | ||||
* Unconditionally schedule an inpcb to be freed by decrementing its | * Unconditionally schedule an inpcb to be freed by decrementing its | ||||
* reference count, which should occur only after the inpcb has been detached | * reference count, which should occur only after the inpcb has been detached | ||||
* from its socket. If another thread holds a temporary reference (acquired | * from its socket. If another thread holds a temporary reference (acquired | ||||
* using in_pcbref()) then the free is deferred until that reference is | * using in_pcbref()) then the free is deferred until that reference is | ||||
* released using in_pcbrele(), but the inpcb is still unlocked. Almost all | * released using in_pcbrele(), but the inpcb is still unlocked. Almost all | ||||
* 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. */ | |||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | |||||
if (inp->inp_sp != NULL) | |||||
ipsec_delete_pcbpolicy(inp); | |||||
#endif | |||||
INP_LIST_WLOCK(pcbinfo); | INP_LIST_WLOCK(pcbinfo); | ||||
inp->inp_gencnt = ++pcbinfo->ipi_gencnt; | |||||
in_pcbremlists(inp); | in_pcbremlists(inp); | ||||
INP_LIST_WUNLOCK(pcbinfo); | INP_LIST_WUNLOCK(pcbinfo); | ||||
#ifdef INET6 | |||||
if (inp->inp_vflag & INP_IPV6PROTO) { | |||||
ip6_freepcbopts(inp->in6p_outputopts); | |||||
im6o = inp->in6p_moptions; | |||||
inp->in6p_moptions = NULL; | |||||
} | |||||
#endif | |||||
if (inp->inp_options) | |||||
(void)m_free(inp->inp_options); | |||||
RO_INVALIDATE_CACHE(&inp->inp_route); | RO_INVALIDATE_CACHE(&inp->inp_route); | ||||
inp->inp_vflag = 0; | |||||
inp->inp_flags2 |= INP_FREED; | inp->inp_flags2 |= INP_FREED; | ||||
crfree(inp->inp_cred); | |||||
#ifdef MAC | |||||
mac_inpcb_destroy(inp); | |||||
#endif | |||||
#ifdef INET6 | |||||
ip6_freemoptions(im6o); | |||||
#endif | |||||
#ifdef INET | |||||
inp_freemoptions(imo); | |||||
#endif | |||||
if (!in_pcbrele_wlocked(inp)) | |||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
epoch_call(net_epoch_preempt, &inp->inp_epoch_ctx, in_pcbfree_deferred); | |||||
} | } | ||||
/* | /* | ||||
* 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 All 16 Lines | in_pcbdrop(struct inpcb *inp) | ||||
* the hash lock...? | * the hash lock...? | ||||
*/ | */ | ||||
inp->inp_flags |= INP_DROPPED; | inp->inp_flags |= INP_DROPPED; | ||||
if (inp->inp_flags & INP_INHASHLIST) { | if (inp->inp_flags & INP_INHASHLIST) { | ||||
struct inpcbport *phd = inp->inp_phd; | struct inpcbport *phd = inp->inp_phd; | ||||
INP_HASH_WLOCK(inp->inp_pcbinfo); | INP_HASH_WLOCK(inp->inp_pcbinfo); | ||||
in_pcbremlbgrouphash(inp); | in_pcbremlbgrouphash(inp); | ||||
LIST_REMOVE(inp, inp_hash); | CK_LIST_REMOVE(inp, inp_hash); | ||||
LIST_REMOVE(inp, inp_portlist); | CK_LIST_REMOVE(inp, inp_portlist); | ||||
if (LIST_FIRST(&phd->phd_pcblist) == NULL) { | if (CK_LIST_FIRST(&phd->phd_pcblist) == NULL) { | ||||
LIST_REMOVE(phd, phd_hash); | CK_LIST_REMOVE(phd, phd_hash); | ||||
free(phd, M_PCB); | epoch_call(net_epoch_preempt, &phd->phd_epoch_ctx, inpcbport_free); | ||||
} | } | ||||
INP_HASH_WUNLOCK(inp->inp_pcbinfo); | INP_HASH_WUNLOCK(inp->inp_pcbinfo); | ||||
inp->inp_flags &= ~INP_INHASHLIST; | inp->inp_flags &= ~INP_INHASHLIST; | ||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
in_pcbgroup_remove(inp); | in_pcbgroup_remove(inp); | ||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr faddr, int errno, | in_pcbnotifyall(struct inpcbinfo *pcbinfo, struct in_addr faddr, int errno, | ||||
struct inpcb *(*notify)(struct inpcb *, int)) | struct inpcb *(*notify)(struct inpcb *, int)) | ||||
{ | { | ||||
struct inpcb *inp, *inp_temp; | struct inpcb *inp, *inp_temp; | ||||
INP_INFO_WLOCK(pcbinfo); | INP_INFO_WLOCK(pcbinfo); | ||||
LIST_FOREACH_SAFE(inp, pcbinfo->ipi_listhead, inp_list, inp_temp) { | CK_LIST_FOREACH_SAFE(inp, pcbinfo->ipi_listhead, inp_list, inp_temp) { | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if ((inp->inp_vflag & INP_IPV4) == 0) { | if ((inp->inp_vflag & INP_IPV4) == 0) { | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
continue; | continue; | ||||
} | } | ||||
#endif | #endif | ||||
if (inp->inp_faddr.s_addr != faddr.s_addr || | if (inp->inp_faddr.s_addr != faddr.s_addr || | ||||
Show All 10 Lines | |||||
void | void | ||||
in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) | in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
struct ip_moptions *imo; | struct ip_moptions *imo; | ||||
int i, gap; | int i, gap; | ||||
INP_INFO_WLOCK(pcbinfo); | INP_INFO_WLOCK(pcbinfo); | ||||
LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { | CK_LIST_FOREACH(inp, pcbinfo->ipi_listhead, inp_list) { | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
imo = inp->inp_moptions; | imo = inp->inp_moptions; | ||||
if ((inp->inp_vflag & INP_IPV4) && | if ((inp->inp_vflag & INP_IPV4) && | ||||
imo != NULL) { | imo != NULL) { | ||||
/* | /* | ||||
* Unselect the outgoing interface if it is being | * Unselect the outgoing interface if it is being | ||||
* detached. | * detached. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
if ((lookupflags & INPLOOKUP_WILDCARD) == 0) { | if ((lookupflags & INPLOOKUP_WILDCARD) == 0) { | ||||
struct inpcbhead *head; | struct inpcbhead *head; | ||||
/* | /* | ||||
* Look for an unconnected (wildcard foreign addr) PCB that | * Look for an unconnected (wildcard foreign addr) PCB that | ||||
* matches the local address and port we're looking for. | * matches the local address and port we're looking for. | ||||
*/ | */ | ||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, | head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, | ||||
0, pcbinfo->ipi_hashmask)]; | 0, pcbinfo->ipi_hashmask)]; | ||||
LIST_FOREACH(inp, head, inp_hash) { | CK_LIST_FOREACH(inp, head, inp_hash) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
/* XXX inp locking */ | /* XXX inp locking */ | ||||
if ((inp->inp_vflag & INP_IPV4) == 0) | if ((inp->inp_vflag & INP_IPV4) == 0) | ||||
continue; | continue; | ||||
#endif | #endif | ||||
if (inp->inp_faddr.s_addr == INADDR_ANY && | if (inp->inp_faddr.s_addr == INADDR_ANY && | ||||
inp->inp_laddr.s_addr == laddr.s_addr && | inp->inp_laddr.s_addr == laddr.s_addr && | ||||
inp->inp_lport == lport) { | inp->inp_lport == lport) { | ||||
Show All 17 Lines | #endif | ||||
/* | /* | ||||
* Best fit PCB lookup. | * Best fit PCB lookup. | ||||
* | * | ||||
* First see if this local port is in use by looking on the | * First see if this local port is in use by looking on the | ||||
* port hash list. | * port hash list. | ||||
*/ | */ | ||||
porthash = &pcbinfo->ipi_porthashbase[INP_PCBPORTHASH(lport, | porthash = &pcbinfo->ipi_porthashbase[INP_PCBPORTHASH(lport, | ||||
pcbinfo->ipi_porthashmask)]; | pcbinfo->ipi_porthashmask)]; | ||||
LIST_FOREACH(phd, porthash, phd_hash) { | CK_LIST_FOREACH(phd, porthash, phd_hash) { | ||||
if (phd->phd_port == lport) | if (phd->phd_port == lport) | ||||
break; | break; | ||||
} | } | ||||
if (phd != NULL) { | if (phd != NULL) { | ||||
/* | /* | ||||
* Port is in use by one or more PCBs. Look for best | * Port is in use by one or more PCBs. Look for best | ||||
* fit. | * fit. | ||||
*/ | */ | ||||
LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { | CK_LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) { | ||||
wildcard = 0; | wildcard = 0; | ||||
if (cred != NULL && | if (cred != NULL && | ||||
!prison_equal_ip4(inp->inp_cred->cr_prison, | !prison_equal_ip4(inp->inp_cred->cr_prison, | ||||
cred->cr_prison)) | cred->cr_prison)) | ||||
continue; | continue; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
/* XXX inp locking */ | /* XXX inp locking */ | ||||
if ((inp->inp_vflag & INP_IPV4) == 0) | if ((inp->inp_vflag & INP_IPV4) == 0) | ||||
▲ Show 20 Lines • Show All 342 Lines • ▼ Show 20 Lines | in_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in_addr faddr, | ||||
INP_HASH_LOCK_ASSERT(pcbinfo); | INP_HASH_LOCK_ASSERT(pcbinfo); | ||||
/* | /* | ||||
* First look for an exact match. | * First look for an exact match. | ||||
*/ | */ | ||||
tmpinp = NULL; | tmpinp = NULL; | ||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, | head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, | ||||
pcbinfo->ipi_hashmask)]; | pcbinfo->ipi_hashmask)]; | ||||
LIST_FOREACH(inp, head, inp_hash) { | CK_LIST_FOREACH(inp, head, inp_hash) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
/* XXX inp locking */ | /* XXX inp locking */ | ||||
if ((inp->inp_vflag & INP_IPV4) == 0) | if ((inp->inp_vflag & INP_IPV4) == 0) | ||||
continue; | continue; | ||||
#endif | #endif | ||||
if (inp->inp_faddr.s_addr == faddr.s_addr && | if (inp->inp_faddr.s_addr == faddr.s_addr && | ||||
inp->inp_laddr.s_addr == laddr.s_addr && | inp->inp_laddr.s_addr == laddr.s_addr && | ||||
inp->inp_fport == fport && | inp->inp_fport == fport && | ||||
Show All 40 Lines | #endif | ||||
* 1. jailed, non-wild. | * 1. jailed, non-wild. | ||||
* 2. jailed, wild. | * 2. jailed, wild. | ||||
* 3. non-jailed, non-wild. | * 3. non-jailed, non-wild. | ||||
* 4. non-jailed, wild. | * 4. non-jailed, wild. | ||||
*/ | */ | ||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, | head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport, | ||||
0, pcbinfo->ipi_hashmask)]; | 0, pcbinfo->ipi_hashmask)]; | ||||
LIST_FOREACH(inp, head, inp_hash) { | CK_LIST_FOREACH(inp, head, inp_hash) { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
/* XXX inp locking */ | /* XXX inp locking */ | ||||
if ((inp->inp_vflag & INP_IPV4) == 0) | if ((inp->inp_vflag & INP_IPV4) == 0) | ||||
continue; | continue; | ||||
#endif | #endif | ||||
if (inp->inp_faddr.s_addr != INADDR_ANY || | if (inp->inp_faddr.s_addr != INADDR_ANY || | ||||
inp->inp_lport != lport) | inp->inp_lport != lport) | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | inp = in_pcblookup_hash_locked(pcbinfo, faddr, fport, laddr, lport, | ||||
(lookupflags & ~(INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)), ifp); | (lookupflags & ~(INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)), ifp); | ||||
if (inp != NULL) { | if (inp != NULL) { | ||||
if (lookupflags & INPLOOKUP_WLOCKPCB) | if (lookupflags & INPLOOKUP_WLOCKPCB) | ||||
locked = INP_TRY_WLOCK(inp); | locked = INP_TRY_WLOCK(inp); | ||||
else if (lookupflags & INPLOOKUP_RLOCKPCB) | else if (lookupflags & INPLOOKUP_RLOCKPCB) | ||||
locked = INP_TRY_RLOCK(inp); | locked = INP_TRY_RLOCK(inp); | ||||
else | else | ||||
panic("%s: locking bug", __func__); | panic("%s: locking bug", __func__); | ||||
if (!locked) | if (__predict_false(locked && (inp->inp_flags2 & INP_FREED))) { | ||||
if (lookupflags & INPLOOKUP_WLOCKPCB) | |||||
INP_WUNLOCK(inp); | |||||
else | |||||
INP_RUNLOCK(inp); | |||||
INP_HASH_RUNLOCK(pcbinfo); | |||||
return (NULL); | |||||
} else if (!locked) | |||||
in_pcbref(inp); | in_pcbref(inp); | ||||
INP_HASH_RUNLOCK(pcbinfo); | INP_HASH_RUNLOCK(pcbinfo); | ||||
if (!locked) { | if (!locked) { | ||||
if (lookupflags & INPLOOKUP_WLOCKPCB) { | if (lookupflags & INPLOOKUP_WLOCKPCB) { | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
if (in_pcbrele_wlocked(inp)) | if (in_pcbrele_wlocked(inp)) | ||||
return (NULL); | return (NULL); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | if (ret) { | ||||
/* pcb lb group malloc fail (ret=ENOBUFS). */ | /* pcb lb group malloc fail (ret=ENOBUFS). */ | ||||
return (ret); | return (ret); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Go through port list and look for a head for this lport. | * Go through port list and look for a head for this lport. | ||||
*/ | */ | ||||
LIST_FOREACH(phd, pcbporthash, phd_hash) { | CK_LIST_FOREACH(phd, pcbporthash, phd_hash) { | ||||
if (phd->phd_port == inp->inp_lport) | if (phd->phd_port == inp->inp_lport) | ||||
break; | break; | ||||
} | } | ||||
/* | /* | ||||
* If none exists, malloc one and tack it on. | * If none exists, malloc one and tack it on. | ||||
*/ | */ | ||||
if (phd == NULL) { | if (phd == NULL) { | ||||
phd = malloc(sizeof(struct inpcbport), M_PCB, M_NOWAIT); | phd = malloc(sizeof(struct inpcbport), M_PCB, M_NOWAIT|M_ZERO); | ||||
if (phd == NULL) { | if (phd == NULL) { | ||||
return (ENOBUFS); /* XXX */ | return (ENOBUFS); /* XXX */ | ||||
} | } | ||||
phd->phd_port = inp->inp_lport; | phd->phd_port = inp->inp_lport; | ||||
LIST_INIT(&phd->phd_pcblist); | CK_LIST_INIT(&phd->phd_pcblist); | ||||
LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); | CK_LIST_INSERT_HEAD(pcbporthash, phd, phd_hash); | ||||
} | } | ||||
inp->inp_phd = phd; | inp->inp_phd = phd; | ||||
LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); | CK_LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist); | ||||
LIST_INSERT_HEAD(pcbhash, inp, inp_hash); | CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash); | ||||
inp->inp_flags |= INP_INHASHLIST; | inp->inp_flags |= INP_INHASHLIST; | ||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
if (do_pcbgroup_update) | if (do_pcbgroup_update) | ||||
in_pcbgroup_update(inp); | in_pcbgroup_update(inp); | ||||
#endif | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | if (inp->inp_vflag & INP_IPV6) | ||||
hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr); | hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr); | ||||
else | else | ||||
#endif | #endif | ||||
hashkey_faddr = inp->inp_faddr.s_addr; | hashkey_faddr = inp->inp_faddr.s_addr; | ||||
head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, | head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr, | ||||
inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; | inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)]; | ||||
LIST_REMOVE(inp, inp_hash); | CK_LIST_REMOVE(inp, inp_hash); | ||||
LIST_INSERT_HEAD(head, inp, inp_hash); | CK_LIST_INSERT_HEAD(head, inp, inp_hash); | ||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
if (m != NULL) | if (m != NULL) | ||||
in_pcbgroup_update_mbuf(inp, m); | in_pcbgroup_update_mbuf(inp, m); | ||||
else | else | ||||
in_pcbgroup_update(inp); | in_pcbgroup_update(inp); | ||||
#endif | #endif | ||||
} | } | ||||
void | void | ||||
in_pcbrehash(struct inpcb *inp) | in_pcbrehash(struct inpcb *inp) | ||||
{ | { | ||||
in_pcbrehash_mbuf(inp, NULL); | in_pcbrehash_mbuf(inp, NULL); | ||||
} | } | ||||
/* | /* | ||||
* Remove PCB from various lists. | * Remove PCB from various lists. | ||||
*/ | */ | ||||
static void | static void | ||||
in_pcbremlists(struct inpcb *inp) | in_pcbremlists(struct inpcb *inp) | ||||
{ | { | ||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
if (pcbinfo == &V_tcbinfo) { | if (pcbinfo == &V_tcbinfo) { | ||||
INP_INFO_RLOCK_ASSERT(pcbinfo); | INP_INFO_RLOCK_ASSERT(pcbinfo); | ||||
} else { | } else { | ||||
INP_INFO_WLOCK_ASSERT(pcbinfo); | INP_INFO_WLOCK_ASSERT(pcbinfo); | ||||
} | } | ||||
#endif | #endif | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
INP_LIST_WLOCK_ASSERT(pcbinfo); | INP_LIST_WLOCK_ASSERT(pcbinfo); | ||||
inp->inp_gencnt = ++pcbinfo->ipi_gencnt; | inp->inp_gencnt = ++pcbinfo->ipi_gencnt; | ||||
if (inp->inp_flags & INP_INHASHLIST) { | if (inp->inp_flags & INP_INHASHLIST) { | ||||
struct inpcbport *phd = inp->inp_phd; | struct inpcbport *phd = inp->inp_phd; | ||||
INP_HASH_WLOCK(pcbinfo); | INP_HASH_WLOCK(pcbinfo); | ||||
/* XXX: Only do if SO_REUSEPORT_LB set? */ | /* XXX: Only do if SO_REUSEPORT_LB set? */ | ||||
in_pcbremlbgrouphash(inp); | in_pcbremlbgrouphash(inp); | ||||
CK_LIST_REMOVE(inp, inp_hash); | |||||
LIST_REMOVE(inp, inp_hash); | CK_LIST_REMOVE(inp, inp_portlist); | ||||
LIST_REMOVE(inp, inp_portlist); | if (CK_LIST_FIRST(&phd->phd_pcblist) == NULL) { | ||||
if (LIST_FIRST(&phd->phd_pcblist) == NULL) { | CK_LIST_REMOVE(phd, phd_hash); | ||||
LIST_REMOVE(phd, phd_hash); | epoch_call(net_epoch_preempt, &phd->phd_epoch_ctx, inpcbport_free); | ||||
free(phd, M_PCB); | |||||
} | } | ||||
INP_HASH_WUNLOCK(pcbinfo); | INP_HASH_WUNLOCK(pcbinfo); | ||||
inp->inp_flags &= ~INP_INHASHLIST; | inp->inp_flags &= ~INP_INHASHLIST; | ||||
} | } | ||||
LIST_REMOVE(inp, inp_list); | CK_LIST_REMOVE(inp, inp_list); | ||||
pcbinfo->ipi_count--; | pcbinfo->ipi_count--; | ||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
in_pcbgroup_remove(inp); | in_pcbgroup_remove(inp); | ||||
#endif | #endif | ||||
} | } | ||||
/* | /* | ||||
* Check for alternatives when higher level complains | * Check for alternatives when higher level complains | ||||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
void | void | ||||
inp_apply_all(void (*func)(struct inpcb *, void *), void *arg) | inp_apply_all(void (*func)(struct inpcb *, void *), void *arg) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
INP_INFO_WLOCK(&V_tcbinfo); | INP_INFO_WLOCK(&V_tcbinfo); | ||||
LIST_FOREACH(inp, V_tcbinfo.ipi_listhead, inp_list) { | CK_LIST_FOREACH(inp, V_tcbinfo.ipi_listhead, inp_list) { | ||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
func(inp, arg); | func(inp, arg); | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
} | } | ||||
INP_INFO_WUNLOCK(&V_tcbinfo); | INP_INFO_WUNLOCK(&V_tcbinfo); | ||||
} | } | ||||
struct socket * | struct socket * | ||||
▲ Show 20 Lines • Show All 619 Lines • Show Last 20 Lines |