Author: tuexen
Date: Sat Aug  6 12:33:15 2016
New Revision: 303792
URL: https://svnweb.freebsd.org/changeset/base/303792

Log:
  Fix various bugs in relation to the I-DATA chunk support
  
  This is joint work with rrs.
  
  MFC after:    3 days

Modified:
  head/sys/netinet/sctp_indata.c
  head/sys/netinet/sctp_output.c
  head/sys/netinet/sctp_pcb.c
  head/sys/netinet/sctp_ss_functions.c
  head/sys/netinet/sctp_structs.h
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctputil.c

Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c      Sat Aug  6 11:02:07 2016        
(r303791)
+++ head/sys/netinet/sctp_indata.c      Sat Aug  6 12:33:15 2016        
(r303792)
@@ -64,7 +64,7 @@ sctp_add_chk_to_control(struct sctp_queu
     struct sctp_stream_in *strm,
     struct sctp_tcb *stcb,
     struct sctp_association *asoc,
-    struct sctp_tmit_chunk *chk);
+    struct sctp_tmit_chunk *chk, int lock_held);
 
 
 void
@@ -448,7 +448,7 @@ sctp_abort_in_reasm(struct sctp_tcb *stc
 }
 
 static void
-clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read *control)
+sctp_clean_up_control(struct sctp_tcb *stcb, struct sctp_queued_to_read 
*control)
 {
        /*
         * The control could not be placed and must be cleaned.
@@ -612,7 +612,7 @@ protocol_error:
                        snprintf(msg, sizeof(msg),
                            "Queue to str msg_id: %u duplicate",
                            control->msg_id);
-                       clean_up_control(stcb, control);
+                       sctp_clean_up_control(stcb, control);
                        op_err = 
sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
                        stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA 
+ SCTP_LOC_3;
                        sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, 
SCTP_SO_NOT_LOCKED);
@@ -739,9 +739,28 @@ sctp_build_readq_entry_from_ctl(struct s
        nc->port_from = control->port_from;
 }
 
+static void
+sctp_reset_a_control(struct sctp_queued_to_read *control,
+    struct sctp_inpcb *inp, uint32_t tsn)
+{
+       control->fsn_included = tsn;
+       if (control->on_read_q) {
+               /*
+                * We have to purge it from there, hopefully this will work
+                * :-)
+                */
+               TAILQ_REMOVE(&inp->read_queue, control, next);
+               control->on_read_q = 0;
+       }
+}
+
 static int
-sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, 
struct sctp_stream_in *strm,
-    struct sctp_queued_to_read *control, uint32_t pd_point)
+sctp_handle_old_unordered_data(struct sctp_tcb *stcb,
+    struct sctp_association *asoc,
+    struct sctp_stream_in *strm,
+    struct sctp_queued_to_read *control,
+    uint32_t pd_point,
+    int inp_read_lock_held)
 {
        /*
         * Special handling for the old un-ordered data chunk. All the
@@ -774,7 +793,7 @@ restart:
                        }
                        memset(nc, 0, sizeof(struct sctp_queued_to_read));
                        TAILQ_REMOVE(&control->reasm, chk, sctp_next);
-                       sctp_add_chk_to_control(control, strm, stcb, asoc, chk);
+                       sctp_add_chk_to_control(control, strm, stcb, asoc, chk, 
SCTP_READ_LOCK_NOT_HELD);
                        fsn++;
                        cnt_added++;
                        chk = NULL;
@@ -793,6 +812,8 @@ restart:
                                                nc->first_frag_seen = 1;
                                                nc->fsn_included = 
tchk->rec.data.fsn_num;
                                                nc->data = tchk->data;
+                                               nc->sinfo_ppid = 
tchk->rec.data.payloadtype;
+                                               nc->sinfo_tsn = 
tchk->rec.data.TSN_seq;
                                                sctp_mark_non_revokable(asoc, 
tchk->rec.data.TSN_seq);
                                                tchk->data = NULL;
                                                sctp_free_a_chunk(stcb, tchk, 
SCTP_SO_NOT_LOCKED);
@@ -828,7 +849,7 @@ restart:
                                if (control->on_read_q == 0) {
                                        sctp_add_to_readq(stcb->sctp_ep, stcb, 
control,
                                            &stcb->sctp_socket->so_rcv, 
control->end_added,
-                                           SCTP_READ_LOCK_NOT_HELD, 
SCTP_SO_NOT_LOCKED);
+                                           inp_read_lock_held, 
SCTP_SO_NOT_LOCKED);
                                }
                                sctp_wakeup_the_read_socket(stcb->sctp_ep, 
stcb, SCTP_SO_NOT_LOCKED);
                                if ((nc->first_frag_seen) && 
!TAILQ_EMPTY(&nc->reasm)) {
@@ -839,7 +860,9 @@ restart:
                                        control = nc;
                                        goto restart;
                                } else {
-                                       sctp_free_a_readq(stcb, nc);
+                                       if (nc->on_strm_q == 0) {
+                                               sctp_free_a_readq(stcb, nc);
+                                       }
                                }
                                return (1);
                        } else {
@@ -855,7 +878,7 @@ restart:
                control->pdapi_started = 1;
                sctp_add_to_readq(stcb->sctp_ep, stcb, control,
                    &stcb->sctp_socket->so_rcv, control->end_added,
-                   SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
+                   inp_read_lock_held, SCTP_SO_NOT_LOCKED);
                sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, 
SCTP_SO_NOT_LOCKED);
                return (0);
        } else {
@@ -864,13 +887,14 @@ restart:
 }
 
 static void
-sctp_inject_old_data_unordered(struct sctp_tcb *stcb, struct sctp_association 
*asoc,
+sctp_inject_old_unordered_data(struct sctp_tcb *stcb,
+    struct sctp_association *asoc,
     struct sctp_queued_to_read *control,
     struct sctp_tmit_chunk *chk,
     int *abort_flag)
 {
        struct sctp_tmit_chunk *at;
-       int inserted = 0;
+       int inserted;
 
        /*
         * Here we need to place the chunk into the control structure sorted
@@ -926,18 +950,29 @@ sctp_inject_old_data_unordered(struct sc
                        tdata = control->data;
                        control->data = chk->data;
                        chk->data = tdata;
-                       /* Swap the lengths */
-                       tmp = control->length;
-                       control->length = chk->send_size;
-                       chk->send_size = tmp;
+                       /* Save the lengths */
+                       chk->send_size = control->length;
+                       /* Recompute length of control and tail pointer */
+                       sctp_setup_tail_pointer(control);
                        /* Fix the FSN included */
                        tmp = control->fsn_included;
                        control->fsn_included = chk->rec.data.fsn_num;
                        chk->rec.data.fsn_num = tmp;
+                       /* Fix the TSN included */
+                       tmp = control->sinfo_tsn;
+                       control->sinfo_tsn = chk->rec.data.TSN_seq;
+                       chk->rec.data.TSN_seq = tmp;
+                       /* Fix the PPID included */
+                       tmp = control->sinfo_ppid;
+                       control->sinfo_ppid = chk->rec.data.payloadtype;
+                       chk->rec.data.payloadtype = tmp;
+                       /* Fix tail pointer */
                        goto place_chunk;
                }
                control->first_frag_seen = 1;
                control->top_fsn = control->fsn_included = 
