diff options
author | rrs <rrs@FreeBSD.org> | 2007-07-02 19:22:22 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-07-02 19:22:22 +0000 |
commit | a400d04306bce1d90fa1fb76eb5ed9c3977a1c32 (patch) | |
tree | 1af5bea59680545d915388b260052ee36e2b1ab6 /sys | |
parent | bb6f1c3d9ba9c5a3452440ffdafda555b482e1b2 (diff) | |
download | FreeBSD-src-a400d04306bce1d90fa1fb76eb5ed9c3977a1c32.zip FreeBSD-src-a400d04306bce1d90fa1fb76eb5ed9c3977a1c32.tar.gz |
- 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)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/sctp_indata.c | 26 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 79 | ||||
-rw-r--r-- | sys/netinet/sctp_input.h | 3 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 20 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_var.h | 5 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 6 |
7 files changed, 97 insertions, 43 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index d49721c..06fcddc 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -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 @@ failed_pdapi_express_del: /* 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 @@ failed_pdapi_express_del: 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 @@ failed_pdapi_express_del: 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 @@ skip_segments: } 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 { /* diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index a66369b..8b1ebce 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -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; } diff --git a/sys/netinet/sctp_input.h b/sys/netinet/sctp_input.h index 3de05fe..01a67c6 100644 --- a/sys/netinet/sctp_input.h +++ b/sys/netinet/sctp_input.h @@ -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 diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index ac2da30..7234ce7 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -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 @@ dataless_eof: (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; } diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 91d509c..84b367b 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -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; diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h index 74e514b..f05a368 100644 --- a/sys/netinet/sctp_var.h +++ b/sys/netinet/sctp_var.h @@ -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); \ diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index f68f2d5..319bbcc 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -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); |