Fix various bugs in relation to the I-DATA chunk support

This is joint work with rrs.

MFC after:	3 days
This commit is contained in:
tuexen 2016-08-06 12:33:15 +00:00
parent e3997b40b9
commit 1f7e02ab3c
7 changed files with 377 additions and 320 deletions

View File

@ -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 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb,
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 @@ sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struc
}
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 @@ sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struc
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 @@ sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struc
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 @@ sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struc
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 @@ sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struc
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 @@ sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struc
}
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 @@ sctp_inject_old_data_unordered(struct sctp_tcb *stcb, struct sctp_association *a
}
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 @@ 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);
}
control = nctl;
}
@ -1160,7 +1192,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);
}
strm->last_sequence_delivered = next_to_del;
if (done) {
@ -1177,11 +1209,12 @@ sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc, s
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 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
* 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 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
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 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
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)) {

View File

@ -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;
@ -6694,7 +6694,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
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 *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 +7160,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 +7185,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;
@ -7261,8 +7248,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
}
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 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
* 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 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
/* 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 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
}
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 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
}
} 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 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb,
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 @@ sctp_chunk_output(struct sctp_inpcb *inp,
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,
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,
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 @@ sctp_lower_sosend(struct socket *so,
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 @@ sctp_lower_sosend(struct socket *so,
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) &&

View File

@ -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) &&
@ -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;

View File

@ -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 @@ sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
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,23 @@ sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
}
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)
{
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 +265,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 +288,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 +317,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 +326,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 +352,7 @@ sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net
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 +360,7 @@ sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net
}
}
}
asoc->last_out_stream = strq;
asoc->ss_data.last_out_stream = strq;
return;
}
@ -345,18 +376,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 +395,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 +429,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 +464,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 +491,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 +520,7 @@ sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
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 +566,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 +584,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 +617,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 +640,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 +667,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 +688,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 +724,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 +745,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 +779,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 +790,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 +813,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 +824,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 +842,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 +858,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 +900,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 +915,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 +930,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 +945,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 +960,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 +975,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
}
};

View File

@ -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

View File

@ -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) &&

View File

@ -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,7 +3906,6 @@ 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--;
TAILQ_REMOVE(&outs->outqueue, sp, next);
@ -4878,6 +4876,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++;