svn commit: r303792 - head/sys/netinet
Michael Tuexen
tuexen at FreeBSD.org
Sat Aug 6 12:33:17 UTC 2016
Author: tuexen
Date: Sat Aug 6 12:33:15 2016
New Revision: 303792
URL: https://svnweb.freebsd.org/changeset/base/303792
Log:
Fix various bugs in relation to the I-DATA chunk support
This is joint work with rrs.
MFC after: 3 days
Modified:
head/sys/netinet/sctp_indata.c
head/sys/netinet/sctp_output.c
head/sys/netinet/sctp_pcb.c
head/sys/netinet/sctp_ss_functions.c
head/sys/netinet/sctp_structs.h
head/sys/netinet/sctp_usrreq.c
head/sys/netinet/sctputil.c
Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c Sat Aug 6 11:02:07 2016 (r303791)
+++ head/sys/netinet/sctp_indata.c Sat Aug 6 12:33:15 2016 (r303792)
@@ -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: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c Sat Aug 6 11:02:07 2016 (r303791)
+++ head/sys/netinet/sctp_output.c Sat Aug 6 12:33:15 2016 (r303792)
@@ -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;
@@ -6694,7 +6694,7 @@ sctp_sendall_iterator(struct sctp_inpcb
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(cnt == 0)) {
- if (asoc->locked_on_sending) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
goto abort_anyway;
}
/*
@@ -6736,18 +6736,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 +7160,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 +7185,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;
@@ -7261,8 +7248,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 +7259,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 +7267,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 +7289,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 +7352,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;
@@ -7716,14 +7691,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 +7715,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 +7744,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));
@@ -10227,9 +10178,8 @@ 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;
}
}
@@ -12262,19 +12212,18 @@ sctp_send_str_reset_req(struct sctp_tcb
stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.strmout[i].state = oldstream[i].state;
- stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
+ /* FIX ME FIX ME */
+ /*
+ * This should be a SS_COPY operation FIX ME STREAM
+ * SCHEDULER EXPERT
+ */
+ stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], &oldstream[i]);
/* now anything on those queues? */
TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) {
TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
}
- /* Now move assoc pointers too */
- if (stcb->asoc.last_out_stream == &oldstream[i]) {
- stcb->asoc.last_out_stream = &stcb->asoc.strmout[i];
- }
- if (stcb->asoc.locked_on_sending == &oldstream[i]) {
- stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i];
- }
+
}
/* now the new streams */
stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
@@ -12294,7 +12243,7 @@ sctp_send_str_reset_req(struct sctp_tcb
stcb->asoc.strmout[i].next_mid_unordered = 0;
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
- 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);
stcb->asoc.strmout[i].state = SCTP_STREAM_CLOSED;
}
stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o;
@@ -13518,7 +13467,7 @@ dataless_eof:
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(cnt == 0)) {
- if (asoc->locked_on_sending) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
goto abort_anyway;
}
/* there is nothing queued to send, so I'm done... */
@@ -13563,15 +13512,8 @@ dataless_eof:
SCTP_TCB_LOCK(stcb);
hold_tcblock = 1;
}
- 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) &&
Modified: head/sys/netinet/sctp_pcb.c
==============================================================================
--- head/sys/netinet/sctp_pcb.c Sat Aug 6 11:02:07 2016 (r303791)
+++ head/sys/netinet/sctp_pcb.c Sat Aug 6 12:33:15 2016 (r303792)
@@ -3444,7 +3444,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp,
} else if (TAILQ_EMPTY(&asoc->asoc.send_queue) &&
TAILQ_EMPTY(&asoc->asoc.sent_queue) &&
(asoc->asoc.stream_queue_cnt == 0)) {
- if (asoc->asoc.locked_on_sending) {
+ if ((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete) (asoc, &asoc->asoc)) {
goto abort_anyway;
}
if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
@@ -3476,22 +3476,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp,
}
} else {
/* mark into shutdown pending */
- struct sctp_stream_queue_pending *sp;
-
asoc->asoc.state |= SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
asoc->asoc.primary_destination);
- if (asoc->asoc.locked_on_sending) {
- sp = TAILQ_LAST(&((asoc->asoc.locked_on_sending)->outqueue),
- sctp_streamhead);
- if (sp == NULL) {
- SCTP_PRINTF("Error, sp is NULL, locked on sending is %p strm:%d\n",
- (void *)asoc->asoc.locked_on_sending,
- asoc->asoc.locked_on_sending->stream_no);
- } else {
- if ((sp->length == 0) && (sp->msg_is_complete == 0))
- asoc->asoc.state |= SCTP_STATE_PARTIAL_MSG_LEFT;
- }
+ if ((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete) (asoc, &asoc->asoc)) {
+ asoc->asoc.state |= SCTP_STATE_PARTIAL_MSG_LEFT;
}
if (TAILQ_EMPTY(&asoc->asoc.send_queue) &&
TAILQ_EMPTY(&asoc->asoc.sent_queue) &&
@@ -6874,6 +6863,15 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
/* Ok that was fun, now we will drain all the inbound streams? */
for (strmat = 0; strmat < asoc->streamincnt; strmat++) {
TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, next_instrm, nctl) {
+#ifdef INVARIANTS
+ if (ctl->on_strm_q != SCTP_ON_ORDERED) {
+ panic("Huh control: %p on_q: %d -- not ordered?",
+ ctl, ctl->on_strm_q);
+ }
+#endif
+ if (ctl->on_read_q) {
+ continue;
+ }
if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
@@ -6881,7 +6879,12 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
+ if (ctl->on_read_q) {
+ TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next);
+ ctl->on_read_q = 0;
+ }
TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, ctl, next_instrm);
+ ctl->on_strm_q = 0;
if (ctl->data) {
sctp_m_freem(ctl->data);
ctl->data = NULL;
@@ -6905,6 +6908,12 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
}
}
TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].uno_inqueue, next_instrm, nctl) {
+#ifdef INVARIANTS
+ if (ctl->on_strm_q != SCTP_ON_UNORDERED) {
+ panic("Huh control: %p on_q: %d -- not unordered?",
+ ctl, ctl->on_strm_q);
+ }
+#endif
if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
@@ -6912,7 +6921,12 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
asoc->size_on_all_streams = sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
sctp_ucount_decr(asoc->cnt_on_all_streams);
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
+ if (ctl->on_read_q) {
+ TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next);
+ ctl->on_read_q = 0;
+ }
TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, ctl, next_instrm);
+ ctl->on_strm_q = 0;
if (ctl->data) {
sctp_m_freem(ctl->data);
ctl->data = NULL;
Modified: head/sys/netinet/sctp_ss_functions.c
==============================================================================
--- head/sys/netinet/sctp_ss_functions.c Sat Aug 6 11:02:07 2016 (r303791)
+++ head/sys/netinet/sctp_ss_functions.c Sat Aug 6 12:33:15 2016 (r303792)
@@ -52,7 +52,9 @@ sctp_ss_default_init(struct sctp_tcb *st
{
uint16_t i;
- TAILQ_INIT(&asoc->ss_data.out_wheel);
+ asoc->ss_data.locked_on_sending = NULL;
+ asoc->ss_data.last_out_stream = NULL;
+ TAILQ_INIT(&asoc->ss_data.out.wheel);
/*
* If there is data in the stream queues already, the scheduler of
* an existing association has been changed. We need to add all
@@ -73,14 +75,14 @@ sctp_ss_default_clear(struct sctp_tcb *s
if (holds_lock == 0) {
SCTP_TCB_SEND_LOCK(stcb);
}
- while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
- struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+ struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.rr.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.rr.next_spoke);
strq->ss_params.rr.next_spoke.tqe_next = NULL;
strq->ss_params.rr.next_spoke.tqe_prev = NULL;
}
- asoc->last_out_stream = NULL;
+ asoc->ss_data.last_out_stream = NULL;
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
}
@@ -88,8 +90,16 @@ sctp_ss_default_clear(struct sctp_tcb *s
}
static void
-sctp_ss_default_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq SCTP_UNUSED)
+sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
{
+ if (with_strq != NULL) {
+ if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ }
+ if (stcb->asoc.ss_data.last_out_stream == with_strq) {
+ stcb->asoc.ss_data.last_out_stream = strq;
+ }
+ }
strq->ss_params.rr.next_spoke.tqe_next = NULL;
strq->ss_params.rr.next_spoke.tqe_prev = NULL;
return;
@@ -107,7 +117,7 @@ sctp_ss_default_add(struct sctp_tcb *stc
if (!TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
(strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel,
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
strq, ss_params.rr.next_spoke);
}
if (holds_lock == 0) {
@@ -119,7 +129,7 @@ sctp_ss_default_add(struct sctp_tcb *stc
static int
sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
{
- if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
+ if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
return (1);
} else {
return (0);
@@ -141,19 +151,19 @@ sctp_ss_default_remove(struct sctp_tcb *
if (TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.rr.next_spoke.tqe_next != NULL ||
strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream,
+ if (asoc->ss_data.last_out_stream == strq) {
+ asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
sctpwheel_listhead,
ss_params.rr.next_spoke);
- if (asoc->last_out_stream == NULL) {
- asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel,
+ if (asoc->ss_data.last_out_stream == NULL) {
+ asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
sctpwheel_listhead);
}
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = NULL;
+ if (asoc->ss_data.last_out_stream == strq) {
+ asoc->ss_data.last_out_stream = NULL;
}
}
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
strq->ss_params.rr.next_spoke.tqe_next = NULL;
strq->ss_params.rr.next_spoke.tqe_prev = NULL;
}
@@ -170,15 +180,18 @@ sctp_ss_default_select(struct sctp_tcb *
{
struct sctp_stream_out *strq, *strqt;
- strqt = asoc->last_out_stream;
+ if (asoc->ss_data.locked_on_sending) {
+ return (asoc->ss_data.locked_on_sending);
+ }
+ strqt = asoc->ss_data.last_out_stream;
default_again:
/* Find the next stream to use */
if (strqt == NULL) {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
if (strq == NULL) {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list