From 1f7e02ab3c6330ae79c89318fc97ac21fd261cdf Mon Sep 17 00:00:00 2001 From: tuexen Date: Sat, 6 Aug 2016 12:33:15 +0000 Subject: [PATCH] Fix various bugs in relation to the I-DATA chunk support This is joint work with rrs. MFC after: 3 days --- sys/netinet/sctp_indata.c | 226 ++++++++++++++++++----------- sys/netinet/sctp_output.c | 112 ++++---------- sys/netinet/sctp_pcb.c | 42 ++++-- sys/netinet/sctp_ss_functions.c | 249 ++++++++++++++++++++------------ sys/netinet/sctp_structs.h | 27 ++-- sys/netinet/sctp_usrreq.c | 34 +---- sys/netinet/sctputil.c | 7 +- 7 files changed, 377 insertions(+), 320 deletions(-) diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 357a047ab952..e5ff349e7322 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -64,7 +64,7 @@ sctp_add_chk_to_control(struct sctp_queued_to_read *control, struct sctp_stream_in *strm, struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_tmit_chunk *chk); + struct sctp_tmit_chunk *chk, int lock_held); void @@ -448,7 +448,7 @@ sctp_abort_in_reasm(struct sctp_tcb *stcb, } static void -clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control) +sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control) { /* * The control could not be placed and must be cleaned. @@ -612,7 +612,7 @@ 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)) { diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 1ad3d0cf4386..dd14e8ac42fa 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3657,7 +3657,7 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er stcb->asoc.strmout[i].stream_no = i; stcb->asoc.strmout[i].last_msg_incomplete = 0; stcb->asoc.strmout[i].state = SCTP_STREAM_OPENING; - stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL); + stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); } } break; @@ -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) && diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 36e4c012a6f2..7351c0feaf09 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -3444,7 +3444,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) } else if (TAILQ_EMPTY(&asoc->asoc.send_queue) && TAILQ_EMPTY(&asoc->asoc.sent_queue) && (asoc->asoc.stream_queue_cnt == 0)) { - if (asoc->asoc.locked_on_sending) { + if ((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete) (asoc, &asoc->asoc)) { goto abort_anyway; } if ((SCTP_GET_STATE(&asoc->asoc) != SCTP_STATE_SHUTDOWN_SENT) && @@ -3476,22 +3476,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) } } else { /* mark into shutdown pending */ - struct sctp_stream_queue_pending *sp; - asoc->asoc.state |= SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc, asoc->asoc.primary_destination); - if (asoc->asoc.locked_on_sending) { - sp = TAILQ_LAST(&((asoc->asoc.locked_on_sending)->outqueue), - sctp_streamhead); - if (sp == NULL) { - SCTP_PRINTF("Error, sp is NULL, locked on sending is %p strm:%d\n", - (void *)asoc->asoc.locked_on_sending, - asoc->asoc.locked_on_sending->stream_no); - } else { - if ((sp->length == 0) && (sp->msg_is_complete == 0)) - asoc->asoc.state |= SCTP_STATE_PARTIAL_MSG_LEFT; - } + if ((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete) (asoc, &asoc->asoc)) { + asoc->asoc.state |= SCTP_STATE_PARTIAL_MSG_LEFT; } if (TAILQ_EMPTY(&asoc->asoc.send_queue) && TAILQ_EMPTY(&asoc->asoc.sent_queue) && @@ -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; diff --git a/sys/netinet/sctp_ss_functions.c b/sys/netinet/sctp_ss_functions.c index c4cbb05ee482..abac82aeba4b 100644 --- a/sys/netinet/sctp_ss_functions.c +++ b/sys/netinet/sctp_ss_functions.c @@ -52,7 +52,9 @@ sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc, { uint16_t i; - TAILQ_INIT(&asoc->ss_data.out_wheel); + asoc->ss_data.locked_on_sending = NULL; + asoc->ss_data.last_out_stream = NULL; + TAILQ_INIT(&asoc->ss_data.out.wheel); /* * If there is data in the stream queues already, the scheduler of * an existing association has been changed. We need to add all @@ -73,14 +75,14 @@ sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { - struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { + struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); - TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.rr.next_spoke); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.rr.next_spoke); strq->ss_params.rr.next_spoke.tqe_next = NULL; strq->ss_params.rr.next_spoke.tqe_prev = NULL; } - asoc->last_out_stream = NULL; + asoc->ss_data.last_out_stream = NULL; if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); } @@ -88,8 +90,16 @@ sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, } static void -sctp_ss_default_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq SCTP_UNUSED) +sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) { + if (with_strq != NULL) { + if (stcb->asoc.ss_data.locked_on_sending == with_strq) { + stcb->asoc.ss_data.locked_on_sending = strq; + } + if (stcb->asoc.ss_data.last_out_stream == with_strq) { + stcb->asoc.ss_data.last_out_stream = strq; + } + } strq->ss_params.rr.next_spoke.tqe_next = NULL; strq->ss_params.rr.next_spoke.tqe_prev = NULL; return; @@ -107,7 +117,7 @@ sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, if (!TAILQ_EMPTY(&strq->outqueue) && (strq->ss_params.rr.next_spoke.tqe_next == NULL) && (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { - TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, + TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke); } if (holds_lock == 0) { @@ -119,7 +129,7 @@ sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, static int sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) { - if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { + if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) { return (1); } else { return (0); @@ -141,19 +151,19 @@ sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, if (TAILQ_EMPTY(&strq->outqueue) && (strq->ss_params.rr.next_spoke.tqe_next != NULL || strq->ss_params.rr.next_spoke.tqe_prev != NULL)) { - if (asoc->last_out_stream == strq) { - asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, + if (asoc->ss_data.last_out_stream == strq) { + asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead, ss_params.rr.next_spoke); - if (asoc->last_out_stream == NULL) { - asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel, + if (asoc->ss_data.last_out_stream == NULL) { + asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead); } - if (asoc->last_out_stream == strq) { - asoc->last_out_stream = NULL; + if (asoc->ss_data.last_out_stream == strq) { + asoc->ss_data.last_out_stream = NULL; } } - TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); + TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke); strq->ss_params.rr.next_spoke.tqe_next = NULL; strq->ss_params.rr.next_spoke.tqe_prev = NULL; } @@ -170,15 +180,18 @@ sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, { struct sctp_stream_out *strq, *strqt; - strqt = asoc->last_out_stream; + if (asoc->ss_data.locked_on_sending) { + return (asoc->ss_data.locked_on_sending); + } + strqt = asoc->ss_data.last_out_stream; default_again: /* Find the next stream to use */ if (strqt == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } else { strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); if (strq == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); + strq = TAILQ_FIRST(&asoc->ss_data.out.wheel); } } @@ -196,7 +209,7 @@ 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 } }; diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index ad9d9783a4ab..280100bbd163 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -555,6 +555,7 @@ struct sctp_stream_in { TAILQ_HEAD(sctpwheel_listhead, sctp_stream_out); TAILQ_HEAD(sctplist_listhead, sctp_stream_queue_pending); + /* Round-robin schedulers */ struct ss_rr { /* next link in wheel */ @@ -581,9 +582,14 @@ struct ss_fb { * This union holds all data necessary for * different stream schedulers. */ -union scheduling_data { - struct sctpwheel_listhead out_wheel; - struct sctplist_listhead out_list; +struct scheduling_data { + struct sctp_stream_out *locked_on_sending; + /* circular looking for output selection */ + struct sctp_stream_out *last_out_stream; + union { + struct sctpwheel_listhead wheel; + struct sctplist_listhead list; + } out; }; /* @@ -735,7 +741,7 @@ struct sctp_ss_functions { int holds_lock); void (*sctp_ss_clear) (struct sctp_tcb *stcb, struct sctp_association *asoc, int clear_values, int holds_lock); - void (*sctp_ss_init_stream) (struct sctp_stream_out *strq, struct sctp_stream_out *with_strq); + void (*sctp_ss_init_stream) (struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq); void (*sctp_ss_add_to_stream) (struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, int holds_lock); int (*sctp_ss_is_empty) (struct sctp_tcb *stcb, struct sctp_association *asoc); @@ -751,6 +757,7 @@ struct sctp_ss_functions { struct sctp_stream_out *strq, uint16_t * value); int (*sctp_ss_set_value) (struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_stream_out *strq, uint16_t value); + int (*sctp_ss_is_user_msgs_incomplete) (struct sctp_tcb *stcb, struct sctp_association *asoc); }; /* used to save ASCONF chunks for retransmission */ @@ -831,15 +838,7 @@ struct sctp_association { struct sctpchunk_listhead send_queue; /* Scheduling queues */ - union scheduling_data ss_data; - - /* - * This pointer will be set to NULL most of the time. But when we - * have a fragmented message, where we could not get out all of the - * message at the last send then this will point to the stream to go - * get data from. - */ - struct sctp_stream_out *locked_on_sending; + struct scheduling_data ss_data; /* If an iterator is looking at me, this is it */ struct sctp_iterator *stcb_starting_point_for_iterator; @@ -872,8 +871,6 @@ struct sctp_association { /* last place I got a control from */ struct sctp_nets *last_control_chunk_from; - /* circular looking for output selection */ - struct sctp_stream_out *last_out_stream; /* * wait to the point the cum-ack passes req->send_reset_at_tsn for diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 274702b45fa6..fc2b9bbf9d30 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -95,6 +95,7 @@ sctp_finish(void *unused __unused) { sctp_pcb_finish(); } + VNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL); #endif @@ -727,7 +728,7 @@ sctp_disconnect(struct socket *so) TAILQ_EMPTY(&asoc->sent_queue) && (asoc->stream_queue_cnt == 0)) { /* there is nothing queued to send, so done */ - if (asoc->locked_on_sending) { + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) { goto abort_anyway; } if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && @@ -776,18 +777,8 @@ sctp_disconnect(struct socket *so) asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, netp); - if (asoc->locked_on_sending) { - /* Locked to send out the data */ - struct sctp_stream_queue_pending *sp; - - sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); - if (sp == NULL) { - SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", - asoc->locked_on_sending->stream_no); - } else { - if ((sp->length == 0) && (sp->msg_is_complete == 0)) - asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; - } + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) { + asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; } if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && @@ -951,7 +942,7 @@ sctp_shutdown(struct socket *so) TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && (asoc->stream_queue_cnt == 0)) { - if (asoc->locked_on_sending) { + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) { goto abort_anyway; } /* there is nothing queued to send, so I'm done... */ @@ -968,19 +959,8 @@ sctp_shutdown(struct socket *so) * SHUTDOWN_PENDING. */ SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); - if (asoc->locked_on_sending) { - /* Locked to send out the data */ - struct sctp_stream_queue_pending *sp; - - sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); - if (sp == NULL) { - SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", - asoc->locked_on_sending->stream_no); - } else { - if ((sp->length == 0) && (sp->msg_is_complete == 0)) { - SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT); - } - } + if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) { + SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT); } if (TAILQ_EMPTY(&asoc->send_queue) && TAILQ_EMPTY(&asoc->sent_queue) && diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 15c2dd18a88e..9cd3bffb9279 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1077,7 +1077,6 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->minrto = inp->sctp_ep.sctp_minrto; asoc->maxrto = inp->sctp_ep.sctp_maxrto; - asoc->locked_on_sending = NULL; asoc->stream_locked_on = 0; asoc->ecn_echo_cnt_onq = 0; asoc->stream_locked = 0; @@ -1139,7 +1138,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->strmout[i].stream_no = i; asoc->strmout[i].last_msg_incomplete = 0; asoc->strmout[i].state = SCTP_STREAM_OPENING; - asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL); + asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL); } asoc->ss_functions.sctp_ss_init(stcb, asoc, 0); @@ -3907,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++;