summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/sctp_indata.c26
-rw-r--r--sys/netinet/sctp_input.c79
-rw-r--r--sys/netinet/sctp_input.h3
-rw-r--r--sys/netinet/sctp_output.c20
-rw-r--r--sys/netinet/sctp_pcb.c1
-rw-r--r--sys/netinet/sctp_var.h5
-rw-r--r--sys/netinet/sctputil.c6
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);
OpenPOWER on IntegriCloud