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:
parent
e3997b40b9
commit
1f7e02ab3c
@ -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)) {
|
||||
|
@ -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) &&
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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) &&
|
||||
|
@ -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++;
|
||||
|
Loading…
Reference in New Issue
Block a user