svn commit: r303956 - stable/11/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Thu Aug 11 10:14:05 UTC 2016
Author: tuexen
Date: Thu Aug 11 10:14:03 2016
New Revision: 303956
URL: https://svnweb.freebsd.org/changeset/base/303956
Log:
MFC r303792:
Fix various bugs in relation to the I-DATA chunk support
This is joint work with rrs.
MFC r303793:
Mark an unused parameter as such.
MFC r303798:
Don't modify a structure without holding a reference count on it.
MFC r303813:
Remove stream queue entry consistently from wheel.
While there, improve the handling of drain.
MFC r303819:
Consistently check for unsent data on the stream queues.
MFC r303831:
Fix a locking issue found by stress testing with tsctp.
The inp read lock neeeds to be held when considering control->do_not_ref_stcb.
MFC r303834:
Fix the sending of FORWARD-TSN and I-FORWARD-TSN chunks. The
last SID/SSN pair wasn't filled in.
Thanks to Julian Cordes for providing a packetdrill script
triggering the issue and making me aware of the bug.
Approved by: re (kib)
Modified:
stable/11/sys/netinet/sctp_indata.c
stable/11/sys/netinet/sctp_input.c
stable/11/sys/netinet/sctp_output.c
stable/11/sys/netinet/sctp_pcb.c
stable/11/sys/netinet/sctp_ss_functions.c
stable/11/sys/netinet/sctp_structs.h
stable/11/sys/netinet/sctp_usrreq.c
stable/11/sys/netinet/sctputil.c
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/netinet/sctp_indata.c
==============================================================================
--- stable/11/sys/netinet/sctp_indata.c Thu Aug 11 10:10:10 2016 (r303955)
+++ stable/11/sys/netinet/sctp_indata.c Thu Aug 11 10:14:03 2016 (r303956)
@@ -64,7 +64,7 @@ sctp_add_chk_to_control(struct sctp_queu
struct sctp_stream_in *strm,
struct sctp_tcb *stcb,
struct sctp_association *asoc,
- struct sctp_tmit_chunk *chk);
+ struct sctp_tmit_chunk *chk, int lock_held);
void
@@ -448,7 +448,7 @@ sctp_abort_in_reasm(struct sctp_tcb *stc
}
static void
-clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control)
+sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control)
{
/*
* The control could not be placed and must be cleaned.
@@ -612,7 +612,7 @@ protocol_error:
snprintf(msg, sizeof(msg),
"Queue to str msg_id: %u duplicate",
control->msg_id);
- clean_up_control(stcb, control);
+ sctp_clean_up_control(stcb, control);
op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3;
sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
@@ -739,9 +739,28 @@ sctp_build_readq_entry_from_ctl(struct s
nc->port_from = control->port_from;
}
+static void
+sctp_reset_a_control(struct sctp_queued_to_read *control,
+ struct sctp_inpcb *inp, uint32_t tsn)
+{
+ control->fsn_included = tsn;
+ if (control->on_read_q) {
+ /*
+ * We have to purge it from there, hopefully this will work
+ * :-)
+ */
+ TAILQ_REMOVE(&inp->read_queue, control, next);
+ control->on_read_q = 0;
+ }
+}
+
static int
-sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_in *strm,
- struct sctp_queued_to_read *control, uint32_t pd_point)
+sctp_handle_old_unordered_data(struct sctp_tcb *stcb,
+ struct sctp_association *asoc,
+ struct sctp_stream_in *strm,
+ struct sctp_queued_to_read *control,
+ uint32_t pd_point,
+ int inp_read_lock_held)
{
/*
* Special handling for the old un-ordered data chunk. All the
@@ -774,7 +793,7 @@ restart:
}
memset(nc, 0, sizeof(struct sctp_queued_to_read));
TAILQ_REMOVE(&control->reasm, chk, sctp_next);
- sctp_add_chk_to_control(control, strm, stcb, asoc, chk);
+ sctp_add_chk_to_control(control, strm, stcb, asoc, chk, SCTP_READ_LOCK_NOT_HELD);
fsn++;
cnt_added++;
chk = NULL;
@@ -793,6 +812,8 @@ restart:
nc->first_frag_seen = 1;
nc->fsn_included = tchk->rec.data.fsn_num;
nc->data = tchk->data;
+ nc->sinfo_ppid = tchk->rec.data.payloadtype;
+ nc->sinfo_tsn = tchk->rec.data.TSN_seq;
sctp_mark_non_revokable(asoc, tchk->rec.data.TSN_seq);
tchk->data = NULL;
sctp_free_a_chunk(stcb, tchk, SCTP_SO_NOT_LOCKED);
@@ -828,7 +849,7 @@ restart:
if (control->on_read_q == 0) {
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
&stcb->sctp_socket->so_rcv, control->end_added,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
}
sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) {
@@ -839,7 +860,9 @@ restart:
control = nc;
goto restart;
} else {
- sctp_free_a_readq(stcb, nc);
+ if (nc->on_strm_q == 0) {
+ sctp_free_a_readq(stcb, nc);
+ }
}
return (1);
} else {
@@ -855,7 +878,7 @@ restart:
control->pdapi_started = 1;
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
&stcb->sctp_socket->so_rcv, control->end_added,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
return (0);
} else {
@@ -864,13 +887,14 @@ restart:
}
static void
-sctp_inject_old_data_unordered(struct sctp_tcb *stcb, struct sctp_association *asoc,
+sctp_inject_old_unordered_data(struct sctp_tcb *stcb,
+ struct sctp_association *asoc,
struct sctp_queued_to_read *control,
struct sctp_tmit_chunk *chk,
int *abort_flag)
{
struct sctp_tmit_chunk *at;
- int inserted = 0;
+ int inserted;
/*
* Here we need to place the chunk into the control structure sorted
@@ -926,18 +950,29 @@ sctp_inject_old_data_unordered(struct sc
tdata = control->data;
control->data = chk->data;
chk->data = tdata;
- /* Swap the lengths */
- tmp = control->length;
- control->length = chk->send_size;
- chk->send_size = tmp;
+ /* Save the lengths */
+ chk->send_size = control->length;
+ /* Recompute length of control and tail pointer */
+ sctp_setup_tail_pointer(control);
/* Fix the FSN included */
tmp = control->fsn_included;
control->fsn_included = chk->rec.data.fsn_num;
chk->rec.data.fsn_num = tmp;
+ /* Fix the TSN included */
+ tmp = control->sinfo_tsn;
+ control->sinfo_tsn = chk->rec.data.TSN_seq;
+ chk->rec.data.TSN_seq = tmp;
+ /* Fix the PPID included */
+ tmp = control->sinfo_ppid;
+ control->sinfo_ppid = chk->rec.data.payloadtype;
+ chk->rec.data.payloadtype = tmp;
+ /* Fix tail pointer */
goto place_chunk;
}
control->first_frag_seen = 1;
control->top_fsn = control->fsn_included = chk->rec.data.fsn_num;
+ control->sinfo_tsn = chk->rec.data.TSN_seq;
+ control->sinfo_ppid = chk->rec.data.payloadtype;
control->data = chk->data;
sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
chk->data = NULL;
@@ -946,12 +981,7 @@ sctp_inject_old_data_unordered(struct sc
return;
}
place_chunk:
- if (TAILQ_EMPTY(&control->reasm)) {
- TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
- asoc->size_on_reasm_queue += chk->send_size;
- sctp_ucount_incr(asoc->cnt_on_reasm_queue);
- return;
- }
+ inserted = 0;
TAILQ_FOREACH(at, &control->reasm, sctp_next) {
if (SCTP_TSN_GT(at->rec.data.fsn_num, chk->rec.data.fsn_num)) {
/*
@@ -985,7 +1015,8 @@ place_chunk:
}
static int
-sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_in *strm)
+sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
+ struct sctp_stream_in *strm, int inp_read_lock_held)
{
/*
* Given a stream, strm, see if any of the SSN's on it that are
@@ -1005,10 +1036,11 @@ sctp_deliver_reasm_check(struct sctp_tcb
pd_point = stcb->sctp_ep->partial_delivery_point;
}
control = TAILQ_FIRST(&strm->uno_inqueue);
+
if ((control) &&
(asoc->idata_supported == 0)) {
/* Special handling needed for "old" data format */
- if (sctp_handle_old_data(stcb, asoc, strm, control, pd_point)) {
+ if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, pd_point, inp_read_lock_held)) {
goto done_un;
}
}
@@ -1037,7 +1069,7 @@ sctp_deliver_reasm_check(struct sctp_tcb
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, control->end_added,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
}
} else {
/* Can we do a PD-API for this un-ordered guy? */
@@ -1047,7 +1079,7 @@ sctp_deliver_reasm_check(struct sctp_tcb
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, control->end_added,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
break;
}
@@ -1096,7 +1128,7 @@ done_un:
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, control->end_added,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
}
control = nctl;
}
@@ -1160,7 +1192,7 @@ deliver_more:
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, control->end_added,
- SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+ inp_read_lock_held, SCTP_SO_NOT_LOCKED);
}
strm->last_sequence_delivered = next_to_del;
if (done) {
@@ -1177,11 +1209,12 @@ out:
return (ret);
}
+
void
sctp_add_chk_to_control(struct sctp_queued_to_read *control,
struct sctp_stream_in *strm,
struct sctp_tcb *stcb, struct sctp_association *asoc,
- struct sctp_tmit_chunk *chk)
+ struct sctp_tmit_chunk *chk, int hold_rlock)
{
/*
* Given a control and a chunk, merge the data from the chk onto the
@@ -1189,7 +1222,7 @@ sctp_add_chk_to_control(struct sctp_queu
*/
int i_locked = 0;
- if (control->on_read_q) {
+ if (control->on_read_q && (hold_rlock == 0)) {
/*
* Its being pd-api'd so we must do some locks.
*/
@@ -1271,7 +1304,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
if (created_control) {
if (sctp_place_control_in_stream(strm, asoc, control)) {
/* Duplicate SSN? */
- clean_up_control(stcb, control);
+ sctp_clean_up_control(stcb, control);
sctp_abort_in_reasm(stcb, control, chk,
abort_flag,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_6);
@@ -1292,7 +1325,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
}
}
if ((asoc->idata_supported == 0) && (unordered == 1)) {
- sctp_inject_old_data_unordered(stcb, asoc, control, chk, abort_flag);
+ sctp_inject_old_unordered_data(stcb, asoc, control, chk, abort_flag);
return;
}
/*
@@ -1482,7 +1515,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
at->rec.data.fsn_num,
next_fsn, control->fsn_included);
TAILQ_REMOVE(&control->reasm, at, sctp_next);
- sctp_add_chk_to_control(control, strm, stcb, asoc, at);
+ sctp_add_chk_to_control(control, strm, stcb, asoc, at, SCTP_READ_LOCK_NOT_HELD);
if (control->on_read_q) {
do_wakeup = 1;
}
@@ -1513,7 +1546,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
}
static struct sctp_queued_to_read *
-find_reasm_entry(struct sctp_stream_in *strm, uint32_t msg_id, int ordered, int old)
+sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t msg_id, int ordered, int old)
{
struct sctp_queued_to_read *control;
@@ -1573,6 +1606,7 @@ sctp_process_a_data_chunk(struct sctp_tc
clen = sizeof(struct sctp_idata_chunk);
tsn = ntohl(ch->dp.tsn);
msg_id = ntohl(nch->dp.msg_id);
+ protocol_id = nch->dp.ppid_fsn.protocol_id;
if (ch->ch.chunk_flags & SCTP_DATA_FIRST_FRAG)
fsn = 0;
else
@@ -1582,6 +1616,7 @@ sctp_process_a_data_chunk(struct sctp_tc
ch = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset,
sizeof(struct sctp_data_chunk), (uint8_t *) & chunk_buf);
tsn = ntohl(ch->dp.tsn);
+ protocol_id = ch->dp.protocol_id;
clen = sizeof(struct sctp_data_chunk);
fsn = tsn;
msg_id = (uint32_t) (ntohs(ch->dp.stream_sequence));
@@ -1602,7 +1637,6 @@ sctp_process_a_data_chunk(struct sctp_tc
if ((chunk_flags & SCTP_DATA_SACK_IMMEDIATELY) == SCTP_DATA_SACK_IMMEDIATELY) {
asoc->send_sack = 1;
}
- protocol_id = ch->dp.protocol_id;
ordered = ((chunk_flags & SCTP_DATA_UNORDERED) == 0);
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS);
@@ -1722,7 +1756,7 @@ sctp_process_a_data_chunk(struct sctp_tc
}
if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
/* See if we can find the re-assembly entity */
- control = find_reasm_entry(strm, msg_id, ordered, old_data);
+ control = sctp_find_reasm_entry(strm, msg_id, ordered, old_data);
SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on queues %p\n",
chunk_flags, control);
if (control) {
@@ -1758,7 +1792,7 @@ sctp_process_a_data_chunk(struct sctp_tc
*/
SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for msg in case we have dup\n",
chunk_flags);
- if (find_reasm_entry(strm, msg_id, ordered, old_data)) {
+ if (sctp_find_reasm_entry(strm, msg_id, ordered, old_data)) {
SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected on msg_id: %u\n",
chunk_flags,
msg_id);
@@ -2179,12 +2213,12 @@ finish_express_del:
* Now service re-assembly to pick up anything that has been
* held on reassembly queue?
*/
- (void)sctp_deliver_reasm_check(stcb, asoc, strm);
+ (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
need_reasm_check = 0;
}
if (need_reasm_check) {
/* Another one waits ? */
- (void)sctp_deliver_reasm_check(stcb, asoc, strm);
+ (void)sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_NOT_HELD);
}
return (1);
}
@@ -4152,28 +4186,8 @@ again:
if ((asoc->stream_queue_cnt == 1) &&
((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
(asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) &&
- (asoc->locked_on_sending)
- ) {
- struct sctp_stream_queue_pending *sp;
-
- /*
- * I may be in a state where we got all across.. but
- * cannot write more due to a shutdown... we abort
- * since the user did not indicate EOR in this case.
- * The sp will be cleaned during free of the asoc.
- */
- sp = TAILQ_LAST(&((asoc->locked_on_sending)->outqueue),
- sctp_streamhead);
- if ((sp) && (sp->length == 0)) {
- /* Let cleanup code purge it */
- if (sp->msg_is_complete) {
- asoc->stream_queue_cnt--;
- } else {
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- asoc->locked_on_sending = NULL;
- asoc->stream_queue_cnt--;
- }
- }
+ ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
+ asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
}
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
(asoc->stream_queue_cnt == 0)) {
@@ -4868,26 +4882,8 @@ hopeless_peer:
if ((asoc->stream_queue_cnt == 1) &&
((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
(asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) &&
- (asoc->locked_on_sending)
- ) {
- struct sctp_stream_queue_pending *sp;
-
- /*
- * I may be in a state where we got all across.. but
- * cannot write more due to a shutdown... we abort
- * since the user did not indicate EOR in this case.
- */
- sp = TAILQ_LAST(&((asoc->locked_on_sending)->outqueue),
- sctp_streamhead);
- if ((sp) && (sp->length == 0)) {
- asoc->locked_on_sending = NULL;
- if (sp->msg_is_complete) {
- asoc->stream_queue_cnt--;
- } else {
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- asoc->stream_queue_cnt--;
- }
- }
+ ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc))) {
+ asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
}
if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
(asoc->stream_queue_cnt == 0)) {
@@ -5215,7 +5211,7 @@ sctp_kick_prsctp_reorder_queue(struct sc
if (need_reasm_check) {
int ret;
- ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin);
+ ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
if (SCTP_MSGID_GT(old, tt, strmin->last_sequence_delivered)) {
/* Restore the next to deliver unless we are ahead */
strmin->last_sequence_delivered = tt;
@@ -5279,19 +5275,21 @@ sctp_kick_prsctp_reorder_queue(struct sc
}
}
if (need_reasm_check) {
- (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin);
+ (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, SCTP_READ_LOCK_HELD);
}
}
+
static void
sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
struct sctp_association *asoc,
- uint16_t stream, uint32_t seq, int ordered, int old)
+ uint16_t stream, uint32_t seq, int ordered, int old, uint32_t cumtsn)
{
struct sctp_queued_to_read *control;
struct sctp_stream_in *strm;
struct sctp_tmit_chunk *chk, *nchk;
+ int cnt_removed = 0;
/*
* For now large messages held on the stream reasm that are complete
@@ -5302,13 +5300,19 @@ sctp_flush_reassm_for_str_seq(struct sct
* queue.
*/
strm = &asoc->strmin[stream];
- control = find_reasm_entry(strm, (uint32_t) seq, ordered, old);
+ control = sctp_find_reasm_entry(strm, (uint32_t) seq, ordered, old);
if (control == NULL) {
/* Not found */
return;
}
TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
/* Purge hanging chunks */
+ if (old && (ordered == 0)) {
+ if (SCTP_TSN_GT(chk->rec.data.TSN_seq, cumtsn)) {
+ break;
+ }
+ }
+ cnt_removed++;
TAILQ_REMOVE(&control->reasm, chk, sctp_next);
asoc->size_on_reasm_queue -= chk->send_size;
sctp_ucount_decr(asoc->cnt_on_reasm_queue);
@@ -5318,7 +5322,35 @@ sctp_flush_reassm_for_str_seq(struct sct
}
sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
}
- TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ if (!TAILQ_EMPTY(&control->reasm)) {
+ /* This has to be old data, unordered */
+ if (control->data) {
+ sctp_m_freem(control->data);
+ control->data = NULL;
+ }
+ sctp_reset_a_control(control, stcb->sctp_ep, cumtsn);
+ chk = TAILQ_FIRST(&control->reasm);
+ if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
+ TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+ sctp_add_chk_to_control(control, strm, stcb, asoc,
+ chk, SCTP_READ_LOCK_HELD);
+ }
+ sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD);
+ return;
+ }
+ if (control->on_strm_q == SCTP_ON_ORDERED) {
+ TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+ } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+ TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
+ control->on_strm_q = 0;
+#ifdef INVARIANTS
+ } else if (control->on_strm_q) {
+ panic("strm: %p ctl: %p unknown %d",
+ strm, control, control->on_strm_q);
+#endif
+ }
+ control->on_strm_q = 0;
if (control->on_read_q == 0) {
sctp_free_remote_addr(control->whoFrom);
if (control->data) {
@@ -5329,7 +5361,6 @@ sctp_flush_reassm_for_str_seq(struct sct
}
}
-
void
sctp_handle_forward_tsn(struct sctp_tcb *stcb,
struct sctp_forward_tsn_chunk *fwd,
@@ -5423,7 +5454,16 @@ sctp_handle_forward_tsn(struct sctp_tcb
/*************************************************************/
/* This is now done as part of clearing up the stream/seq */
+ if (asoc->idata_supported == 0) {
+ uint16_t sid;
+ /* Flush all the un-ordered data based on cum-tsn */
+ SCTP_INP_READ_LOCK(stcb->sctp_ep);
+ for (sid = 0; sid < asoc->streamincnt; sid++) {
+ sctp_flush_reassm_for_str_seq(stcb, asoc, sid, 0, 0, 1, new_cum_tsn);
+ }
+ SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
+ }
/*******************************************************/
/* 3. Update the PR-stream re-ordering queues and fix */
/* delivery issues as needed. */
@@ -5502,7 +5542,19 @@ sctp_handle_forward_tsn(struct sctp_tcb
asoc->fragmented_delivery_inprogress = 0;
}
strm = &asoc->strmin[stream];
- sctp_flush_reassm_for_str_seq(stcb, asoc, stream, sequence, ordered, old);
+ if (asoc->idata_supported == 0) {
+ uint16_t strm_at;
+
+ for (strm_at = strm->last_sequence_delivered; SCTP_MSGID_GE(1, sequence, strm_at); strm_at++) {
+ sctp_flush_reassm_for_str_seq(stcb, asoc, stream, strm_at, ordered, old, new_cum_tsn);
+ }
+ } else {
+ uint32_t strm_at;
+
+ for (strm_at = strm->last_sequence_delivered; SCTP_MSGID_GE(0, sequence, strm_at); strm_at++) {
+ sctp_flush_reassm_for_str_seq(stcb, asoc, stream, strm_at, ordered, old, new_cum_tsn);
+ }
+ }
TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) {
if ((ctl->sinfo_stream == stream) &&
(ctl->sinfo_ssn == sequence)) {
Modified: stable/11/sys/netinet/sctp_input.c
==============================================================================
--- stable/11/sys/netinet/sctp_input.c Thu Aug 11 10:10:10 2016 (r303955)
+++ stable/11/sys/netinet/sctp_input.c Thu Aug 11 10:14:03 2016 (r303956)
@@ -221,18 +221,18 @@ sctp_is_there_unsent_data(struct sctp_tc
#endif
)
{
- int unsent_data = 0;
+ int unsent_data;
unsigned int i;
struct sctp_stream_queue_pending *sp;
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.
+ * This function returns if any stream has true unsent data on it.
+ * 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;
+ unsent_data = 0;
SCTP_TCB_SEND_LOCK(stcb);
if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
/* Check to see if some data queued */
@@ -260,6 +260,7 @@ sctp_is_there_unsent_data(struct sctp_tc
}
atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1);
TAILQ_REMOVE(&stcb->asoc.strmout[i].outqueue, sp, next);
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, &asoc->strmout[i], sp, 1);
if (sp->net) {
sctp_free_remote_addr(sp->net);
sp->net = NULL;
@@ -269,8 +270,13 @@ sctp_is_there_unsent_data(struct sctp_tc
sp->data = NULL;
}
sctp_free_a_strmoq(stcb, sp, so_locked);
+ if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
+ unsent_data++;
+ }
} else {
unsent_data++;
+ }
+ if (unsent_data > 0) {
break;
}
}
@@ -341,8 +347,9 @@ sctp_process_init(struct sctp_init_chunk
for (i = newcnt; i < asoc->pre_open_streams; i++) {
outs = &asoc->strmout[i];
TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
+ atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1);
TAILQ_REMOVE(&outs->outqueue, sp, next);
- asoc->stream_queue_cnt--;
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1);
sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL,
stcb, 0, sp, SCTP_SO_NOT_LOCKED);
if (sp->data) {
@@ -1047,7 +1054,7 @@ sctp_handle_shutdown_ack(struct sctp_shu
#ifdef INVARIANTS
if (!TAILQ_EMPTY(&asoc->send_queue) ||
!TAILQ_EMPTY(&asoc->sent_queue) ||
- !stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED)) {
panic("Queues are not empty when handling SHUTDOWN-ACK");
}
#endif
@@ -3213,7 +3220,7 @@ sctp_handle_shutdown_complete(struct sct
#ifdef INVARIANTS
if (!TAILQ_EMPTY(&asoc->send_queue) ||
!TAILQ_EMPTY(&asoc->sent_queue) ||
- !stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED)) {
panic("Queues are not empty when handling SHUTDOWN-COMPLETE");
}
#endif
Modified: stable/11/sys/netinet/sctp_output.c
==============================================================================
--- stable/11/sys/netinet/sctp_output.c Thu Aug 11 10:10:10 2016 (r303955)
+++ stable/11/sys/netinet/sctp_output.c Thu Aug 11 10:14:03 2016 (r303956)
@@ -3657,7 +3657,7 @@ sctp_process_cmsgs_for_init(struct sctp_
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
stcb->asoc.strmout[i].state = SCTP_STREAM_OPENING;
- stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+ stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL);
}
}
break;
@@ -6687,14 +6687,10 @@ sctp_sendall_iterator(struct sctp_inpcb
asoc = &stcb->asoc;
if (ca->sndrcv.sinfo_flags & SCTP_EOF) {
/* shutdown this assoc */
- int cnt;
-
- cnt = sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED);
-
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
- (cnt == 0)) {
- if (asoc->locked_on_sending) {
+ sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED) == 0) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
goto abort_anyway;
}
/*
@@ -6736,18 +6732,8 @@ sctp_sendall_iterator(struct sctp_inpcb
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
- if (asoc->locked_on_sending) {
- /*
- * Locked to send out the
- * data
- */
- struct sctp_stream_queue_pending *sp;
-
- sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
- if (sp) {
- if ((sp->length == 0) && (sp->msg_is_complete == 0))
- asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
+ asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
}
asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
if (TAILQ_EMPTY(&asoc->send_queue) &&
@@ -7170,7 +7156,6 @@ sctp_move_to_outqueue(struct sctp_tcb *s
struct sctp_stream_out *strq,
uint32_t goal_mtu,
uint32_t frag_point,
- int *locked,
int *giveup,
int eeor_mode,
int *bail,
@@ -7196,10 +7181,8 @@ sctp_move_to_outqueue(struct sctp_tcb *s
asoc = &stcb->asoc;
one_more_time:
/* sa_ignore FREED_MEMORY */
- *locked = 0;
sp = TAILQ_FIRST(&strq->outqueue);
if (sp == NULL) {
- *locked = 0;
if (send_lock_up == 0) {
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
@@ -7245,12 +7228,12 @@ one_more_time:
}
atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&strq->outqueue, sp, next);
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up);
if ((strq->state == SCTP_STREAM_RESET_PENDING) &&
(strq->chunks_on_queues == 0) &&
TAILQ_EMPTY(&strq->outqueue)) {
stcb->asoc.trigger_reset = 1;
}
- stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up);
if (sp->net) {
sctp_free_remote_addr(sp->net);
sp->net = NULL;
@@ -7261,8 +7244,6 @@ one_more_time:
}
sctp_free_a_strmoq(stcb, sp, so_locked);
/* we can't be locked to it */
- *locked = 0;
- stcb->asoc.locked_on_sending = NULL;
if (send_lock_up) {
SCTP_TCB_SEND_UNLOCK(stcb);
send_lock_up = 0;
@@ -7274,8 +7255,6 @@ one_more_time:
* sender just finished this but still holds a
* reference
*/
- if (stcb->asoc.idata_supported == 0)
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7284,8 +7263,6 @@ one_more_time:
/* is there some to get */
if (sp->length == 0) {
/* no */
- if (stcb->asoc.idata_supported == 0)
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7308,8 +7285,6 @@ one_more_time:
}
sp->length = 0;
sp->some_taken = 1;
- if (stcb->asoc.idata_supported == 0)
- *locked = 1;
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7373,10 +7348,6 @@ re_look:
}
} else {
/* Nothing to take. */
- if ((sp->some_taken) &&
- (stcb->asoc.idata_supported == 0)) {
- *locked = 1;
- }
*giveup = 1;
to_move = 0;
goto out_of;
@@ -7686,7 +7657,6 @@ dont_do_it:
}
if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) {
/* All done pull and kill the message */
- atomic_subtract_int(&asoc->stream_queue_cnt, 1);
if (sp->put_last_out == 0) {
SCTP_PRINTF("Gak, put out entire msg with NO end!-2\n");
SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n",
@@ -7700,13 +7670,14 @@ dont_do_it:
SCTP_TCB_SEND_LOCK(stcb);
send_lock_up = 1;
}
+ atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&strq->outqueue, sp, next);
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up);
if ((strq->state == SCTP_STREAM_RESET_PENDING) &&
(strq->chunks_on_queues == 0) &&
TAILQ_EMPTY(&strq->outqueue)) {
stcb->asoc.trigger_reset = 1;
}
- stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp, send_lock_up);
if (sp->net) {
sctp_free_remote_addr(sp->net);
sp->net = NULL;
@@ -7716,14 +7687,6 @@ dont_do_it:
sp->data = NULL;
}
sctp_free_a_strmoq(stcb, sp, so_locked);
-
- /* we can't be locked to it */
- *locked = 0;
- stcb->asoc.locked_on_sending = NULL;
- } else {
- /* more to go, we are locked */
- if (stcb->asoc.idata_supported == 0)
- *locked = 1;
}
asoc->chunks_on_out_queue++;
strq->chunks_on_queues++;
@@ -7748,7 +7711,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb
struct sctp_association *asoc;
struct sctp_stream_out *strq;
int goal_mtu, moved_how_much, total_moved = 0, bail = 0;
- int locked, giveup;
+ int giveup;
SCTP_TCB_LOCK_ASSERT(stcb);
asoc = &stcb->asoc;
@@ -7777,36 +7740,20 @@ sctp_fill_outqueue(struct sctp_tcb *stcb
/* must make even word boundary */
goal_mtu &= 0xfffffffc;
- if (asoc->locked_on_sending) {
- /* We are stuck on one stream until the message completes. */
- strq = asoc->locked_on_sending;
- locked = 1;
- } else {
- strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
- locked = 0;
- }
+ strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
while ((goal_mtu > 0) && strq) {
giveup = 0;
bail = 0;
- moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point, &locked,
+ moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point,
&giveup, eeor_mode, &bail, so_locked);
- if (moved_how_much)
- stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved_how_much);
+ stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, moved_how_much);
- if (locked) {
- asoc->locked_on_sending = strq;
- if ((moved_how_much == 0) || (giveup) || bail)
- /* no more to move for now */
- break;
- } else {
- asoc->locked_on_sending = NULL;
- if ((giveup) || bail) {
- break;
- }
- strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
- if (strq == NULL) {
- break;
- }
+ if ((giveup) || bail) {
+ break;
+ }
+ strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
+ if (strq == NULL) {
+ break;
}
total_moved += moved_how_much;
goal_mtu -= (moved_how_much + sizeof(struct sctp_data_chunk));
@@ -7951,7 +7898,7 @@ sctp_med_chunk_output(struct sctp_inpcb
(asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) &&
TAILQ_EMPTY(&asoc->asconf_send_queue) &&
TAILQ_EMPTY(&asoc->send_queue) &&
- stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, so_locked) == 0) {
nothing_to_send:
*reason_code = 9;
return (0);
@@ -10227,15 +10174,14 @@ do_it_again:
un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
(stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
if ((un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) &&
- (stcb->asoc.total_flight > 0) &&
- ((stcb->asoc.locked_on_sending == NULL) ||
- sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {
+ (stcb->asoc.total_flight > 0)) {
+/* && sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/
break;
}
}
if (TAILQ_EMPTY(&asoc->control_send_queue) &&
TAILQ_EMPTY(&asoc->send_queue) &&
- stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc)) {
+ sctp_is_there_unsent_data(stcb, so_locked) == 0) {
/* Nothing left to send */
break;
}
@@ -10312,9 +10258,14 @@ void
send_forward_tsn(struct sctp_tcb *stcb,
struct sctp_association *asoc)
{
- struct sctp_tmit_chunk *chk;
+ struct sctp_tmit_chunk *chk, *at, *tp1, *last;
struct sctp_forward_tsn_chunk *fwdtsn;
+ struct sctp_strseq *strseq;
+ struct sctp_strseq_mid *strseq_m;
uint32_t advance_peer_ack_point;
+ unsigned int cnt_of_space, i, ovh;
+ unsigned int space_needed;
+ unsigned int cnt_of_skipped = 0;
int old;
if (asoc->idata_supported) {
@@ -10369,165 +10320,155 @@ sctp_fill_in_rest:
* stream/seq of the ones we skip.
*/
SCTP_BUF_LEN(chk->data) = 0;
- {
- struct sctp_tmit_chunk *at, *tp1, *last;
- struct sctp_strseq *strseq;
- struct sctp_strseq_mid *strseq_m;
- unsigned int cnt_of_space, i, ovh;
- unsigned int space_needed;
- unsigned int cnt_of_skipped = 0;
-
- TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
- if ((at->sent != SCTP_FORWARD_TSN_SKIP) &&
- (at->sent != SCTP_DATAGRAM_NR_ACKED)) {
- /* no more to look at */
- break;
- }
- if ((at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) && old) {
- /* We don't report these */
- continue;
- }
- cnt_of_skipped++;
+ TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
+ if ((at->sent != SCTP_FORWARD_TSN_SKIP) &&
+ (at->sent != SCTP_DATAGRAM_NR_ACKED)) {
+ /* no more to look at */
+ break;
}
- if (old) {
- space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
- (cnt_of_skipped * sizeof(struct sctp_strseq)));
- } else {
- space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
- (cnt_of_skipped * sizeof(struct sctp_strseq_mid)));
+ if (old && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
+ /* We don't report these */
+ continue;
}
- cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data);
+ cnt_of_skipped++;
+ }
+ if (old) {
+ space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
+ (cnt_of_skipped * sizeof(struct sctp_strseq)));
+ } else {
+ space_needed = (sizeof(struct sctp_forward_tsn_chunk) +
+ (cnt_of_skipped * sizeof(struct sctp_strseq_mid)));
+ }
+ cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data);
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MIN_OVERHEAD;
- } else {
- ovh = SCTP_MIN_V4_OVERHEAD;
- }
- if (cnt_of_space > (asoc->smallest_mtu - ovh)) {
- /* trim to a mtu size */
- cnt_of_space = asoc->smallest_mtu - ovh;
- }
+ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+ ovh = SCTP_MIN_OVERHEAD;
+ } else {
+ ovh = SCTP_MIN_V4_OVERHEAD;
+ }
+ if (cnt_of_space > (asoc->smallest_mtu - ovh)) {
+ /* trim to a mtu size */
+ cnt_of_space = asoc->smallest_mtu - ovh;
+ }
+ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
+ sctp_misc_ints(SCTP_FWD_TSN_CHECK,
+ 0xff, 0, cnt_of_skipped,
+ asoc->advanced_peer_ack_point);
+ }
+ advance_peer_ack_point = asoc->advanced_peer_ack_point;
+ if (cnt_of_space < space_needed) {
+ /*-
+ * ok we must trim down the chunk by lowering the
+ * advance peer ack point.
+ */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, 0, cnt_of_skipped,
- asoc->advanced_peer_ack_point);
-
+ 0xff, 0xff, cnt_of_space,
+ space_needed);
}
- advance_peer_ack_point = asoc->advanced_peer_ack_point;
- if (cnt_of_space < space_needed) {
- /*-
- * ok we must trim down the chunk by lowering the
- * advance peer ack point.
- */
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
- sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, 0xff, cnt_of_space,
- space_needed);
- }
- if (old) {
- cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
- cnt_of_skipped /= sizeof(struct sctp_strseq);
- } else {
- cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk);
- cnt_of_skipped /= sizeof(struct sctp_strseq_mid);
- }
- /*-
- * Go through and find the TSN that will be the one
- * we report.
- */
- at = TAILQ_FIRST(&asoc->sent_queue);
- if (at != NULL) {
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable-11
mailing list