chk->rec.data.fsn_num;
+               control->sinfo_tsn = chk->rec.data.TSN_seq;
+               control->sinfo_ppid = chk->rec.data.payloadtype;
                control->data = chk->data;
                sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
                chk->data = NULL;
@@ -946,12 +981,7 @@ sctp_inject_old_data_unordered(struct sc
                return;
        }
 place_chunk:
-       if (TAILQ_EMPTY(&control->reasm)) {
-               TAILQ_INSERT_TAIL(&control->reasm, chk, sctp_next);
-               asoc->size_on_reasm_queue += chk->send_size;
-               sctp_ucount_incr(asoc->cnt_on_reasm_queue);
-               return;
-       }
+       inserted = 0;
        TAILQ_FOREACH(at, &control->reasm, sctp_next) {
                if (SCTP_TSN_GT(at->rec.data.fsn_num, chk->rec.data.fsn_num)) {
                        /*
@@ -985,7 +1015,8 @@ place_chunk:
 }
 
 static int
-sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc, 
struct sctp_stream_in *strm)
+sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc,
+    struct sctp_stream_in *strm, int inp_read_lock_held)
 {
        /*
         * Given a stream, strm, see if any of the SSN's on it that are
@@ -1005,10 +1036,11 @@ sctp_deliver_reasm_check(struct sctp_tcb
                pd_point = stcb->sctp_ep->partial_delivery_point;
        }
        control = TAILQ_FIRST(&strm->uno_inqueue);
+
        if ((control) &&
            (asoc->idata_supported == 0)) {
                /* Special handling needed for "old" data format */
-               if (sctp_handle_old_data(stcb, asoc, strm, control, pd_point)) {
+               if (sctp_handle_old_unordered_data(stcb, asoc, strm, control, 
pd_point, inp_read_lock_held)) {
                        goto done_un;
                }
        }
@@ -1037,7 +1069,7 @@ sctp_deliver_reasm_check(struct sctp_tcb
                                sctp_add_to_readq(stcb->sctp_ep, stcb,
                                    control,
                                    &stcb->sctp_socket->so_rcv, 
control->end_added,
-                                   SCTP_READ_LOCK_NOT_HELD, 
SCTP_SO_NOT_LOCKED);
+                                   inp_read_lock_held, SCTP_SO_NOT_LOCKED);
                        }
                } else {
                        /* Can we do a PD-API for this un-ordered guy? */
@@ -1047,7 +1079,7 @@ sctp_deliver_reasm_check(struct sctp_tcb
                                sctp_add_to_readq(stcb->sctp_ep, stcb,
                                    control,
                                    &stcb->sctp_socket->so_rcv, 
control->end_added,
-                                   SCTP_READ_LOCK_NOT_HELD, 
SCTP_SO_NOT_LOCKED);
+                                   inp_read_lock_held, SCTP_SO_NOT_LOCKED);
 
                                break;
                        }
@@ -1096,7 +1128,7 @@ done_un:
                                sctp_add_to_readq(stcb->sctp_ep, stcb,
                                    control,
                                    &stcb->sctp_socket->so_rcv, 
control->end_added,
-                                   SCTP_READ_LOCK_NOT_HELD, 
SCTP_SO_NOT_LOCKED);
+                                   inp_read_lock_held, SCTP_SO_NOT_LOCKED);
                        }
                        control = nctl;
                }
@@ -1160,7 +1192,7 @@ deliver_more:
                                sctp_add_to_readq(stcb->sctp_ep, stcb,
                                    control,
                                    &stcb->sctp_socket->so_rcv, 
control->end_added,
-                                   SCTP_READ_LOCK_NOT_HELD, 
SCTP_SO_NOT_LOCKED);
+                                   inp_read_lock_held, SCTP_SO_NOT_LOCKED);
                        }
                        strm->last_sequence_delivered = next_to_del;
                        if (done) {
@@ -1177,11 +1209,12 @@ out:
        return (ret);
 }
 
