From owner-svn-src-head@freebsd.org Sat Aug 6 12:33:17 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7402FBAF10F; Sat, 6 Aug 2016 12:33:17 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 0CE671510; Sat, 6 Aug 2016 12:33:16 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u76CXGPt092480; Sat, 6 Aug 2016 12:33:16 GMT (envelope-from tuexen@FreeBSD.org) Received: (from tuexen@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u76CXGUp092475; Sat, 6 Aug 2016 12:33:16 GMT (envelope-from tuexen@FreeBSD.org) Message-Id: <201608061233.u76CXGUp092475@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tuexen set sender to tuexen@FreeBSD.org using -f From: Michael Tuexen Date: Sat, 6 Aug 2016 12:33:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r303792 - head/sys/netinet X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 06 Aug 2016 12:33:17 -0000 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 ***