diff options
-rw-r--r-- | sys/netinet/sctp_auth.c | 31 | ||||
-rw-r--r-- | sys/netinet/sctp_constants.h | 8 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.c | 309 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 30 | ||||
-rw-r--r-- | sys/netinet/sctp_os_bsd.h | 7 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 293 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 29 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.h | 24 | ||||
-rw-r--r-- | sys/netinet/sctp_structs.h | 14 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.c | 22 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.h | 64 | ||||
-rw-r--r-- | sys/netinet/sctp_uio.h | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 35 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 26 | ||||
-rw-r--r-- | sys/netinet6/sctp6_usrreq.c | 8 |
15 files changed, 532 insertions, 370 deletions
diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c index 81973b7..999e877 100644 --- a/sys/netinet/sctp_auth.c +++ b/sys/netinet/sctp_auth.c @@ -1413,7 +1413,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, struct sctp_paramhdr *phdr, tmp_param; uint16_t plen, ptype; uint8_t random_store[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_auth_random *random = NULL; + struct sctp_auth_random *p_random = NULL; uint16_t random_len = 0; uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE]; struct sctp_auth_hmac_algo *hmacs = NULL; @@ -1444,8 +1444,8 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, if (phdr == NULL) return; /* save the random and length for the key */ - random = (struct sctp_auth_random *)phdr; - random_len = plen - sizeof(*random); + p_random = (struct sctp_auth_random *)phdr; + random_len = plen - sizeof(*p_random); } else if (ptype == SCTP_HMAC_LIST) { int num_hmacs; int i; @@ -1503,18 +1503,18 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, new_key = sctp_alloc_key(keylen); if (new_key != NULL) { /* copy in the RANDOM */ - if (random != NULL) - bcopy(random->random_data, new_key->key, random_len); + if (p_random != NULL) + bcopy(p_random->random_data, new_key->key, random_len); } #else - keylen = sizeof(*random) + random_len + sizeof(*chunks) + num_chunks + + keylen = sizeof(*p_random) + random_len + sizeof(*chunks) + num_chunks + sizeof(*hmacs) + hmacs_len; new_key = sctp_alloc_key(keylen); if (new_key != NULL) { /* copy in the RANDOM */ - if (random != NULL) { - keylen = sizeof(*random) + random_len; - bcopy(random, new_key->key, keylen); + if (p_random != NULL) { + keylen = sizeof(*p_random) + random_len; + bcopy(p_random, new_key->key, keylen); } /* append in the AUTH chunks */ if (chunks != NULL) { @@ -1829,7 +1829,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit) uint16_t ptype, plen; int peer_supports_asconf = 0; int peer_supports_auth = 0; - int got_random = 0, got_hmacs = 0; + int got_random = 0, got_hmacs = 0, got_chklist = 0; /* go through each of the params. */ phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf)); @@ -1904,6 +1904,10 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit) return (-1); } got_hmacs = 1; + } else if (ptype == SCTP_CHUNK_LIST) { + /* did the peer send a non-empty chunk list? */ + if (plen > 0) + got_chklist = 1; } offset += SCTP_SIZE32(plen); if (offset >= limit) { @@ -1918,6 +1922,13 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit) } else { peer_supports_auth = 0; } + if (!peer_supports_auth && got_chklist) { +#ifdef SCTP_DEBUG + if (sctp_debug_on & SCTP_DEBUG_AUTH1) + printf("SCTP: peer sent chunk list w/o AUTH\n"); +#endif + return (-1); + } if (!sctp_asconf_auth_nochk && peer_supports_asconf && !peer_supports_auth) { #ifdef SCTP_DEBUG diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index f892f9c..97b8c87 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -440,9 +440,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_STICKY_OPTIONS_MASK 0x0c -/* Chunk flags */ -#define SCTP_WINDOW_PROBE 0x01 - /* * SCTP states for internal state machine XXX (should match "user" values) */ @@ -787,7 +784,7 @@ __FBSDID("$FreeBSD$"); * want to take will fill up a full MTU (assuming * a 1500 byte MTU). */ -#define SCTP_DEFAULT_SPLIT_POINT_MIN 1452 +#define SCTP_DEFAULT_SPLIT_POINT_MIN 2904 /* ABORT CODES and other tell-tale location * codes are generated by adding the below @@ -911,6 +908,9 @@ __FBSDID("$FreeBSD$"); #define SCTP_UNSET_TSN_PRESENT(arry, gap) (arry[(gap >> 3)] &= ((~(0x01 << ((gap & 0x07)))) & 0xff)) +#define SCTP_RETRAN_DONE -1 +#define SCTP_RETRAN_EXIT -2 + /* * This value defines the number of vtag block time wait entry's per list * element. Each entry will take 2 4 byte ints (and of course the overhead diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 5786782..462013e 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -3201,7 +3201,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, if (stcb->asoc.peer_supports_prsctp) { if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) { /* Is it expired? */ - if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) { + if ( + (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) + ) { /* Yes so drop it */ if (tp1->data != NULL) { sctp_release_pr_sctp_chunk(stcb, tp1, @@ -3285,7 +3287,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->sent, SCTP_FR_LOG_STRIKE_CHUNK); #endif - tp1->sent++; + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->sent++; + } if (sctp_cmt_on_off && sctp_cmt_use_dac) { /* * CMT DAC algorithm: If SACK flag is set to @@ -3296,7 +3300,11 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * not between two sacked TSNs, then mark by * one more. */ - if ((tp1->sent != SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && + /* + * Jana FIX, does this mean you strike it + * twice (see code above?) + */ + if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && compare_with_wrap(this_sack_lowest_newack, tp1->rec.data.TSN_seq, MAX_TSN)) { #ifdef SCTP_FR_LOGGING sctp_log_fr(16 + num_dests_sacked, @@ -3314,6 +3322,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * biggest_newly_acked must be higher than the * sending_seq at the time we did the FR. */ + if ( #ifdef SCTP_FR_TO_ALTERNATE /* * If FR's go to new networks, then we must only do @@ -3321,11 +3330,12 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * go to the same network (Armando's work) then its * ok to FR multiple times. */ - if (asoc->numnets < 2) + (asoc->numnets < 2) #else - if (1) + (1) #endif - { + ) { + if ((compare_with_wrap(biggest_tsn_newly_acked, tp1->rec.data.fast_retran_tsn, MAX_TSN)) || (biggest_tsn_newly_acked == @@ -3341,7 +3351,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->sent, SCTP_FR_LOG_STRIKE_CHUNK); #endif - tp1->sent++; + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->sent++; + } strike_flag = 1; if (sctp_cmt_on_off && sctp_cmt_use_dac) { /* @@ -3357,15 +3369,20 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * sacked TSNs, then mark by * one more. */ - if ((tp1->sent != SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && - compare_with_wrap(this_sack_lowest_newack, tp1->rec.data.TSN_seq, MAX_TSN)) { + if ((tp1->sent < SCTP_DATAGRAM_RESEND) && + (num_dests_sacked == 1) && + compare_with_wrap(this_sack_lowest_newack, + tp1->rec.data.TSN_seq, MAX_TSN)) { #ifdef SCTP_FR_LOGGING sctp_log_fr(32 + num_dests_sacked, tp1->rec.data.TSN_seq, tp1->sent, SCTP_FR_LOG_STRIKE_CHUNK); #endif - tp1->sent++; + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->sent++; + + } } } } @@ -3390,7 +3407,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->sent, SCTP_FR_LOG_STRIKE_CHUNK); #endif - tp1->sent++; + if (tp1->sent < SCTP_DATAGRAM_RESEND) { + tp1->sent++; + } if (sctp_cmt_on_off && sctp_cmt_use_dac) { /* * CMT DAC algorithm: If SACK flag is set to @@ -3401,7 +3420,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, * not between two sacked TSNs, then mark by * one more. */ - if ((tp1->sent != SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && + if ((tp1->sent < SCTP_DATAGRAM_RESEND) && (num_dests_sacked == 1) && compare_with_wrap(this_sack_lowest_newack, tp1->rec.data.TSN_seq, MAX_TSN)) { #ifdef SCTP_FR_LOGGING sctp_log_fr(48 + num_dests_sacked, @@ -3426,8 +3445,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, /* This is a subsequent FR */ SCTP_STAT_INCR(sctps_sendmultfastretrans); } - sctp_ucount_incr(asoc->sent_queue_retran_cnt); - + sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); if (sctp_cmt_on_off) { /* * CMT: Using RTX_SSTHRESH policy for CMT. @@ -4061,10 +4079,16 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, struct sctp_nets *net; struct sctp_association *asoc; struct sctp_tmit_chunk *tp1, *tp2; + uint32_t old_rwnd; + int win_probe_recovery = 0; int j; SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; + if (compare_with_wrap(asoc->last_acked_seq, cumack, MAX_TSN)) { + /* old ack */ + return; + } /* First setup for CC stuff */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { net->prev_cwnd = net->cwnd; @@ -4116,118 +4140,126 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, #endif } } + old_rwnd = asoc->peers_rwnd; asoc->this_sack_highest_gap = cumack; stcb->asoc.overall_error_count = 0; - /* process the new consecutive TSN first */ - tp1 = TAILQ_FIRST(&asoc->sent_queue); - while (tp1) { - tp2 = TAILQ_NEXT(tp1, sctp_next); - if (compare_with_wrap(cumack, tp1->rec.data.TSN_seq, - MAX_TSN) || - cumack == tp1->rec.data.TSN_seq) { - if (tp1->sent != SCTP_DATAGRAM_UNSENT) { - /* - * ECN Nonce: Add the nonce to the sender's - * nonce sum - */ - asoc->nonce_sum_expect_base += tp1->rec.data.ect_nonce; - if (tp1->sent < SCTP_DATAGRAM_ACKED) { + if (compare_with_wrap(cumack, asoc->last_acked_seq, MAX_TSN)) { + /* process the new consecutive TSN first */ + tp1 = TAILQ_FIRST(&asoc->sent_queue); + while (tp1) { + tp2 = TAILQ_NEXT(tp1, sctp_next); + if (compare_with_wrap(cumack, tp1->rec.data.TSN_seq, + MAX_TSN) || + cumack == tp1->rec.data.TSN_seq) { + if (tp1->sent != SCTP_DATAGRAM_UNSENT) { /* - * If it is less than ACKED, it is - * now no-longer in flight. Higher - * values may occur during marking + * ECN Nonce: Add the nonce to the + * sender's nonce sum */ + asoc->nonce_sum_expect_base += tp1->rec.data.ect_nonce; + if (tp1->sent < SCTP_DATAGRAM_ACKED) { + /* + * If it is less than ACKED, + * it is now no-longer in + * flight. Higher values may + * occur during marking + */ #ifdef SCTP_FLIGHT_LOGGING - sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, - tp1->whoTo->flight_size, - tp1->book_size, - (uintptr_t) stcb, - tp1->rec.data.TSN_seq); + sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN, + tp1->whoTo->flight_size, + tp1->book_size, + (uintptr_t) stcb, + tp1->rec.data.TSN_seq); #endif - if (tp1->whoTo->flight_size >= tp1->book_size) { - tp1->whoTo->flight_size -= tp1->book_size; - } else { - tp1->whoTo->flight_size = 0; - } + if (tp1->whoTo->flight_size >= tp1->book_size) { + tp1->whoTo->flight_size -= tp1->book_size; + } else { + tp1->whoTo->flight_size = 0; + } - if (asoc->total_flight >= tp1->book_size) { - asoc->total_flight -= tp1->book_size; - if (asoc->total_flight_count > 0) - asoc->total_flight_count--; - } else { - asoc->total_flight = 0; - asoc->total_flight_count = 0; - } - tp1->whoTo->net_ack += tp1->send_size; - if (tp1->snd_count < 2) { + if (asoc->total_flight >= tp1->book_size) { + asoc->total_flight -= tp1->book_size; + if (asoc->total_flight_count > 0) + asoc->total_flight_count--; + } else { + asoc->total_flight = 0; + asoc->total_flight_count = 0; + } + tp1->whoTo->net_ack += tp1->send_size; + if (tp1->snd_count < 2) { + /* + * True + * non-retransmited + * chunk + */ + tp1->whoTo->net_ack2 += + tp1->send_size; + + /* update RTO too? */ + if (tp1->do_rtt) { + tp1->whoTo->RTO = + sctp_calculate_rto(stcb, + asoc, tp1->whoTo, + &tp1->sent_rcv_time); + tp1->do_rtt = 0; + } + } /* - * True non-retransmited - * chunk + * CMT: CUCv2 algorithm. + * From the cumack'd TSNs, + * for each TSN being acked + * for the first time, set + * the following variables + * for the corresp + * destination. + * new_pseudo_cumack will + * trigger a cwnd update. + * find_(rtx_)pseudo_cumack + * will trigger search for + * the next expected + * (rtx-)pseudo-cumack. */ - tp1->whoTo->net_ack2 += - tp1->send_size; - - /* update RTO too? */ - if (tp1->do_rtt) { - tp1->whoTo->RTO = - sctp_calculate_rto(stcb, - asoc, tp1->whoTo, - &tp1->sent_rcv_time); - tp1->do_rtt = 0; - } - } - /* - * CMT: CUCv2 algorithm. From the - * cumack'd TSNs, for each TSN being - * acked for the first time, set the - * following variables for the - * corresp destination. - * new_pseudo_cumack will trigger a - * cwnd update. - * find_(rtx_)pseudo_cumack will - * trigger search for the next - * expected (rtx-)pseudo-cumack. - */ - tp1->whoTo->new_pseudo_cumack = 1; - tp1->whoTo->find_pseudo_cumack = 1; - tp1->whoTo->find_rtx_pseudo_cumack = 1; + tp1->whoTo->new_pseudo_cumack = 1; + tp1->whoTo->find_pseudo_cumack = 1; + tp1->whoTo->find_rtx_pseudo_cumack = 1; #ifdef SCTP_CWND_LOGGING - sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK); + sctp_log_cwnd(stcb, tp1->whoTo, tp1->rec.data.TSN_seq, SCTP_CWND_LOG_FROM_SACK); #endif + } + if (tp1->sent == SCTP_DATAGRAM_RESEND) { + sctp_ucount_decr(asoc->sent_queue_retran_cnt); + } + if (tp1->rec.data.chunk_was_revoked) { + /* deflate the cwnd */ + tp1->whoTo->cwnd -= tp1->book_size; + tp1->rec.data.chunk_was_revoked = 0; + } + tp1->sent = SCTP_DATAGRAM_ACKED; } - if (tp1->sent == SCTP_DATAGRAM_RESEND) { - sctp_ucount_decr(asoc->sent_queue_retran_cnt); - } - if (tp1->rec.data.chunk_was_revoked) { - /* deflate the cwnd */ - tp1->whoTo->cwnd -= tp1->book_size; - tp1->rec.data.chunk_was_revoked = 0; - } - tp1->sent = SCTP_DATAGRAM_ACKED; + } else { + break; + } + TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); + if (tp1->data) { + sctp_free_bufspace(stcb, asoc, tp1, 1); + sctp_m_freem(tp1->data); } - } else { - break; - } - TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); - if (tp1->data) { - sctp_free_bufspace(stcb, asoc, tp1, 1); - sctp_m_freem(tp1->data); - } #ifdef SCTP_SACK_LOGGING - sctp_log_sack(asoc->last_acked_seq, - cumack, - tp1->rec.data.TSN_seq, - 0, - 0, - SCTP_LOG_FREE_SENT); + sctp_log_sack(asoc->last_acked_seq, + cumack, + tp1->rec.data.TSN_seq, + 0, + 0, + SCTP_LOG_FREE_SENT); #endif - tp1->data = NULL; - asoc->sent_queue_cnt--; - sctp_free_remote_addr(tp1->whoTo); - sctp_free_a_chunk(stcb, tp1); - tp1 = tp2; + tp1->data = NULL; + asoc->sent_queue_cnt--; + sctp_free_remote_addr(tp1->whoTo); + sctp_free_a_chunk(stcb, tp1); + tp1 = tp2; + } } if (stcb->sctp_socket) { SOCKBUF_LOCK(&stcb->sctp_socket->so_snd); @@ -4241,9 +4273,12 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, #endif } + if (asoc->last_acked_seq != cumack) sctp_cwnd_update(stcb, asoc, 1, 0, 0); + asoc->last_acked_seq = cumack; + if (TAILQ_EMPTY(&asoc->sent_queue)) { /* nothing left in-flight */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { @@ -4312,10 +4347,35 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, /* SWS sender side engages */ asoc->peers_rwnd = 0; } + if (asoc->peers_rwnd > old_rwnd) { + win_probe_recovery = 1; + } /* Now assure a timer where data is queued at */ again: j = 0; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + if (win_probe_recovery && (net->window_probe)) { + net->window_probe = 0; + /* + * Find first chunk that was used with window probe + * and clear the sent + */ + TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { + if (tp1->window_probe) { + /* move back to data send queue */ + tp1->sent = SCTP_DATAGRAM_UNSENT; + tp1->window_probe = 0; + net->flight_size -= tp1->book_size; + asoc->total_flight -= tp1->book_size; + TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); + TAILQ_INSERT_HEAD(&asoc->send_queue, tp1, sctp_next); + asoc->sent_queue_cnt--; + asoc->send_queue_cnt++; + asoc->total_flight_count--; + break; + } + } + } if (net->flight_size) { int to_ticks; @@ -4474,7 +4534,8 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, long j; int accum_moved = 0; int will_exit_fast_recovery = 0; - uint32_t a_rwnd; + uint32_t a_rwnd, old_rwnd; + int win_probe_recovery = 0; struct sctp_nets *net = NULL; int nonce_sum_flag, ecn_seg_sums = 0; uint8_t reneged_all = 0; @@ -4526,7 +4587,7 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, cmt_dac_flag = ch->ch.chunk_flags & SCTP_SACK_CMT_DAC; num_dup = ntohs(sack->num_dup_tsns); - + old_rwnd = stcb->asoc.peers_rwnd; stcb->asoc.overall_error_count = 0; asoc = &stcb->asoc; #ifdef SCTP_SACK_LOGGING @@ -5323,6 +5384,9 @@ done_with_it: /* SWS sender side engages */ asoc->peers_rwnd = 0; } + if (asoc->peers_rwnd > old_rwnd) { + win_probe_recovery = 1; + } /* * Now we must setup so we have a timer up for anyone with * outstanding data. @@ -5330,6 +5394,29 @@ done_with_it: again: j = 0; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { + if (win_probe_recovery && (net->window_probe)) { + net->window_probe = 0; + /*- + * Find first chunk that was used with + * window probe and clear the event. Put + * it back into the send queue as if has + * not been sent. + */ + TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { + if (tp1->window_probe) { + tp1->sent = SCTP_DATAGRAM_UNSENT; + tp1->window_probe = 0; + net->flight_size -= tp1->book_size; + asoc->total_flight -= tp1->book_size; + TAILQ_REMOVE(&asoc->sent_queue, tp1, sctp_next); + TAILQ_INSERT_HEAD(&asoc->send_queue, tp1, sctp_next); + asoc->sent_queue_cnt--; + asoc->send_queue_cnt++; + asoc->total_flight_count--; + break; + } + } + } if (net->flight_size) { j++; sctp_timer_start(SCTP_TIMER_TYPE_SEND, diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 2317cea..b5bbb34 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -1313,7 +1313,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { if (chk->sent < SCTP_DATAGRAM_RESEND) { chk->sent = SCTP_DATAGRAM_RESEND; - stcb->asoc.sent_queue_retran_cnt++; + sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); spec_flag++; } } @@ -4702,9 +4702,6 @@ sctp_input(i_pak, off) SCTP_STAT_INCR(sctps_recvpackets); SCTP_STAT_INCR_COUNTER64(sctps_inpackets); - /* - * Strip IP options, we don't allow any in or out. - */ #ifdef SCTP_MBUF_LOGGING /* Log in any input mbufs */ mat = m; @@ -4715,10 +4712,7 @@ sctp_input(i_pak, off) mat = SCTP_BUF_NEXT(mat); } #endif - if ((size_t)iphlen > sizeof(struct ip)) { - ip_stripoptions(m, (struct mbuf *)0); - iphlen = sizeof(struct ip); - } + /* * Get IP, SCTP, and first chunk header together in first mbuf. */ @@ -4738,23 +4732,15 @@ sctp_input(i_pak, off) if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { goto bad; } - if (((ch->chunk_type == SCTP_INITIATION) || - (ch->chunk_type == SCTP_INITIATION_ACK) || - (ch->chunk_type == SCTP_COOKIE_ECHO)) && - (SCTP_IS_IT_BROADCAST(ip->ip_dst, i_pak))) { + if (SCTP_IS_IT_BROADCAST(ip->ip_dst, m)) { /* * We only look at broadcast if its a front state, All * others we will not have a tcb for anyway. */ goto bad; } - /* destination port of 0 is illegal, based on RFC2960. */ - if (sh->dest_port == 0) { - SCTP_STAT_INCR(sctps_hdrops); - goto bad; - } /* validate SCTP checksum */ - if ((sctp_no_csum_on_loopback == 0) || !SCTP_IS_IT_LOOPBACK(i_pak)) { + if ((sctp_no_csum_on_loopback == 0) || !SCTP_IS_IT_LOOPBACK(m)) { /* * we do NOT validate things from the loopback if the sysctl * is set to 1. @@ -4795,7 +4781,13 @@ sctp_input(i_pak, off) sh->checksum = calc_check; } else { sctp_skip_csum_4: - mlen = SCTP_HEADER_LEN(i_pak); + mlen = SCTP_HEADER_LEN(m); + } + + /* destination port of 0 is illegal, based on RFC2960. */ + if (sh->dest_port == 0) { + SCTP_STAT_INCR(sctps_hdrops); + goto bad; } /* validate mbuf chain length with IP payload length */ if (mlen < (ip->ip_len - iphlen)) { diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index e1b7a1f..e74ccfa 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -201,6 +201,13 @@ typedef struct callout sctp_os_timer_t; #define SCTP_BUF_TYPE(m) (m->m_type) #define SCTP_BUF_RECVIF(m) (m->m_pkthdr.rcvif) #define SCTP_BUF_PREPEND M_PREPEND + +#define SCTP_ALIGN_TO_END(m, len) if(m->m_flags & M_PKTHDR) { \ + MH_ALIGN(m, len); \ + } else if ((m->m_flags & M_EXT) == 0) { \ + M_ALIGN(m, len); \ + } + /*************************/ /* These are for logging */ /*************************/ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index b23edb3..416ab64 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3445,6 +3445,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, sctp_m_freem(m); return (ENOMEM); } + SCTP_ALIGN_TO_END(o_pak, sizeof(struct ip)); SCTP_BUF_LEN(SCTP_HEADER_TO_CHAIN(o_pak)) = sizeof(struct ip); packet_length += sizeof(struct ip); SCTP_ATTACH_CHAIN(o_pak, m, packet_length); @@ -3670,6 +3671,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, sctp_m_freem(m); return (ENOMEM); } + SCTP_ALIGN_TO_END(o_pak, sizeof(struct ip6_hdr)); + SCTP_BUF_LEN(SCTP_HEADER_TO_CHAIN(o_pak)) = sizeof(struct ip6_hdr); packet_length += sizeof(struct ip6_hdr); SCTP_ATTACH_CHAIN(o_pak, m, packet_length); @@ -6019,9 +6022,6 @@ all_done: (bundle_at == 1)) { /* Mark the chunk as being a window probe */ SCTP_STAT_INCR(sctps_windowprobed); - data_list[i]->rec.data.state_flags |= SCTP_WINDOW_PROBE; - } else { - data_list[i]->rec.data.state_flags &= ~SCTP_WINDOW_PROBE; } #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xC2, 3); @@ -6102,6 +6102,10 @@ sctp_can_we_split_this(struct sctp_tcb *stcb, /* you don't want enough */ return (0); } + if ((sp->length <= goal_mtu) || ((sp->length - goal_mtu) < sctp_min_residual)) { + /* Sub-optimial residual don't split */ + return (0); + } if (sp->msg_is_complete == 0) { if (eeor_on) { /* @@ -6186,18 +6190,21 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, panic("sp length is 0?"); } some_taken = sp->some_taken; - if ((goal_mtu >= sp->length) && (sp->msg_is_complete)) { - /* It all fits and its a complete msg, no brainer */ + if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { + sp->msg_is_complete = 1; + } + if (sp->msg_is_complete) { + /* The message is complete */ to_move = min(sp->length, frag_point); if (to_move == sp->length) { - /* Getting it all */ + /* All of it fits in the MTU */ if (sp->some_taken) { rcv_flags |= SCTP_DATA_LAST_FRAG; } else { rcv_flags |= SCTP_DATA_NOT_FRAG; } } else { - /* Not getting it all, frag point overrides */ + /* Not all of it fits, we fragment */ if (sp->some_taken == 0) { rcv_flags |= SCTP_DATA_FIRST_FRAG; } @@ -6562,7 +6569,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb, } } total_moved += moved_how_much; - goal_mtu -= moved_how_much; + goal_mtu -= (moved_how_much + sizeof(struct sctp_data_chunk)); goal_mtu &= 0xfffffffc; } if (total_moved == 0) { @@ -6724,6 +6731,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, 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; } @@ -7106,9 +7114,9 @@ again_one_more_time: continue; } if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) { - /* + /*- * strange, we have a chunk that is - * to bit for its destination and + * to big for its destination and * yet no fragment ok flag. * Something went wrong when the * PMTU changed...we did not mark @@ -7178,12 +7186,13 @@ again_one_more_time: to_out += chk->send_size; if (to_out > mx_mtu) { #ifdef INVARIANTS - panic("gag"); + panic("Exceeding mtu of %d out size is %d", mx_mtu, to_out); #else printf("Exceeding mtu of %d out size is %d\n", mx_mtu, to_out); #endif } + chk->window_probe = 0; data_list[bundle_at++] = chk; if (bundle_at >= SCTP_MAX_DATA_BUNDLING) { mtu = 0; @@ -7209,6 +7218,10 @@ again_one_more_time: SCTP_STAT_INCR_COUNTER64(sctps_fragusrmsgs); } if ((mtu == 0) || (r_mtu == 0) || (one_chunk)) { + if (one_chunk) { + data_list[0]->window_probe = 1; + net->window_probe = 1; + } break; } } else { @@ -7218,7 +7231,7 @@ again_one_more_time: */ break; } - } /* for () */ + } /* for (chunk gather loop for this net) */ } /* if asoc.state OPEN */ /* Is there something to send for this destination? */ if (outchain) { @@ -7252,7 +7265,9 @@ again_one_more_time: shdr->v_tag = htonl(stcb->asoc.peer_vtag); shdr->checksum = 0; auth_offset += sizeof(struct sctphdr); - if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, + if ((error = sctp_lowlevel_chunk_output(inp, + stcb, + net, (struct sockaddr *)&net->ro._l_addr, outchain, auth_offset, @@ -7293,7 +7308,15 @@ again_one_more_time: sctp_move_to_an_alt(stcb, asoc, net); } *reason_code = 6; - continue; + /*- + * I add this line to be paranoid. As far as + * I can tell the continue, takes us back to + * the top of the for, but just to make sure + * I will reset these again here. + */ + ctl_cnt = bundle_at = 0; + continue; /* This takes us back to the + * for() for the nets. */ } else { asoc->ifp_had_enobuf = 0; } @@ -7371,7 +7394,7 @@ again_one_more_time: void sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) { - /* + /*- * Prepend a OPERATIONAL_ERROR chunk header and put on the end of * the control chunk queue. */ @@ -7423,7 +7446,7 @@ sctp_send_cookie_echo(struct mbuf *m, struct sctp_tcb *stcb, struct sctp_nets *net) { - /* + /*- * pull out the cookie and put it at the front of the control chunk * queue. */ @@ -7812,12 +7835,12 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, struct sctp_association *asoc, int *cnt_out, struct timeval *now, int *now_filled, int *fr_done) { - /* + /*- * send out one MTU of retransmission. If fast_retransmit is * happening we ignore the cwnd. Otherwise we obey the cwnd and * rwnd. For a Cookie or Asconf in the control chunk queue we * retransmit them by themselves. - * + * * For data chunks we will pick out the lowest TSN's in the sent_queue * marked for resend and bundle them all together (up to a MTU of * destination). The address to send to should have been @@ -7950,7 +7973,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, * fwd-tsn with it all. */ if (TAILQ_EMPTY(&asoc->sent_queue)) { - return (-1); + return (SCTP_RETRAN_DONE); } if ((SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) || (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_WAIT)) { @@ -7966,6 +7989,18 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, continue; } + if ((sctp_max_retran_chunk) && (chk->snd_count >= sctp_max_retran_chunk)) { + /* Gak, we have exceeded max unlucky retran, abort! */ + +#ifdef SCTP_DEBUG + printf("Gak, chk->snd_count:%d >= max:%d - send abort\n", + chk->snd_count, + sctp_max_retran_chunk); +#endif + sctp_send_abort_tcb(stcb, NULL); + sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); + return (SCTP_RETRAN_EXIT); + } /* pick up the net */ net = chk->whoTo; if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { @@ -7993,6 +8028,11 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, one_chunk_around: if (asoc->peers_rwnd < mtu) { one_chunk = 1; + if ((asoc->peers_rwnd == 0) && + (asoc->total_flight == 0)) { + chk->window_probe = 1; + chk->whoTo->window_probe = 1; + } } #ifdef SCTP_AUDITING_ENABLED sctp_audit_log(0xC3, 2); @@ -8056,7 +8096,6 @@ one_chunk_around: data_list[bundle_at++] = chk; if (one_chunk && (asoc->total_flight <= 0)) { SCTP_STAT_INCR(sctps_windowprobed); - chk->rec.data.state_flags |= SCTP_WINDOW_PROBE; } } if (one_chunk == 0) { @@ -8193,9 +8232,6 @@ one_chunk_around: sctp_ucount_decr(asoc->sent_queue_retran_cnt); /* record the time */ data_list[i]->sent_rcv_time = asoc->time_last_sent; - if (asoc->sent_queue_retran_cnt < 0) { - asoc->sent_queue_retran_cnt = 0; - } if (data_list[i]->book_size_scale) { /* * need to double the book size on @@ -8240,7 +8276,7 @@ one_chunk_around: SCTP_STAT_INCR(sctps_sendfastretrans); if ((data_list[i] == TAILQ_FIRST(&asoc->sent_queue)) && (tmr_started == 0)) { - /* + /*- * ok we just fast-retrans'd * the lowest TSN, i.e the * first on the list. In @@ -8312,7 +8348,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_where) { - /* + /*- * Ok this is the generic chunk service queue. we must do the * following: - See if there are retransmits pending, if so we must * do these first and return. - Service the stream queue that is @@ -8361,15 +8397,15 @@ sctp_chunk_output(struct sctp_inpcb *inp, SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer); } while (asoc->sent_queue_retran_cnt) { - /* + /*- * Ok, it is retransmission time only, we send out only ONE * packet with a single call off to the retran code. */ if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) { - /* - * Special hook for handling cookiess discarded by - * peer that carried data. Send cookie-ack only and - * then the next call with get the retran's. + /*- + *Special hook for handling cookiess discarded + * by peer that carried data. Send cookie-ack only + * 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, @@ -8391,7 +8427,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, } if (ret > 0) { /* Can't send anymore */ - /* + /*- * now lets push out control by calling med-level * output once. this assures that we WILL send HB's * if queued too. @@ -8405,13 +8441,16 @@ sctp_chunk_output(struct sctp_inpcb *inp, return (sctp_timer_validation(inp, stcb, asoc, ret)); } if (ret < 0) { - /* + /*- * The count was off.. retran is not happening so do * the normal retransmission. */ #ifdef SCTP_AUDITING_ENABLED sctp_auditing(9, inp, stcb, NULL); #endif + if (ret == SCTP_RETRAN_EXIT) { + return (-1); + } break; } if (from_where == SCTP_OUTPUT_FROM_T3) { @@ -8442,7 +8481,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, TAILQ_FOREACH(net, &asoc->nets, sctp_next) { if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == SCTP_ADDR_NOT_REACHABLE) { - /* + /*- * if possible move things off of this address we * still may send below due to the dormant state but * we try to find an alternate address to send to @@ -8452,7 +8491,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, if (net->ref_count > 1) sctp_move_to_an_alt(stcb, asoc, net); } else { - /* + /*- * if ((asoc->sat_network) || (net->addr_is_local)) * { burst_limit = asoc->max_burst * * SCTP_SAT_NETWORK_BURST_INCR; } @@ -8521,10 +8560,10 @@ sctp_chunk_output(struct sctp_inpcb *inp, } #endif if (nagle_on) { - /* - * When nagle is on, we look at how much is un_sent, - * then if its smaller than an MTU and we have data - * in flight we stop. + /*- + * When nagle is on, we look at how much is un_sent, then + * if its smaller than an MTU and we have data in + * flight we stop. */ un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + ((stcb->asoc.chunks_on_out_queue - stcb->asoc.total_flight_count) @@ -8566,7 +8605,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, printf("Ok, we have put out %d chunks\n", tot_out); } #endif - /* + /*- * Now we need to clean up the control chunk chain if a ECNE is on * it. It must be marked as UNSENT again so next call will continue * to send it until such time that we get a CWR, to remove it. @@ -8647,7 +8686,7 @@ send_forward_tsn(struct sctp_tcb *stcb, TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next); asoc->ctrl_queue_cnt++; sctp_fill_in_rest: - /* + /*- * Here we go through and fill out the part that deals with * stream/seq of the ones we skip. */ @@ -8685,14 +8724,14 @@ sctp_fill_in_rest: cnt_of_space = asoc->smallest_mtu - ovh; } if (cnt_of_space < space_needed) { - /* + /*- * ok we must trim down the chunk by lowering the * advance peer ack point. */ cnt_of_skipped = (cnt_of_space - ((sizeof(struct sctp_forward_tsn_chunk)) / sizeof(struct sctp_strseq))); - /* + /*- * Go through and find the TSN that will be the one * we report. */ @@ -8702,7 +8741,7 @@ sctp_fill_in_rest: at = tp1; } last = at; - /* + /*- * last now points to last one I can report, update * peer ack point */ @@ -8720,12 +8759,12 @@ sctp_fill_in_rest: (cnt_of_skipped * sizeof(struct sctp_strseq))); SCTP_BUF_LEN(chk->data) = chk->send_size; fwdtsn++; - /* + /*- * Move pointer to after the fwdtsn and transfer to the * strseq pointer. */ strseq = (struct sctp_strseq *)fwdtsn; - /* + /*- * Now populate the strseq list. This is done blindly * without pulling out duplicate stream info. This is * inefficent but won't harm the process since the peer will @@ -8759,7 +8798,7 @@ sctp_fill_in_rest: void sctp_send_sack(struct sctp_tcb *stcb) { - /* + /*- * Queue up a SACK in the control queue. We must first check to see * if a SACK is somehow on the control queue. If so, we will take * and and remove the old one. @@ -8833,7 +8872,7 @@ sctp_send_sack(struct sctp_tcb *stcb) if ((asoc->numduptsns) || (asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE) ) { - /* + /*- * Ok, we have some duplicates or the destination for the * sack is unreachable, lets see if we can select an * alternate than asoc->last_data_chunk_from @@ -8913,7 +8952,7 @@ sctp_send_sack(struct sctp_tcb *stcb) sack->ch.chunk_flags = 0; if (sctp_cmt_on_off && sctp_cmt_use_dac) { - /* + /*- * CMT DAC algorithm: If 2 (i.e., 0x10) packets have been * received, then set high bit to 1, else 0. Reset * pkts_rcvd. @@ -8934,14 +8973,14 @@ sctp_send_sack(struct sctp_tcb *stcb) siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; if (asoc->cumulative_tsn < asoc->mapping_array_base_tsn) { offset = 1; - /* + /*- * cum-ack behind the mapping array, so we start and use all * entries. */ jstart = 0; } else { offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn; - /* + /*- * we skip the first one when the cum-ack is at or above the * mapping array base. */ @@ -9046,7 +9085,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr) struct sctp_auth_chunk *auth = NULL; struct sctphdr *shdr; - /* + /*- * Add an AUTH chunk, if chunk requires it and save the offset into * the chain for AUTH */ @@ -9290,7 +9329,7 @@ sctp_select_hb_destination(struct sctp_tcb *stcb, struct timeval *now) } else /* Never been sent to */ ms_goneby = 0x7fffffff; - /* + /*- * When the address state is unconfirmed but still * considered reachable, we HB at a higher rate. Once it * goes confirmed OR reaches the "unreachable" state, thenw @@ -9316,7 +9355,7 @@ sctp_select_hb_destination(struct sctp_tcb *stcb, struct timeval *now) } if (highest_ms && (((unsigned int)highest_ms >= hnet->RTO) || state_overide)) { - /* + /*- * Found the one with longest delay bounds OR it is * unconfirmed and still not marked unreachable. */ @@ -9352,7 +9391,7 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net) if (user_req == 0) { net = sctp_select_hb_destination(stcb, &now); if (net == NULL) { - /* + /*- * All our busy none to send to, just start the * timer again. */ @@ -9447,12 +9486,12 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net) if (sctp_threshold_management(stcb->sctp_ep, stcb, net, stcb->asoc.max_send_times)) { - /* - * we have lost the association, in a way this is quite bad - * since we really are one less time since we really did not - * send yet. This is the down side to the Q's style as - * defined in the RFC and not my alternate style defined in - * the RFC. + /*- + * we have lost the association, in a way this is + * quite bad since we really are one less time since + * we really did not send yet. This is the down side + * to the Q's style as defined in the RFC and not my + * alternate style defined in the RFC. */ atomic_subtract_int(&chk->whoTo->ref_count, 1); if (chk->data != NULL) { @@ -9466,7 +9505,7 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net) TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); stcb->asoc.ctrl_queue_cnt++; SCTP_STAT_INCR(sctps_sendheartbeat); - /* + /*- * Call directly med level routine to put out the chunk. It will * always tumble out control chunks aka HB but it may even tumble * out data too. @@ -9541,7 +9580,7 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, asoc = &stcb->asoc; SCTP_TCB_LOCK_ASSERT(stcb); if (asoc->peer_supports_pktdrop == 0) { - /* + /*- * peer must declare support before I send one. */ return; @@ -9631,7 +9670,7 @@ jump_out: asoc->my_rwnd_control_len + stcb->sctp_socket->so_rcv.sb_cc); } else { - /* + /*- * If my rwnd is 0, possibly from mbuf depletion as well as * space used, tell the peer there is NO space aka onq == bw */ @@ -9723,7 +9762,7 @@ sctp_add_stream_reset_out(struct sctp_tmit_chunk *chk, } } if (SCTP_SIZE32(len) > len) { - /* + /*- * Need to worry about the pad we may end up adding to the * end. This is easy since the struct is either aligned to 4 * bytes or 2 bytes off. @@ -9767,7 +9806,7 @@ sctp_add_stream_reset_in(struct sctp_tmit_chunk *chk, } } if (SCTP_SIZE32(len) > len) { - /* + /*- * Need to worry about the pad we may end up adding to the * end. This is easy since the struct is either aligned to 4 * bytes or 2 bytes off. @@ -9897,7 +9936,7 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, asoc = &stcb->asoc; if (asoc->stream_reset_outstanding) { - /* + /*- * Already one pending, must get ACK back to clear the flag. */ return (EBUSY); @@ -9972,7 +10011,7 @@ void sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, struct mbuf *err_cause) { - /* + /*- * Formulate the abort message, and send it back down. */ struct mbuf *o_pak; @@ -10345,7 +10384,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp, if (m == NULL) { return (ENOMEM); } - /* + /*- * Add this one for m in now, that way if the alloc fails we won't * have a bad cnt. */ @@ -10398,7 +10437,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb, int *error, int non_blocking) { - /* + /*- * This routine must be very careful in its work. Protocol * processing is up and running so care must be taken to spl...() * when you need to do something that may effect the stcb/asoc. The @@ -10614,9 +10653,10 @@ sctp_lower_sosend(struct socket *so, } hold_tcblock = 0; } else if (addr) { - /* - * Since we did not use findep we must increment it, and if - * we don't find a tcb decrement it. + /*- + * Since we did not use findep we must + * increment it, and if we don't find a tcb + * decrement it. */ SCTP_INP_WLOCK(inp); SCTP_INP_INCR_REF(inp); @@ -10677,7 +10717,7 @@ sctp_lower_sosend(struct socket *so, ((srcv->sinfo_flags & SCTP_ABORT) || ((srcv->sinfo_flags & SCTP_EOF) && (uio->uio_resid == 0)))) { - /* + /*- * User asks to abort a non-existant assoc, * or EOF a non-existant assoc with no data */ @@ -10770,26 +10810,20 @@ sctp_lower_sosend(struct socket *so, } } for (i = 0; i < asoc->streamoutcnt; i++) { - /* - * inbound side must - * be set to 0xffff, - * also NOTE when we - * get the INIT-ACK - * back (for INIT - * sender) we MUST + /*- + * inbound side must be set + * to 0xffff, also NOTE when + * we get the INIT-ACK back + * (for INIT sender) we MUST * reduce the count - * (streamoutcnt) - * but first check - * if we sent to any - * of the upper - * streams that were - * dropped (if some - * were). Those that - * were dropped must - * be notified to - * the upper layer - * as failed to - * send. + * (streamoutcnt) but first + * check if we sent to any + * of the upper streams that + * were dropped (if some + * were). Those that were + * dropped must be notified + * to the upper layer as + * failed to send. */ asoc->strmout[i].next_sequence_sent = 0x0; TAILQ_INIT(&asoc->strmout[i].outqueue); @@ -10804,12 +10838,11 @@ sctp_lower_sosend(struct socket *so, hold_tcblock = 1; /* out with the INIT */ queue_only_for_init = 1; - /* - * we may want to dig in after this call and adjust - * the MTU value. It defaulted to 1500 (constant) - * but the ro structure may now have an update and - * thus we may need to change it BEFORE we append - * the message. + /*- + * we may want to dig in after this call and adjust the MTU + * value. It defaulted to 1500 (constant) but the ro + * structure may now have an update and thus we may need to + * change it BEFORE we append the message. */ net = stcb->asoc.primary_destination; asoc = &stcb->asoc; @@ -10889,7 +10922,7 @@ sctp_lower_sosend(struct socket *so, } } if ((net->flight_size > net->cwnd) && (sctp_cmt_on_off == 0)) { - /* + /*- * CMT: Added check for CMT above. net above is the primary * dest. If CMT is ON, sender should always attempt to send * with the output routine sctp_fill_outqueue() that loops @@ -10964,7 +10997,7 @@ sctp_lower_sosend(struct socket *so, if (top == NULL) { error = uiomove((caddr_t)ph, (int)tot_out, uio); if (error) { - /* + /*- * Here if we can't get his data we * still abort we just don't get to * send the users note :-0 @@ -11249,11 +11282,10 @@ sctp_lower_sosend(struct socket *so, (un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) ) { - /* - * Ok, Nagle is set on and we have data - * outstanding. Don't send anything and let - * SACKs drive out the data unless wen have - * a "full" segment to send. + /*- + * Ok, Nagle is set on and we have data outstanding. + * Don't send anything and let SACKs drive out the + * data unless wen have a "full" segment to send. */ #ifdef SCTP_NAGLE_LOGGING sctp_log_nagle_event(stcb, SCTP_NAGLE_APPLIED); @@ -11292,12 +11324,12 @@ sctp_lower_sosend(struct socket *so, } if ((queue_only == 0) && (nagle_applies == 0) ) { - /* - * need to start chunk output before - * blocking.. note that if a lock is already - * applied, then the input via the net is - * happening and I don't need to start - * output :-D + /*- + * need to start chunk output + * before blocking.. note that if + * a lock is already applied, then + * the input via the net is happening + * and I don't need to start output :-D */ if (hold_tcblock == 0) { if (SCTP_TCB_TRYLOCK(stcb)) { @@ -11318,20 +11350,19 @@ sctp_lower_sosend(struct socket *so, } } SOCKBUF_LOCK(&so->so_snd); - /* - * This is a bit strange, but I think it will work. - * The total_output_queue_size is locked and - * protected by the TCB_LOCK, which we just - * released. There is a race that can occur between - * releasing it above, and me getting the socket - * lock, where sacks come in but we have not put the - * SB_WAIT on the so_snd buffer to get the wakeup. - * After the LOCK is applied the sack_processing - * will also need to LOCK the so->so_snd to do the - * actual sowwakeup(). So once we have the socket - * buffer lock if we recheck the size we KNOW we - * will get to sleep safely with the wakeup flag in - * place. + /*- + * This is a bit strange, but I think it will + * work. The total_output_queue_size is locked and + * protected by the TCB_LOCK, which we just released. + * There is a race that can occur between releasing it + * above, and me getting the socket lock, where sacks + * come in but we have not put the SB_WAIT on the + * so_snd buffer to get the wakeup. After the LOCK + * is applied the sack_processing will also need to + * LOCK the so->so_snd to do the actual sowwakeup(). So + * once we have the socket buffer lock if we recheck the + * size we KNOW we will get to sleep safely with the + * wakeup flag in place. */ if (SCTP_SB_LIMIT_SND(so) < (stcb->asoc.total_output_queue_size + sctp_add_more_threshold)) { #ifdef SCTP_BLK_LOGGING @@ -11419,11 +11450,11 @@ dataless_eof: asoc->primary_destination); } } else { - /* + /*- * we still got (or just got) data to send, so set * SHUTDOWN_PENDING */ - /* + /*- * XXX sockets draft says that SCTP_EOF should be * sent with no data. currently, we will allow user * data to be sent first and move to @@ -11500,10 +11531,10 @@ skip_out_eof: (un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) ) { - /* - * Ok, Nagle is set on and we have data outstanding. Don't - * send anything and let SACKs drive out the data unless wen - * have a "full" segment to send. + /*- + * Ok, Nagle is set on and we have data outstanding. + * Don't send anything and let SACKs drive out the + * data unless wen have a "full" segment to send. */ #ifdef SCTP_NAGLE_LOGGING sctp_log_nagle_event(stcb, SCTP_NAGLE_APPLIED); diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index b2197e3..ac9c196 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -3887,7 +3887,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre asoc->streamoutcnt = 0; if (asoc->strmin) { struct sctp_queued_to_read *ctl; - int i; for (i = 0; i < asoc->streamincnt; i++) { if (!TAILQ_EMPTY(&asoc->strmin[i].inqueue)) { @@ -4530,7 +4529,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, struct sockaddr_in sin; struct sockaddr_in6 sin6; uint8_t random_store[SCTP_PARAM_BUFFER_SIZE]; - struct sctp_auth_random *random = NULL; + struct sctp_auth_random *p_random = NULL; uint16_t random_len = 0; uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE]; struct sctp_auth_hmac_algo *hmacs = NULL; @@ -4887,8 +4886,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, plen); if (phdr == NULL) return (-26); - random = (struct sctp_auth_random *)phdr; - random_len = plen - sizeof(*random); + p_random = (struct sctp_auth_random *)phdr; + random_len = plen - sizeof(*p_random); /* enforce the random length */ if (random_len != SCTP_AUTH_RANDOM_SIZE_REQUIRED) { #ifdef SCTP_DEBUG @@ -5007,9 +5006,14 @@ next_param: } else { stcb->asoc.peer_supports_auth = 0; } + if (!stcb->asoc.peer_supports_auth && got_chklist) { + /* peer does not support auth but sent a chunks list? */ + return (-31); + } if (!sctp_asconf_auth_nochk && stcb->asoc.peer_supports_asconf && !stcb->asoc.peer_supports_auth) { - return (-31); + /* peer supports asconf but not auth? */ + return (-32); } /* concatenate the full random key */ #ifdef SCTP_AUTH_DRAFT_04 @@ -5017,18 +5021,18 @@ next_param: new_key = sctp_alloc_key(keylen); if (new_key != NULL) { /* copy in the RANDOM */ - if (random != NULL) - bcopy(random->random_data, new_key->key, random_len); + if (p_random != NULL) + bcopy(p_random->random_data, new_key->key, random_len); } #else - keylen = sizeof(*random) + random_len + sizeof(*chunks) + num_chunks + + keylen = sizeof(*p_random) + random_len + sizeof(*chunks) + num_chunks + sizeof(*hmacs) + hmacs_len; new_key = sctp_alloc_key(keylen); if (new_key != NULL) { /* copy in the RANDOM */ - if (random != NULL) { - keylen = sizeof(*random) + random_len; - bcopy(random, new_key->key, keylen); + if (p_random != NULL) { + keylen = sizeof(*p_random) + random_len; + bcopy(p_random, new_key->key, keylen); } /* append in the AUTH chunks */ if (chunks != NULL) { @@ -5044,7 +5048,8 @@ next_param: } #endif else { - return (-32); + /* failed to get memory for the key */ + return (-33); } if (stcb->asoc.authinfo.peer_random != NULL) sctp_free_key(stcb->asoc.authinfo.peer_random); diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 16d03de..34a8452 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -192,7 +192,7 @@ struct sctp_epinfo { struct sctpasochead *sctp_restarthash; u_long hashrestartmark; - /* + /*- * The TCP model represents a substantial overhead in that we get an * additional hash table to keep explicit connections in. The * listening TCP endpoint will exist in the usual ephash above and @@ -265,7 +265,7 @@ struct sctp_epinfo { }; -/* +/*- * Here we have all the relevant information for each SCTP entity created. We * will need to modify this as approprate. We also need to figure out how to * access /dev/random. @@ -337,7 +337,7 @@ struct sctp_pcb { #define sctp_lport ip_inp.inp.inp_lport struct sctp_inpcb { - /* + /*- * put an inpcb in front of it all, kind of a waste but we need to * for compatability with all the other stuff. */ @@ -383,11 +383,13 @@ struct sctp_inpcb { uint32_t partial_delivery_point; uint32_t sctp_context; struct sctp_sndrcvinfo def_send; - /* - * These three are here for the sosend_dgram (pkt, pkt_last and - * control). routine. However, I don't think anyone in the current - * FreeBSD kernel calls this. So they are candidates with sctp_sendm - * for de-supporting. + /*- + * These three are here for the sosend_dgram + * (pkt, pkt_last and control). + * routine. However, I don't think anyone in + * the current FreeBSD kernel calls this. So + * they are candidates with sctp_sendm for + * de-supporting. */ struct mbuf *pkt, *pkt_last; struct mbuf *control; @@ -415,7 +417,7 @@ struct sctp_tcb { struct sctp_block_entry *block_entry; /* pointer locked by socket * send buffer */ struct sctp_association asoc; - /* + /*- * freed_by_sorcv_sincelast is protected by the sockbuf_lock NOT the * tcb_lock. Its special in this way to help avoid extra mutex calls * in the reading of data. @@ -485,7 +487,7 @@ void sctp_move_pcb_and_assoc(struct sctp_inpcb *, struct sctp_inpcb *, struct sctp_tcb *); -/* +/*- * For this call ep_addr, the to is the destination endpoint address of the * peer (relative to outbound). The from field is only used if the TCP model * is enabled and helps distingush amongst the subset bound (non-boundall). @@ -556,7 +558,7 @@ int sctp_is_vtag_good(struct sctp_inpcb *, uint32_t, struct timeval *); int sctp_destination_is_reachable(struct sctp_tcb *, struct sockaddr *); -/* +/*- * Null in last arg inpcb indicate run on ALL ep's. Specific inp in last arg * indicates run on ONLY assoc's of the specified endpoint. */ diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index d57e3a0..fb45fc8 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -201,7 +201,6 @@ struct sctp_nets { uint32_t cwnd; /* actual cwnd */ uint32_t prev_cwnd; /* cwnd before any processing */ uint32_t partial_bytes_acked; /* in CA tracks when to incr a MTU */ - uint32_t rtt_variance; uint32_t prev_rtt; /* tracking variables to avoid the aloc/free in sack processing */ unsigned int net_ack; @@ -226,6 +225,12 @@ struct sctp_nets { uint32_t heartbeat_random2; uint32_t tos_flowlabel; + struct timeval start_time; /* time when this net was created */ + + uint32_t marked_retrans;/* number or DATA chunks marked for timer + * based retransmissions */ + uint32_t marked_fastretrans; + /* if this guy is ok or not ... status */ uint16_t dest_state; /* number of transmit failures to down this guy */ @@ -236,7 +241,6 @@ struct sctp_nets { uint8_t fast_retran_loss_recovery; uint8_t will_exit_fast_recovery; /* Flags that probably can be combined into dest_state */ - uint8_t rto_variance_dir; /* increase = 1, decreasing = 0 */ uint8_t fast_retran_ip; /* fast retransmit in progress */ uint8_t hb_responded; uint8_t saw_newack; /* CMT's SFR algorithm flag */ @@ -266,13 +270,10 @@ struct sctp_nets { uint8_t new_pseudo_cumack; /* CMT CUC algorithm. Flag used to * indicate if a new pseudo-cumack or * rtx-pseudo-cumack has been received */ + uint8_t window_probe; /* Doing a window probe? */ #ifdef SCTP_HIGH_SPEED uint8_t last_hs_used; /* index into the last HS table entry we used */ #endif - struct timeval start_time; /* time when this net was created */ - uint32_t marked_retrans;/* number or DATA chunks marked for timer - * based retransmissions */ - uint32_t marked_fastretrans; }; @@ -341,6 +342,7 @@ struct sctp_tmit_chunk { uint8_t no_fr_allowed; uint8_t pr_sctp_on; uint8_t copy_by_ref; + uint8_t window_probe; }; /* diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 37c572f..c2aac0d 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -91,15 +91,19 @@ uint32_t sctp_chunkscale = SCTP_CHUNKQUEUE_SCALE; uint32_t sctp_cmt_on_off = 0; uint32_t sctp_cmt_use_dac = 0; +uint32_t sctp_max_retran_chunk = SCTPCTL_MAX_RETRAN_DEFAULT; + uint32_t sctp_L2_abc_variable = 1; uint32_t sctp_early_fr = 0; uint32_t sctp_early_fr_msec = SCTP_MINFR_MSEC_TIMER; -uint32_t sctp_use_rttvar_cc = 0; uint32_t sctp_says_check_for_deadlock = 0; uint32_t sctp_asconf_auth_nochk = 0; uint32_t sctp_auth_disable = 0; uint32_t sctp_nat_friendly = 1; +uint32_t sctp_min_residual = SCTPCTL_MIN_RESIDUAL_DEFAULT;; + + struct sctpstat sctpstat; #ifdef SCTP_DEBUG @@ -434,10 +438,6 @@ SYSCTL_UINT(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLFLAG_RW, &sctp_early_fr, 0, "Early Fast Retransmit with timer"); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, use_rttvar_congctrl, CTLFLAG_RW, - &sctp_use_rttvar_cc, 0, - "Use congestion control via rtt variation"); - SYSCTL_UINT(_net_inet_sctp, OID_AUTO, deadlock_detect, CTLFLAG_RW, &sctp_says_check_for_deadlock, 0, "SMP Deadlock detection on/off"); @@ -486,6 +486,18 @@ SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_data_order, CTLFLAG_RW, &sctp_strict_data_order, 0, "Enforce strict data ordering, abort if control inside data"); +SYSCTL_INT(_net_inet_sctp, OID_AUTO, min_residual, CTLFLAG_RW, + &sctp_min_residual, 0, + SCTPCTL_MIN_RESIDUAL_DESC); + + +SYSCTL_INT(_net_inet_sctp, OID_AUTO, max_retran_chunk, CTLFLAG_RW, + &sctp_max_retran_chunk, 0, + SCTPCTL_MAX_RETRAN_DESC); + + + + SYSCTL_STRUCT(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_RW, &sctpstat, sctpstat, "SCTP statistics (struct sctps_stat, netinet/sctp.h"); diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h index fcd03fe..0ad6cf5 100644 --- a/sys/netinet/sctp_sysctl.h +++ b/sys/netinet/sctp_sysctl.h @@ -292,108 +292,118 @@ __FBSDID("$FreeBSD$"); #define SCTPCTL_EARLY_FAST_RETRAN_MAX 0xFFFFFFFF #define SCTPCTL_EARLY_FAST_RETRAN_DEFAULT 0 -/* use_rttvar_congctrl: Use Congestion Control via rtt variation */ -#define SCTPCTL_USE_RTTVAR_CONGCTRL 37 -#define SCTPCTL_USE_RTTVAR_CONGCTRL_DESC "Use Congestion Control via rtt variation" -#define SCTPCTL_USE_RTTVAR_CONGCTRL_MIN 0 -#define SCTPCTL_USE_RTTVAR_CONGCTRL_MAX 1 -#define SCTPCTL_USE_RTTVAR_CONGCTRL_DEFAULT 0 /* UNUSED?? */ - /* deadlock_detect: SMP Deadlock detection on/off */ -#define SCTPCTL_DEADLOCK_DETECT 38 +#define SCTPCTL_DEADLOCK_DETECT 37 #define SCTPCTL_DEADLOCK_DETECT_DESC "SMP Deadlock detection on/off" #define SCTPCTL_DEADLOCK_DETECT_MIN 0 #define SCTPCTL_DEADLOCK_DETECT_MAX 1 #define SCTPCTL_DEADLOCK_DETECT_DEFAULT 0 /* early_fast_retran_msec: Early Fast Retransmit minimum timer value */ -#define SCTPCTL_EARLY_FAST_RETRAN_MSEC 39 +#define SCTPCTL_EARLY_FAST_RETRAN_MSEC 38 #define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC "Early Fast Retransmit minimum timer value" #define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN 0 #define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX 0xFFFFFFFF #define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT SCTP_MINFR_MSEC_TIMER /* asconf_auth_nochk: Disable SCTP ASCONF AUTH requirement */ -#define SCTPCTL_ASCONF_AUTH_NOCHK 40 +#define SCTPCTL_ASCONF_AUTH_NOCHK 39 #define SCTPCTL_ASCONF_AUTH_NOCHK_DESC "Disable SCTP ASCONF AUTH requirement" #define SCTPCTL_ASCONF_AUTH_NOCHK_MIN 0 #define SCTPCTL_ASCONF_AUTH_NOCHK_MAX 1 #define SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT 0 /* auth_disable: Disable SCTP AUTH function */ -#define SCTPCTL_AUTH_DISABLE 41 +#define SCTPCTL_AUTH_DISABLE 40 #define SCTPCTL_AUTH_DISABLE_DESC "Disable SCTP AUTH function" #define SCTPCTL_AUTH_DISABLE_MIN 0 #define SCTPCTL_AUTH_DISABLE_MAX 1 #define SCTPCTL_AUTH_DISABLE_DEFAULT 0 /* nat_friendly: SCTP NAT friendly operation */ -#define SCTPCTL_NAT_FRIENDLY 42 +#define SCTPCTL_NAT_FRIENDLY 41 #define SCTPCTL_NAT_FRIENDLY_DESC "SCTP NAT friendly operation" #define SCTPCTL_NAT_FRIENDLY_MIN 0 #define SCTPCTL_NAT_FRIENDLY_MAX 1 #define SCTPCTL_NAT_FRIENDLY_DEFAULT 1 /* abc_l_var: SCTP ABC max increase per SACK (L) */ -#define SCTPCTL_ABC_L_VAR 43 +#define SCTPCTL_ABC_L_VAR 42 #define SCTPCTL_ABC_L_VAR_DESC "SCTP ABC max increase per SACK (L)" #define SCTPCTL_ABC_L_VAR_MIN 0 #define SCTPCTL_ABC_L_VAR_MAX 0xFFFFFFFF #define SCTPCTL_ABC_L_VAR_DEFAULT 1 /* max_chained_mbufs: Default max number of small mbufs on a chain */ -#define SCTPCTL_MAX_CHAINED_MBUFS 44 +#define SCTPCTL_MAX_CHAINED_MBUFS 43 #define SCTPCTL_MAX_CHAINED_MBUFS_DESC "Default max number of small mbufs on a chain" #define SCTPCTL_MAX_CHAINED_MBUFS_MIN 0 #define SCTPCTL_MAX_CHAINED_MBUFS_MAX 0xFFFFFFFF #define SCTPCTL_MAX_CHAINED_MBUFS_DEFAULT SCTP_DEFAULT_MBUFS_IN_CHAIN /* cmt_use_dac: CMT DAC on/off flag */ -#define SCTPCTL_CMT_USE_DAC 45 +#define SCTPCTL_CMT_USE_DAC 44 #define SCTPCTL_CMT_USE_DAC_DESC "CMT DAC on/off flag" #define SCTPCTL_CMT_USE_DAC_MIN 0 #define SCTPCTL_CMT_USE_DAC_MAX 1 #define SCTPCTL_CMT_USE_DAC_DEFAULT 0 /* do_sctp_drain: Should SCTP respond to the drain calls */ -#define SCTPCTL_DO_SCTP_DRAIN 46 +#define SCTPCTL_DO_SCTP_DRAIN 45 #define SCTPCTL_DO_SCTP_DRAIN_DESC "Should SCTP respond to the drain calls" #define SCTPCTL_DO_SCTP_DRAIN_MIN 0 #define SCTPCTL_DO_SCTP_DRAIN_MAX 1 #define SCTPCTL_DO_SCTP_DRAIN_DEFAULT 1 /* hb_max_burst: Confirmation Heartbeat max burst? */ -#define SCTPCTL_HB_MAX_BURST 47 +#define SCTPCTL_HB_MAX_BURST 46 #define SCTPCTL_HB_MAX_BURST_DESC "Confirmation Heartbeat max burst?" #define SCTPCTL_HB_MAX_BURST_MIN 1 #define SCTPCTL_HB_MAX_BURST_MAX 0xFFFFFFFF #define SCTPCTL_HB_MAX_BURST_DEFAULT SCTP_DEF_MAX_BURST /* abort_at_limit: When one-2-one hits qlimit abort */ -#define SCTPCTL_ABORT_AT_LIMIT 48 +#define SCTPCTL_ABORT_AT_LIMIT 47 #define SCTPCTL_ABORT_AT_LIMIT_DESC "When one-2-one hits qlimit abort" #define SCTPCTL_ABORT_AT_LIMIT_MIN 0 #define SCTPCTL_ABORT_AT_LIMIT_MAX 1 #define SCTPCTL_ABORT_AT_LIMIT_DEFAULT 0 /* strict_data_order: Enforce strict data ordering, abort if control inside data */ -#define SCTPCTL_STRICT_DATA_ORDER 49 +#define SCTPCTL_STRICT_DATA_ORDER 48 #define SCTPCTL_STRICT_DATA_ORDER_DESC "Enforce strict data ordering, abort if control inside data" #define SCTPCTL_STRICT_DATA_ORDER_MIN 0 #define SCTPCTL_STRICT_DATA_ORDER_MAX 1 #define SCTPCTL_STRICT_DATA_ORDER_DEFAULT 0 +/* min residual in in a data fragment leftover */ +#define SCTPCTL_MIN_REDIDUAL 49 +#define SCTPCTL_MIN_RESIDUAL_DESC "Minimum residual data chunk in second part of split" +#define SCTPCTL_MIN_RESIDUAL_MIN 20 +#define SCTPCTL_MIN_RESIDUAL_MAX 65535 +#define SCTPCTL_MIN_RESIDUAL_DEFAULT 1452 + +/* min residual in in a data fragment leftover */ +#define SCTPCTL_MAX_RETRAN 50 +#define SCTPCTL_MAX_RETRAN_DESC "Maximum times a unlucky chunk can be retran'd before assoc abort " +#define SCTPCTL_MAX_RETRAN_MIN 0 +#define SCTPCTL_MAX_RETRAN_MAX 65535 +#define SCTPCTL_MAX_RETRAN_DEFAULT 30 + + + +#ifdef SCTP_DEBUG /* debug: Configure debug output */ -#define SCTPCTL_DEBUG 50 +#define SCTPCTL_DEBUG 51 #define SCTPCTL_DEBUG_DESC "Configure debug output" #define SCTPCTL_DEBUG_MIN 0 #define SCTPCTL_DEBUG_MAX 0xFFFFFFFF #define SCTPCTL_DEBUG_DEFAULT 0 -#ifdef SCTP_DEBUG -#define SCTPCTL_MAXID 50 + +#define SCTPCTL_MAXID 51 #else -#define SCTPCTL_MAXID 49 +#define SCTPCTL_MAXID 50 #endif /* @@ -432,7 +442,6 @@ __FBSDID("$FreeBSD$"); { "cmt_on_off", CTLTYPE_INT }, \ { "cwnd_maxburst", CTLTYPE_INT }, \ { "early_fast_retran", CTLTYPE_INT }, \ - { "use_rttvar_congctrl", CTLTYPE_INT }, \ { "deadlock_detect", CTLTYPE_INT }, \ { "early_fast_retran_msec", CTLTYPE_INT }, \ { "asconf_auth_nochk", CTLTYPE_INT }, \ @@ -452,6 +461,8 @@ __FBSDID("$FreeBSD$"); { "add_more_on_output", CTLTYPE_INT }, \ { "sys_resource", CTLTYPE_INT }, \ { "asoc_resource", CTLTYPE_INT }, \ + { "min_residual", CTLTYPE_INT }, \ + { "max_retran_chunk", CTLTYPE_INT }, \ { "debug", CTLTYPE_INT }, \ } #else @@ -486,7 +497,6 @@ __FBSDID("$FreeBSD$"); { "cmt_on_off", CTLTYPE_INT }, \ { "cwnd_maxburst", CTLTYPE_INT }, \ { "early_fast_retran", CTLTYPE_INT }, \ - { "use_rttvar_congctrl", CTLTYPE_INT }, \ { "deadlock_detect", CTLTYPE_INT }, \ { "early_fast_retran_msec", CTLTYPE_INT }, \ { "asconf_auth_nochk", CTLTYPE_INT }, \ @@ -506,6 +516,8 @@ __FBSDID("$FreeBSD$"); { "add_more_on_output", CTLTYPE_INT }, \ { "sys_resource", CTLTYPE_INT }, \ { "asoc_resource", CTLTYPE_INT }, \ + { "max_retran_chunk", CTLTYPE_INT }, \ + { "min_residual", CTLTYPE_INT }, \ } #endif @@ -564,6 +576,8 @@ extern uint32_t sctp_do_drain; extern uint32_t sctp_hb_maxburst; extern uint32_t sctp_abort_if_one_2_one_hits_limit; extern uint32_t sctp_strict_data_order; +extern uint32_t sctp_min_residual; +extern uint32_t sctp_max_retran_chunk; #if defined(SCTP_DEBUG) extern uint32_t sctp_debug_on; diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index 1d60215..506e9e9 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -658,8 +658,6 @@ struct sctp_lock_log { struct sctp_rto_log { void *net; uint32_t rtt; - uint32_t rttvar; - uint8_t direction; }; struct sctp_nagle_log { diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 9899671..b3ef38a 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -996,7 +996,7 @@ sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) static size_t -sctp_fill_up_addresses(struct sctp_inpcb *inp, +sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, struct sctp_tcb *stcb, size_t limit, struct sockaddr_storage *sas, @@ -1153,8 +1153,22 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, return (actual); } +static size_t +sctp_fill_up_addresses(struct sctp_inpcb *inp, + struct sctp_tcb *stcb, + size_t limit, + struct sockaddr_storage *sas) +{ + size_t size = 0; + + /* fill up addresses for the endpoint's default vrf */ + size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, + inp->def_vrf_id); + return (size); +} + static int -sctp_count_max_addresses(struct sctp_inpcb *inp, uint32_t vrf_id) +sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) { int cnt = 0; struct sctp_vrf *vrf = NULL; @@ -1204,6 +1218,16 @@ sctp_count_max_addresses(struct sctp_inpcb *inp, uint32_t vrf_id) return (cnt); } +static int +sctp_count_max_addresses(struct sctp_inpcb *inp) +{ + int cnt = 0; + + /* count addresses for the endpoint's default VRF */ + cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); + return (cnt); +} + static int sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, @@ -1416,7 +1440,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, { struct sctp_inpcb *inp; int error, val = 0; - uint32_t vrf_id; struct sctp_tcb *stcb = NULL; if (optval == NULL) { @@ -1425,8 +1448,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, inp = (struct sctp_inpcb *)so->so_pcb; if (inp == 0) return EINVAL; - vrf_id = SCTP_DEFAULT_VRFID; - error = 0; switch (optname) { @@ -1797,7 +1818,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); SCTP_INP_RLOCK(inp); - *value = sctp_count_max_addresses(inp, vrf_id); + *value = sctp_count_max_addresses(inp); SCTP_INP_RUNLOCK(inp); *optsize = sizeof(uint32_t); } @@ -1898,7 +1919,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, sas = (struct sockaddr_storage *)&saddr->addr[0]; limit = *optsize - sizeof(sctp_assoc_t); - actual = sctp_fill_up_addresses(inp, stcb, limit, sas, vrf_id); + actual = sctp_fill_up_addresses(inp, stcb, limit, sas); if (stcb) SCTP_TCB_UNLOCK(stcb); *optsize = sizeof(struct sockaddr_storage) + actual; diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index aa84b98..ee8407a 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -133,8 +133,6 @@ rto_logging(struct sctp_nets *net, int from) sctp_clog[sctp_cwnd_log_at].event_type = (uint8_t) SCTP_LOG_EVENT_RTT; sctp_clog[sctp_cwnd_log_at].x.rto.net = (void *)net; sctp_clog[sctp_cwnd_log_at].x.rto.rtt = net->prev_rtt; - sctp_clog[sctp_cwnd_log_at].x.rto.rttvar = net->rtt_variance; - sctp_clog[sctp_cwnd_log_at].x.rto.direction = net->rto_variance_dir; } void @@ -2464,7 +2462,7 @@ sctp_calculate_rto(struct sctp_tcb *stcb, */ int calc_time = 0; int o_calctime; - unsigned int new_rto = 0; + uint32_t new_rto = 0; int first_measure = 0; struct timeval now; @@ -2493,7 +2491,7 @@ sctp_calculate_rto(struct sctp_tcb *stcb, (u_long)old->tv_usec) / 1000; } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) { /* impossible .. garbage in nothing out */ - return (((net->lastsa >> 2) + net->lastsv) >> 1); + goto calc_rto; } else if ((u_long)now.tv_usec == (u_long)old->tv_usec) { /* * We have to have 1 usec :-D this must be the @@ -2502,11 +2500,11 @@ sctp_calculate_rto(struct sctp_tcb *stcb, calc_time = 1; } else { /* impossible .. garbage in nothing out */ - return (((net->lastsa >> 2) + net->lastsv) >> 1); + goto calc_rto; } } else { /* Clock wrapped? */ - return (((net->lastsa >> 2) + net->lastsv) >> 1); + goto calc_rto; } /***************************/ /* 2. update RTTVAR & SRTT */ @@ -2515,15 +2513,6 @@ sctp_calculate_rto(struct sctp_tcb *stcb, /* this is Van Jacobson's integer version */ if (net->RTO) { calc_time -= (net->lastsa >> 3); - if ((int)net->prev_rtt > o_calctime) { - net->rtt_variance = net->prev_rtt - o_calctime; - /* decreasing */ - net->rto_variance_dir = 0; - } else { - /* increasing */ - net->rtt_variance = o_calctime - net->prev_rtt; - net->rto_variance_dir = 1; - } #ifdef SCTP_RTTVAR_LOGGING rto_logging(net, SCTP_LOG_RTTVAR); #endif @@ -2542,13 +2531,12 @@ sctp_calculate_rto(struct sctp_tcb *stcb, net->lastsa = calc_time; net->lastsv = calc_time >> 1; first_measure = 1; - net->rto_variance_dir = 1; net->prev_rtt = o_calctime; - net->rtt_variance = 0; #ifdef SCTP_RTTVAR_LOGGING rto_logging(net, SCTP_LOG_INITIAL_RTT); #endif } +calc_rto: new_rto = ((net->lastsa >> 2) + net->lastsv) >> 1; if ((new_rto > SCTP_SAT_NETWORK_MIN) && (stcb->asoc.sat_network_lockout == 0)) { @@ -2564,8 +2552,8 @@ sctp_calculate_rto(struct sctp_tcb *stcb, if (new_rto > stcb->asoc.maxrto) { new_rto = stcb->asoc.maxrto; } - /* we are now returning the RTT Smoothed */ - return ((uint32_t) new_rto); + /* we are now returning the RTO */ + return (new_rto); } /* diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index 7fba888..b4f4d33 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -80,12 +80,6 @@ sctp6_input(mp, offp, proto) m = SCTP_HEADER_TO_CHAIN(*mp); ip6 = mtod(m, struct ip6_hdr *); -#ifndef PULLDOWN_TEST - /* If PULLDOWN_TEST off, must be in a single mbuf. */ - IP6_EXTHDR_CHECK(m, off, (int)(sizeof(*sh) + sizeof(*ch)), IPPROTO_DONE); - sh = (struct sctphdr *)((caddr_t)ip6 + off); - ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(*sh)); -#else /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */ IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch)); if (sh == NULL) { @@ -93,8 +87,6 @@ sctp6_input(mp, offp, proto) return IPPROTO_DONE; } ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); -#endif - iphlen = off; offset = iphlen + sizeof(*sh) + sizeof(*ch); |