+
 void
 sctp_add_chk_to_control(struct sctp_queued_to_read *control,
     struct sctp_stream_in *strm,
     struct sctp_tcb *stcb, struct sctp_association *asoc,
-    struct sctp_tmit_chunk *chk)
+    struct sctp_tmit_chunk *chk, int hold_rlock)
 {
        /*
         * Given a control and a chunk, merge the data from the chk onto the
@@ -1189,7 +1222,7 @@ sctp_add_chk_to_control(struct sctp_queu
         */
        int i_locked = 0;
 
-       if (control->on_read_q) {
+       if (control->on_read_q && (hold_rlock == 0)) {
                /*
                 * Its being pd-api'd so we must do some locks.
                 */
@@ -1271,7 +1304,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
        if (created_control) {
                if (sctp_place_control_in_stream(strm, asoc, control)) {
                        /* Duplicate SSN? */
-                       clean_up_control(stcb, control);
+                       sctp_clean_up_control(stcb, control);
                        sctp_abort_in_reasm(stcb, control, chk,
                            abort_flag,
                            SCTP_FROM_SCTP_INDATA + SCTP_LOC_6);
@@ -1292,7 +1325,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
                }
        }
        if ((asoc->idata_supported == 0) && (unordered == 1)) {
-               sctp_inject_old_data_unordered(stcb, asoc, control, chk, 
abort_flag);
+               sctp_inject_old_unordered_data(stcb, asoc, control, chk, 
abort_flag);
                return;
        }
        /*
@@ -1482,7 +1515,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
                                    at->rec.data.fsn_num,
                                    next_fsn, control->fsn_included);
                                TAILQ_REMOVE(&control->reasm, at, sctp_next);
-                               sctp_add_chk_to_control(control, strm, stcb, 
asoc, at);
+                               sctp_add_chk_to_control(control, strm, stcb, 
asoc, at, SCTP_READ_LOCK_NOT_HELD);
                                if (control->on_read_q) {
                                        do_wakeup = 1;
                                }
@@ -1513,7 +1546,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
 }
 
 static struct sctp_queued_to_read *
-find_reasm_entry(struct sctp_stream_in *strm, uint32_t msg_id, int ordered, 
int old)
+sctp_find_reasm_entry(struct sctp_stream_in *strm, uint32_t msg_id, int 
ordered, int old)
 {
        struct sctp_queued_to_read *control;
 
@@ -1573,6 +1606,7 @@ sctp_process_a_data_chunk(struct sctp_tc
                clen = sizeof(struct sctp_idata_chunk);
                tsn = ntohl(ch->dp.tsn);
                msg_id = ntohl(nch->dp.msg_id);
+               protocol_id = nch->dp.ppid_fsn.protocol_id;
                if (ch->ch.chunk_flags & SCTP_DATA_FIRST_FRAG)
                        fsn = 0;
                else
@@ -1582,6 +1616,7 @@ sctp_process_a_data_chunk(struct sctp_tc
                ch = (struct sctp_data_chunk *)sctp_m_getptr(*m, offset,
                    sizeof(struct sctp_data_chunk), (uint8_t *) & chunk_buf);
                tsn = ntohl(ch->dp.tsn);
+               protocol_id = ch->dp.protocol_id;
                clen = sizeof(struct sctp_data_chunk);
                fsn = tsn;
                msg_id = (uint32_t) (ntohs(ch->dp.stream_sequence));
@@ -1602,7 +1637,6 @@ sctp_process_a_data_chunk(struct sctp_tc
        if ((chunk_flags & SCTP_DATA_SACK_IMMEDIATELY) == 
SCTP_DATA_SACK_IMMEDIATELY) {
                asoc->send_sack = 1;
        }
-       protocol_id = ch->dp.protocol_id;
        ordered = ((chunk_flags & SCTP_DATA_UNORDERED) == 0);
        if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
                sctp_log_map(tsn, asoc->cumulative_tsn, 
asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS);
@@ -1722,7 +1756,7 @@ sctp_process_a_data_chunk(struct sctp_tc
        }
        if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
                /* See if we can find the re-assembly entity */
-               control = find_reasm_entry(strm, msg_id, ordered, old_data);
+               control = sctp_find_reasm_entry(strm, msg_id, ordered, 
old_data);
                SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for control on 
queues %p\n",
                    chunk_flags, control);
                if (control) {
@@ -1758,7 +1792,7 @@ sctp_process_a_data_chunk(struct sctp_tc
                 */
                SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags:0x%x look for msg in case 
we have dup\n",
                    chunk_flags);
-               if (find_reasm_entry(strm, msg_id, ordered, old_data)) {
+               if (sctp_find_reasm_entry(strm, msg_id, ordered, old_data)) {
                        SCTPDBG(SCTP_DEBUG_XXX, "chunk_flags: 0x%x dup detected 
on msg_id: %u\n",
                            chunk_flags,
                            msg_id);
@@ -2179,12 +2213,12 @@ finish_express_del:
                 * Now service re-assembly to pick up anything that has been
                 * held on reassembly queue?
                 */
-               (void)sctp_deliver_reasm_check(stcb, asoc, strm);
+               (void)sctp_deliver_reasm_check(stcb, asoc, strm, 
SCTP_READ_LOCK_NOT_HELD);
                need_reasm_check = 0;
        }
        if (need_reasm_check) {
                /* Another one waits ? */
-               (void)sctp_deliver_reasm_check(stcb, asoc, strm);
+               (void)sctp_deliver_reasm_check(stcb, asoc, strm, 
SCTP_READ_LOCK_NOT_HELD);
        }
        return (1);
 }
@@ -4152,28 +4186,8 @@ again:
                if ((asoc->stream_queue_cnt == 1) &&
                    ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
                    (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) &&
-                   (asoc->locked_on_sending)
-                   ) {
-                       struct sctp_stream_queue_pending *sp;
-
-                       /*
-                        * I may be in a state where we got all across.. but
-                        * cannot write more due to a shutdown... we abort
-                        * since the user did not indicate EOR in this case.
-                        * The sp will be cleaned during free of the asoc.
-                        */
-                       sp = TAILQ_LAST(&((asoc->locked_on_sending)->outqueue),
-                           sctp_streamhead);
-                       if ((sp) && (sp->length == 0)) {
-                               /* Let cleanup code purge it */
-                               if (sp->msg_is_complete) {
-                                       asoc->stream_queue_cnt--;
-                               } else {
-                                       asoc->state |= 
SCTP_STATE_PARTIAL_MSG_LEFT;
-                                       asoc->locked_on_sending = NULL;
-                                       asoc->stream_queue_cnt--;
-                               }
-                       }
+                   ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) 
(stcb, asoc))) {
+                       asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
                }
                if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
                    (asoc->stream_queue_cnt == 0)) {
@@ -4868,26 +4882,8 @@ hopeless_peer:
                if ((asoc->stream_queue_cnt == 1) &&
                    ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) ||
                    (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED)) &&
