diff options
Diffstat (limited to 'sys/netinet/sctp_indata.c')
-rw-r--r-- | sys/netinet/sctp_indata.c | 39 |
1 files changed, 27 insertions, 12 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 7a2f42c..357a047 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -753,7 +753,7 @@ sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struc */ struct sctp_tmit_chunk *chk, *lchk, *tchk; uint32_t fsn; - struct sctp_queued_to_read *nc = NULL; + struct sctp_queued_to_read *nc; int cnt_added; if (control->first_frag_seen == 0) { @@ -768,6 +768,11 @@ restart: TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) { if (chk->rec.data.fsn_num == fsn) { /* Ok lets add it */ + sctp_alloc_a_readq(stcb, nc); + if (nc == NULL) { + break; + } + 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); fsn++; @@ -781,7 +786,6 @@ restart: * on the control queue to a new * control. */ - sctp_alloc_a_readq(stcb, nc); sctp_build_readq_entry_from_ctl(nc, control); tchk = TAILQ_FIRST(&control->reasm); if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) { @@ -819,6 +823,7 @@ restart: if (control->on_strm_q) { TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); control->on_strm_q = 0; + SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); } if (control->on_read_q == 0) { sctp_add_to_readq(stcb->sctp_ep, stcb, control, @@ -826,16 +831,19 @@ restart: SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); } sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED); - if ((nc) && (nc->first_frag_seen)) { + if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) { /* * Switch to the new guy and * continue */ control = nc; - nc = NULL; goto restart; + } else { + sctp_free_a_readq(stcb, nc); } return (1); + } else { + sctp_free_a_readq(stcb, nc); } } else { /* Can't add more */ @@ -961,11 +969,6 @@ place_chunk: * should not happen since the FSN is a TSN and it * should have been dropped earlier. */ - if (chk->data) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); sctp_abort_in_reasm(stcb, control, chk, abort_flag, SCTP_FROM_SCTP_INDATA + SCTP_LOC_5); @@ -1026,6 +1029,7 @@ sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc, s control, control->on_strm_q); } #endif + SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm); control->on_strm_q = 0; } @@ -1080,6 +1084,7 @@ done_un: control, control->on_strm_q); } #endif + SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); TAILQ_REMOVE(&strm->inqueue, control, next_instrm); control->on_strm_q = 0; } @@ -1125,6 +1130,7 @@ deliver_more: control, control->on_strm_q); } #endif + SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs); TAILQ_REMOVE(&strm->inqueue, control, next_instrm); control->on_strm_q = 0; } @@ -5277,10 +5283,11 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, } } + static void sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb, struct sctp_association *asoc, - uint16_t stream, uint32_t seq) + uint16_t stream, uint32_t seq, int ordered, int old) { struct sctp_queued_to_read *control; struct sctp_stream_in *strm; @@ -5295,7 +5302,7 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb, * queue. */ strm = &asoc->strmin[stream]; - control = find_reasm_entry(strm, (uint32_t) seq, 0, 0); + control = find_reasm_entry(strm, (uint32_t) seq, ordered, old); if (control == NULL) { /* Not found */ return; @@ -5427,6 +5434,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, unsigned int num_str; uint32_t sequence; uint16_t stream; + uint16_t ordered, flags; int old; struct sctp_strseq *stseq, strseqbuf; struct sctp_strseq_mid *stseq_m, strseqbuf_m; @@ -5452,6 +5460,12 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, } stream = ntohs(stseq_m->stream); sequence = ntohl(stseq_m->msg_id); + flags = ntohs(stseq_m->flags); + if (flags & PR_SCTP_UNORDERED_FLAG) { + ordered = 0; + } else { + ordered = 1; + } } else { stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset, sizeof(struct sctp_strseq), @@ -5462,6 +5476,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, } stream = ntohs(stseq->stream); sequence = (uint32_t) ntohs(stseq->sequence); + ordered = 1; } /* Convert */ @@ -5487,7 +5502,7 @@ 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); + sctp_flush_reassm_for_str_seq(stcb, asoc, stream, sequence, ordered, old); TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) { if ((ctl->sinfo_stream == stream) && (ctl->sinfo_ssn == sequence)) { |