Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/sctp_pcb.c
Show First 20 Lines • Show All 1,540 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
/* | /* | ||||
* Use my the assoc_id to find a endpoint | * Use my the assoc_id to find a endpoint | ||||
*/ | */ | ||||
struct sctpasochead *head; | struct sctpasochead *head; | ||||
struct sctp_tcb *stcb; | struct sctp_tcb *stcb; | ||||
uint32_t id; | uint32_t id; | ||||
if (inp == NULL) { | |||||
SCTP_PRINTF("TSNH ep_associd\n"); | |||||
return (NULL); | |||||
} | |||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { | if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { | ||||
SCTP_PRINTF("TSNH ep_associd0\n"); | SCTP_PRINTF("TSNH ep_associd0\n"); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
id = (uint32_t)asoc_id; | id = (uint32_t)asoc_id; | ||||
head = &inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(id, inp->hashasocidmark)]; | head = &inp->sctp_asocidhash[SCTP_PCBHASH_ASOC(id, inp->hashasocidmark)]; | ||||
if (head == NULL) { | if (head == NULL) { | ||||
/* invalid id TSNH */ | /* invalid id TSNH */ | ||||
▲ Show 20 Lines • Show All 2,585 Lines • ▼ Show 20 Lines | try_again: | ||||
return (id); | return (id); | ||||
} | } | ||||
/* | /* | ||||
* allocate an association and add it to the endpoint. The caller must be | * allocate an association and add it to the endpoint. The caller must be | ||||
* careful to add all additional addresses once they are know right away or | * careful to add all additional addresses once they are know right away or | ||||
* else the assoc will be may experience a blackout scenario. | * else the assoc will be may experience a blackout scenario. | ||||
*/ | */ | ||||
struct sctp_tcb * | static struct sctp_tcb * | ||||
sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, | sctp_aloc_assoc_locked(struct sctp_inpcb *inp, struct sockaddr *firstaddr, | ||||
int *error, uint32_t override_tag, uint32_t initial_tsn, | int *error, uint32_t override_tag, uint32_t initial_tsn, | ||||
uint32_t vrf_id, uint16_t o_streams, uint16_t port, | uint32_t vrf_id, uint16_t o_streams, uint16_t port, | ||||
struct thread *p, | struct thread *p, int initialize_auth_params) | ||||
tuexen: Putting the last two arguments in a line might be hard to maintain. The upstream code has… | |||||
markjAuthorUnsubmitted Done Inline ActionsI can revert this bit, but should the new wrappers use the same formatting? markj: I can revert this bit, but should the new wrappers use the same formatting? | |||||
tuexenUnsubmitted Not Done Inline ActionsI guess so. But you can go ahead and commit your version. Once I have integrated it upstream, I can commit a whitespace change. I just wanted to make you aware that I might have to change some formatting back... tuexen: I guess so. But you can go ahead and commit your version. Once I have integrated it upstream, I… | |||||
int initialize_auth_params) | |||||
{ | { | ||||
/* note the p argument is only valid in unbound sockets */ | /* note the p argument is only valid in unbound sockets */ | ||||
struct sctp_tcb *stcb; | struct sctp_tcb *stcb; | ||||
struct sctp_association *asoc; | struct sctp_association *asoc; | ||||
struct sctpasochead *head; | struct sctpasochead *head; | ||||
uint16_t rport; | uint16_t rport; | ||||
int err; | int err; | ||||
SCTP_INP_INFO_WLOCK_ASSERT(); | |||||
SCTP_INP_WLOCK_ASSERT(inp); | |||||
/* | /* | ||||
* Assumption made here: Caller has done a | * Assumption made here: Caller has done a | ||||
* sctp_findassociation_ep_addr(ep, addr's); to make sure the | * sctp_findassociation_ep_addr(ep, addr's); to make sure the | ||||
* address does not exist already. | * address does not exist already. | ||||
*/ | */ | ||||
if (SCTP_BASE_INFO(ipi_count_asoc) >= SCTP_MAX_NUM_OF_ASOC) { | if (SCTP_BASE_INFO(ipi_count_asoc) >= SCTP_MAX_NUM_OF_ASOC) { | ||||
/* Hit max assoc, sorry no more */ | /* Hit max assoc, sorry no more */ | ||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); | ||||
*error = ENOBUFS; | *error = ENOBUFS; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if (firstaddr == NULL) { | if (firstaddr == NULL) { | ||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | ||||
*error = EINVAL; | *error = EINVAL; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
SCTP_INP_RLOCK(inp); | if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { | ||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | |||||
*error = EINVAL; | |||||
return (NULL); | |||||
} | |||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && | if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && | ||||
((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE)) || | ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE)) || | ||||
(inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { | (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { | ||||
/* | /* | ||||
* If its in the TCP pool, its NOT allowed to create an | * If its in the TCP pool, its NOT allowed to create an | ||||
* association. The parent listener needs to call | * association. The parent listener needs to call | ||||
* sctp_aloc_assoc.. or the one-2-many socket. If a peeled | * sctp_aloc_assoc.. or the one-2-many socket. If a peeled | ||||
* off, or connected one does this.. its an error. | * off, or connected one does this.. its an error. | ||||
*/ | */ | ||||
SCTP_INP_RUNLOCK(inp); | |||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | ||||
*error = EINVAL; | *error = EINVAL; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || | if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || | ||||
(inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { | (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { | ||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) || | if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) || | ||||
(inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED)) { | (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED)) { | ||||
SCTP_INP_RUNLOCK(inp); | |||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | ||||
*error = EINVAL; | *error = EINVAL; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
} | } | ||||
SCTPDBG(SCTP_DEBUG_PCB3, "Allocate an association for peer:"); | SCTPDBG(SCTP_DEBUG_PCB3, "Allocate an association for peer:"); | ||||
#ifdef SCTP_DEBUG | #ifdef SCTP_DEBUG | ||||
if (firstaddr) { | if (firstaddr) { | ||||
Show All 27 Lines | case AF_INET: | ||||
sin = (struct sockaddr_in *)firstaddr; | sin = (struct sockaddr_in *)firstaddr; | ||||
if ((ntohs(sin->sin_port) == 0) || | if ((ntohs(sin->sin_port) == 0) || | ||||
(sin->sin_addr.s_addr == INADDR_ANY) || | (sin->sin_addr.s_addr == INADDR_ANY) || | ||||
(sin->sin_addr.s_addr == INADDR_BROADCAST) || | (sin->sin_addr.s_addr == INADDR_BROADCAST) || | ||||
IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) || | IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) || | ||||
(((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) != 0) && | (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) != 0) && | ||||
(SCTP_IPV6_V6ONLY(inp) != 0))) { | (SCTP_IPV6_V6ONLY(inp) != 0))) { | ||||
/* Invalid address */ | /* Invalid address */ | ||||
SCTP_INP_RUNLOCK(inp); | |||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | ||||
*error = EINVAL; | *error = EINVAL; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
rport = sin->sin_port; | rport = sin->sin_port; | ||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
case AF_INET6: | case AF_INET6: | ||||
{ | { | ||||
struct sockaddr_in6 *sin6; | struct sockaddr_in6 *sin6; | ||||
sin6 = (struct sockaddr_in6 *)firstaddr; | sin6 = (struct sockaddr_in6 *)firstaddr; | ||||
if ((ntohs(sin6->sin6_port) == 0) || | if ((ntohs(sin6->sin6_port) == 0) || | ||||
IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || | IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || | ||||
IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) || | IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr) || | ||||
((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)) { | ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)) { | ||||
/* Invalid address */ | /* Invalid address */ | ||||
SCTP_INP_RUNLOCK(inp); | |||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | ||||
*error = EINVAL; | *error = EINVAL; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
rport = sin6->sin6_port; | rport = sin6->sin6_port; | ||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
default: | default: | ||||
/* not supported family type */ | /* not supported family type */ | ||||
SCTP_INP_RUNLOCK(inp); | |||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | ||||
*error = EINVAL; | *error = EINVAL; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
SCTP_INP_RUNLOCK(inp); | |||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { | if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { | ||||
/* | /* | ||||
* If you have not performed a bind, then we need to do the | * If you have not performed a bind, then we need to do the | ||||
* ephemeral bind for you. | * ephemeral bind for you. | ||||
*/ | */ | ||||
if ((err = sctp_inpcb_bind(inp->sctp_socket, NULL, NULL, p))) { | if ((err = sctp_inpcb_bind_locked(inp, NULL, NULL, p))) { | ||||
/* bind error, probably perm */ | /* bind error, probably perm */ | ||||
*error = err; | *error = err; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
} | } | ||||
stcb = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asoc), struct sctp_tcb); | stcb = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asoc), struct sctp_tcb); | ||||
if (stcb == NULL) { | if (stcb == NULL) { | ||||
/* out of memory? */ | /* out of memory? */ | ||||
Show All 16 Lines | if ((err = sctp_init_asoc(inp, stcb, override_tag, initial_tsn, vrf_id, o_streams))) { | ||||
/* failed */ | /* failed */ | ||||
SCTP_TCB_LOCK_DESTROY(stcb); | SCTP_TCB_LOCK_DESTROY(stcb); | ||||
SCTP_TCB_SEND_LOCK_DESTROY(stcb); | SCTP_TCB_SEND_LOCK_DESTROY(stcb); | ||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); | SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); | ||||
SCTP_DECR_ASOC_COUNT(); | SCTP_DECR_ASOC_COUNT(); | ||||
*error = err; | *error = err; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* and the port */ | |||||
SCTP_INP_INFO_WLOCK(); | |||||
SCTP_INP_WLOCK(inp); | |||||
if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { | |||||
/* inpcb freed while alloc going on */ | |||||
SCTP_TCB_LOCK_DESTROY(stcb); | |||||
SCTP_TCB_SEND_LOCK_DESTROY(stcb); | |||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); | |||||
SCTP_INP_WUNLOCK(inp); | |||||
SCTP_INP_INFO_WUNLOCK(); | |||||
SCTP_DECR_ASOC_COUNT(); | |||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); | |||||
*error = EINVAL; | |||||
return (NULL); | |||||
} | |||||
SCTP_TCB_LOCK(stcb); | SCTP_TCB_LOCK(stcb); | ||||
asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb); | asoc->assoc_id = sctp_aloc_a_assoc_id(inp, stcb); | ||||
/* now that my_vtag is set, add it to the hash */ | /* now that my_vtag is set, add it to the hash */ | ||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))]; | head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(stcb->asoc.my_vtag, SCTP_BASE_INFO(hashasocmark))]; | ||||
/* put it in the bucket in the vtag hash of assoc's for the system */ | /* put it in the bucket in the vtag hash of assoc's for the system */ | ||||
LIST_INSERT_HEAD(head, stcb, sctp_asocs); | LIST_INSERT_HEAD(head, stcb, sctp_asocs); | ||||
SCTP_INP_INFO_WUNLOCK(); | |||||
if (sctp_add_remote_addr(stcb, firstaddr, NULL, port, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC)) { | if (sctp_add_remote_addr(stcb, firstaddr, NULL, port, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC)) { | ||||
/* failure.. memory error? */ | /* failure.. memory error? */ | ||||
if (asoc->strmout) { | if (asoc->strmout) { | ||||
SCTP_FREE(asoc->strmout, SCTP_M_STRMO); | SCTP_FREE(asoc->strmout, SCTP_M_STRMO); | ||||
asoc->strmout = NULL; | asoc->strmout = NULL; | ||||
} | } | ||||
if (asoc->mapping_array) { | if (asoc->mapping_array) { | ||||
SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); | SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); | ||||
asoc->mapping_array = NULL; | asoc->mapping_array = NULL; | ||||
} | } | ||||
if (asoc->nr_mapping_array) { | if (asoc->nr_mapping_array) { | ||||
SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); | SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); | ||||
asoc->nr_mapping_array = NULL; | asoc->nr_mapping_array = NULL; | ||||
} | } | ||||
SCTP_DECR_ASOC_COUNT(); | SCTP_DECR_ASOC_COUNT(); | ||||
SCTP_TCB_UNLOCK(stcb); | SCTP_TCB_UNLOCK(stcb); | ||||
SCTP_TCB_LOCK_DESTROY(stcb); | SCTP_TCB_LOCK_DESTROY(stcb); | ||||
SCTP_TCB_SEND_LOCK_DESTROY(stcb); | SCTP_TCB_SEND_LOCK_DESTROY(stcb); | ||||
LIST_REMOVE(stcb, sctp_asocs); | |||||
LIST_REMOVE(stcb, sctp_tcbasocidhash); | LIST_REMOVE(stcb, sctp_tcbasocidhash); | ||||
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); | SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asoc), stcb); | ||||
SCTP_INP_WUNLOCK(inp); | SCTP_INP_WUNLOCK(inp); | ||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); | ||||
*error = ENOBUFS; | *error = ENOBUFS; | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* Init all the timers */ | /* Init all the timers */ | ||||
Show All 9 Lines | #endif | ||||
if (inp->sctp_tcbhash != NULL) { | if (inp->sctp_tcbhash != NULL) { | ||||
head = &inp->sctp_tcbhash[SCTP_PCBHASH_ALLADDR(stcb->rport, | head = &inp->sctp_tcbhash[SCTP_PCBHASH_ALLADDR(stcb->rport, | ||||
inp->sctp_hashmark)]; | inp->sctp_hashmark)]; | ||||
LIST_INSERT_HEAD(head, stcb, sctp_tcbhash); | LIST_INSERT_HEAD(head, stcb, sctp_tcbhash); | ||||
} | } | ||||
if (initialize_auth_params == SCTP_INITIALIZE_AUTH_PARAMS) { | if (initialize_auth_params == SCTP_INITIALIZE_AUTH_PARAMS) { | ||||
sctp_initialize_auth_params(inp, stcb); | sctp_initialize_auth_params(inp, stcb); | ||||
} | } | ||||
SCTP_INP_WUNLOCK(inp); | |||||
SCTPDBG(SCTP_DEBUG_PCB1, "Association %p now allocated\n", (void *)stcb); | SCTPDBG(SCTP_DEBUG_PCB1, "Association %p now allocated\n", (void *)stcb); | ||||
return (stcb); | return (stcb); | ||||
} | } | ||||
struct sctp_tcb * | |||||
sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, | |||||
int *error, uint32_t override_tag, uint32_t initial_tsn, | |||||
uint32_t vrf_id, uint16_t o_streams, uint16_t port, | |||||
struct thread *p, int initialize_auth_params) | |||||
{ | |||||
struct sctp_tcb *stcb; | |||||
SCTP_INP_INFO_WLOCK(); | |||||
SCTP_INP_WLOCK(inp); | |||||
stcb = sctp_aloc_assoc_locked(inp, firstaddr, error, override_tag, | |||||
initial_tsn, vrf_id, o_streams, port, p, initialize_auth_params); | |||||
SCTP_INP_INFO_WUNLOCK(); | |||||
SCTP_INP_WUNLOCK(inp); | |||||
return (stcb); | |||||
} | |||||
struct sctp_tcb * | |||||
sctp_aloc_assoc_connected(struct sctp_inpcb *inp, struct sockaddr *firstaddr, | |||||
int *error, uint32_t override_tag, uint32_t initial_tsn, | |||||
uint32_t vrf_id, uint16_t o_streams, uint16_t port, | |||||
struct thread *p, int initialize_auth_params) | |||||
{ | |||||
struct sctp_tcb *stcb; | |||||
SCTP_INP_INFO_WLOCK(); | |||||
SCTP_INP_WLOCK(inp); | |||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && | |||||
SCTP_IS_LISTENING(inp)) { | |||||
SCTP_INP_INFO_WUNLOCK(); | |||||
SCTP_INP_WUNLOCK(inp); | |||||
*error = EINVAL; | |||||
return (NULL); | |||||
} | |||||
stcb = sctp_aloc_assoc_locked(inp, firstaddr, error, override_tag, | |||||
initial_tsn, vrf_id, o_streams, port, p, initialize_auth_params); | |||||
SCTP_INP_INFO_WUNLOCK(); | |||||
if (stcb != NULL && (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) { | |||||
inp->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; | |||||
soisconnecting(inp->sctp_socket); | |||||
} | |||||
SCTP_INP_WUNLOCK(inp); | |||||
return (stcb); | |||||
} | |||||
void | void | ||||
sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net) | sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net) | ||||
{ | { | ||||
struct sctp_inpcb *inp; | struct sctp_inpcb *inp; | ||||
struct sctp_association *asoc; | struct sctp_association *asoc; | ||||
inp = stcb->sctp_ep; | inp = stcb->sctp_ep; | ||||
asoc = &stcb->asoc; | asoc = &stcb->asoc; | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
static bool | static bool | ||||
sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport, uint32_t now) | sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport, uint32_t now) | ||||
{ | { | ||||
struct sctpvtaghead *chain; | struct sctpvtaghead *chain; | ||||
struct sctp_tagblock *twait_block; | struct sctp_tagblock *twait_block; | ||||
int i; | int i; | ||||
SCTP_INP_INFO_RLOCK_ASSERT(); | SCTP_INP_INFO_LOCK_ASSERT(); | ||||
chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; | chain = &SCTP_BASE_INFO(vtag_timewait)[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; | ||||
LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { | LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { | ||||
for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { | for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { | ||||
if ((twait_block->vtag_block[i].tv_sec_at_expire >= now) && | if ((twait_block->vtag_block[i].tv_sec_at_expire >= now) && | ||||
(twait_block->vtag_block[i].v_tag == tag) && | (twait_block->vtag_block[i].v_tag == tag) && | ||||
(twait_block->vtag_block[i].lport == lport) && | (twait_block->vtag_block[i].lport == lport) && | ||||
(twait_block->vtag_block[i].rport == rport)) { | (twait_block->vtag_block[i].rport == rport)) { | ||||
return (true); | return (true); | ||||
▲ Show 20 Lines • Show All 2,150 Lines • ▼ Show 20 Lines | |||||
bool | bool | ||||
sctp_is_vtag_good(uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *now) | sctp_is_vtag_good(uint32_t tag, uint16_t lport, uint16_t rport, struct timeval *now) | ||||
{ | { | ||||
struct sctpasochead *head; | struct sctpasochead *head; | ||||
struct sctp_tcb *stcb; | struct sctp_tcb *stcb; | ||||
bool result; | bool result; | ||||
SCTP_INP_INFO_RLOCK(); | SCTP_INP_INFO_LOCK_ASSERT(); | ||||
head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, SCTP_BASE_INFO(hashasocmark))]; | head = &SCTP_BASE_INFO(sctp_asochash)[SCTP_PCBHASH_ASOC(tag, SCTP_BASE_INFO(hashasocmark))]; | ||||
LIST_FOREACH(stcb, head, sctp_asocs) { | LIST_FOREACH(stcb, head, sctp_asocs) { | ||||
/* | /* | ||||
* We choose not to lock anything here. TCB's can't be | * We choose not to lock anything here. TCB's can't be | ||||
* removed since we have the read lock, so they can't be | * removed since we have the read lock, so they can't be | ||||
* freed on us, same thing for the INP. I may be wrong with | * freed on us, same thing for the INP. I may be wrong with | ||||
* this assumption, but we will go with it for now :-) | * this assumption, but we will go with it for now :-) | ||||
*/ | */ | ||||
Show All 10 Lines | if (stcb->asoc.my_vtag == tag) { | ||||
} | } | ||||
/* The tag is currently used, so don't use it. */ | /* The tag is currently used, so don't use it. */ | ||||
result = false; | result = false; | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
result = !sctp_is_in_timewait(tag, lport, rport, (uint32_t)now->tv_sec); | result = !sctp_is_in_timewait(tag, lport, rport, (uint32_t)now->tv_sec); | ||||
out: | out: | ||||
SCTP_INP_INFO_RUNLOCK(); | |||||
return (result); | return (result); | ||||
} | } | ||||
static void | static void | ||||
sctp_drain_mbufs(struct sctp_tcb *stcb) | sctp_drain_mbufs(struct sctp_tcb *stcb) | ||||
{ | { | ||||
/* | /* | ||||
* We must hunt this association for MBUF's past the cumack (i.e. | * We must hunt this association for MBUF's past the cumack (i.e. | ||||
▲ Show 20 Lines • Show All 323 Lines • Show Last 20 Lines |
Putting the last two arguments in a line might be hard to maintain. The upstream code has multiple variants of the but-last argument.