-                   (asoc->locked_on_sending)
-                   ) {
-                       struct sctp_stream_queue_pending *sp;
-
-                       /*
-                        * I may be in a state where we got all across.. but
-                        * cannot write more due to a shutdown... we abort
-                        * since the user did not indicate EOR in this case.
-                        */
-                       sp = TAILQ_LAST(&((asoc->locked_on_sending)->outqueue),
-                           sctp_streamhead);
-                       if ((sp) && (sp->length == 0)) {
-                               asoc->locked_on_sending = NULL;
-                               if (sp->msg_is_complete) {
-                                       asoc->stream_queue_cnt--;
-                               } else {
-                                       asoc->state |= 
SCTP_STATE_PARTIAL_MSG_LEFT;
-                                       asoc->stream_queue_cnt--;
-                               }
-                       }
+                   ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) 
(stcb, asoc))) {
+                       asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
                }
                if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) &&
                    (asoc->stream_queue_cnt == 0)) {
@@ -5215,7 +5211,7 @@ sctp_kick_prsctp_reorder_queue(struct sc
        if (need_reasm_check) {
                int ret;
 
-               ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin);
+               ret = sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, 
SCTP_READ_LOCK_HELD);
                if (SCTP_MSGID_GT(old, tt, strmin->last_sequence_delivered)) {
                        /* Restore the next to deliver unless we are ahead */
                        strmin->last_sequence_delivered = tt;
@@ -5279,19 +5275,21 @@ sctp_kick_prsctp_reorder_queue(struct sc
                }
        }
        if (need_reasm_check) {
-               (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin);
+               (void)sctp_deliver_reasm_check(stcb, &stcb->asoc, strmin, 
SCTP_READ_LOCK_HELD);
        }
 }
 
 
+
 static void
 sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
     struct sctp_association *asoc,
-    uint16_t stream, uint32_t seq, int ordered, int old)
+    uint16_t stream, uint32_t seq, int ordered, int old, uint32_t cumtsn)
 {
        struct sctp_queued_to_read *control;
        struct sctp_stream_in *strm;
        struct sctp_tmit_chunk *chk, *nchk;
+       int cnt_removed = 0;
 
        /*
         * For now large messages held on the stream reasm that are complete
@@ -5302,13 +5300,19 @@ sctp_flush_reassm_for_str_seq(struct sct
         * queue.
         */
        strm = &asoc->strmin[stream];
-       control = find_reasm_entry(strm, (uint32_t) seq, ordered, old);
+       control = sctp_find_reasm_entry(strm, (uint32_t) seq, ordered, old);
        if (control == NULL) {
                /* Not found */
                return;
        }
        TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, nchk) {
                /* Purge hanging chunks */
+               if (old && (ordered == 0)) {
+                       if (SCTP_TSN_GT(chk->rec.data.TSN_seq, cumtsn)) {
+                               break;
+                       }
+               }
+               cnt_removed++;
                TAILQ_REMOVE(&control->reasm, chk, sctp_next);
                asoc->size_on_reasm_queue -= chk->send_size;
                sctp_ucount_decr(asoc->cnt_on_reasm_queue);
@@ -5318,7 +5322,35 @@ sctp_flush_reassm_for_str_seq(struct sct
                }
                sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
        }
