summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_input.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-07-02 19:22:22 +0000
committerrrs <rrs@FreeBSD.org>2007-07-02 19:22:22 +0000
commita400d04306bce1d90fa1fb76eb5ed9c3977a1c32 (patch)
tree1af5bea59680545d915388b260052ee36e2b1ab6 /sys/netinet/sctp_input.c
parentbb6f1c3d9ba9c5a3452440ffdafda555b482e1b2 (diff)
downloadFreeBSD-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/netinet/sctp_input.c')
-rw-r--r--sys/netinet/sctp_input.c79
1 files changed, 64 insertions, 15 deletions
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;
}
OpenPOWER on IntegriCloud