diff options
author | Randall Stewart <rrs@FreeBSD.org> | 2009-04-04 11:43:32 +0000 |
---|---|---|
committer | Randall Stewart <rrs@FreeBSD.org> | 2009-04-04 11:43:32 +0000 |
commit | 8933fa13b62331282dff2653b8b7c98fdd5113dd (patch) | |
tree | aa1f0e7c08d66758879376d7bd3ed3ff5a7c7bb3 | |
parent | dc60165b73e4c4d829a2cb9fed5cce585e93d9a9 (diff) | |
download | src-8933fa13b62331282dff2653b8b7c98fdd5113dd.tar.gz src-8933fa13b62331282dff2653b8b7c98fdd5113dd.zip |
Many bug fixes (from the IETF hack-fest):
- PR-SCTP had major issues when skipping through a multi-part message.
o Did not look at socket buffer.
o Did not properly handle the reassmebly queue.
o The MARKED segments could interfere and un-skip a chunk causing
a problem with the proper FWD-TSN.
o No FR of FWD-TSN's was being done.
- NR-Sack code was basically disabled. It needed fixes that
never got into the real code.
- CMT code had issues when the two paths were NOT the same b/w. We
found a few small bugs, but also the critcal one here was not
dividing the rwnd amongst the paths.
Obtained from: Michael Tuexen and myself at the IETF hack-fest ;-)
Notes
Notes:
svn path=/head/; revision=190689
-rw-r--r-- | sys/netinet/sctp_indata.c | 332 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 9 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 2052 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 12 | ||||
-rw-r--r-- | sys/netinet/sctp_structs.h | 3 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.c | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.h | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_uio.h | 5 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 6 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 62 |
10 files changed, 365 insertions, 2119 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 0075007d2776..a9f315cb161a 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -423,12 +423,13 @@ abandon: if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) { nr_tsn = chk->rec.data.TSN_seq; - if (nr_tsn >= asoc->nr_mapping_array_base_tsn) { + if ((compare_with_wrap(nr_tsn, asoc->nr_mapping_array_base_tsn, MAX_TSN)) || + (nr_tsn == asoc->nr_mapping_array_base_tsn)) { nr_gap = nr_tsn - asoc->nr_mapping_array_base_tsn; } else { nr_gap = (MAX_TSN - asoc->nr_mapping_array_base_tsn) + nr_tsn + 1; } - if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) || + if ((nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3)) || (nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) { /* * EY The 1st should never happen, as in @@ -440,10 +441,11 @@ abandon: * nr_mapping_array is always expanded when * mapping_array is expanded */ + printf("Impossible nr_gap ack range failed\n"); } else { SCTP_TCB_LOCK_ASSERT(stcb); SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap); - if (nr_tsn > asoc->highest_tsn_inside_nr_map) + if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) asoc->highest_tsn_inside_nr_map = nr_tsn; } } @@ -550,7 +552,9 @@ abandon: } else { SCTP_TCB_LOCK_ASSERT(stcb); SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap); - if (nr_tsn > asoc->highest_tsn_inside_nr_map) + if (compare_with_wrap(nr_tsn, + asoc->highest_tsn_inside_nr_map, + MAX_TSN)) asoc->highest_tsn_inside_nr_map = nr_tsn; } } @@ -699,7 +703,7 @@ protocol_error: } else { SCTP_TCB_LOCK_ASSERT(stcb); SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap); - if (nr_tsn > asoc->highest_tsn_inside_nr_map) + if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) asoc->highest_tsn_inside_nr_map = nr_tsn; } } @@ -760,7 +764,8 @@ protocol_error: } else { SCTP_TCB_LOCK_ASSERT(stcb); SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap); - if (nr_tsn > asoc->highest_tsn_inside_nr_map) + if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map, + MAX_TSN)) asoc->highest_tsn_inside_nr_map = nr_tsn; } } @@ -2390,6 +2395,15 @@ finish_express_del: } SCTP_TCB_LOCK_ASSERT(stcb); SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap); + + if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && + asoc->peer_supports_nr_sack && + (SCTP_BASE_SYSCTL(sctp_do_drain) == 0)) { + SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); + if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) { + asoc->highest_tsn_inside_nr_map = tsn; + } + } /* check the special flag for stream resets */ if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && ((compare_with_wrap(asoc->cumulative_tsn, liste->tsn, MAX_TSN)) || @@ -2498,9 +2512,9 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort int slide_from, slide_end, lgap, distance; /* EY nr_mapping array variables */ - int nr_at; - int nr_last_all_ones = 0; - int nr_slide_from, nr_slide_end, nr_lgap, nr_distance; + /* int nr_at; */ + /* int nr_last_all_ones = 0; */ + /* int nr_slide_from, nr_slide_end, nr_lgap, nr_distance; */ uint32_t old_cumack, old_base, old_highest; unsigned char aux_array[64]; @@ -2683,102 +2697,19 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); } - } - } - /* - * EY if doing nr_sacks then slide the nr_mapping_array accordingly - * please - */ - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) { - - nr_at = 0; - for (nr_slide_from = 0; nr_slide_from < stcb->asoc.nr_mapping_array_size; nr_slide_from++) { - - if (asoc->nr_mapping_array[nr_slide_from] == 0xff) { - nr_at += 8; - nr_last_all_ones = 1; - } else { - /* there is a 0 bit */ - nr_at += sctp_map_lookup_tab[asoc->nr_mapping_array[nr_slide_from]]; - nr_last_all_ones = 0; - break; - } - } - - nr_at++; - - if (compare_with_wrap(asoc->cumulative_tsn, - asoc->highest_tsn_inside_nr_map, MAX_TSN) && (at >= 8)) { - /* The complete array was completed by a single FR */ - /* higest becomes the cum-ack */ - int clr; - - clr = (nr_at >> 3) + 1; - - if (clr > asoc->nr_mapping_array_size) - clr = asoc->nr_mapping_array_size; - - memset(asoc->nr_mapping_array, 0, clr); - /* base becomes one ahead of the cum-ack */ - asoc->nr_mapping_array_base_tsn = asoc->cumulative_tsn + 1; - asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn; - - } else if (nr_at >= 8) { - /* we can slide the mapping array down */ - /* Calculate the new byte postion we can move down */ - /* - * now calculate the ceiling of the move using our - * highest TSN value + * EY if doing nr_sacks then slide the + * nr_mapping_array accordingly please */ - if (asoc->highest_tsn_inside_nr_map >= asoc->nr_mapping_array_base_tsn) { - nr_lgap = asoc->highest_tsn_inside_nr_map - - asoc->nr_mapping_array_base_tsn; - } else { - nr_lgap = (MAX_TSN - asoc->nr_mapping_array_base_tsn) + - asoc->highest_tsn_inside_nr_map + 1; - } - nr_slide_end = nr_lgap >> 3; - if (nr_slide_end < nr_slide_from) { -#ifdef INVARIANTS - panic("impossible slide"); -#else - printf("impossible slide?\n"); - return; -#endif - } - if (nr_slide_end > asoc->nr_mapping_array_size) { -#ifdef INVARIANTS - panic("would overrun buffer"); -#else - printf("Gak, would have overrun map end:%d nr_slide_end:%d\n", - asoc->nr_mapping_array_size, nr_slide_end); - nr_slide_end = asoc->nr_mapping_array_size; -#endif - } - nr_distance = (nr_slide_end - nr_slide_from) + 1; - - if (nr_distance + nr_slide_from > asoc->nr_mapping_array_size || - nr_distance < 0) { - /* - * Here we do NOT slide forward the array so - * that hopefully when more data comes in to - * fill it up we will be able to slide it - * forward. Really I don't think this should - * happen :-0 - */ - ; - } else { - int ii; - - for (ii = 0; ii < nr_distance; ii++) { + if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) { + for (ii = 0; ii < distance; ii++) { asoc->nr_mapping_array[ii] = - asoc->nr_mapping_array[nr_slide_from + ii]; + asoc->nr_mapping_array[slide_from + ii]; } - for (ii = nr_distance; ii <= nr_slide_end; ii++) { + for (ii = distance; ii <= slide_end; ii++) { asoc->nr_mapping_array[ii] = 0; } - asoc->nr_mapping_array_base_tsn += (nr_slide_from << 3); + asoc->nr_mapping_array_base_tsn += (slide_from << 3); } } } @@ -2802,7 +2733,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort * EY if nr_sacks used then send an nr-sack , a sack * otherwise */ - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) + if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack) sctp_send_nr_sack(stcb); else sctp_send_sack(stcb); @@ -3496,9 +3427,13 @@ sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct /* * All chunks NOT UNSENT * fall through here and are - * marked + * marked (leave PR-SCTP + * ones that are to skip + * alone though) */ - tp1->sent = SCTP_DATAGRAM_MARKED; + if (tp1->sent != SCTP_FORWARD_TSN_SKIP) + tp1->sent = SCTP_DATAGRAM_MARKED; + if (tp1->rec.data.chunk_was_revoked) { /* deflate the cwnd */ tp1->whoTo->cwnd -= tp1->book_size; @@ -5798,7 +5733,9 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, } else { SCTP_TCB_LOCK_ASSERT(stcb); SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap); - if (nr_tsn > asoc->highest_tsn_inside_nr_map) + if (compare_with_wrap(nr_tsn, + asoc->highest_tsn_inside_nr_map, + MAX_TSN)) asoc->highest_tsn_inside_nr_map = nr_tsn; } @@ -5901,7 +5838,8 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb, } else { SCTP_TCB_LOCK_ASSERT(stcb); SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap); - if (nr_tsn > asoc->highest_tsn_inside_nr_map) + if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map, + MAX_TSN)) asoc->highest_tsn_inside_nr_map = nr_tsn; } @@ -5963,6 +5901,91 @@ 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, uint16_t seq) +{ + struct sctp_tmit_chunk *chk, *at; + + if (!TAILQ_EMPTY(&asoc->reasmqueue)) { + /* For each one on here see if we need to toss it */ + /* + * For now large messages held on the reasmqueue that are + * complete will be tossed too. We could in theory do more + * work to spin through and stop after dumping one msg aka + * seeing the start of a new msg at the head, and call the + * delivery function... to see if it can be delivered... But + * for now we just dump everything on the queue. + */ + chk = TAILQ_FIRST(&asoc->reasmqueue); + while (chk) { + at = TAILQ_NEXT(chk, sctp_next); + if (chk->rec.data.stream_number != stream) { + chk = at; + continue; + } + if (chk->rec.data.stream_seq == seq) { + /* It needs to be tossed */ + TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next); + if (compare_with_wrap(chk->rec.data.TSN_seq, + asoc->tsn_last_delivered, MAX_TSN)) { + asoc->tsn_last_delivered = + chk->rec.data.TSN_seq; + asoc->str_of_pdapi = + chk->rec.data.stream_number; + asoc->ssn_of_pdapi = + chk->rec.data.stream_seq; + asoc->fragment_flags = + chk->rec.data.rcv_flags; + } + asoc->size_on_reasm_queue -= chk->send_size; + sctp_ucount_decr(asoc->cnt_on_reasm_queue); + + /* Clear up any stream problem */ + if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != + SCTP_DATA_UNORDERED && + (compare_with_wrap(chk->rec.data.stream_seq, + asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered, + MAX_SEQ))) { + /* + * We must dump forward this streams + * sequence number if the chunk is + * not unordered that is being + * skipped. There is a chance that + * if the peer does not include the + * last fragment in its FWD-TSN we + * WILL have a problem here since + * you would have a partial chunk in + * queue that may not be + * deliverable. Also if a Partial + * delivery API as started the user + * may get a partial chunk. The next + * read returning a new chunk... + * really ugly but I see no way + * around it! Maybe a notify?? + */ + asoc->strmin[chk->rec.data.stream_number].last_sequence_delivered = + chk->rec.data.stream_seq; + } + if (chk->data) { + sctp_m_freem(chk->data); + chk->data = NULL; + } + sctp_free_a_chunk(stcb, chk); + } else if (compare_with_wrap(chk->rec.data.stream_seq, seq, MAX_SEQ)) { + /* + * If the stream_seq is > than the purging + * one, we are done + */ + break; + } + chk = at; + } + } +} + + void sctp_handle_forward_tsn(struct sctp_tcb *stcb, struct sctp_forward_tsn_chunk *fwd, int *abort_flag, struct mbuf *m, int offset) @@ -5992,13 +6015,14 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, */ struct sctp_association *asoc; uint32_t new_cum_tsn, gap; - unsigned int i, cnt_gone, fwd_sz, cumack_set_flag, m_size; + unsigned int i, fwd_sz, cumack_set_flag, m_size; + uint32_t str_seq; struct sctp_stream_in *strm; struct sctp_tmit_chunk *chk, *at; + struct sctp_queued_to_read *ctl, *sv; cumack_set_flag = 0; asoc = &stcb->asoc; - cnt_gone = 0; if ((fwd_sz = ntohs(fwd->ch.chunk_length)) < sizeof(struct sctp_forward_tsn_chunk)) { SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size too small/big fwd-tsn\n"); @@ -6102,6 +6126,14 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, SCTP_TCB_LOCK_ASSERT(stcb); for (i = 0; i <= gap; i++) { SCTP_SET_TSN_PRESENT(asoc->mapping_array, i); + /* + * EY if drain is off then every gap-ack is an + * nr-gap-ack + */ + if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack + && SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { + SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i); + } } /* * Now after marking all, slide thing forward but no sack @@ -6152,7 +6184,6 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, } asoc->size_on_reasm_queue -= chk->send_size; sctp_ucount_decr(asoc->cnt_on_reasm_queue); - cnt_gone++; /* Clear up any stream problem */ if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) != @@ -6188,45 +6219,17 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, } else { /* * Ok we have gone beyond the end of the - * fwd-tsn's mark. Some checks... + * fwd-tsn's mark. */ - if ((asoc->fragmented_delivery_inprogress) && - (chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) { - uint32_t str_seq; - - /* - * Special case PD-API is up and - * what we fwd-tsn' over includes - * one that had the LAST_FRAG. We no - * longer need to do the PD-API. - */ - asoc->fragmented_delivery_inprogress = 0; - - str_seq = (asoc->str_of_pdapi << 16) | asoc->ssn_of_pdapi; - sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, - stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq, SCTP_SO_NOT_LOCKED); - - } break; } chk = at; } } - if (asoc->fragmented_delivery_inprogress) { - /* - * Ok we removed cnt_gone chunks in the PD-API queue that - * were being delivered. So now we must turn off the flag. - */ - uint32_t str_seq; - - str_seq = (asoc->str_of_pdapi << 16) | asoc->ssn_of_pdapi; - sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION, - stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq, SCTP_SO_NOT_LOCKED); - asoc->fragmented_delivery_inprogress = 0; - } - /*************************************************************/ - /* 3. Update the PR-stream re-ordering queues */ - /*************************************************************/ + /*******************************************************/ + /* 3. Update the PR-stream re-ordering queues and fix */ + /* delivery issues as needed. */ + /*******************************************************/ fwd_sz -= sizeof(*fwd); if (m && fwd_sz) { /* New method. */ @@ -6235,6 +6238,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, offset += sizeof(*fwd); + SCTP_INP_READ_LOCK(stcb->sctp_ep); num_str = fwd_sz / sizeof(struct sctp_strseq); for (i = 0; i < num_str; i++) { uint16_t st; @@ -6251,11 +6255,49 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, stseq->stream = st; st = ntohs(stseq->sequence); stseq->sequence = st; + /* now process */ + + /* + * Ok we now look for the stream/seq on the read + * queue where its not all delivered. If we find it + * we transmute the read entry into a PDI_ABORTED. + */ if (stseq->stream >= asoc->streamincnt) { /* screwed up streams, stop! */ break; } + if ((asoc->str_of_pdapi == stseq->stream) && + (asoc->ssn_of_pdapi == stseq->sequence)) { + /* + * If this is the one we were partially + * delivering now then we no longer are. + * Note this will change with the reassembly + * re-write. + */ + asoc->fragmented_delivery_inprogress = 0; + } + sctp_flush_reassm_for_str_seq(stcb, asoc, stseq->stream, stseq->sequence); + TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) { + if ((ctl->sinfo_stream == stseq->stream) && + (ctl->sinfo_ssn == stseq->sequence)) { + str_seq = (stseq->stream << 16) | stseq->sequence; + ctl->end_added = 1; + ctl->pdapi_aborted = 1; + sv = stcb->asoc.control_pdapi; + stcb->asoc.control_pdapi = ctl; + sctp_notify_partial_delivery_indication(stcb, + SCTP_PARTIAL_DELIVERY_ABORTED, + SCTP_HOLDS_LOCK, + str_seq); + stcb->asoc.control_pdapi = sv; + break; + } else if ((ctl->sinfo_stream == stseq->stream) && + (compare_with_wrap(ctl->sinfo_ssn, stseq->sequence, MAX_SEQ))) { + /* We are past our victim SSN */ + break; + } + } strm = &asoc->strmin[stseq->stream]; if (compare_with_wrap(stseq->sequence, strm->last_sequence_delivered, MAX_SEQ)) { @@ -6267,6 +6309,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, /* sa_ignore NO_NULL_CHK */ sctp_kick_prsctp_reorder_queue(stcb, strm); } + SCTP_INP_READ_UNLOCK(stcb->sctp_ep); } if (TAILQ_FIRST(&asoc->reasmqueue)) { /* now lets kick out and check for more fragmented delivery */ @@ -7067,7 +7110,8 @@ sctp_handle_nr_sack_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, * fall through here and are * marked */ - tp1->sent = SCTP_DATAGRAM_MARKED; + if (tp1->sent != SCTP_FORWARD_TSN_SKIP) + tp1->sent = SCTP_DATAGRAM_NR_MARKED; if (tp1->rec.data.chunk_was_revoked) { /* deflate the cwnd */ tp1->whoTo->cwnd -= tp1->book_size; @@ -7079,7 +7123,8 @@ sctp_handle_nr_sack_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, * nr_marked */ if (all_bit) { - tp1->sent = SCTP_DATAGRAM_NR_MARKED; + if (tp1->sent != SCTP_FORWARD_TSN_SKIP) + tp1->sent = SCTP_DATAGRAM_NR_MARKED; /* * TAILQ_REMOVE(&asoc * ->sent_queue, @@ -7198,7 +7243,8 @@ sctp_handle_nr_sack_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, while (tp1) { if (tp1->rec.data.TSN_seq == j) { if (tp1->sent != SCTP_DATAGRAM_UNSENT) { - tp1->sent = SCTP_DATAGRAM_NR_MARKED; + if (tp1->sent != SCTP_FORWARD_TSN_SKIP) + tp1->sent = SCTP_DATAGRAM_NR_MARKED; /* * TAILQ_REMOVE(&asoc * ->sent_queue, diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 494929bc0feb..c962e4dfacc1 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -3150,8 +3150,10 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc, (uintptr_t) stcb, tp1->rec.data.TSN_seq); } - sctp_flight_size_decrease(tp1); - sctp_total_flight_decrease(stcb, tp1); + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + sctp_flight_size_decrease(tp1); + sctp_total_flight_decrease(stcb, tp1); + } } { /* audit code */ unsigned int audit; @@ -5606,11 +5608,14 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, /* there was a gap before this data was processed */ was_a_gap = 1; } + stcb->asoc.send_sack = 1; sctp_sack_check(stcb, 1, was_a_gap, &abort_flag); if (abort_flag) { /* Again, we aborted so NO UNLOCK needed */ goto out_now; } + } else if (fwd_tsn_seen) { + stcb->asoc.send_sack = 1; } /* trigger send of any chunks in queue... */ trigger_send: diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 9c5603d1db52..5885474302a3 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -1859,1812 +1859,6 @@ struct sack_track sack_array[256] = { } }; -/* EY below are nr_sacks version of the preceeding two data structures, identical except their names */ -#define SCTP_MAX_NR_GAPS_INARRAY 4 -struct nr_sack_track { - uint8_t right_edge; /* mergable on the right edge */ - uint8_t left_edge; /* mergable on the left edge */ - uint8_t num_entries; - uint8_t spare; - struct sctp_nr_gap_ack_block nr_gaps[SCTP_MAX_NR_GAPS_INARRAY]; -}; - -struct nr_sack_track nr_sack_array[256] = { - {0, 0, 0, 0, /* 0x00 */ - {{0, 0}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x01 */ - {{0, 0}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x02 */ - {{1, 1}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x03 */ - {{0, 1}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x04 */ - {{2, 2}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x05 */ - {{0, 0}, - {2, 2}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x06 */ - {{1, 2}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x07 */ - {{0, 2}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x08 */ - {{3, 3}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x09 */ - {{0, 0}, - {3, 3}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x0a */ - {{1, 1}, - {3, 3}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x0b */ - {{0, 1}, - {3, 3}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x0c */ - {{2, 3}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x0d */ - {{0, 0}, - {2, 3}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x0e */ - {{1, 3}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x0f */ - {{0, 3}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x10 */ - {{4, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x11 */ - {{0, 0}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x12 */ - {{1, 1}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x13 */ - {{0, 1}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x14 */ - {{2, 2}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x15 */ - {{0, 0}, - {2, 2}, - {4, 4}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x16 */ - {{1, 2}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x17 */ - {{0, 2}, - {4, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x18 */ - {{3, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x19 */ - {{0, 0}, - {3, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x1a */ - {{1, 1}, - {3, 4}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x1b */ - {{0, 1}, - {3, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x1c */ - {{2, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x1d */ - {{0, 0}, - {2, 4}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x1e */ - {{1, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x1f */ - {{0, 4}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x20 */ - {{5, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x21 */ - {{0, 0}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x22 */ - {{1, 1}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x23 */ - {{0, 1}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x24 */ - {{2, 2}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x25 */ - {{0, 0}, - {2, 2}, - {5, 5}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x26 */ - {{1, 2}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x27 */ - {{0, 2}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x28 */ - {{3, 3}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x29 */ - {{0, 0}, - {3, 3}, - {5, 5}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x2a */ - {{1, 1}, - {3, 3}, - {5, 5}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x2b */ - {{0, 1}, - {3, 3}, - {5, 5}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x2c */ - {{2, 3}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x2d */ - {{0, 0}, - {2, 3}, - {5, 5}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x2e */ - {{1, 3}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x2f */ - {{0, 3}, - {5, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x30 */ - {{4, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x31 */ - {{0, 0}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x32 */ - {{1, 1}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x33 */ - {{0, 1}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x34 */ - {{2, 2}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x35 */ - {{0, 0}, - {2, 2}, - {4, 5}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x36 */ - {{1, 2}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x37 */ - {{0, 2}, - {4, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x38 */ - {{3, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x39 */ - {{0, 0}, - {3, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x3a */ - {{1, 1}, - {3, 5}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x3b */ - {{0, 1}, - {3, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x3c */ - {{2, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x3d */ - {{0, 0}, - {2, 5}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x3e */ - {{1, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x3f */ - {{0, 5}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x40 */ - {{6, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x41 */ - {{0, 0}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x42 */ - {{1, 1}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x43 */ - {{0, 1}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x44 */ - {{2, 2}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x45 */ - {{0, 0}, - {2, 2}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x46 */ - {{1, 2}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x47 */ - {{0, 2}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x48 */ - {{3, 3}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x49 */ - {{0, 0}, - {3, 3}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x4a */ - {{1, 1}, - {3, 3}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x4b */ - {{0, 1}, - {3, 3}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x4c */ - {{2, 3}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x4d */ - {{0, 0}, - {2, 3}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x4e */ - {{1, 3}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x4f */ - {{0, 3}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x50 */ - {{4, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x51 */ - {{0, 0}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x52 */ - {{1, 1}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x53 */ - {{0, 1}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x54 */ - {{2, 2}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 4, 0, /* 0x55 */ - {{0, 0}, - {2, 2}, - {4, 4}, - {6, 6} - } - }, - {0, 0, 3, 0, /* 0x56 */ - {{1, 2}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x57 */ - {{0, 2}, - {4, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x58 */ - {{3, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x59 */ - {{0, 0}, - {3, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x5a */ - {{1, 1}, - {3, 4}, - {6, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x5b */ - {{0, 1}, - {3, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x5c */ - {{2, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x5d */ - {{0, 0}, - {2, 4}, - {6, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x5e */ - {{1, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x5f */ - {{0, 4}, - {6, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x60 */ - {{5, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x61 */ - {{0, 0}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x62 */ - {{1, 1}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x63 */ - {{0, 1}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x64 */ - {{2, 2}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x65 */ - {{0, 0}, - {2, 2}, - {5, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x66 */ - {{1, 2}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x67 */ - {{0, 2}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x68 */ - {{3, 3}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x69 */ - {{0, 0}, - {3, 3}, - {5, 6}, - {0, 0} - } - }, - {0, 0, 3, 0, /* 0x6a */ - {{1, 1}, - {3, 3}, - {5, 6}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x6b */ - {{0, 1}, - {3, 3}, - {5, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x6c */ - {{2, 3}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x6d */ - {{0, 0}, - {2, 3}, - {5, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x6e */ - {{1, 3}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x6f */ - {{0, 3}, - {5, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x70 */ - {{4, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x71 */ - {{0, 0}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x72 */ - {{1, 1}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x73 */ - {{0, 1}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x74 */ - {{2, 2}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 3, 0, /* 0x75 */ - {{0, 0}, - {2, 2}, - {4, 6}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x76 */ - {{1, 2}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x77 */ - {{0, 2}, - {4, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x78 */ - {{3, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x79 */ - {{0, 0}, - {3, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 2, 0, /* 0x7a */ - {{1, 1}, - {3, 6}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x7b */ - {{0, 1}, - {3, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x7c */ - {{2, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 2, 0, /* 0x7d */ - {{0, 0}, - {2, 6}, - {0, 0}, - {0, 0} - } - }, - {0, 0, 1, 0, /* 0x7e */ - {{1, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 0, 1, 0, /* 0x7f */ - {{0, 6}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0x80 */ - {{7, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x81 */ - {{0, 0}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x82 */ - {{1, 1}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x83 */ - {{0, 1}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x84 */ - {{2, 2}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x85 */ - {{0, 0}, - {2, 2}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x86 */ - {{1, 2}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x87 */ - {{0, 2}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x88 */ - {{3, 3}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x89 */ - {{0, 0}, - {3, 3}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0x8a */ - {{1, 1}, - {3, 3}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x8b */ - {{0, 1}, - {3, 3}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x8c */ - {{2, 3}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x8d */ - {{0, 0}, - {2, 3}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x8e */ - {{1, 3}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x8f */ - {{0, 3}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x90 */ - {{4, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x91 */ - {{0, 0}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0x92 */ - {{1, 1}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x93 */ - {{0, 1}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0x94 */ - {{2, 2}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0x95 */ - {{0, 0}, - {2, 2}, - {4, 4}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0x96 */ - {{1, 2}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x97 */ - {{0, 2}, - {4, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x98 */ - {{3, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x99 */ - {{0, 0}, - {3, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0x9a */ - {{1, 1}, - {3, 4}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x9b */ - {{0, 1}, - {3, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x9c */ - {{2, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0x9d */ - {{0, 0}, - {2, 4}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0x9e */ - {{1, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0x9f */ - {{0, 4}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xa0 */ - {{5, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xa1 */ - {{0, 0}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xa2 */ - {{1, 1}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xa3 */ - {{0, 1}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xa4 */ - {{2, 2}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xa5 */ - {{0, 0}, - {2, 2}, - {5, 5}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0xa6 */ - {{1, 2}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xa7 */ - {{0, 2}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xa8 */ - {{3, 3}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xa9 */ - {{0, 0}, - {3, 3}, - {5, 5}, - {7, 7} - } - }, - {0, 1, 4, 0, /* 0xaa */ - {{1, 1}, - {3, 3}, - {5, 5}, - {7, 7} - } - }, - {1, 1, 4, 0, /* 0xab */ - {{0, 1}, - {3, 3}, - {5, 5}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0xac */ - {{2, 3}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xad */ - {{0, 0}, - {2, 3}, - {5, 5}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0xae */ - {{1, 3}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xaf */ - {{0, 3}, - {5, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xb0 */ - {{4, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xb1 */ - {{0, 0}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xb2 */ - {{1, 1}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xb3 */ - {{0, 1}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xb4 */ - {{2, 2}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xb5 */ - {{0, 0}, - {2, 2}, - {4, 5}, - {7, 7} - } - }, - {0, 1, 3, 0, /* 0xb6 */ - {{1, 2}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xb7 */ - {{0, 2}, - {4, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xb8 */ - {{3, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xb9 */ - {{0, 0}, - {3, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xba */ - {{1, 1}, - {3, 5}, - {7, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xbb */ - {{0, 1}, - {3, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xbc */ - {{2, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xbd */ - {{0, 0}, - {2, 5}, - {7, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xbe */ - {{1, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xbf */ - {{0, 5}, - {7, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xc0 */ - {{6, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xc1 */ - {{0, 0}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xc2 */ - {{1, 1}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xc3 */ - {{0, 1}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xc4 */ - {{2, 2}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xc5 */ - {{0, 0}, - {2, 2}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xc6 */ - {{1, 2}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xc7 */ - {{0, 2}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xc8 */ - {{3, 3}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xc9 */ - {{0, 0}, - {3, 3}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xca */ - {{1, 1}, - {3, 3}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xcb */ - {{0, 1}, - {3, 3}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xcc */ - {{2, 3}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xcd */ - {{0, 0}, - {2, 3}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xce */ - {{1, 3}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xcf */ - {{0, 3}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xd0 */ - {{4, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xd1 */ - {{0, 0}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xd2 */ - {{1, 1}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xd3 */ - {{0, 1}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xd4 */ - {{2, 2}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 4, 0, /* 0xd5 */ - {{0, 0}, - {2, 2}, - {4, 4}, - {6, 7} - } - }, - {0, 1, 3, 0, /* 0xd6 */ - {{1, 2}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xd7 */ - {{0, 2}, - {4, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xd8 */ - {{3, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xd9 */ - {{0, 0}, - {3, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xda */ - {{1, 1}, - {3, 4}, - {6, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xdb */ - {{0, 1}, - {3, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xdc */ - {{2, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xdd */ - {{0, 0}, - {2, 4}, - {6, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xde */ - {{1, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xdf */ - {{0, 4}, - {6, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xe0 */ - {{5, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xe1 */ - {{0, 0}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xe2 */ - {{1, 1}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xe3 */ - {{0, 1}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xe4 */ - {{2, 2}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xe5 */ - {{0, 0}, - {2, 2}, - {5, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xe6 */ - {{1, 2}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xe7 */ - {{0, 2}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xe8 */ - {{3, 3}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xe9 */ - {{0, 0}, - {3, 3}, - {5, 7}, - {0, 0} - } - }, - {0, 1, 3, 0, /* 0xea */ - {{1, 1}, - {3, 3}, - {5, 7}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xeb */ - {{0, 1}, - {3, 3}, - {5, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xec */ - {{2, 3}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xed */ - {{0, 0}, - {2, 3}, - {5, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xee */ - {{1, 3}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xef */ - {{0, 3}, - {5, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xf0 */ - {{4, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xf1 */ - {{0, 0}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xf2 */ - {{1, 1}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xf3 */ - {{0, 1}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xf4 */ - {{2, 2}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 3, 0, /* 0xf5 */ - {{0, 0}, - {2, 2}, - {4, 7}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xf6 */ - {{1, 2}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xf7 */ - {{0, 2}, - {4, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xf8 */ - {{3, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xf9 */ - {{0, 0}, - {3, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 2, 0, /* 0xfa */ - {{1, 1}, - {3, 7}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xfb */ - {{0, 1}, - {3, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xfc */ - {{2, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 2, 0, /* 0xfd */ - {{0, 0}, - {2, 7}, - {0, 0}, - {0, 0} - } - }, - {0, 1, 1, 0, /* 0xfe */ - {{1, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - }, - {1, 1, 1, 0, /* 0xff */ - {{0, 7}, - {0, 0}, - {0, 0}, - {0, 0} - } - } -}; - - int sctp_is_address_in_scope(struct sctp_ifa *ifa, @@ -7920,7 +6114,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, struct sctp_association *asoc, int *num_out, int *reason_code, - int control_only, int *cwnd_full, int from_where, + int control_only, int from_where, struct timeval *now, int *now_filled, int frag_point, int so_locked #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) SCTP_UNUSED @@ -8106,13 +6300,13 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, if (do_chunk_output) sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_NOT_LOCKED); else if (added_control) { - int num_out = 0, reason = 0, cwnd_full = 0, now_filled = 0; + int num_out = 0, reason = 0, now_filled = 0; struct timeval now; int frag_point; frag_point = sctp_get_frag_point(stcb, &stcb->asoc); (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, - &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point, SCTP_SO_NOT_LOCKED); + &reason, 1, 1, &now, &now_filled, frag_point, SCTP_SO_NOT_LOCKED); } no_chunk_output: if (ret) { @@ -9195,7 +7389,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, struct sctp_association *asoc, int *num_out, int *reason_code, - int control_only, int *cwnd_full, int from_where, + int control_only, int from_where, struct timeval *now, int *now_filled, int frag_point, int so_locked #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) SCTP_UNUSED @@ -9211,18 +7405,18 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, * fomulate and send the low level chunks. Making sure to combine * any control in the control chunk queue also. */ - struct sctp_nets *net; + struct sctp_nets *net, *start_at, *old_start_at = NULL; struct mbuf *outchain, *endoutchain; struct sctp_tmit_chunk *chk, *nchk; /* temp arrays for unlinking */ struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; int no_fragmentflg, error; + unsigned int max_rwnd_per_dest; int one_chunk, hbflag, skip_data_for_this_net; int asconf, cookie, no_out_cnt; - int bundle_at, ctl_cnt, no_data_chunks, cwnd_full_ind, eeor_mode; + int bundle_at, ctl_cnt, no_data_chunks, eeor_mode; unsigned int mtu, r_mtu, omtu, mx_mtu, to_out; - struct sctp_nets *start_at, *old_startat = NULL, *send_start_at; int tsns_sent = 0; uint32_t auth_offset = 0; struct sctp_auth_chunk *auth = NULL; @@ -9238,7 +7432,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, int quit_now = 0; *num_out = 0; - cwnd_full_ind = 0; auth_keyid = stcb->asoc.authinfo.active_keyid; if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || @@ -9274,112 +7467,61 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, } if (asoc->peers_rwnd == 0) { /* No room in peers rwnd */ - *cwnd_full = 1; *reason_code = 1; if (asoc->total_flight > 0) { /* we are allowed one chunk in flight */ no_data_chunks = 1; } } + max_rwnd_per_dest = ((asoc->peers_rwnd + asoc->total_flight) / asoc->numnets); if ((no_data_chunks == 0) && (!TAILQ_EMPTY(&asoc->out_wheel))) { - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { - /* - * for CMT we start at the next one past the one we - * last added data to. - */ - if (TAILQ_FIRST(&asoc->send_queue) != NULL) { - goto skip_the_fill_from_streams; - } - if (asoc->last_net_data_came_from) { - net = TAILQ_NEXT(asoc->last_net_data_came_from, sctp_next); - if (net == NULL) { - net = TAILQ_FIRST(&asoc->nets); - } - } else { - /* back to start */ - net = TAILQ_FIRST(&asoc->nets); - } - + TAILQ_FOREACH(net, &asoc->nets, sctp_next) { /* - * JRI-TODO: CMT-MPI. Simply set the first - * destination (net) to be optimized for the next - * message to be pulled out of the outwheel. 1. peek - * at outwheel 2. If large message, set net = - * highest_cwnd 3. If small message, set net = - * lowest rtt + * This for loop we are in takes in each net, if + * its's got space in cwnd and has data sent to it + * (when CMT is off) then it calls + * sctp_fill_outqueue for the net. This gets data on + * the send queue for that network. + * + * In sctp_fill_outqueue TSN's are assigned and data is + * copied out of the stream buffers. Note mostly + * copy by reference (we hope). */ - } else { - net = asoc->primary_destination; - if (net == NULL) { - /* TSNH */ - net = TAILQ_FIRST(&asoc->nets); - } - } - start_at = net; - -one_more_time: - for (; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { net->window_probe = 0; - if (old_startat && (old_startat == net)) { - break; - } - /* - * JRI: if dest is unreachable or unconfirmed, do - * not send data to it - */ if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || (net->dest_state & SCTP_ADDR_UNCONFIRMED)) { - continue; - } - /* - * JRI: if dest is in PF state, do not send data to - * it - */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && - SCTP_BASE_SYSCTL(sctp_cmt_pf) && - (net->dest_state & SCTP_ADDR_PF)) { + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { + sctp_log_cwnd(stcb, net, 1, + SCTP_CWND_LOG_FILL_OUTQ_CALLED); + } continue; } if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) && (net->ref_count < 2)) { /* nothing can be in queue for this guy */ + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { + sctp_log_cwnd(stcb, net, 2, + SCTP_CWND_LOG_FILL_OUTQ_CALLED); + } continue; } if (net->flight_size >= net->cwnd) { - /* skip this network, no room */ - cwnd_full_ind++; + /* skip this network, no room - can't fill */ + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { + sctp_log_cwnd(stcb, net, 3, + SCTP_CWND_LOG_FILL_OUTQ_CALLED); + } continue; } - /* - * JRI : this for loop we are in takes in each net, - * if its's got space in cwnd and has data sent to - * it (when CMT is off) then it calls - * sctp_fill_outqueue for the net. This gets data on - * the send queue for that network. - * - * In sctp_fill_outqueue TSN's are assigned and data is - * copied out of the stream buffers. Note mostly - * copy by reference (we hope). - */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FILL_OUTQ_CALLED); + sctp_log_cwnd(stcb, net, 4, SCTP_CWND_LOG_FILL_OUTQ_CALLED); } sctp_fill_outqueue(stcb, net, frag_point, eeor_mode, &quit_now); if (quit_now) { /* memory alloc failure */ no_data_chunks = 1; - goto skip_the_fill_from_streams; + break; } } - if (start_at != TAILQ_FIRST(&asoc->nets)) { - /* got to pick up the beginning stuff. */ - old_startat = start_at; - start_at = net = TAILQ_FIRST(&asoc->nets); - if (old_startat) - goto one_more_time; - } } -skip_the_fill_from_streams: - *cwnd_full = cwnd_full_ind; - /* now service each destination and send out what we can for it */ /* Nothing to send? */ if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) && @@ -9388,32 +7530,45 @@ skip_the_fill_from_streams: *reason_code = 8; return (0); } - if (no_data_chunks) { - chk = TAILQ_FIRST(&asoc->asconf_send_queue); - if (chk == NULL) - chk = TAILQ_FIRST(&asoc->control_send_queue); - } else { - chk = TAILQ_FIRST(&asoc->send_queue); - } - if (chk) { - send_start_at = chk->whoTo; + if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { + /* get the last start point */ + start_at = asoc->last_net_cmt_send_started; + if (start_at == NULL) { + /* null so to beginning */ + start_at = TAILQ_FIRST(&asoc->nets); + } else { + start_at = TAILQ_NEXT(asoc->last_net_cmt_send_started, sctp_next); + if (start_at == NULL) { + start_at = TAILQ_FIRST(&asoc->nets); + } + } + asoc->last_net_cmt_send_started = start_at; } else { - send_start_at = TAILQ_FIRST(&asoc->nets); + start_at = TAILQ_FIRST(&asoc->nets); } - old_startat = NULL; + old_start_at = NULL; again_one_more_time: - for (net = send_start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { + for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { /* how much can we send? */ /* SCTPDBG("Examine for sending net:%x\n", (uint32_t)net); */ - if (old_startat && (old_startat == net)) { + if (old_start_at && (old_start_at == net)) { /* through list ocmpletely. */ break; } - tsns_sent = 0; - if (net->ref_count < 2) { + tsns_sent = 0xa; + if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) && (net->ref_count < 2)) { /* * Ref-count of 1 so we cannot have data or control - * queued to this address. Skip it. + * queued to this address. Skip it (non-CMT). + */ + continue; + } + if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) && + (TAILQ_FIRST(&asoc->asconf_send_queue) == NULL) && + (net->flight_size >= net->cwnd)) { + /* + * Nothing on control or asconf and flight is full, + * we can skip even in the CMT case. */ continue; } @@ -9885,6 +8040,19 @@ again_one_more_time: } } } + /* JRI: if dest is in PF state, do not send data to it */ + if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && + SCTP_BASE_SYSCTL(sctp_cmt_pf) && + (net->dest_state & SCTP_ADDR_PF)) { + goto no_data_fill; + } + if (net->flight_size >= net->cwnd) { + goto no_data_fill; + } + if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off)) && + (net->flight_size > max_rwnd_per_dest)) { + goto no_data_fill; + } /*********************/ /* Data transmission */ /*********************/ @@ -9920,7 +8088,8 @@ again_one_more_time: omtu = 0; break; } - if ((((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) && (skip_data_for_this_net == 0)) || + if ((((asoc->state & SCTP_STATE_OPEN) == SCTP_STATE_OPEN) && + (skip_data_for_this_net == 0)) || (cookie)) { for (chk = TAILQ_FIRST(&asoc->send_queue); chk; chk = nchk) { if (no_data_chunks) { @@ -9934,7 +8103,18 @@ again_one_more_time: break; } nchk = TAILQ_NEXT(chk, sctp_next); - if (chk->whoTo != net) { + if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { + if (chk->whoTo != net) { + /* + * For CMT, steal the data + * to this network if its + * not set here. + */ + sctp_free_remote_addr(chk->whoTo); + chk->whoTo = net; + atomic_add_int(&chk->whoTo->ref_count, 1); + } + } else if (chk->whoTo != net) { /* No, not sent to this net */ continue; } @@ -10074,6 +8254,7 @@ again_one_more_time: } } /* for (chunk gather loop for this net) */ } /* if asoc.state OPEN */ +no_data_fill: /* Is there something to send for this destination? */ if (outchain) { /* We may need to start a control timer or two */ @@ -10222,10 +8403,10 @@ again_one_more_time: sctp_log_cwnd(stcb, net, tsns_sent, SCTP_CWND_LOG_FROM_SEND); } } - if (old_startat == NULL) { - old_startat = send_start_at; - send_start_at = TAILQ_FIRST(&asoc->nets); - if (old_startat) + if (old_start_at == NULL) { + old_start_at = start_at; + start_at = TAILQ_FIRST(&asoc->nets); + if (old_start_at) goto again_one_more_time; } /* @@ -11270,7 +9451,6 @@ sctp_chunk_output(struct sctp_inpcb *inp, burst_cnt = 0, burst_limit = 0; struct timeval now; int now_filled = 0; - int cwnd_full = 0; int nagle_on = 0; int frag_point = sctp_get_frag_point(stcb, &stcb->asoc); int un_sent = 0; @@ -11321,7 +9501,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, * and then the next call with get the retran's. */ (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, - &cwnd_full, from_where, + from_where, &now, &now_filled, frag_point, so_locked); return; } else if (from_where != SCTP_OUTPUT_FROM_HB_TMR) { @@ -11346,7 +9526,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, * if queued too. */ (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, - &cwnd_full, from_where, + from_where, &now, &now_filled, frag_point, so_locked); #ifdef SCTP_AUDITING_ENABLED sctp_auditing(8, inp, stcb, NULL); @@ -11373,7 +9553,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, sctp_auditing(10, inp, stcb, NULL); #endif /* Push out any control */ - (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, &cwnd_full, from_where, + (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, from_where, &now, &now_filled, frag_point, so_locked); return; } @@ -11444,10 +9624,9 @@ sctp_chunk_output(struct sctp_inpcb *inp, } burst_cnt = 0; - cwnd_full = 0; do { error = sctp_med_chunk_output(inp, stcb, asoc, &num_out, - &reason_code, 0, &cwnd_full, from_where, + &reason_code, 0, from_where, &now, &now_filled, frag_point, so_locked); if (error) { SCTPDBG(SCTP_DEBUG_OUTPUT1, "Error %d was returned from med-c-op\n", error); @@ -11906,7 +10085,11 @@ sctp_send_sack(struct sctp_tcb *stcb) gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)sack + sizeof(struct sctp_sack_chunk)); - siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; + if (asoc->highest_tsn_inside_map > asoc->mapping_array_base_tsn) + siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; + else + siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_map + 7) / 8; + if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) { offset = 1; /*- @@ -12034,7 +10217,7 @@ sctp_send_nr_sack(struct sctp_tcb *stcb) struct sctp_nr_gap_ack_block *nr_gap_descriptor; struct sack_track *selector; - struct nr_sack_track *nr_selector; + struct sack_track *nr_selector; /* EY do we need nr_mergeable, NO */ int mergeable = 0; @@ -12214,9 +10397,12 @@ sctp_send_nr_sack(struct sctp_tcb *stcb) stcb->freed_by_sorcv_sincelast = 0; gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)nr_sack + sizeof(struct sctp_nr_sack_chunk)); - nr_gap_descriptor = (struct sctp_nr_gap_ack_block *)((caddr_t)nr_sack + sizeof(struct sctp_nr_sack_chunk)); - siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; + if (asoc->highest_tsn_inside_map > asoc->mapping_array_base_tsn) + siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; + else + siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_map + 7) / 8; + if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) { offset = 1; /*- @@ -12299,11 +10485,15 @@ sctp_send_nr_sack(struct sctp_tcb *stcb) nr_gap_descriptor = (struct sctp_nr_gap_ack_block *)gap_descriptor; /* EY - there will be gaps + nr_gaps if draining is possible */ - if (SCTP_BASE_SYSCTL(sctp_do_drain)) { + if ((SCTP_BASE_SYSCTL(sctp_do_drain)) && (limit_reached == 0)) { mergeable = 0; - siz = (((asoc->highest_tsn_inside_nr_map - asoc->nr_mapping_array_base_tsn) + 1) + 7) / 8; + if (asoc->highest_tsn_inside_nr_map > asoc->nr_mapping_array_base_tsn) + siz = (((asoc->highest_tsn_inside_nr_map - asoc->nr_mapping_array_base_tsn) + 1) + 7) / 8; + else + siz = (((MAX_TSN - asoc->nr_mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_nr_map + 7) / 8; + if (compare_with_wrap(asoc->nr_mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) { offset = 1; /*- @@ -12322,7 +10512,7 @@ sctp_send_nr_sack(struct sctp_tcb *stcb) if (compare_with_wrap(asoc->highest_tsn_inside_nr_map, asoc->cumulative_tsn, MAX_TSN)) { /* we have a gap .. maybe */ for (i = 0; i < siz; i++) { - nr_selector = &nr_sack_array[asoc->nr_mapping_array[i]]; + nr_selector = &sack_array[asoc->nr_mapping_array[i]]; if (mergeable && nr_selector->right_edge) { /* * Backup, left and right edges were @@ -12348,9 +10538,9 @@ sctp_send_nr_sack(struct sctp_tcb *stcb) * left side */ mergeable = 0; - nr_gap_descriptor->start = htons((nr_selector->nr_gaps[j].start + offset)); + nr_gap_descriptor->start = htons((nr_selector->gaps[j].start + offset)); } - nr_gap_descriptor->end = htons((nr_selector->nr_gaps[j].end + offset)); + nr_gap_descriptor->end = htons((nr_selector->gaps[j].end + offset)); num_nr_gap_blocks++; nr_gap_descriptor++; if (((caddr_t)nr_gap_descriptor + sizeof(struct sctp_nr_gap_ack_block)) > limit) { @@ -12372,7 +10562,7 @@ sctp_send_nr_sack(struct sctp_tcb *stcb) } } } - /*---------------------------------------------------End of---filling the nr_gap_ack blocks----------------------------------------------------*/ + /*---------------------------------------------End of---filling the nr_gap_ack blocks----------------------------------------------------*/ /* now we must add any dups we are going to report. */ if ((limit_reached == 0) && (asoc->numduptsns)) { @@ -15445,7 +13635,7 @@ skip_out_eof: } sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); } else if (some_on_control) { - int num_out, reason, cwnd_full, frag_point; + int num_out, reason, frag_point; /* Here we do control only */ if (hold_tcblock == 0) { @@ -15454,7 +13644,7 @@ skip_out_eof: } frag_point = sctp_get_frag_point(stcb, &stcb->asoc); (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, - &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point, SCTP_SO_LOCKED); + &reason, 1, 1, &now, &now_filled, frag_point, SCTP_SO_LOCKED); } SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d\n", queue_only, stcb->asoc.peers_rwnd, un_sent, diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index d98e760697a8..df519cc2f1d7 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -3157,8 +3157,9 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) SCTP_TCB_UNLOCK(asoc); continue; } - if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_WAIT) || - (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_ECHOED)) { + if (((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_WAIT) || + (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_ECHOED)) && + (asoc->asoc.total_output_queue_size == 0)) { /* * If we have data in queue, we don't want * to just free since the app may have done, @@ -6029,6 +6030,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, stcb->asoc.peer_supports_prsctp = 0; stcb->asoc.peer_supports_pktdrop = 0; stcb->asoc.peer_supports_strreset = 0; + stcb->asoc.peer_supports_nr_sack = 0; stcb->asoc.peer_supports_auth = 0; pr_supported = (struct sctp_supported_chunk_types_param *)phdr; num_ent = plen - sizeof(struct sctp_paramhdr); @@ -6044,6 +6046,12 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, case SCTP_PACKET_DROPPED: stcb->asoc.peer_supports_pktdrop = 1; break; + case SCTP_NR_SELECTIVE_ACK: + if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) + stcb->asoc.peer_supports_nr_sack = 1; + else + stcb->asoc.peer_supports_nr_sack = 0; + break; case SCTP_STREAM_RESET: stcb->asoc.peer_supports_strreset = 1; break; diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index 0d9f67d945dc..24ae10f13882 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -196,6 +196,7 @@ struct sctp_nets { /* smoothed average things for RTT and RTO itself */ int lastsa; int lastsv; + int rtt; /* last measured rtt value in ms */ unsigned int RTO; /* This is used for SHUTDOWN/SHUTDOWN-ACK/SEND or INIT timers */ @@ -677,7 +678,7 @@ struct sctp_association { /* primary destination to use */ struct sctp_nets *primary_destination; /* For CMT */ - struct sctp_nets *last_net_data_came_from; + struct sctp_nets *last_net_cmt_send_started; /* last place I got a data chunk from */ struct sctp_nets *last_data_chunk_from; /* last place I got a control from */ diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index a64aec46ca65..757044640595 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -463,6 +463,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xraddr.cwnd = net->cwnd; xraddr.flight_size = net->flight_size; xraddr.mtu = net->mtu; + /* xraddr.rtt = net->rtt; Not yet */ xraddr.start_time.tv_sec = (uint32_t) net->start_time.tv_sec; xraddr.start_time.tv_usec = (uint32_t) net->start_time.tv_usec; SCTP_INP_RUNLOCK(inp); diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h index dd42d412e4e4..74195682872c 100644 --- a/sys/netinet/sctp_sysctl.h +++ b/sys/netinet/sctp_sysctl.h @@ -74,7 +74,7 @@ struct sctp_sysctl { uint32_t sctp_nr_outgoing_streams_default; uint32_t sctp_cmt_on_off; uint32_t sctp_cmt_use_dac; -/* EY 5/5/08 - nr_sack flag variable */ + /* EY 5/5/08 - nr_sack flag variable */ uint32_t sctp_nr_sack_on_off; uint32_t sctp_cmt_pf; uint32_t sctp_use_cwnd_based_maxburst; diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index b8d2ecdd1897..dc799393a0a5 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -565,9 +565,9 @@ struct sctp_sack_info { struct sctp_cwnd_args { struct sctp_nets *net; /* network to *//* FIXME: LP64 issue */ uint32_t cwnd_new_value;/* cwnd in k */ - uint32_t inflight; /* flightsize in k */ uint32_t pseudo_cumack; - uint32_t cwnd_augment; /* increment to it */ + uint16_t inflight; /* flightsize in k */ + uint16_t cwnd_augment; /* increment to it */ uint8_t meets_pseudo_cumack; uint8_t need_new_pseudo_cumack; uint8_t cnt_in_send; @@ -1042,6 +1042,7 @@ struct xsctp_raddr { uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */ struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */ uint32_t extra_padding[8]; /* future */ + }; #define SCTP_MAX_LOGGING_SIZE 30000 diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index b3bfea596d6c..c80cca0cc8f3 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -126,6 +126,10 @@ sctp_pathmtu_adjustment(struct sctp_inpcb *inp, * since we sent to big of chunk */ chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; + if (chk->sent < SCTP_DATAGRAM_RESEND) { + sctp_flight_size_decrease(chk); + sctp_total_flight_decrease(stcb, chk); + } if (chk->sent != SCTP_DATAGRAM_RESEND) { sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); } @@ -140,8 +144,6 @@ sctp_pathmtu_adjustment(struct sctp_inpcb *inp, } /* Clear any time so NO RTT is being done */ chk->do_rtt = 0; - sctp_flight_size_decrease(chk); - sctp_total_flight_decrease(stcb, chk); } } } diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 42a47ac7964b..aea7376143f4 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -970,7 +970,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, asoc->sent_queue_retran_cnt = 0; /* for CMT */ - asoc->last_net_data_came_from = NULL; + asoc->last_net_cmt_send_started = NULL; /* This will need to be adjusted */ asoc->last_cwr_tsn = asoc->init_seq_number - 1; @@ -1222,33 +1222,25 @@ sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed) SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); asoc->mapping_array = new_array; asoc->mapping_array_size = new_size; - return (0); -} - -/* EY - nr_sack version of the above method */ -int -sctp_expand_nr_mapping_array(struct sctp_association *asoc, uint32_t needed) -{ - /* nr mapping array needs to grow */ - uint8_t *new_array; - uint32_t new_size; - - new_size = asoc->nr_mapping_array_size + ((needed + 7) / 8 + SCTP_NR_MAPPING_ARRAY_INCR); - SCTP_MALLOC(new_array, uint8_t *, new_size, SCTP_M_MAP); - if (new_array == NULL) { - /* can't get more, forget it */ - SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", - new_size); - return (-1); + if (asoc->peer_supports_nr_sack) { + new_size = asoc->nr_mapping_array_size + ((needed + 7) / 8 + SCTP_NR_MAPPING_ARRAY_INCR); + SCTP_MALLOC(new_array, uint8_t *, new_size, SCTP_M_MAP); + if (new_array == NULL) { + /* can't get more, forget it */ + SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", + new_size); + return (-1); + } + memset(new_array, 0, new_size); + memcpy(new_array, asoc->nr_mapping_array, asoc->nr_mapping_array_size); + SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); + asoc->nr_mapping_array = new_array; + asoc->nr_mapping_array_size = new_size; } - memset(new_array, 0, new_size); - memcpy(new_array, asoc->nr_mapping_array, asoc->nr_mapping_array_size); - SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); - asoc->nr_mapping_array = new_array; - asoc->nr_mapping_array_size = new_size; return (0); } + #if defined(SCTP_USE_THREAD_BASED_ITERATOR) static void sctp_iterator_work(struct sctp_iterator *it) @@ -2589,7 +2581,7 @@ sctp_calculate_rto(struct sctp_tcb *stcb, /***************************/ /* 2. update RTTVAR & SRTT */ /***************************/ - o_calctime = calc_time; + net->rtt = o_calctime = calc_time; /* this is Van Jacobson's integer version */ if (net->RTO_measured) { calc_time -= (net->lastsa >> SCTP_RTT_SHIFT); /* take away 1/8th when @@ -4650,18 +4642,12 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, seq = tp1->rec.data.stream_seq; do { ret_sz += tp1->book_size; - tp1->sent = SCTP_FORWARD_TSN_SKIP; if (tp1->data != NULL) { -#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - struct socket *so; - -#endif - printf("Release PR-SCTP chunk tsn:%u flags:%x\n", - tp1->rec.data.TSN_seq, - (unsigned int)tp1->rec.data.rcv_flags); + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + sctp_flight_size_decrease(tp1); + sctp_total_flight_decrease(stcb, tp1); + } sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); - sctp_flight_size_decrease(tp1); - sctp_total_flight_decrease(stcb, tp1); stcb->asoc.peers_rwnd += tp1->send_size; stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked); @@ -4672,6 +4658,7 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, stcb->asoc.sent_queue_cnt_removeable--; } } + tp1->sent = SCTP_FORWARD_TSN_SKIP; if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == SCTP_DATA_NOT_FRAG) { /* not frag'ed we ae done */ @@ -4715,6 +4702,8 @@ next_on_sent: sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked); sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); sctp_m_freem(tp1->data); + /* No flight involved here book the size to 0 */ + tp1->book_size = 0; tp1->data = NULL; if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { foundeom = 1; @@ -4780,6 +4769,7 @@ next_on_sent: chk->pr_sctp_on = 1; TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next); stcb->asoc.sent_queue_cnt++; + stcb->asoc.pr_sctp_cnt++; } else { chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; } @@ -4810,6 +4800,8 @@ next_on_sent: } if (do_wakeup_routine) { #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + struct socket *so; + so = SCTP_INP_SO(stcb->sctp_ep); if (!so_locked) { atomic_add_int(&stcb->asoc.refcnt, 1); |