-       TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+       if (!TAILQ_EMPTY(&control->reasm)) {
+               /* This has to be old data, unordered */
+               if (control->data) {
+                       sctp_m_freem(control->data);
+                       control->data = NULL;
+               }
+               sctp_reset_a_control(control, stcb->sctp_ep, cumtsn);
+               chk = TAILQ_FIRST(&control->reasm);
+               if (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
+                       TAILQ_REMOVE(&control->reasm, chk, sctp_next);
+                       sctp_add_chk_to_control(control, strm, stcb, asoc,
+                           chk, SCTP_READ_LOCK_HELD);
+               }
+               sctp_deliver_reasm_check(stcb, asoc, strm, SCTP_READ_LOCK_HELD);
+               return;
+       }
+       if (control->on_strm_q == SCTP_ON_ORDERED) {
+               TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
+               control->on_strm_q = 0;
+       } else if (control->on_strm_q == SCTP_ON_UNORDERED) {
+               TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
+               control->on_strm_q = 0;
+#ifdef INVARIANTS
+       } else if (control->on_strm_q) {
+               panic("strm: %p ctl: %p unknown %d",
+                   strm, control, control->on_strm_q);
+#endif
+       }
+       control->on_strm_q = 0;
        if (control->on_read_q == 0) {
                sctp_free_remote_addr(control->whoFrom);
                if (control->data) {
@@ -5329,7 +5361,6 @@ sctp_flush_reassm_for_str_seq(struct sct
        }
 }
 
-
 void
 sctp_handle_forward_tsn(struct sctp_tcb *stcb,
     struct sctp_forward_tsn_chunk *fwd,
@@ -5423,7 +5454,16 @@ sctp_handle_forward_tsn(struct sctp_tcb 
        /*************************************************************/
 
        /* This is now done as part of clearing up the stream/seq */
+       if (asoc->idata_supported == 0) {
+               uint16_t sid;
 
+               /* Flush all the un-ordered data based on cum-tsn */
+               SCTP_INP_READ_LOCK(stcb->sctp_ep);
+               for (sid = 0; sid < asoc->streamincnt; sid++) {
+                       sctp_flush_reassm_for_str_seq(stcb, asoc, sid, 0, 0, 1, 
new_cum_tsn);
+               }
+               SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
+       }
        /*******************************************************/
        /* 3. Update the PR-stream re-ordering queues and fix  */
        /* delivery issues as needed.                       */
@@ -5502,7 +5542,19 @@ sctp_handle_forward_tsn(struct sctp_tcb 
                                asoc->fragmented_delivery_inprogress = 0;
                        }
                        strm = &asoc->strmin[stream];
-                       sctp_flush_reassm_for_str_seq(stcb, asoc, stream, 
sequence, ordered, old);
+                       if (asoc->idata_supported == 0) {
+                               uint16_t strm_at;
+
+                               for (strm_at = strm->last_sequence_delivered; 
SCTP_MSGID_GE(1, sequence, strm_at); strm_at++) {
+                                       sctp_flush_reassm_for_str_seq(stcb, 
asoc, stream, strm_at, ordered, old, new_cum_tsn);
+                               }
+                       } else {
+                               uint32_t strm_at;
+
+                               for (strm_at = strm->last_sequence_delivered; 
SCTP_MSGID_GE(0, sequence, strm_at); strm_at++) {
+                                       sctp_flush_reassm_for_str_seq(stcb, 
asoc, stream, strm_at, ordered, old, new_cum_tsn);
+                               }
+                       }
                        TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) {
                                if ((ctl->sinfo_stream == stream) &&
                                    (ctl->sinfo_ssn == sequence)) {

Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c      Sat Aug  6 11:02:07 2016        
(r303791)
+++ head/sys/netinet/sctp_output.c      Sat Aug  6 12:33:15 2016        
(r303792)
@@ -3657,7 +3657,7 @@ sctp_process_cmsgs_for_init(struct sctp_
                                                stcb->asoc.strmout[i].stream_no 
= i;
                                                
stcb->asoc.strmout[i].last_msg_incomplete = 0;
                                                stcb->asoc.strmout[i].state = 
SCTP_STREAM_OPENING;
-                                               
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+                                               
stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL);
                                        }
                                }
                                break;
@@ -6694,7 +6694,7 @@ sctp_sendall_iterator(struct sctp_inpcb 
                        if (TAILQ_EMPTY(&asoc->send_queue) &&
                            TAILQ_EMPTY(&asoc->sent_queue) &&
                            (cnt == 0)) {
-                               if (asoc->locked_on_sending) {
+                               if 
((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
                                        goto abort_anyway;
                                }
                                /*
@@ -6736,18 +6736,8 @@ sctp_sendall_iterator(struct sctp_inpcb 
                                if ((SCTP_GET_STATE(asoc) != 
SCTP_STATE_SHUTDOWN_SENT) &&
                                    (SCTP_GET_STATE(asoc) != 
SCTP_STATE_SHUTDOWN_RECEIVED) &&
                                    (SCTP_GET_STATE(asoc) != 
SCTP_STATE_SHUTDOWN_ACK_SENT)) {
-                                       if (asoc->locked_on_sending) {
-                                               /*
-                                                * Locked to send out the
-                                                * data
-                                                */
-                                               struct 
sctp_stream_queue_pending *sp;
-
-                                               sp = 
TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
-                                               if (sp) {
-                                                       if ((sp->length == 0) 
&& (sp->msg_is_complete == 0))
-                                                               asoc->state |= 
SCTP_STATE_PARTIAL_MSG_LEFT;
-                                               }
+                                       if 
((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
+                                               asoc->state |= 
SCTP_STATE_PARTIAL_MSG_LEFT;
                                        }
                                        asoc->state |= 
SCTP_STATE_SHUTDOWN_PENDING;
                                        if (TAILQ_EMPTY(&asoc->send_queue) &&
@@ -7170,7 +7160,6 @@ sctp_move_to_outqueue(struct sctp_tcb *s
     struct sctp_stream_out *strq,
     uint32_t goal_mtu,
     uint32_t frag_point,
-    int *locked,
     int *giveup,
     int eeor_mode,
     int *bail,
@@ -7196,10 +7185,8 @@ sctp_move_to_outqueue(struct sctp_tcb *s
        asoc = &stcb->asoc;
 one_more_time:
        /* sa_ignore FREED_MEMORY */
-       *locked = 0;
        sp = TAILQ_FIRST(&strq->outqueue);
        if (sp == NULL) {
-               *locked = 0;
                if (send_lock_up == 0) {
                        SCTP_TCB_SEND_LOCK(stcb);
                        send_lock_up = 1;
@@ -7261,8 +7248,6 @@ one_more_time:
                        }
                        sctp_free_a_strmoq(stcb, sp, so_locked);
                        /* we can't be locked to it */
-                       *locked = 0;
-                       stcb->asoc.locked_on_sending = NULL;
                        if (send_lock_up) {
                                SCTP_TCB_SEND_UNLOCK(stcb);
                                send_lock_up = 0;
@@ -7274,8 +7259,6 @@ one_more_time:
                         * sender just finished this but still holds a
                         * reference
                         */
-                       if (stcb->asoc.idata_supported == 0)
-                               *locked = 1;
                        *giveup = 1;
                        to_move = 0;
                        goto out_of;
@@ -7284,8 +7267,6 @@ one_more_time:
                /* is there some to get */
                if (sp->length == 0) {
                        /* no */
-                       if (stcb->asoc.idata_supported == 0)
-                               *locked = 1;
                        *giveup = 1;
                        to_move = 0;
                        goto out_of;
@@ -7308,8 +7289,6 @@ one_more_time:
                        }
                        sp->length = 0;
                        sp->some_taken = 1;
-                       if (stcb->asoc.idata_supported == 0)
-                               *locked = 1;
                        *giveup = 1;
                        to_move = 0;
                        goto out_of;
@@ -7373,10 +7352,6 @@ re_look:
                        }
                } else {
                        /* Nothing to take. */
-                       if ((sp->some_taken) &&
-                           (stcb->asoc.idata_supported == 0)) {
-                               *locked = 1;
-                       }
                        *giveup = 1;
                        to_move = 0;
                        goto out_of;
@@ -7716,14 +7691,6 @@ dont_do_it:
                        sp->data = NULL;
                }
                sctp_free_a_strmoq(stcb, sp, so_locked);
-
-               /* we can't be locked to it */
-               *locked = 0;
-               stcb->asoc.locked_on_sending = NULL;
-       } else {
-               /* more to go, we are locked */
-               if (stcb->asoc.idata_supported == 0)
-                       *locked = 1;
        }
        asoc->chunks_on_out_queue++;
        strq->chunks_on_queues++;
@@ -7748,7 +7715,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb
        struct sctp_association *asoc;
        struct sctp_stream_out *strq;
        int goal_mtu, moved_how_much, total_moved = 0, bail = 0;
-       int locked, giveup;
+       int giveup;
 
        SCTP_TCB_LOCK_ASSERT(stcb);
        asoc = &stcb->asoc;
@@ -7777,36 +7744,20 @@ sctp_fill_outqueue(struct sctp_tcb *stcb
 
        /* must make even word boundary */
        goal_mtu &= 0xfffffffc;
-       if (asoc->locked_on_sending) {
-               /* We are stuck on one stream until the message completes. */
-               strq = asoc->locked_on_sending;
-               locked = 1;
-       } else {
-               strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, 
asoc);
-               locked = 0;
-       }
+       strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
        while ((goal_mtu > 0) && strq) {
                giveup = 0;
                bail = 0;
-               moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, 
frag_point, &locked,
+               moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, 
frag_point,
                    &giveup, eeor_mode, &bail, so_locked);
-               if (moved_how_much)
-                       stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, 
asoc, strq, moved_how_much);
+               stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, 
strq, moved_how_much);
 
-               if (locked) {
-                       asoc->locked_on_sending = strq;
-                       if ((moved_how_much == 0) || (giveup) || bail)
-                               /* no more to move for now */
-                               break;
-               } else {
-                       asoc->locked_on_sending = NULL;
-                       if ((giveup) || bail) {
-                               break;
-                       }
-                       strq = 
stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc);
-                       if (strq == NULL) {
-                               break;
-                       }
+               if ((giveup) || bail) {
+                       break;
+               }
+               strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, 
asoc);
+               if (strq == NULL) {
+                       break;
                }
                total_moved += moved_how_much;
                goal_mtu -= (moved_how_much + sizeof(struct sctp_data_chunk));
@@ -10227,9 +10178,8 @@ do_it_again:
                        un_sent = ((stcb->asoc.total_output_queue_size - 
stcb->asoc.total_flight) +
                            (stcb->asoc.stream_queue_cnt * sizeof(struct 
sctp_data_chunk)));
                        if ((un_sent < (int)(stcb->asoc.smallest_mtu - 
SCTP_MIN_OVERHEAD)) &&
-                           (stcb->asoc.total_flight > 0) &&
-                           ((stcb->asoc.locked_on_sending == NULL) ||
-                           sctp_is_feature_on(inp, 
SCTP_PCB_FLAGS_EXPLICIT_EOR))) {
+                           (stcb->asoc.total_flight > 0)) {
+/*     &&                   sctp_is_feature_on(inp, 
SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/
                                break;
                        }
                }
@@ -12262,19 +12212,18 @@ sctp_send_str_reset_req(struct sctp_tcb 
                        stcb->asoc.strmout[i].last_msg_incomplete = 
oldstream[i].last_msg_incomplete;
                        stcb->asoc.strmout[i].stream_no = i;
                        stcb->asoc.strmout[i].state = oldstream[i].state;
-                       
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], 
&oldstream[i]);
+                       /* FIX ME FIX ME */
+                       /*
+                        * This should be a SS_COPY operation FIX ME STREAM
+                        * SCHEDULER EXPERT
+                        */
+                       stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, 
&stcb->asoc.strmout[i], &oldstream[i]);
                        /* now anything on those queues? */
                        TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, 
nsp) {
                                TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
                                
TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
                        }
-                       /* Now move assoc pointers too */
-                       if (stcb->asoc.last_out_stream == &oldstream[i]) {
-                               stcb->asoc.last_out_stream = 
&stcb->asoc.strmout[i];
-                       }
-                       if (stcb->asoc.locked_on_sending == &oldstream[i]) {
-                               stcb->asoc.locked_on_sending = 
&stcb->asoc.strmout[i];
-                       }
+
                }
                /* now the new streams */
                stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
@@ -12294,7 +12243,7 @@ sctp_send_str_reset_req(struct sctp_tcb 
                        stcb->asoc.strmout[i].next_mid_unordered = 0;
                        stcb->asoc.strmout[i].stream_no = i;
                        stcb->asoc.strmout[i].last_msg_incomplete = 0;
-                       
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+                       stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, 
&stcb->asoc.strmout[i], NULL);
                        stcb->asoc.strmout[i].state = SCTP_STREAM_CLOSED;
                }
                stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + 
adding_o;
@@ -13518,7 +13467,7 @@ dataless_eof:
                if (TAILQ_EMPTY(&asoc->send_queue) &&
                    TAILQ_EMPTY(&asoc->sent_queue) &&
                    (cnt == 0)) {
-                       if (asoc->locked_on_sending) {
+                       if 
((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
                                goto abort_anyway;
                        }
                        /* there is nothing queued to send, so I'm done... */
@@ -13563,15 +13512,8 @@ dataless_eof:
                                        SCTP_TCB_LOCK(stcb);
                                        hold_tcblock = 1;
                                }
-                               if (asoc->locked_on_sending) {
-                                       /* Locked to send out the data */
-                                       struct sctp_stream_queue_pending *sp;
-
-                                       sp = 
TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
-                                       if (sp) {
-                                               if ((sp->length == 0) && 
(sp->msg_is_complete == 0))
-                                                       asoc->state |= 
SCTP_STATE_PARTIAL_MSG_LEFT;
-                                       }
+                               if 
((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
+                                       asoc->state |= 
SCTP_STATE_PARTIAL_MSG_LEFT;
                                }
                                asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
                                if (TAILQ_EMPTY(&asoc->send_queue) &&

Modified: head/sys/netinet/sctp_pcb.c
==============================================================================
--- head/sys/netinet/sctp_pcb.c Sat Aug  6 11:02:07 2016        (r303791)
+++ head/sys/netinet/sctp_pcb.c Sat Aug  6 12:33:15 2016        (r303792)
@@ -3444,7 +3444,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, 
                        } else if (TAILQ_EMPTY(&asoc->asoc.send_queue) &&
                                    TAILQ_EMPTY(&asoc->asoc.sent_queue) &&
                            (asoc->asoc.stream_queue_cnt == 0)) {
-                               if (asoc->asoc.locked_on_sending) {
+                               if 
((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete) (asoc, 
&asoc->asoc)) {
                                        goto abort_anyway;
                                }
                                if ((SCTP_GET_STATE(&asoc->asoc) != 
SCTP_STATE_SHUTDOWN_SENT) &&
@@ -3476,22 +3476,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, 
                                }
                        } else {
                                /* mark into shutdown pending */
-                               struct sctp_stream_queue_pending *sp;
-
                                asoc->asoc.state |= SCTP_STATE_SHUTDOWN_PENDING;
                                sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 
asoc->sctp_ep, asoc,
                                    asoc->asoc.primary_destination);
-                               if (asoc->asoc.locked_on_sending) {
-                                       sp = 
TAILQ_LAST(&((asoc->asoc.locked_on_sending)->outqueue),
-                                           sctp_streamhead);
-                                       if (sp == NULL) {
-                                               SCTP_PRINTF("Error, sp is NULL, 
locked on sending is %p strm:%d\n",
-                                                   (void 
*)asoc->asoc.locked_on_sending,
-                                                   
asoc->asoc.locked_on_sending->stream_no);
-                                       } else {
-                                               if ((sp->length == 0) && 
(sp->msg_is_complete == 0))
-                                                       asoc->asoc.state |= 
SCTP_STATE_PARTIAL_MSG_LEFT;
-                                       }
+                               if 
((*asoc->asoc.ss_functions.sctp_ss_is_user_msgs_incomplete) (asoc, 
&asoc->asoc)) {
+                                       asoc->asoc.state |= 
SCTP_STATE_PARTIAL_MSG_LEFT;
                                }
                                if (TAILQ_EMPTY(&asoc->asoc.send_queue) &&
                                    TAILQ_EMPTY(&asoc->asoc.sent_queue) &&
@@ -6874,6 +6863,15 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
        /* Ok that was fun, now we will drain all the inbound streams? */
        for (strmat = 0; strmat < asoc->streamincnt; strmat++) {
                TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].inqueue, 
next_instrm, nctl) {
+#ifdef INVARIANTS
+                       if (ctl->on_strm_q != SCTP_ON_ORDERED) {
+                               panic("Huh control: %p on_q: %d -- not 
ordered?",
+                                   ctl, ctl->on_strm_q);
+                       }
+#endif
+                       if (ctl->on_read_q) {
+                               continue;
+                       }
                        if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
                                /* Yep it is above cum-ack */
                                cnt++;
@@ -6881,7 +6879,12 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
                                asoc->size_on_all_streams = 
sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
                                sctp_ucount_decr(asoc->cnt_on_all_streams);
                                SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, 
gap);
+                               if (ctl->on_read_q) {
+                                       
TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next);
+                                       ctl->on_read_q = 0;
+                               }
                                TAILQ_REMOVE(&asoc->strmin[strmat].inqueue, 
ctl, next_instrm);
+                               ctl->on_strm_q = 0;
                                if (ctl->data) {
                                        sctp_m_freem(ctl->data);
                                        ctl->data = NULL;
@@ -6905,6 +6908,12 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
                        }
                }
                TAILQ_FOREACH_SAFE(ctl, &asoc->strmin[strmat].uno_inqueue, 
next_instrm, nctl) {
+#ifdef INVARIANTS
+                       if (ctl->on_strm_q != SCTP_ON_UNORDERED) {
+                               panic("Huh control: %p on_q: %d -- not 
unordered?",
+                                   ctl, ctl->on_strm_q);
+                       }
+#endif
                        if (SCTP_TSN_GT(ctl->sinfo_tsn, cumulative_tsn_p1)) {
                                /* Yep it is above cum-ack */
                                cnt++;
@@ -6912,7 +6921,12 @@ sctp_drain_mbufs(struct sctp_tcb *stcb)
                                asoc->size_on_all_streams = 
sctp_sbspace_sub(asoc->size_on_all_streams, ctl->length);
                                sctp_ucount_decr(asoc->cnt_on_all_streams);
                                SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, 
gap);
+                               if (ctl->on_read_q) {
+                                       
TAILQ_REMOVE(&stcb->sctp_ep->read_queue, ctl, next);
+                                       ctl->on_read_q = 0;
+                               }
                                TAILQ_REMOVE(&asoc->strmin[strmat].uno_inqueue, 
ctl, next_instrm);
+                               ctl->on_strm_q = 0;
                                if (ctl->data) {
                                        sctp_m_freem(ctl->data);
                                        ctl->data = NULL;

Modified: head/sys/netinet/sctp_ss_functions.c
==============================================================================
--- head/sys/netinet/sctp_ss_functions.c        Sat Aug  6 11:02:07 2016        
(r303791)
+++ head/sys/netinet/sctp_ss_functions.c        Sat Aug  6 12:33:15 2016        
(r303792)
@@ -52,7 +52,9 @@ sctp_ss_default_init(struct sctp_tcb *st
 {
        uint16_t i;
 
-       TAILQ_INIT(&asoc->ss_data.out_wheel);
+       asoc->ss_data.locked_on_sending = NULL;
+       asoc->ss_data.last_out_stream = NULL;
+       TAILQ_INIT(&asoc->ss_data.out.wheel);
        /*
         * If there is data in the stream queues already, the scheduler of
         * an existing association has been changed. We need to add all
@@ -73,14 +75,14 @@ sctp_ss_default_clear(struct sctp_tcb *s
        if (holds_lock == 0) {
                SCTP_TCB_SEND_LOCK(stcb);
        }
-       while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
-               struct sctp_stream_out *strq = 
TAILQ_FIRST(&asoc->ss_data.out_wheel);
+       while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
+               struct sctp_stream_out *strq = 
TAILQ_FIRST(&asoc->ss_data.out.wheel);
 
-               TAILQ_REMOVE(&asoc->ss_data.out_wheel, 
TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.rr.next_spoke);
+               TAILQ_REMOVE(&asoc->ss_data.out.wheel, 
TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.rr.next_spoke);
                strq->ss_params.rr.next_spoke.tqe_next = NULL;
                strq->ss_params.rr.next_spoke.tqe_prev = NULL;
        }
-       asoc->last_out_stream = NULL;
+       asoc->ss_data.last_out_stream = NULL;
        if (holds_lock == 0) {
                SCTP_TCB_SEND_UNLOCK(stcb);
        }
@@ -88,8 +90,16 @@ sctp_ss_default_clear(struct sctp_tcb *s
 }
 
 static void
-sctp_ss_default_init_stream(struct sctp_stream_out *strq, struct 
sctp_stream_out *with_strq SCTP_UNUSED)
+sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out 
*strq, struct sctp_stream_out *with_strq)
 {
+       if (with_strq != NULL) {
+               if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
+                       stcb->asoc.ss_data.locked_on_sending = strq;
+               }
+               if (stcb->asoc.ss_data.last_out_stream == with_strq) {
+                       stcb->asoc.ss_data.last_out_stream = strq;
+               }
+       }
        strq->ss_params.rr.next_spoke.tqe_next = NULL;
        strq->ss_params.rr.next_spoke.tqe_prev = NULL;
        return;
@@ -107,7 +117,7 @@ sctp_ss_default_add(struct sctp_tcb *stc
        if (!TAILQ_EMPTY(&strq->outqueue) &&
            (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
            (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
-               TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel,
+               TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
                    strq, ss_params.rr.next_spoke);
        }
        if (holds_lock == 0) {
@@ -119,7 +129,7 @@ sctp_ss_default_add(struct sctp_tcb *stc
 static int
 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct 
sctp_association *asoc)
 {
-       if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
+       if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
                return (1);
        } else {
                return (0);
@@ -141,19 +151,19 @@ sctp_ss_default_remove(struct sctp_tcb *
        if (TAILQ_EMPTY(&strq->outqueue) &&
            (strq->ss_params.rr.next_spoke.tqe_next != NULL ||
            strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
-               if (asoc->last_out_stream == strq) {
-                       asoc->last_out_stream = 
TAILQ_PREV(asoc->last_out_stream,
+               if (asoc->ss_data.last_out_stream == strq) {
+                       asoc->ss_data.last_out_stream = 
TAILQ_PREV(asoc->ss_data.last_out_stream,
                            sctpwheel_listhead,
                            ss_params.rr.next_spoke);
-                       if (asoc->last_out_stream == NULL) {
-                               asoc->last_out_stream = 
TAILQ_LAST(&asoc->ss_data.out_wheel,
+                       if (asoc->ss_data.last_out_stream == NULL) {
+                               asoc->ss_data.last_out_stream = 
TAILQ_LAST(&asoc->ss_data.out.wheel,
                                    sctpwheel_listhead);
                        }
-                       if (asoc->last_out_stream == strq) {
-                               asoc->last_out_stream = NULL;
+                       if (asoc->ss_data.last_out_stream == strq) {
+                               asoc->ss_data.last_out_stream = NULL;
                        }
                }
-               TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, 
ss_params.rr.next_spoke);
+               TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, 
ss_params.rr.next_spoke);
                strq->ss_params.rr.next_spoke.tqe_next = NULL;
                strq->ss_params.rr.next_spoke.tqe_prev = NULL;
        }
@@ -170,15 +180,18 @@ sctp_ss_default_select(struct sctp_tcb *
 {
        struct sctp_stream_out *strq, *strqt;
 
-       strqt = asoc->last_out_stream;
+       if (asoc->ss_data.locked_on_sending) {
+               return (asoc->ss_data.locked_on_sending);
+       }
+       strqt = asoc->ss_data.last_out_stream;
 default_again:
        /* Find the next stream to use */
        if (strqt == NULL) {
-               strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
+               strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
        } else {
                strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
                if (strq == NULL) {
-                       strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to