- Consolidate the code that free's chunks to actually also
call the sctp_free_remote_address() function. - Assure that when we allocate a chunk the whoTo is NULL, also when we free it and place it into the cache we NULL it (that way the consolidation code will always work). - Fix a small race, when a empty data holder is left on the stream out queue, and both sides do a shutdown, the empty data holder would prevent us from sending a SHUTDOWN-ACK and at the same time we never would cleanup the empty holder (since nothing was ever in queue). We now add a utility function that a) cleans up empty holders and b) properly determines if there are still pending data chunks on the stream out wheel. Approved by: re@freebsd.org (Ken Smith)
This commit is contained in:
parent
02dd4b5cbd
commit
5bead43650
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=171158
@ -387,7 +387,6 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
chk->data = NULL;
|
||||
}
|
||||
/* Now free the address and data */
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
/* sa_ignore FREED_MEMORY */
|
||||
chk = TAILQ_FIRST(&asoc->reasmqueue);
|
||||
@ -481,7 +480,6 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
|
||||
/* free up the chk */
|
||||
chk->data = NULL;
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
|
||||
if (asoc->fragmented_delivery_inprogress == 0) {
|
||||
@ -690,7 +688,9 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
control->data = NULL;
|
||||
asoc->size_on_all_streams -= control->length;
|
||||
sctp_ucount_decr(asoc->cnt_on_all_streams);
|
||||
sctp_free_remote_addr(control->whoFrom);
|
||||
if (control->whoFrom)
|
||||
sctp_free_remote_addr(control->whoFrom);
|
||||
control->whoFrom = NULL;
|
||||
sctp_free_a_readq(stcb, control);
|
||||
return;
|
||||
} else {
|
||||
@ -1009,7 +1009,6 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
return;
|
||||
} else {
|
||||
@ -1876,7 +1875,10 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
/* Evil/Broke peer */
|
||||
sctp_m_freem(control->data);
|
||||
control->data = NULL;
|
||||
sctp_free_remote_addr(control->whoFrom);
|
||||
if (control->whoFrom) {
|
||||
sctp_free_remote_addr(control->whoFrom);
|
||||
control->whoFrom = NULL;
|
||||
}
|
||||
sctp_free_a_readq(stcb, control);
|
||||
oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + 3 * sizeof(uint32_t)),
|
||||
0, M_DONTWAIT, 1, MT_DATA);
|
||||
@ -1908,7 +1910,10 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
if (sctp_does_tsn_belong_to_reasm(asoc, control->sinfo_tsn)) {
|
||||
sctp_m_freem(control->data);
|
||||
control->data = NULL;
|
||||
sctp_free_remote_addr(control->whoFrom);
|
||||
if (control->whoFrom) {
|
||||
sctp_free_remote_addr(control->whoFrom);
|
||||
control->whoFrom = NULL;
|
||||
}
|
||||
sctp_free_a_readq(stcb, control);
|
||||
|
||||
oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + 3 * sizeof(uint32_t)),
|
||||
@ -1953,7 +1958,10 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
if (sctp_does_tsn_belong_to_reasm(asoc, control->sinfo_tsn)) {
|
||||
sctp_m_freem(control->data);
|
||||
control->data = NULL;
|
||||
sctp_free_remote_addr(control->whoFrom);
|
||||
if (control->whoFrom) {
|
||||
sctp_free_remote_addr(control->whoFrom);
|
||||
control->whoFrom = NULL;
|
||||
}
|
||||
sctp_free_a_readq(stcb, control);
|
||||
oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + 3 * sizeof(uint32_t)),
|
||||
0, M_DONTWAIT, 1, MT_DATA);
|
||||
@ -4318,7 +4326,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
}
|
||||
tp1->data = NULL;
|
||||
asoc->sent_queue_cnt--;
|
||||
sctp_free_remote_addr(tp1->whoTo);
|
||||
sctp_free_a_chunk(stcb, tp1);
|
||||
tp1 = tp2;
|
||||
}
|
||||
@ -5029,8 +5036,6 @@ sctp_handle_sack(struct mbuf *m, int offset,
|
||||
}
|
||||
tp1->data = NULL;
|
||||
asoc->sent_queue_cnt--;
|
||||
sctp_free_remote_addr(tp1->whoTo);
|
||||
|
||||
sctp_free_a_chunk(stcb, tp1);
|
||||
wake_him++;
|
||||
tp1 = tp2;
|
||||
@ -5825,7 +5830,6 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
} else {
|
||||
/*
|
||||
|
@ -164,6 +164,67 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
|
||||
/*
|
||||
* process peer "INIT/INIT-ACK" chunk returns value < 0 on error
|
||||
*/
|
||||
|
||||
int
|
||||
sctp_is_there_unsent_data(struct sctp_tcb *stcb)
|
||||
{
|
||||
int unsent_data = 0;
|
||||
struct sctp_stream_queue_pending *sp;
|
||||
struct sctp_stream_out *strq;
|
||||
struct sctp_association *asoc;
|
||||
|
||||
/*
|
||||
* This function returns the number of streams that have true unsent
|
||||
* data on them. Note that as it looks through it will clean up any
|
||||
* places that have old data that has been sent but left at top of
|
||||
* stream queue.
|
||||
*/
|
||||
asoc = &stcb->asoc;
|
||||
SCTP_TCB_SEND_LOCK(stcb);
|
||||
if (!TAILQ_EMPTY(&asoc->out_wheel)) {
|
||||
/* Check to see if some data queued */
|
||||
TAILQ_FOREACH(strq, &asoc->out_wheel, next_spoke) {
|
||||
/* sa_ignore FREED_MEMORY */
|
||||
is_there_another:
|
||||
sp = TAILQ_FIRST(&strq->outqueue);
|
||||
if (sp == NULL) {
|
||||
continue;
|
||||
}
|
||||
if ((sp->msg_is_complete) &&
|
||||
(sp->length == 0) &&
|
||||
(sp->sender_all_done)) {
|
||||
/*
|
||||
* We are doing differed cleanup. Last time
|
||||
* through when we took all the data the
|
||||
* sender_all_done was not set.
|
||||
*/
|
||||
if (sp->put_last_out == 0) {
|
||||
SCTP_PRINTF("Gak, put out entire msg with NO end!-1\n");
|
||||
SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n",
|
||||
sp->sender_all_done,
|
||||
sp->length,
|
||||
sp->msg_is_complete,
|
||||
sp->put_last_out);
|
||||
}
|
||||
atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1);
|
||||
TAILQ_REMOVE(&strq->outqueue, sp, next);
|
||||
sctp_free_remote_addr(sp->net);
|
||||
if (sp->data) {
|
||||
sctp_m_freem(sp->data);
|
||||
sp->data = NULL;
|
||||
}
|
||||
sctp_free_a_strmoq(stcb, sp);
|
||||
goto is_there_another;
|
||||
} else {
|
||||
unsent_data++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
SCTP_TCB_SEND_UNLOCK(stcb);
|
||||
return (unsent_data);
|
||||
}
|
||||
|
||||
static int
|
||||
sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
@ -253,6 +314,7 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb,
|
||||
while (ctl) {
|
||||
TAILQ_REMOVE(&asoc->strmin[i].inqueue, ctl, next);
|
||||
sctp_free_remote_addr(ctl->whoFrom);
|
||||
ctl->whoFrom = NULL;
|
||||
sctp_m_freem(ctl->data);
|
||||
ctl->data = NULL;
|
||||
sctp_free_a_readq(stcb, ctl);
|
||||
@ -569,19 +631,9 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
|
||||
*/
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_7);
|
||||
}
|
||||
/* Now are we there yet? */
|
||||
some_on_streamwheel = 0;
|
||||
if (!TAILQ_EMPTY(&asoc->out_wheel)) {
|
||||
/* Check to see if some data queued */
|
||||
struct sctp_stream_out *outs;
|
||||
/* Now is there unsent data on a stream somewhere? */
|
||||
some_on_streamwheel = sctp_is_there_unsent_data(stcb);
|
||||
|
||||
TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
|
||||
if (!TAILQ_EMPTY(&outs->outqueue)) {
|
||||
some_on_streamwheel = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!TAILQ_EMPTY(&asoc->send_queue) ||
|
||||
!TAILQ_EMPTY(&asoc->sent_queue) ||
|
||||
some_on_streamwheel) {
|
||||
@ -2371,7 +2423,6 @@ sctp_handle_ecn_cwr(struct sctp_cwr_chunk *cp, struct sctp_tcb *stcb)
|
||||
chk->data = NULL;
|
||||
}
|
||||
stcb->asoc.ctrl_queue_cnt--;
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
break;
|
||||
}
|
||||
@ -2764,8 +2815,6 @@ sctp_clean_up_stream_reset(struct sctp_tcb *stcb)
|
||||
chk->data = NULL;
|
||||
}
|
||||
asoc->ctrl_queue_cnt--;
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
stcb->asoc.str_reset = NULL;
|
||||
}
|
||||
|
@ -50,5 +50,8 @@ void
|
||||
sctp_reset_in_stream(struct sctp_tcb *stcb, int number_entries,
|
||||
uint16_t * list);
|
||||
|
||||
|
||||
int sctp_is_there_unsent_data(struct sctp_tcb *stcb);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/sctp_asconf.h>
|
||||
#include <netinet/sctp_indata.h>
|
||||
#include <netinet/sctp_bsd_addr.h>
|
||||
#include <netinet/sctp_input.h>
|
||||
|
||||
|
||||
|
||||
@ -5642,9 +5643,13 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
asoc = &stcb->asoc;
|
||||
if (ca->sndrcv.sinfo_flags & SCTP_EOF) {
|
||||
/* shutdown this assoc */
|
||||
int cnt;
|
||||
|
||||
cnt = sctp_is_there_unsent_data(stcb);
|
||||
|
||||
if (TAILQ_EMPTY(&asoc->send_queue) &&
|
||||
TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(asoc->stream_queue_cnt == 0)) {
|
||||
(cnt == 0)) {
|
||||
if (asoc->locked_on_sending) {
|
||||
goto abort_anyway;
|
||||
}
|
||||
@ -5887,8 +5892,6 @@ sctp_toss_old_cookies(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
chk->data = NULL;
|
||||
}
|
||||
asoc->ctrl_queue_cnt--;
|
||||
if (chk->whoTo)
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
}
|
||||
chk = nchk;
|
||||
@ -5914,8 +5917,6 @@ sctp_toss_old_asconf(struct sctp_tcb *stcb)
|
||||
chk->data = NULL;
|
||||
}
|
||||
asoc->ctrl_queue_cnt--;
|
||||
if (chk->whoTo)
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
}
|
||||
}
|
||||
@ -6037,7 +6038,6 @@ sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
chk->data = NULL;
|
||||
}
|
||||
asoc->ctrl_queue_cnt--;
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
} else if (chk->rec.chunk_id.id == SCTP_STREAM_RESET) {
|
||||
/* special handling, we must look into the param */
|
||||
@ -8989,8 +8989,6 @@ sctp_send_sack(struct sctp_tcb *stcb)
|
||||
sctp_m_freem(a_chk->data);
|
||||
a_chk->data = NULL;
|
||||
}
|
||||
if (a_chk->whoTo)
|
||||
atomic_subtract_int(&a_chk->whoTo->ref_count, 1);
|
||||
sctp_free_a_chunk(stcb, a_chk);
|
||||
if (stcb->asoc.delayed_ack) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
|
||||
@ -9576,7 +9574,6 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net)
|
||||
* to the Q's style as defined in the RFC and not my
|
||||
* alternate style defined in the RFC.
|
||||
*/
|
||||
atomic_subtract_int(&chk->whoTo->ref_count, 1);
|
||||
if (chk->data != NULL) {
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
@ -11576,15 +11573,18 @@ sctp_lower_sosend(struct socket *so,
|
||||
(got_all_of_the_send == 1) &&
|
||||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)
|
||||
) {
|
||||
int cnt;
|
||||
|
||||
SCTP_STAT_INCR(sctps_sends_with_eof);
|
||||
error = 0;
|
||||
if (hold_tcblock == 0) {
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
hold_tcblock = 1;
|
||||
}
|
||||
cnt = sctp_is_there_unsent_data(stcb);
|
||||
if (TAILQ_EMPTY(&asoc->send_queue) &&
|
||||
TAILQ_EMPTY(&asoc->sent_queue) &&
|
||||
(asoc->stream_queue_cnt == 0)) {
|
||||
(cnt == 0)) {
|
||||
if (asoc->locked_on_sending) {
|
||||
goto abort_anyway;
|
||||
}
|
||||
|
@ -5472,7 +5472,6 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
}
|
||||
chk = nchk;
|
||||
|
@ -90,6 +90,10 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
|
||||
|
||||
#define sctp_free_a_chunk(_stcb, _chk) { \
|
||||
if ((_chk)->whoTo) { \
|
||||
sctp_free_remote_addr((_chk)->whoTo); \
|
||||
(_chk)->whoTo = NULL; \
|
||||
} \
|
||||
if (((_stcb)->asoc.free_chunk_cnt > sctp_asoc_free_resc_limit) || \
|
||||
(sctppcbinfo.ipi_free_chunks > sctp_system_free_resc_limit)) { \
|
||||
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, (_chk)); \
|
||||
@ -106,6 +110,7 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
(_chk) = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_chunk, struct sctp_tmit_chunk); \
|
||||
if ((_chk)) { \
|
||||
SCTP_INCR_CHK_COUNT(); \
|
||||
(_chk)->whoTo = NULL; \
|
||||
} \
|
||||
} else { \
|
||||
(_chk) = TAILQ_FIRST(&(_stcb)->asoc.free_chunks); \
|
||||
|
@ -3450,9 +3450,6 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
if (chk->whoTo)
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
chk->whoTo = NULL;
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
/* sa_ignore FREED_MEMORY */
|
||||
chk = TAILQ_FIRST(&asoc->sent_queue);
|
||||
@ -3481,9 +3478,6 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
if (chk->whoTo)
|
||||
sctp_free_remote_addr(chk->whoTo);
|
||||
chk->whoTo = NULL;
|
||||
sctp_free_a_chunk(stcb, chk);
|
||||
/* sa_ignore FREED_MEMORY */
|
||||
chk = TAILQ_FIRST(&asoc->send_queue);
|
||||
|
Loading…
Reference in New Issue
Block a user