- 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:
Randall Stewart 2007-07-02 19:22:22 +00:00
parent 02dd4b5cbd
commit 5bead43650
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=171158
7 changed files with 97 additions and 43 deletions

View File

@ -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 {
/*

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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); \

View File

@ -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);