summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/sctp_indata.c226
-rw-r--r--sys/netinet/sctp_input.c23
-rw-r--r--sys/netinet/sctp_output.c412
-rw-r--r--sys/netinet/sctp_pcb.c41
-rw-r--r--sys/netinet/sctp_ss_functions.c251
-rw-r--r--sys/netinet/sctp_structs.h27
-rw-r--r--sys/netinet/sctp_usrreq.c34
-rw-r--r--sys/netinet/sctputil.c32
8 files changed, 552 insertions, 494 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 357a047..e5ff349 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -64,7 +64,7 @@ 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 lock_held);
void
@@ -448,7 +448,7 @@ sctp_abort_in_reasm(struct sctp_tcb *stcb,
}
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 sctp_queued_to_read *nc, struct sctp_queu
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 sctp_tcb *stcb, struct sctp_association *a
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 sctp_tcb *stcb, struct sctp_association *a
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 *stcb, struct sctp_association *asoc, s
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 *stcb, struct sctp_association *asoc, s
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 *stcb, struct sctp_association *asoc, s
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_queued_to_read *control,
*/
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_tcb *stcb, struct sctp_association *asoc,
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_tcb *stcb, struct sctp_association *asoc,
}
}
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_tcb *stcb, struct sctp_association *asoc,
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_tcb *stcb, struct sctp_association *asoc,
}
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_tcb *stcb, struct sctp_association *asoc,
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_tcb *stcb, struct sctp_association *asoc,
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_tcb *stcb, struct sctp_association *asoc,
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_tcb *stcb, struct sctp_association *asoc,
}
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_tcb *stcb, struct sctp_association *asoc,
*/
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 sctp_tcb *stcb,
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 sctp_tcb *stcb,
}
}
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 sctp_tcb *stcb,
* 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 sctp_tcb *stcb,
}
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 sctp_tcb *stcb,
}
}
-
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 *stcb,
/*************************************************************/
/* 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 *stcb,
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)) {
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index c07019c..1525a0a 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -221,18 +221,18 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked
#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_tcb *stcb, int so_locked
}
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_tcb *stcb, int so_locked
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 *cp, struct sctp_tcb *stcb)
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_shutdown_ack_chunk *cp SCTP_UNUSED,
#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 sctp_shutdown_complete_chunk *cp SCTP_UNUSE
#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
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 1ad3d0c..621b25e 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -3657,7 +3657,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er
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 *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, 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 *inp, struct sctp_tcb *stcb, void *ptr,
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 *stcb,
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 *stcb,
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 *inp,
(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) {
- for (i = 0; i < cnt_of_skipped; i++) {
- tp1 = TAILQ_NEXT(at, sctp_next);
- if (tp1 == NULL) {
- break;
- }
- at = tp1;
+ 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) {
+ for (i = 0; i < cnt_of_skipped; i++) {
+ tp1 = TAILQ_NEXT(at, sctp_next);
+ if (tp1 == NULL) {
+ break;
}
- }
- if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
- sctp_misc_ints(SCTP_FWD_TSN_CHECK,
- 0xff, cnt_of_skipped, at->rec.data.TSN_seq,
- asoc->advanced_peer_ack_point);
- }
- last = at;
- /*-
- * last now points to last one I can report, update
- * peer ack point
- */
- if (last)
- advance_peer_ack_point = last->rec.data.TSN_seq;
- 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);
+ at = tp1;
}
}
- chk->send_size = space_needed;
- /* Setup the chunk */
- fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *);
- fwdtsn->ch.chunk_length = htons(chk->send_size);
- fwdtsn->ch.chunk_flags = 0;
- if (old) {
- fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN;
- } else {
- fwdtsn->ch.chunk_type = SCTP_IFORWARD_CUM_TSN;
+ if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
+ sctp_misc_ints(SCTP_FWD_TSN_CHECK,
+ 0xff, cnt_of_skipped, at->rec.data.TSN_seq,
+ asoc->advanced_peer_ack_point);
}
- fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point);
- SCTP_BUF_LEN(chk->data) = chk->send_size;
- fwdtsn++;
+ last = at;
/*-
- * Move pointer to after the fwdtsn and transfer to the
- * strseq pointer.
+ * last now points to last one I can report, update
+ * peer ack point
*/
+ if (last) {
+ advance_peer_ack_point = last->rec.data.TSN_seq;
+ }
if (old) {
- strseq = (struct sctp_strseq *)fwdtsn;
+ space_needed = sizeof(struct sctp_forward_tsn_chunk) +
+ cnt_of_skipped * sizeof(struct sctp_strseq);
} else {
- strseq_m = (struct sctp_strseq_mid *)fwdtsn;
+ space_needed = sizeof(struct sctp_forward_tsn_chunk) +
+ cnt_of_skipped * sizeof(struct sctp_strseq_mid);
}
- /*-
- * Now populate the strseq list. This is done blindly
- * without pulling out duplicate stream info. This is
- * inefficent but won't harm the process since the peer will
- * look at these in sequence and will thus release anything.
- * It could mean we exceed the PMTU and chop off some that
- * we could have included.. but this is unlikely (aka 1432/4
- * would mean 300+ stream seq's would have to be reported in
- * one FWD-TSN. With a bit of work we can later FIX this to
- * optimize and pull out duplcates.. but it does add more
- * overhead. So for now... not!
- */
- at = TAILQ_FIRST(&asoc->sent_queue);
- for (i = 0; i < cnt_of_skipped; i++) {
- tp1 = TAILQ_NEXT(at, sctp_next);
- if (tp1 == NULL)
- break;
- if (old && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
- /* We don't report these */
- i--;
- at = tp1;
- continue;
- }
- if (at->rec.data.TSN_seq == advance_peer_ack_point) {
- at->rec.data.fwd_tsn_cnt = 0;
- }
- if (old) {
- strseq->stream = ntohs(at->rec.data.stream_number);
- strseq->sequence = ntohs(at->rec.data.stream_seq);
- strseq++;
+ }
+ chk->send_size = space_needed;
+ /* Setup the chunk */
+ fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *);
+ fwdtsn->ch.chunk_length = htons(chk->send_size);
+ fwdtsn->ch.chunk_flags = 0;
+ if (old) {
+ fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN;
+ } else {
+ fwdtsn->ch.chunk_type = SCTP_IFORWARD_CUM_TSN;
+ }
+ fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point);
+ SCTP_BUF_LEN(chk->data) = chk->send_size;
+ fwdtsn++;
+ /*-
+ * Move pointer to after the fwdtsn and transfer to the
+ * strseq pointer.
+ */
+ if (old) {
+ strseq = (struct sctp_strseq *)fwdtsn;
+ } else {
+ strseq_m = (struct sctp_strseq_mid *)fwdtsn;
+ }
+ /*-
+ * Now populate the strseq list. This is done blindly
+ * without pulling out duplicate stream info. This is
+ * inefficent but won't harm the process since the peer will
+ * look at these in sequence and will thus release anything.
+ * It could mean we exceed the PMTU and chop off some that
+ * we could have included.. but this is unlikely (aka 1432/4
+ * would mean 300+ stream seq's would have to be reported in
+ * one FWD-TSN. With a bit of work we can later FIX this to
+ * optimize and pull out duplicates.. but it does add more
+ * overhead. So for now... not!
+ */
+ i = 0;
+ TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) {
+ if (i >= cnt_of_skipped) {
+ break;
+ }
+ if (old && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
+ /* We don't report these */
+ continue;
+ }
+ if (at->rec.data.TSN_seq == advance_peer_ack_point) {
+ at->rec.data.fwd_tsn_cnt = 0;
+ }
+ if (old) {
+ strseq->stream = htons(at->rec.data.stream_number);
+ strseq->sequence = htons((uint16_t) at->rec.data.stream_seq);
+ strseq++;
+ } else {
+ strseq_m->stream = htons(at->rec.data.stream_number);
+ if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) {
+ strseq_m->flags = htons(PR_SCTP_UNORDERED_FLAG);
} else {
- strseq_m->stream = ntohs(at->rec.data.stream_number);
- strseq_m->msg_id = ntohl(at->rec.data.stream_seq);
- if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)
- strseq_m->flags = ntohs(PR_SCTP_UNORDERED_FLAG);
- else
- strseq_m->flags = 0;
- strseq_m++;
+ strseq_m->flags = 0;
}
- at = tp1;
+ strseq_m->msg_id = htonl(at->rec.data.stream_seq);
+ strseq_m++;
}
+ i++;
}
return;
}
@@ -12262,19 +12203,18 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
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 +12234,7 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
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;
@@ -13506,19 +13446,16 @@ dataless_eof:
/* EOF thing ? */
if ((srcv->sinfo_flags & SCTP_EOF) &&
(got_all_of_the_send == 1)) {
- 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, SCTP_SO_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_LOCKED) == 0) {
+ 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 +13500,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) &&
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 36e4c01..90e564f 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -3444,7 +3444,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
} 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, int immediate, int from)
}
} 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) &&
@@ -4989,7 +4978,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
outs = &asoc->strmout[i];
/* now clean up any chunks here */
TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
+ atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&outs->outqueue, sp, next);
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 0);
sctp_free_spbufspace(stcb, asoc, sp);
if (sp->data) {
if (so) {
@@ -6874,6 +6865,12 @@ 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 (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
/* Yep it is above cum-ack */
cnt++;
@@ -6881,7 +6878,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 +6907,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 +6920,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;
diff --git a/sys/netinet/sctp_ss_functions.c b/sys/netinet/sctp_ss_functions.c
index c4cbb05..672da91 100644
--- a/sys/netinet/sctp_ss_functions.c
+++ b/sys/netinet/sctp_ss_functions.c
@@ -52,7 +52,9 @@ sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
{
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 *stcb, struct sctp_association *asoc,
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 *stcb, struct sctp_association *asoc,
}
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 *stcb, struct sctp_association *asoc,
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 *stcb, struct sctp_association *asoc,
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 *stcb, struct sctp_association *asoc,
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 *stcb SCTP_UNUSED, struct sctp_nets *net,
{
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);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
@@ -196,7 +209,7 @@ default_again:
if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) {
- if (strq == asoc->last_out_stream) {
+ if (strq == asoc->ss_data.last_out_stream) {
return (NULL);
} else {
strqt = strq;
@@ -208,11 +221,25 @@ default_again:
}
static void
-sctp_ss_default_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
- struct sctp_association *asoc SCTP_UNUSED,
- struct sctp_stream_out *strq, int moved_how_much SCTP_UNUSED)
+sctp_ss_default_scheduled(struct sctp_tcb *stcb,
+ struct sctp_nets *net SCTP_UNUSED,
+ struct sctp_association *asoc,
+ struct sctp_stream_out *strq,
+ int moved_how_much SCTP_UNUSED)
{
- asoc->last_out_stream = strq;
+ struct sctp_stream_queue_pending *sp;
+
+ asoc->ss_data.last_out_stream = strq;
+ if (stcb->asoc.idata_supported == 0) {
+ sp = TAILQ_FIRST(&strq->outqueue);
+ if ((sp != NULL) && (sp->some_taken == 1)) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ } else {
+ stcb->asoc.ss_data.locked_on_sending = NULL;
+ }
+ } else {
+ stcb->asoc.ss_data.locked_on_sending = NULL;
+ }
return;
}
@@ -240,6 +267,12 @@ sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_associa
return (-1);
}
+static int
+sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED)
+{
+ return (0);
+}
+
/*
* Real round-robin algorithm.
* Always interates the streams in ascending order.
@@ -257,17 +290,17 @@ sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (!TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
(strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
- if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
- TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
+ if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+ TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
} else {
- strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
while (strqt != NULL && (strqt->stream_no < strq->stream_no)) {
strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
}
if (strqt != NULL) {
TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
} else {
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
}
}
}
@@ -286,7 +319,7 @@ static struct sctp_stream_out *
sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
struct sctp_association *asoc)
{
- return (asoc->last_out_stream);
+ return (asoc->ss_data.last_out_stream);
}
static void
@@ -295,15 +328,15 @@ sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net
{
struct sctp_stream_out *strq, *strqt;
- strqt = asoc->last_out_stream;
+ strqt = asoc->ss_data.last_out_stream;
rrp_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);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
@@ -321,7 +354,7 @@ rrp_again:
if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) {
- if (strq == asoc->last_out_stream) {
+ if (strq == asoc->ss_data.last_out_stream) {
strq = NULL;
} else {
strqt = strq;
@@ -329,7 +362,7 @@ rrp_again:
}
}
}
- asoc->last_out_stream = strq;
+ asoc->ss_data.last_out_stream = strq;
return;
}
@@ -345,18 +378,18 @@ sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
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);
if (clear_values) {
strq->ss_params.prio.priority = 0;
}
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.prio.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.prio.next_spoke);
strq->ss_params.prio.next_spoke.tqe_next = NULL;
strq->ss_params.prio.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);
}
@@ -364,8 +397,16 @@ sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
static void
-sctp_ss_prio_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
+sctp_ss_prio_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.prio.next_spoke.tqe_next = NULL;
strq->ss_params.prio.next_spoke.tqe_prev = NULL;
if (with_strq != NULL) {
@@ -390,17 +431,17 @@ sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (!TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
(strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
- if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
- TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke);
+ if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+ TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
} else {
- strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
}
if (strqt != NULL) {
TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
} else {
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke);
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
}
}
}
@@ -425,18 +466,18 @@ sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.prio.next_spoke.tqe_next != NULL ||
strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead,
+ 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.prio.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.prio.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
strq->ss_params.prio.next_spoke.tqe_next = NULL;
strq->ss_params.prio.next_spoke.tqe_prev = NULL;
}
@@ -452,18 +493,18 @@ sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
{
struct sctp_stream_out *strq, *strqt, *strqn;
- strqt = asoc->last_out_stream;
+ strqt = asoc->ss_data.last_out_stream;
prio_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 {
strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
if (strqn != NULL &&
strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
strq = strqn;
} else {
- strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
}
@@ -481,7 +522,7 @@ prio_again:
if (TAILQ_FIRST(&strq->outqueue) &&
TAILQ_FIRST(&strq->outqueue)->net != NULL &&
TAILQ_FIRST(&strq->outqueue)->net != net) {
- if (strq == asoc->last_out_stream) {
+ if (strq == asoc->ss_data.last_out_stream) {
return (NULL);
} else {
strqt = strq;
@@ -527,17 +568,17 @@ sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
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);
if (clear_values) {
strq->ss_params.fb.rounds = -1;
}
- TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.fb.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.fb.next_spoke);
strq->ss_params.fb.next_spoke.tqe_next = NULL;
strq->ss_params.fb.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);
}
@@ -545,8 +586,16 @@ sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
static void
-sctp_ss_fb_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
+sctp_ss_fb_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.fb.next_spoke.tqe_next = NULL;
strq->ss_params.fb.next_spoke.tqe_prev = NULL;
if (with_strq != NULL) {
@@ -570,7 +619,7 @@ sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
(strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
if (strq->ss_params.fb.rounds < 0)
strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke);
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
}
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -593,18 +642,18 @@ sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (TAILQ_EMPTY(&strq->outqueue) &&
(strq->ss_params.fb.next_spoke.tqe_next != NULL ||
strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
- if (asoc->last_out_stream == strq) {
- asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead,
+ 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.fb.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.fb.next_spoke);
+ TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
strq->ss_params.fb.next_spoke.tqe_next = NULL;
strq->ss_params.fb.next_spoke.tqe_prev = NULL;
}
@@ -620,11 +669,11 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
{
struct sctp_stream_out *strq = NULL, *strqt;
- if (asoc->last_out_stream == NULL ||
- TAILQ_FIRST(&asoc->ss_data.out_wheel) == TAILQ_LAST(&asoc->ss_data.out_wheel, sctpwheel_listhead)) {
- strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ if (asoc->ss_data.last_out_stream == NULL ||
+ TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
+ strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
} else {
- strqt = TAILQ_NEXT(asoc->last_out_stream, ss_params.fb.next_spoke);
+ strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
}
do {
if ((strqt != NULL) &&
@@ -641,22 +690,33 @@ sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
if (strqt != NULL) {
strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
} else {
- strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+ strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
}
} while (strqt != strq);
return (strq);
}
static void
-sctp_ss_fb_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
+sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
struct sctp_association *asoc, struct sctp_stream_out *strq,
int moved_how_much SCTP_UNUSED)
{
+ struct sctp_stream_queue_pending *sp;
struct sctp_stream_out *strqt;
int subtract;
+ if (stcb->asoc.idata_supported == 0) {
+ sp = TAILQ_FIRST(&strq->outqueue);
+ if ((sp != NULL) && (sp->some_taken == 1)) {
+ stcb->asoc.ss_data.locked_on_sending = strq;
+ } else {
+ stcb->asoc.ss_data.locked_on_sending = NULL;
+ }
+ } else {
+ stcb->asoc.ss_data.locked_on_sending = NULL;
+ }
subtract = strq->ss_params.fb.rounds;
- TAILQ_FOREACH(strqt, &asoc->ss_data.out_wheel, ss_params.fb.next_spoke) {
+ TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
strqt->ss_params.fb.rounds -= subtract;
if (strqt->ss_params.fb.rounds < 0)
strqt->ss_params.fb.rounds = 0;
@@ -666,7 +726,7 @@ sctp_ss_fb_scheduled(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SC
} else {
strq->ss_params.fb.rounds = -1;
}
- asoc->last_out_stream = strq;
+ asoc->ss_data.last_out_stream = strq;
return;
}
@@ -687,7 +747,7 @@ sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_stream_queue_pending *sp;
uint16_t i;
- TAILQ_INIT(&asoc->ss_data.out_list);
+ TAILQ_INIT(&asoc->ss_data.out.list);
/*
* If there is data in the stream queues already, the scheduler of
* an existing association has been changed. We can only cycle
@@ -721,8 +781,8 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (holds_lock == 0) {
SCTP_TCB_SEND_LOCK(stcb);
}
- while (!TAILQ_EMPTY(&asoc->ss_data.out_list)) {
- TAILQ_REMOVE(&asoc->ss_data.out_list, TAILQ_FIRST(&asoc->ss_data.out_list), ss_next);
+ while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
+ TAILQ_REMOVE(&asoc->ss_data.out.list, TAILQ_FIRST(&asoc->ss_data.out.list), ss_next);
}
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -732,9 +792,16 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
static void
-sctp_ss_fcfs_init_stream(struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_out *with_strq SCTP_UNUSED)
+sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
{
- /* Nothing to be done here */
+ 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;
+ }
+ }
return;
}
@@ -748,7 +815,7 @@ sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
if (sp && (sp->ss_next.tqe_next == NULL) &&
(sp->ss_next.tqe_prev == NULL)) {
- TAILQ_INSERT_TAIL(&asoc->ss_data.out_list, sp, ss_next);
+ TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
}
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -759,7 +826,7 @@ sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
static int
sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
{
- if (TAILQ_EMPTY(&asoc->ss_data.out_list)) {
+ if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
return (1);
} else {
return (0);
@@ -777,7 +844,7 @@ sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (sp &&
((sp->ss_next.tqe_next != NULL) ||
(sp->ss_next.tqe_prev != NULL))) {
- TAILQ_REMOVE(&asoc->ss_data.out_list, sp, ss_next);
+ TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
}
if (holds_lock == 0) {
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -793,7 +860,7 @@ sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
struct sctp_stream_out *strq;
struct sctp_stream_queue_pending *sp;
- sp = TAILQ_FIRST(&asoc->ss_data.out_list);
+ sp = TAILQ_FIRST(&asoc->ss_data.out.list);
default_again:
if (sp != NULL) {
strq = &asoc->strmout[sp->stream];
@@ -835,7 +902,8 @@ const struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
},
/* SCTP_SS_ROUND_ROBIN */
{
@@ -849,7 +917,8 @@ const struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
},
/* SCTP_SS_ROUND_ROBIN_PACKET */
{
@@ -863,7 +932,8 @@ const struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_rrp_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
},
/* SCTP_SS_PRIORITY */
{
@@ -877,7 +947,8 @@ const struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_prio_get_value,
- .sctp_ss_set_value = sctp_ss_prio_set_value
+ .sctp_ss_set_value = sctp_ss_prio_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
},
/* SCTP_SS_FAIR_BANDWITH */
{
@@ -891,7 +962,8 @@ const struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_fb_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
},
/* SCTP_SS_FIRST_COME */
{
@@ -905,6 +977,7 @@ const struct sctp_ss_functions sctp_ss_functions[] = {
.sctp_ss_scheduled = sctp_ss_default_scheduled,
.sctp_ss_packet_done = sctp_ss_default_packet_done,
.sctp_ss_get_value = sctp_ss_default_get_value,
- .sctp_ss_set_value = sctp_ss_default_set_value
+ .sctp_ss_set_value = sctp_ss_default_set_value,
+ .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
}
};
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index ad9d978..280100b 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -555,6 +555,7 @@ struct sctp_stream_in {
TAILQ_HEAD(sctpwheel_listhead, sctp_stream_out);
TAILQ_HEAD(sctplist_listhead, sctp_stream_queue_pending);
+
/* Round-robin schedulers */
struct ss_rr {
/* next link in wheel */
@@ -581,9 +582,14 @@ struct ss_fb {
* This union holds all data necessary for
* different stream schedulers.
*/
-union scheduling_data {
- struct sctpwheel_listhead out_wheel;
- struct sctplist_listhead out_list;
+struct scheduling_data {
+ struct sctp_stream_out *locked_on_sending;
+ /* circular looking for output selection */
+ struct sctp_stream_out *last_out_stream;
+ union {
+ struct sctpwheel_listhead wheel;
+ struct sctplist_listhead list;
+ } out;
};
/*
@@ -735,7 +741,7 @@ struct sctp_ss_functions {
int holds_lock);
void (*sctp_ss_clear) (struct sctp_tcb *stcb, struct sctp_association *asoc,
int clear_values, int holds_lock);
- void (*sctp_ss_init_stream) (struct sctp_stream_out *strq, struct sctp_stream_out *with_strq);
+ void (*sctp_ss_init_stream) (struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq);
void (*sctp_ss_add_to_stream) (struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, int holds_lock);
int (*sctp_ss_is_empty) (struct sctp_tcb *stcb, struct sctp_association *asoc);
@@ -751,6 +757,7 @@ struct sctp_ss_functions {
struct sctp_stream_out *strq, uint16_t * value);
int (*sctp_ss_set_value) (struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_stream_out *strq, uint16_t value);
+ int (*sctp_ss_is_user_msgs_incomplete) (struct sctp_tcb *stcb, struct sctp_association *asoc);
};
/* used to save ASCONF chunks for retransmission */
@@ -831,15 +838,7 @@ struct sctp_association {
struct sctpchunk_listhead send_queue;
/* Scheduling queues */
- union scheduling_data ss_data;
-
- /*
- * This pointer will be set to NULL most of the time. But when we
- * have a fragmented message, where we could not get out all of the
- * message at the last send then this will point to the stream to go
- * get data from.
- */
- struct sctp_stream_out *locked_on_sending;
+ struct scheduling_data ss_data;
/* If an iterator is looking at me, this is it */
struct sctp_iterator *stcb_starting_point_for_iterator;
@@ -872,8 +871,6 @@ struct sctp_association {
/* last place I got a control from */
struct sctp_nets *last_control_chunk_from;
- /* circular looking for output selection */
- struct sctp_stream_out *last_out_stream;
/*
* wait to the point the cum-ack passes req->send_reset_at_tsn for
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 274702b..fc2b9bb 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -95,6 +95,7 @@ sctp_finish(void *unused __unused)
{
sctp_pcb_finish();
}
+
VNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL);
#endif
@@ -727,7 +728,7 @@ sctp_disconnect(struct socket *so)
TAILQ_EMPTY(&asoc->sent_queue) &&
(asoc->stream_queue_cnt == 0)) {
/* there is nothing queued to send, so done */
- if (asoc->locked_on_sending) {
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
goto abort_anyway;
}
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
@@ -776,18 +777,8 @@ sctp_disconnect(struct socket *so)
asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
netp);
- 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 == NULL) {
- SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
- asoc->locked_on_sending->stream_no);
- } else {
- 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;
}
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
@@ -951,7 +942,7 @@ sctp_shutdown(struct socket *so)
TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
(asoc->stream_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... */
@@ -968,19 +959,8 @@ sctp_shutdown(struct socket *so)
* SHUTDOWN_PENDING.
*/
SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
- 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 == NULL) {
- SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
- asoc->locked_on_sending->stream_no);
- } else {
- if ((sp->length == 0) && (sp->msg_is_complete == 0)) {
- SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT);
- }
- }
+ if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
+ SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT);
}
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 15c2dd1..148b047 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1077,7 +1077,6 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->minrto = inp->sctp_ep.sctp_minrto;
asoc->maxrto = inp->sctp_ep.sctp_maxrto;
- asoc->locked_on_sending = NULL;
asoc->stream_locked_on = 0;
asoc->ecn_echo_cnt_onq = 0;
asoc->stream_locked = 0;
@@ -1139,7 +1138,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->strmout[i].stream_no = i;
asoc->strmout[i].last_msg_incomplete = 0;
asoc->strmout[i].state = SCTP_STREAM_OPENING;
- asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL);
+ asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL);
}
asoc->ss_functions.sctp_ss_init(stcb, asoc, 0);
@@ -3907,10 +3906,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock,
/* For each stream */
outs = &asoc->strmout[i];
/* clean up any sends there */
- asoc->locked_on_sending = NULL;
TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) {
- asoc->stream_queue_cnt--;
+ atomic_subtract_int(&asoc->stream_queue_cnt, 1);
TAILQ_REMOVE(&outs->outqueue, sp, next);
+ stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, holds_lock);
sctp_free_spbufspace(stcb, asoc, sp);
if (sp->data) {
sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
@@ -4878,6 +4877,9 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
stcb->asoc.pr_sctp_cnt++;
}
chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
+ if (sp->sinfo_flags & SCTP_UNORDERED) {
+ chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED;
+ }
if (stcb->asoc.idata_supported == 0) {
if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) {
strq->next_mid_ordered++;
@@ -5495,20 +5497,16 @@ restart_nosblocks:
}
/* Clear the held length since there is something to read */
control->held_length = 0;
- if (hold_rlock) {
- SCTP_INP_READ_UNLOCK(inp);
- hold_rlock = 0;
- }
found_one:
/*
* If we reach here, control has a some data for us to read off.
* Note that stcb COULD be NULL.
*/
- control->some_taken++;
- if (hold_sblock) {
- SOCKBUF_UNLOCK(&so->so_rcv);
- hold_sblock = 0;
+ if (hold_rlock == 0) {
+ hold_rlock = 1;
+ SCTP_INP_READ_LOCK(inp);
}
+ control->some_taken++;
stcb = control->stcb;
if (stcb) {
if ((control->do_not_ref_stcb == 0) &&
@@ -5682,6 +5680,14 @@ found_one:
}
#endif
}
+ if (hold_rlock) {
+ SCTP_INP_READ_UNLOCK(inp);
+ hold_rlock = 0;
+ }
+ if (hold_sblock) {
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ hold_sblock = 0;
+ }
/* now copy out what data we can */
if (mp == NULL) {
/* copy out each mbuf in the chain up to length */
@@ -6097,9 +6103,9 @@ out:
goto stage_left;
#endif
}
- atomic_add_int(&stcb->asoc.refcnt, -1);
/* Save the value back for next time */
stcb->freed_by_sorcv_sincelast = freed_so_far;
+ atomic_add_int(&stcb->asoc.refcnt, -1);
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) {
if (stcb) {
OpenPOWER on IntegriCloud