1f8829a4aSRandall Stewart /*- 2b1006367SRandall Stewart * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3f8829a4aSRandall Stewart * 4f8829a4aSRandall Stewart * Redistribution and use in source and binary forms, with or without 5f8829a4aSRandall Stewart * modification, are permitted provided that the following conditions are met: 6f8829a4aSRandall Stewart * 7f8829a4aSRandall Stewart * a) Redistributions of source code must retain the above copyright notice, 8f8829a4aSRandall Stewart * this list of conditions and the following disclaimer. 9f8829a4aSRandall Stewart * 10f8829a4aSRandall Stewart * b) Redistributions in binary form must reproduce the above copyright 11f8829a4aSRandall Stewart * notice, this list of conditions and the following disclaimer in 12f8829a4aSRandall Stewart * the documentation and/or other materials provided with the distribution. 13f8829a4aSRandall Stewart * 14f8829a4aSRandall Stewart * c) Neither the name of Cisco Systems, Inc. nor the names of its 15f8829a4aSRandall Stewart * contributors may be used to endorse or promote products derived 16f8829a4aSRandall Stewart * from this software without specific prior written permission. 17f8829a4aSRandall Stewart * 18f8829a4aSRandall Stewart * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19f8829a4aSRandall Stewart * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20f8829a4aSRandall Stewart * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21f8829a4aSRandall Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22f8829a4aSRandall Stewart * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23f8829a4aSRandall Stewart * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24f8829a4aSRandall Stewart * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25f8829a4aSRandall Stewart * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26f8829a4aSRandall Stewart * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27f8829a4aSRandall Stewart * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28f8829a4aSRandall Stewart * THE POSSIBILITY OF SUCH DAMAGE. 29f8829a4aSRandall Stewart */ 30f8829a4aSRandall Stewart 31f8829a4aSRandall Stewart /* $KAME: sctp_timer.c,v 1.29 2005/03/06 16:04:18 itojun Exp $ */ 32f8829a4aSRandall Stewart 33f8829a4aSRandall Stewart #include <sys/cdefs.h> 34f8829a4aSRandall Stewart __FBSDID("$FreeBSD$"); 35f8829a4aSRandall Stewart 36f8829a4aSRandall Stewart #define _IP_VHL 3793164cf9SRandall Stewart #include <netinet/sctp_os.h> 38f8829a4aSRandall Stewart #include <netinet/sctp_pcb.h> 39f8829a4aSRandall Stewart #ifdef INET6 40f8829a4aSRandall Stewart #endif 41f8829a4aSRandall Stewart #include <netinet/sctp_var.h> 4242551e99SRandall Stewart #include <netinet/sctp_sysctl.h> 43f8829a4aSRandall Stewart #include <netinet/sctp_timer.h> 44f8829a4aSRandall Stewart #include <netinet/sctputil.h> 45f8829a4aSRandall Stewart #include <netinet/sctp_output.h> 46f8829a4aSRandall Stewart #include <netinet/sctp_header.h> 47f8829a4aSRandall Stewart #include <netinet/sctp_indata.h> 48f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h> 49f8829a4aSRandall Stewart #include <netinet/sctp_input.h> 50f8829a4aSRandall Stewart #include <netinet/sctp.h> 51f8829a4aSRandall Stewart #include <netinet/sctp_uio.h> 52830d754dSRandall Stewart #include <netinet/udp.h> 53f8829a4aSRandall Stewart 54f8829a4aSRandall Stewart 55f8829a4aSRandall Stewart void 56f8829a4aSRandall Stewart sctp_early_fr_timer(struct sctp_inpcb *inp, 57f8829a4aSRandall Stewart struct sctp_tcb *stcb, 58f8829a4aSRandall Stewart struct sctp_nets *net) 59f8829a4aSRandall Stewart { 60f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk, *tp2; 61f8829a4aSRandall Stewart struct timeval now, min_wait, tv; 62f8829a4aSRandall Stewart unsigned int cur_rtt, cnt = 0, cnt_resend = 0; 63f8829a4aSRandall Stewart 64f8829a4aSRandall Stewart /* an early FR is occuring. */ 656e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 66f8829a4aSRandall Stewart /* get cur rto in micro-seconds */ 67f8829a4aSRandall Stewart if (net->lastsa == 0) { 68f8829a4aSRandall Stewart /* Hmm no rtt estimate yet? */ 69f8829a4aSRandall Stewart cur_rtt = stcb->asoc.initial_rto >> 2; 70f8829a4aSRandall Stewart } else { 71f8829a4aSRandall Stewart 72f8829a4aSRandall Stewart cur_rtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 73f8829a4aSRandall Stewart } 74b3f1ea41SRandall Stewart if (cur_rtt < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) { 75b3f1ea41SRandall Stewart cur_rtt = SCTP_BASE_SYSCTL(sctp_early_fr_msec); 76f8829a4aSRandall Stewart } 77f8829a4aSRandall Stewart cur_rtt *= 1000; 78f8829a4aSRandall Stewart tv.tv_sec = cur_rtt / 1000000; 79f8829a4aSRandall Stewart tv.tv_usec = cur_rtt % 1000000; 80f8829a4aSRandall Stewart min_wait = now; 81f8829a4aSRandall Stewart timevalsub(&min_wait, &tv); 82f8829a4aSRandall Stewart if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { 83f8829a4aSRandall Stewart /* 84f8829a4aSRandall Stewart * if we hit here, we don't have enough seconds on the clock 85f8829a4aSRandall Stewart * to account for the RTO. We just let the lower seconds be 86f8829a4aSRandall Stewart * the bounds and don't worry about it. This may mean we 87f8829a4aSRandall Stewart * will mark a lot more than we should. 88f8829a4aSRandall Stewart */ 89f8829a4aSRandall Stewart min_wait.tv_sec = min_wait.tv_usec = 0; 90f8829a4aSRandall Stewart } 91f8829a4aSRandall Stewart chk = TAILQ_LAST(&stcb->asoc.sent_queue, sctpchunk_listhead); 92f8829a4aSRandall Stewart for (; chk != NULL; chk = tp2) { 93f8829a4aSRandall Stewart tp2 = TAILQ_PREV(chk, sctpchunk_listhead, sctp_next); 94f8829a4aSRandall Stewart if (chk->whoTo != net) { 95f8829a4aSRandall Stewart continue; 96f8829a4aSRandall Stewart } 97f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) 98f8829a4aSRandall Stewart cnt_resend++; 99f8829a4aSRandall Stewart else if ((chk->sent > SCTP_DATAGRAM_UNSENT) && 100f8829a4aSRandall Stewart (chk->sent < SCTP_DATAGRAM_RESEND)) { 101f8829a4aSRandall Stewart /* pending, may need retran */ 102f8829a4aSRandall Stewart if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) { 103f8829a4aSRandall Stewart /* 104f8829a4aSRandall Stewart * we have reached a chunk that was sent 105f8829a4aSRandall Stewart * some seconds past our min.. forget it we 106f8829a4aSRandall Stewart * will find no more to send. 107f8829a4aSRandall Stewart */ 108f8829a4aSRandall Stewart continue; 109f8829a4aSRandall Stewart } else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) { 110f8829a4aSRandall Stewart /* 111f8829a4aSRandall Stewart * we must look at the micro seconds to 112f8829a4aSRandall Stewart * know. 113f8829a4aSRandall Stewart */ 114f8829a4aSRandall Stewart if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { 115f8829a4aSRandall Stewart /* 116f8829a4aSRandall Stewart * ok it was sent after our boundary 117f8829a4aSRandall Stewart * time. 118f8829a4aSRandall Stewart */ 119f8829a4aSRandall Stewart continue; 120f8829a4aSRandall Stewart } 121f8829a4aSRandall Stewart } 122b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_EARLYFR_LOGGING_ENABLE) { 123f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, 124f8829a4aSRandall Stewart 4, SCTP_FR_MARKED_EARLY); 12580fefe0aSRandall Stewart } 126f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_earlyfrmrkretrans); 127f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 128f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 129f8829a4aSRandall Stewart /* double book size since we are doing an early FR */ 130f8829a4aSRandall Stewart chk->book_size_scale++; 131f8829a4aSRandall Stewart cnt += chk->send_size; 132f8829a4aSRandall Stewart if ((cnt + net->flight_size) > net->cwnd) { 133f8829a4aSRandall Stewart /* Mark all we could possibly resend */ 134f8829a4aSRandall Stewart break; 135f8829a4aSRandall Stewart } 136f8829a4aSRandall Stewart } 137f8829a4aSRandall Stewart } 138f8829a4aSRandall Stewart if (cnt) { 139f8829a4aSRandall Stewart /* 140b54d3a6cSRandall Stewart * JRS - Use the congestion control given in the congestion 141b54d3a6cSRandall Stewart * control module 142f8829a4aSRandall Stewart */ 143b54d3a6cSRandall Stewart stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer(inp, stcb, net); 144f8829a4aSRandall Stewart } else if (cnt_resend) { 145ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 146f8829a4aSRandall Stewart } 147f8829a4aSRandall Stewart /* Restart it? */ 148f8829a4aSRandall Stewart if (net->flight_size < net->cwnd) { 149f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_earlyfrstrtmr); 150f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 151f8829a4aSRandall Stewart } 152f8829a4aSRandall Stewart } 153f8829a4aSRandall Stewart 154f8829a4aSRandall Stewart void 155f8829a4aSRandall Stewart sctp_audit_retranmission_queue(struct sctp_association *asoc) 156f8829a4aSRandall Stewart { 157f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 158f8829a4aSRandall Stewart 159ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Audit invoked on send queue cnt:%d onqueue:%d\n", 160f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt, 161f8829a4aSRandall Stewart asoc->sent_queue_cnt); 162f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0; 163f8829a4aSRandall Stewart asoc->sent_queue_cnt = 0; 164f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 165f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 166f8829a4aSRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 167f8829a4aSRandall Stewart } 168f8829a4aSRandall Stewart asoc->sent_queue_cnt++; 169f8829a4aSRandall Stewart } 170f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { 171f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 172f8829a4aSRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 173f8829a4aSRandall Stewart } 174f8829a4aSRandall Stewart } 175c54a18d2SRandall Stewart TAILQ_FOREACH(chk, &asoc->asconf_send_queue, sctp_next) { 176c54a18d2SRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 177c54a18d2SRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 178c54a18d2SRandall Stewart } 179c54a18d2SRandall Stewart } 180ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n", 181f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt, 182f8829a4aSRandall Stewart asoc->sent_queue_cnt); 183f8829a4aSRandall Stewart } 184f8829a4aSRandall Stewart 185f8829a4aSRandall Stewart int 186f8829a4aSRandall Stewart sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 187f8829a4aSRandall Stewart struct sctp_nets *net, uint16_t threshold) 188f8829a4aSRandall Stewart { 189f8829a4aSRandall Stewart if (net) { 190f8829a4aSRandall Stewart net->error_count++; 191ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n", 192f8829a4aSRandall Stewart net, net->error_count, 193f8829a4aSRandall Stewart net->failure_threshold); 194f8829a4aSRandall Stewart if (net->error_count > net->failure_threshold) { 195f8829a4aSRandall Stewart /* We had a threshold failure */ 196f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_REACHABLE) { 197f8829a4aSRandall Stewart net->dest_state &= ~SCTP_ADDR_REACHABLE; 198f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 19942551e99SRandall Stewart net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; 200f8829a4aSRandall Stewart if (net == stcb->asoc.primary_destination) { 201f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_WAS_PRIMARY; 202f8829a4aSRandall Stewart } 203b54d3a6cSRandall Stewart /* 204b54d3a6cSRandall Stewart * JRS 5/14/07 - If a destination is 205b54d3a6cSRandall Stewart * unreachable, the PF bit is turned off. 206b54d3a6cSRandall Stewart * This allows an unambiguous use of the PF 207b54d3a6cSRandall Stewart * bit for destinations that are reachable 208b54d3a6cSRandall Stewart * but potentially failed. If the 209b54d3a6cSRandall Stewart * destination is set to the unreachable 210b54d3a6cSRandall Stewart * state, also set the destination to the PF 211b54d3a6cSRandall Stewart * state. 212b54d3a6cSRandall Stewart */ 213b54d3a6cSRandall Stewart /* 214b54d3a6cSRandall Stewart * Add debug message here if destination is 215b54d3a6cSRandall Stewart * not in PF state. 216b54d3a6cSRandall Stewart */ 217b54d3a6cSRandall Stewart /* Stop any running T3 timers here? */ 218b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { 219b54d3a6cSRandall Stewart net->dest_state &= ~SCTP_ADDR_PF; 220b54d3a6cSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", 221b54d3a6cSRandall Stewart net); 222b54d3a6cSRandall Stewart } 223f8829a4aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 224f8829a4aSRandall Stewart stcb, 225f8829a4aSRandall Stewart SCTP_FAILED_THRESHOLD, 226ceaad40aSRandall Stewart (void *)net, SCTP_SO_NOT_LOCKED); 227f8829a4aSRandall Stewart } 228f8829a4aSRandall Stewart } 229f8829a4aSRandall Stewart /*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE 230f8829a4aSRandall Stewart *********ROUTING CODE 231f8829a4aSRandall Stewart */ 232f8829a4aSRandall Stewart /*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE 233f8829a4aSRandall Stewart *********ROUTING CODE 234f8829a4aSRandall Stewart */ 235f8829a4aSRandall Stewart } 236f8829a4aSRandall Stewart if (stcb == NULL) 237f8829a4aSRandall Stewart return (0); 238f8829a4aSRandall Stewart 239f8829a4aSRandall Stewart if (net) { 240f8829a4aSRandall Stewart if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { 241b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { 242c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_INCR, 243c4739e2fSRandall Stewart stcb->asoc.overall_error_count, 244c4739e2fSRandall Stewart (stcb->asoc.overall_error_count + 1), 245c4739e2fSRandall Stewart SCTP_FROM_SCTP_TIMER, 246c4739e2fSRandall Stewart __LINE__); 247c4739e2fSRandall Stewart } 248f8829a4aSRandall Stewart stcb->asoc.overall_error_count++; 249f8829a4aSRandall Stewart } 250f8829a4aSRandall Stewart } else { 251b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { 252c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_INCR, 253c4739e2fSRandall Stewart stcb->asoc.overall_error_count, 254c4739e2fSRandall Stewart (stcb->asoc.overall_error_count + 1), 255c4739e2fSRandall Stewart SCTP_FROM_SCTP_TIMER, 256c4739e2fSRandall Stewart __LINE__); 257c4739e2fSRandall Stewart } 258f8829a4aSRandall Stewart stcb->asoc.overall_error_count++; 259f8829a4aSRandall Stewart } 260ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n", 261ad81507eSRandall Stewart &stcb->asoc, stcb->asoc.overall_error_count, 262f8829a4aSRandall Stewart (uint32_t) threshold, 263f8829a4aSRandall Stewart ((net == NULL) ? (uint32_t) 0 : (uint32_t) net->dest_state)); 264f8829a4aSRandall Stewart /* 265f8829a4aSRandall Stewart * We specifically do not do >= to give the assoc one more change 266f8829a4aSRandall Stewart * before we fail it. 267f8829a4aSRandall Stewart */ 268f8829a4aSRandall Stewart if (stcb->asoc.overall_error_count > threshold) { 269f8829a4aSRandall Stewart /* Abort notification sends a ULP notify */ 270f8829a4aSRandall Stewart struct mbuf *oper; 271f8829a4aSRandall Stewart 272f8829a4aSRandall Stewart oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 273f8829a4aSRandall Stewart 0, M_DONTWAIT, 1, MT_DATA); 274f8829a4aSRandall Stewart if (oper) { 275f8829a4aSRandall Stewart struct sctp_paramhdr *ph; 276f8829a4aSRandall Stewart uint32_t *ippp; 277f8829a4aSRandall Stewart 278139bc87fSRandall Stewart SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) + 279f8829a4aSRandall Stewart sizeof(uint32_t); 280f8829a4aSRandall Stewart ph = mtod(oper, struct sctp_paramhdr *); 281f8829a4aSRandall Stewart ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 282139bc87fSRandall Stewart ph->param_length = htons(SCTP_BUF_LEN(oper)); 283f8829a4aSRandall Stewart ippp = (uint32_t *) (ph + 1); 284a5d547adSRandall Stewart *ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); 285f8829a4aSRandall Stewart } 286a5d547adSRandall Stewart inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1; 287ceaad40aSRandall Stewart sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper, SCTP_SO_NOT_LOCKED); 288f8829a4aSRandall Stewart return (1); 289f8829a4aSRandall Stewart } 290f8829a4aSRandall Stewart return (0); 291f8829a4aSRandall Stewart } 292f8829a4aSRandall Stewart 293f8829a4aSRandall Stewart struct sctp_nets * 294f8829a4aSRandall Stewart sctp_find_alternate_net(struct sctp_tcb *stcb, 295f8829a4aSRandall Stewart struct sctp_nets *net, 296b54d3a6cSRandall Stewart int mode) 297f8829a4aSRandall Stewart { 298f8829a4aSRandall Stewart /* Find and return an alternate network if possible */ 299b54d3a6cSRandall Stewart struct sctp_nets *alt, *mnet, *min_errors_net = NULL, *max_cwnd_net = NULL; 300f8829a4aSRandall Stewart int once; 301b54d3a6cSRandall Stewart 302b54d3a6cSRandall Stewart /* JRS 5/14/07 - Initialize min_errors to an impossible value. */ 303b54d3a6cSRandall Stewart int min_errors = -1; 304b54d3a6cSRandall Stewart uint32_t max_cwnd = 0; 305f8829a4aSRandall Stewart 306f8829a4aSRandall Stewart if (stcb->asoc.numnets == 1) { 307f8829a4aSRandall Stewart /* No others but net */ 308f8829a4aSRandall Stewart return (TAILQ_FIRST(&stcb->asoc.nets)); 309f8829a4aSRandall Stewart } 310b54d3a6cSRandall Stewart /* 311b54d3a6cSRandall Stewart * JRS 5/14/07 - If mode is set to 2, use the CMT PF find alternate 312b54d3a6cSRandall Stewart * net algorithm. This algorithm chooses the active destination (not 313b54d3a6cSRandall Stewart * in PF state) with the largest cwnd value. If all destinations are 314b54d3a6cSRandall Stewart * in PF state, unreachable, or unconfirmed, choose the desination 315b54d3a6cSRandall Stewart * that is in PF state with the lowest error count. In case of a 316b54d3a6cSRandall Stewart * tie, choose the destination that was most recently active. 317b54d3a6cSRandall Stewart */ 318b54d3a6cSRandall Stewart if (mode == 2) { 319b54d3a6cSRandall Stewart TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { 320b54d3a6cSRandall Stewart /* 321b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination is unreachable 322b54d3a6cSRandall Stewart * or unconfirmed, skip it. 323b54d3a6cSRandall Stewart */ 324b54d3a6cSRandall Stewart if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || 325b54d3a6cSRandall Stewart (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) { 326b54d3a6cSRandall Stewart continue; 327b54d3a6cSRandall Stewart } 328b54d3a6cSRandall Stewart /* 329b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination is reachable 330b54d3a6cSRandall Stewart * but in PF state, compare the error count of the 331b54d3a6cSRandall Stewart * destination to the minimum error count seen thus 332b54d3a6cSRandall Stewart * far. Store the destination with the lower error 333b54d3a6cSRandall Stewart * count. If the error counts are equal, store the 334b54d3a6cSRandall Stewart * destination that was most recently active. 335b54d3a6cSRandall Stewart */ 336b54d3a6cSRandall Stewart if (mnet->dest_state & SCTP_ADDR_PF) { 337b54d3a6cSRandall Stewart /* 338b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination under 339b54d3a6cSRandall Stewart * consideration is the current destination, 340b54d3a6cSRandall Stewart * work as if the error count is one higher. 341b54d3a6cSRandall Stewart * The actual error count will not be 342b54d3a6cSRandall Stewart * incremented until later in the t3 343b54d3a6cSRandall Stewart * handler. 344b54d3a6cSRandall Stewart */ 345b54d3a6cSRandall Stewart if (mnet == net) { 346b54d3a6cSRandall Stewart if (min_errors == -1) { 347b54d3a6cSRandall Stewart min_errors = mnet->error_count + 1; 348b54d3a6cSRandall Stewart min_errors_net = mnet; 349b54d3a6cSRandall Stewart } else if (mnet->error_count + 1 < min_errors) { 350b54d3a6cSRandall Stewart min_errors = mnet->error_count + 1; 351b54d3a6cSRandall Stewart min_errors_net = mnet; 352b54d3a6cSRandall Stewart } else if (mnet->error_count + 1 == min_errors 353b54d3a6cSRandall Stewart && mnet->last_active > min_errors_net->last_active) { 354b54d3a6cSRandall Stewart min_errors_net = mnet; 355b54d3a6cSRandall Stewart min_errors = mnet->error_count + 1; 356b54d3a6cSRandall Stewart } 357b54d3a6cSRandall Stewart continue; 358b54d3a6cSRandall Stewart } else { 359b54d3a6cSRandall Stewart if (min_errors == -1) { 360b54d3a6cSRandall Stewart min_errors = mnet->error_count; 361b54d3a6cSRandall Stewart min_errors_net = mnet; 362b54d3a6cSRandall Stewart } else if (mnet->error_count < min_errors) { 363b54d3a6cSRandall Stewart min_errors = mnet->error_count; 364b54d3a6cSRandall Stewart min_errors_net = mnet; 365b54d3a6cSRandall Stewart } else if (mnet->error_count == min_errors 366b54d3a6cSRandall Stewart && mnet->last_active > min_errors_net->last_active) { 367b54d3a6cSRandall Stewart min_errors_net = mnet; 368b54d3a6cSRandall Stewart min_errors = mnet->error_count; 369b54d3a6cSRandall Stewart } 370b54d3a6cSRandall Stewart continue; 371b54d3a6cSRandall Stewart } 372b54d3a6cSRandall Stewart } 373b54d3a6cSRandall Stewart /* 374b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination is reachable and 375b54d3a6cSRandall Stewart * not in PF state, compare the cwnd of the 376b54d3a6cSRandall Stewart * destination to the highest cwnd seen thus far. 377b54d3a6cSRandall Stewart * Store the destination with the higher cwnd value. 378b54d3a6cSRandall Stewart * If the cwnd values are equal, randomly choose one 379b54d3a6cSRandall Stewart * of the two destinations. 380b54d3a6cSRandall Stewart */ 381b54d3a6cSRandall Stewart if (max_cwnd < mnet->cwnd) { 382b54d3a6cSRandall Stewart max_cwnd_net = mnet; 383b54d3a6cSRandall Stewart max_cwnd = mnet->cwnd; 384b54d3a6cSRandall Stewart } else if (max_cwnd == mnet->cwnd) { 385b54d3a6cSRandall Stewart uint32_t rndval; 386b54d3a6cSRandall Stewart uint8_t this_random; 387b54d3a6cSRandall Stewart 388b54d3a6cSRandall Stewart if (stcb->asoc.hb_random_idx > 3) { 389b54d3a6cSRandall Stewart rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); 390b54d3a6cSRandall Stewart memcpy(stcb->asoc.hb_random_values, &rndval, sizeof(stcb->asoc.hb_random_values)); 391b54d3a6cSRandall Stewart this_random = stcb->asoc.hb_random_values[0]; 392b54d3a6cSRandall Stewart stcb->asoc.hb_random_idx++; 393b54d3a6cSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 394b54d3a6cSRandall Stewart } else { 395b54d3a6cSRandall Stewart this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; 396b54d3a6cSRandall Stewart stcb->asoc.hb_random_idx++; 397b54d3a6cSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 398b54d3a6cSRandall Stewart } 399b54d3a6cSRandall Stewart if (this_random % 2 == 1) { 400b54d3a6cSRandall Stewart max_cwnd_net = mnet; 401fc14de76SRandall Stewart max_cwnd = mnet->cwnd; /* Useless? */ 402b54d3a6cSRandall Stewart } 403b54d3a6cSRandall Stewart } 404b54d3a6cSRandall Stewart } 405b54d3a6cSRandall Stewart /* 406b54d3a6cSRandall Stewart * JRS 5/14/07 - After all destination have been considered 407b54d3a6cSRandall Stewart * as alternates, check to see if there was some active 408b54d3a6cSRandall Stewart * destination (not in PF state). If not, check to see if 409b54d3a6cSRandall Stewart * there was some PF destination with the minimum number of 410b54d3a6cSRandall Stewart * errors. If not, return the original destination. If 411b54d3a6cSRandall Stewart * there is a min_errors_net, remove the PF flag from that 412b54d3a6cSRandall Stewart * destination, set the cwnd to one or two MTUs, and return 413b54d3a6cSRandall Stewart * the destination as an alt. If there was some active 414b54d3a6cSRandall Stewart * destination with a highest cwnd, return the destination 415b54d3a6cSRandall Stewart * as an alt. 416b54d3a6cSRandall Stewart */ 417b54d3a6cSRandall Stewart if (max_cwnd_net == NULL) { 418b54d3a6cSRandall Stewart if (min_errors_net == NULL) { 419b54d3a6cSRandall Stewart return (net); 420b54d3a6cSRandall Stewart } 421b54d3a6cSRandall Stewart min_errors_net->dest_state &= ~SCTP_ADDR_PF; 422b3f1ea41SRandall Stewart min_errors_net->cwnd = min_errors_net->mtu * SCTP_BASE_SYSCTL(sctp_cmt_pf); 423b54d3a6cSRandall Stewart if (SCTP_OS_TIMER_PENDING(&min_errors_net->rxt_timer.timer)) { 424b54d3a6cSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 425b54d3a6cSRandall Stewart stcb, min_errors_net, 426b54d3a6cSRandall Stewart SCTP_FROM_SCTP_TIMER + SCTP_LOC_2); 427b54d3a6cSRandall Stewart } 428b54d3a6cSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to active with %d errors.\n", 429b54d3a6cSRandall Stewart min_errors_net, min_errors_net->error_count); 430b54d3a6cSRandall Stewart return (min_errors_net); 431b54d3a6cSRandall Stewart } else { 432b54d3a6cSRandall Stewart return (max_cwnd_net); 433b54d3a6cSRandall Stewart } 434b54d3a6cSRandall Stewart } 435b54d3a6cSRandall Stewart /* 436b54d3a6cSRandall Stewart * JRS 5/14/07 - If mode is set to 1, use the CMT policy for 437b54d3a6cSRandall Stewart * choosing an alternate net. 438b54d3a6cSRandall Stewart */ 439b54d3a6cSRandall Stewart else if (mode == 1) { 440f8829a4aSRandall Stewart TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { 441f8829a4aSRandall Stewart if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || 442f8829a4aSRandall Stewart (mnet->dest_state & SCTP_ADDR_UNCONFIRMED) 443f8829a4aSRandall Stewart ) { 444f8829a4aSRandall Stewart /* 445f8829a4aSRandall Stewart * will skip ones that are not-reachable or 446f8829a4aSRandall Stewart * unconfirmed 447f8829a4aSRandall Stewart */ 448f8829a4aSRandall Stewart continue; 449f8829a4aSRandall Stewart } 450b54d3a6cSRandall Stewart if (max_cwnd < mnet->cwnd) { 451b54d3a6cSRandall Stewart max_cwnd_net = mnet; 452b54d3a6cSRandall Stewart max_cwnd = mnet->cwnd; 453b54d3a6cSRandall Stewart } else if (max_cwnd == mnet->cwnd) { 454f8829a4aSRandall Stewart uint32_t rndval; 455f8829a4aSRandall Stewart uint8_t this_random; 456f8829a4aSRandall Stewart 457f8829a4aSRandall Stewart if (stcb->asoc.hb_random_idx > 3) { 458f8829a4aSRandall Stewart rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); 459f8829a4aSRandall Stewart memcpy(stcb->asoc.hb_random_values, &rndval, 460f8829a4aSRandall Stewart sizeof(stcb->asoc.hb_random_values)); 461f8829a4aSRandall Stewart this_random = stcb->asoc.hb_random_values[0]; 462f8829a4aSRandall Stewart stcb->asoc.hb_random_idx = 0; 463f8829a4aSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 464f8829a4aSRandall Stewart } else { 465f8829a4aSRandall Stewart this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; 466f8829a4aSRandall Stewart stcb->asoc.hb_random_idx++; 467f8829a4aSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 468f8829a4aSRandall Stewart } 469f8829a4aSRandall Stewart if (this_random % 2) { 470b54d3a6cSRandall Stewart max_cwnd_net = mnet; 471b54d3a6cSRandall Stewart max_cwnd = mnet->cwnd; 472f8829a4aSRandall Stewart } 473f8829a4aSRandall Stewart } 474f8829a4aSRandall Stewart } 475b54d3a6cSRandall Stewart if (max_cwnd_net) { 476b54d3a6cSRandall Stewart return (max_cwnd_net); 477f8829a4aSRandall Stewart } 478f8829a4aSRandall Stewart } 479f8829a4aSRandall Stewart mnet = net; 480f8829a4aSRandall Stewart once = 0; 481f8829a4aSRandall Stewart 482f8829a4aSRandall Stewart if (mnet == NULL) { 483f8829a4aSRandall Stewart mnet = TAILQ_FIRST(&stcb->asoc.nets); 484f8829a4aSRandall Stewart } 485f8829a4aSRandall Stewart do { 486f8829a4aSRandall Stewart alt = TAILQ_NEXT(mnet, sctp_next); 487f8829a4aSRandall Stewart if (alt == NULL) { 488f8829a4aSRandall Stewart once++; 489f8829a4aSRandall Stewart if (once > 1) { 490f8829a4aSRandall Stewart break; 491f8829a4aSRandall Stewart } 492f8829a4aSRandall Stewart alt = TAILQ_FIRST(&stcb->asoc.nets); 493f8829a4aSRandall Stewart } 494f8829a4aSRandall Stewart if (alt->ro.ro_rt == NULL) { 49542551e99SRandall Stewart if (alt->ro._s_addr) { 49642551e99SRandall Stewart sctp_free_ifa(alt->ro._s_addr); 49742551e99SRandall Stewart alt->ro._s_addr = NULL; 49842551e99SRandall Stewart } 499f8829a4aSRandall Stewart alt->src_addr_selected = 0; 500f8829a4aSRandall Stewart } 501f8829a4aSRandall Stewart if ( 502f8829a4aSRandall Stewart ((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) && 503f8829a4aSRandall Stewart (alt->ro.ro_rt != NULL) && 5043c503c28SRandall Stewart /* sa_ignore NO_NULL_CHK */ 505f8829a4aSRandall Stewart (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) 506f8829a4aSRandall Stewart ) { 507f8829a4aSRandall Stewart /* Found a reachable address */ 508f8829a4aSRandall Stewart break; 509f8829a4aSRandall Stewart } 510f8829a4aSRandall Stewart mnet = alt; 511f8829a4aSRandall Stewart } while (alt != NULL); 512f8829a4aSRandall Stewart 513f8829a4aSRandall Stewart if (alt == NULL) { 514f8829a4aSRandall Stewart /* Case where NO insv network exists (dormant state) */ 515f8829a4aSRandall Stewart /* we rotate destinations */ 516f8829a4aSRandall Stewart once = 0; 517f8829a4aSRandall Stewart mnet = net; 518f8829a4aSRandall Stewart do { 519f8829a4aSRandall Stewart alt = TAILQ_NEXT(mnet, sctp_next); 520f8829a4aSRandall Stewart if (alt == NULL) { 521f8829a4aSRandall Stewart once++; 522f8829a4aSRandall Stewart if (once > 1) { 523f8829a4aSRandall Stewart break; 524f8829a4aSRandall Stewart } 525f8829a4aSRandall Stewart alt = TAILQ_FIRST(&stcb->asoc.nets); 526f8829a4aSRandall Stewart } 5273c503c28SRandall Stewart /* sa_ignore NO_NULL_CHK */ 528f8829a4aSRandall Stewart if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) && 529f8829a4aSRandall Stewart (alt != net)) { 530f8829a4aSRandall Stewart /* Found an alternate address */ 531f8829a4aSRandall Stewart break; 532f8829a4aSRandall Stewart } 533f8829a4aSRandall Stewart mnet = alt; 534f8829a4aSRandall Stewart } while (alt != NULL); 535f8829a4aSRandall Stewart } 536f8829a4aSRandall Stewart if (alt == NULL) { 537f8829a4aSRandall Stewart return (net); 538f8829a4aSRandall Stewart } 539f8829a4aSRandall Stewart return (alt); 540f8829a4aSRandall Stewart } 541f8829a4aSRandall Stewart 542b54d3a6cSRandall Stewart 543b54d3a6cSRandall Stewart 544f8829a4aSRandall Stewart static void 545f8829a4aSRandall Stewart sctp_backoff_on_timeout(struct sctp_tcb *stcb, 546f8829a4aSRandall Stewart struct sctp_nets *net, 547f8829a4aSRandall Stewart int win_probe, 548*44fbe462SRandall Stewart int num_marked, int num_abandoned) 549f8829a4aSRandall Stewart { 5509a972525SRandall Stewart if (net->RTO == 0) { 5519a972525SRandall Stewart net->RTO = stcb->asoc.minrto; 5529a972525SRandall Stewart } 553f8829a4aSRandall Stewart net->RTO <<= 1; 554f8829a4aSRandall Stewart if (net->RTO > stcb->asoc.maxrto) { 555f8829a4aSRandall Stewart net->RTO = stcb->asoc.maxrto; 556f8829a4aSRandall Stewart } 557*44fbe462SRandall Stewart if ((win_probe == 0) && (num_marked || num_abandoned)) { 558f8829a4aSRandall Stewart /* We don't apply penalty to window probe scenarios */ 559b54d3a6cSRandall Stewart /* JRS - Use the congestion control given in the CC module */ 560b54d3a6cSRandall Stewart stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net); 561f8829a4aSRandall Stewart } 562f8829a4aSRandall Stewart } 563f8829a4aSRandall Stewart 56483416c88SRandall Stewart #ifndef INVARIANTS 56583416c88SRandall Stewart static void 566df6e0cc3SRandall Stewart sctp_recover_sent_list(struct sctp_tcb *stcb) 567df6e0cc3SRandall Stewart { 568df6e0cc3SRandall Stewart struct sctp_tmit_chunk *chk, *tp2; 569df6e0cc3SRandall Stewart struct sctp_association *asoc; 570df6e0cc3SRandall Stewart 571df6e0cc3SRandall Stewart asoc = &stcb->asoc; 572df6e0cc3SRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 573df6e0cc3SRandall Stewart for (; chk != NULL; chk = tp2) { 574df6e0cc3SRandall Stewart tp2 = TAILQ_NEXT(chk, sctp_next); 575df6e0cc3SRandall Stewart if ((compare_with_wrap(stcb->asoc.last_acked_seq, 576df6e0cc3SRandall Stewart chk->rec.data.TSN_seq, 577df6e0cc3SRandall Stewart MAX_TSN)) || 578df6e0cc3SRandall Stewart (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) { 579df6e0cc3SRandall Stewart 580df6e0cc3SRandall Stewart SCTP_PRINTF("Found chk:%p tsn:%x <= last_acked_seq:%x\n", 581df6e0cc3SRandall Stewart chk, chk->rec.data.TSN_seq, stcb->asoc.last_acked_seq); 582df6e0cc3SRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); 583df6e0cc3SRandall Stewart if (chk->pr_sctp_on) { 584df6e0cc3SRandall Stewart if (asoc->pr_sctp_cnt != 0) 585df6e0cc3SRandall Stewart asoc->pr_sctp_cnt--; 586df6e0cc3SRandall Stewart } 587df6e0cc3SRandall Stewart if (chk->data) { 588df6e0cc3SRandall Stewart /* sa_ignore NO_NULL_CHK */ 589df6e0cc3SRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 590df6e0cc3SRandall Stewart sctp_m_freem(chk->data); 591810ec536SMichael Tuexen if (asoc->peer_supports_prsctp && PR_SCTP_BUF_ENABLED(chk->flags)) { 592df6e0cc3SRandall Stewart asoc->sent_queue_cnt_removeable--; 593df6e0cc3SRandall Stewart } 594df6e0cc3SRandall Stewart } 595df6e0cc3SRandall Stewart chk->data = NULL; 596df6e0cc3SRandall Stewart asoc->sent_queue_cnt--; 597df6e0cc3SRandall Stewart sctp_free_a_chunk(stcb, chk); 598df6e0cc3SRandall Stewart } 599df6e0cc3SRandall Stewart } 600df6e0cc3SRandall Stewart SCTP_PRINTF("after recover order is as follows\n"); 601df6e0cc3SRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 602df6e0cc3SRandall Stewart for (; chk != NULL; chk = tp2) { 603df6e0cc3SRandall Stewart tp2 = TAILQ_NEXT(chk, sctp_next); 604df6e0cc3SRandall Stewart SCTP_PRINTF("chk:%p TSN:%x\n", chk, chk->rec.data.TSN_seq); 605df6e0cc3SRandall Stewart } 606df6e0cc3SRandall Stewart } 607df6e0cc3SRandall Stewart 60883416c88SRandall Stewart #endif 60983416c88SRandall Stewart 610f8829a4aSRandall Stewart static int 611f8829a4aSRandall Stewart sctp_mark_all_for_resend(struct sctp_tcb *stcb, 612f8829a4aSRandall Stewart struct sctp_nets *net, 613f8829a4aSRandall Stewart struct sctp_nets *alt, 614f8829a4aSRandall Stewart int window_probe, 615*44fbe462SRandall Stewart int *num_marked, 616*44fbe462SRandall Stewart int *num_abandoned) 617f8829a4aSRandall Stewart { 618f8829a4aSRandall Stewart 619f8829a4aSRandall Stewart /* 620f8829a4aSRandall Stewart * Mark all chunks (well not all) that were sent to *net for 621f8829a4aSRandall Stewart * retransmission. Move them to alt for there destination as well... 622f8829a4aSRandall Stewart * We only mark chunks that have been outstanding long enough to 623f8829a4aSRandall Stewart * have received feed-back. 624f8829a4aSRandall Stewart */ 625*44fbe462SRandall Stewart struct sctp_tmit_chunk *chk, *tp2; 626f8829a4aSRandall Stewart struct sctp_nets *lnets; 627f8829a4aSRandall Stewart struct timeval now, min_wait, tv; 628f8829a4aSRandall Stewart int cur_rtt; 629*44fbe462SRandall Stewart int cnt_abandoned; 630c105859eSRandall Stewart int audit_tf, num_mk, fir; 631f8829a4aSRandall Stewart unsigned int cnt_mk; 632c105859eSRandall Stewart uint32_t orig_flight, orig_tf; 633f8829a4aSRandall Stewart uint32_t tsnlast, tsnfirst; 634df6e0cc3SRandall Stewart int recovery_cnt = 0; 635f8829a4aSRandall Stewart 636b54d3a6cSRandall Stewart 637f8829a4aSRandall Stewart /* none in flight now */ 638f8829a4aSRandall Stewart audit_tf = 0; 639f8829a4aSRandall Stewart fir = 0; 640f8829a4aSRandall Stewart /* 641f8829a4aSRandall Stewart * figure out how long a data chunk must be pending before we can 642f8829a4aSRandall Stewart * mark it .. 643f8829a4aSRandall Stewart */ 6446e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 645f8829a4aSRandall Stewart /* get cur rto in micro-seconds */ 646f8829a4aSRandall Stewart cur_rtt = (((net->lastsa >> 2) + net->lastsv) >> 1); 647f8829a4aSRandall Stewart cur_rtt *= 1000; 648b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 649f8829a4aSRandall Stewart sctp_log_fr(cur_rtt, 650f8829a4aSRandall Stewart stcb->asoc.peers_rwnd, 651f8829a4aSRandall Stewart window_probe, 652f8829a4aSRandall Stewart SCTP_FR_T3_MARK_TIME); 653f8829a4aSRandall Stewart sctp_log_fr(net->flight_size, 654139bc87fSRandall Stewart SCTP_OS_TIMER_PENDING(&net->fr_timer.timer), 655139bc87fSRandall Stewart SCTP_OS_TIMER_ACTIVE(&net->fr_timer.timer), 656f8829a4aSRandall Stewart SCTP_FR_CWND_REPORT); 657f8829a4aSRandall Stewart sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT); 65880fefe0aSRandall Stewart } 659f8829a4aSRandall Stewart tv.tv_sec = cur_rtt / 1000000; 660f8829a4aSRandall Stewart tv.tv_usec = cur_rtt % 1000000; 661f8829a4aSRandall Stewart min_wait = now; 662f8829a4aSRandall Stewart timevalsub(&min_wait, &tv); 663f8829a4aSRandall Stewart if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { 664f8829a4aSRandall Stewart /* 665f8829a4aSRandall Stewart * if we hit here, we don't have enough seconds on the clock 666f8829a4aSRandall Stewart * to account for the RTO. We just let the lower seconds be 667f8829a4aSRandall Stewart * the bounds and don't worry about it. This may mean we 668f8829a4aSRandall Stewart * will mark a lot more than we should. 669f8829a4aSRandall Stewart */ 670f8829a4aSRandall Stewart min_wait.tv_sec = min_wait.tv_usec = 0; 671f8829a4aSRandall Stewart } 672b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 673f8829a4aSRandall Stewart sctp_log_fr(cur_rtt, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); 674f8829a4aSRandall Stewart sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); 67580fefe0aSRandall Stewart } 676f8829a4aSRandall Stewart /* 677f8829a4aSRandall Stewart * Our rwnd will be incorrect here since we are not adding back the 678f8829a4aSRandall Stewart * cnt * mbuf but we will fix that down below. 679f8829a4aSRandall Stewart */ 680f8829a4aSRandall Stewart orig_flight = net->flight_size; 681c105859eSRandall Stewart orig_tf = stcb->asoc.total_flight; 682c105859eSRandall Stewart 683f8829a4aSRandall Stewart net->fast_retran_ip = 0; 684f8829a4aSRandall Stewart /* Now on to each chunk */ 685*44fbe462SRandall Stewart cnt_abandoned = 0; 686f8829a4aSRandall Stewart num_mk = cnt_mk = 0; 687f8829a4aSRandall Stewart tsnfirst = tsnlast = 0; 68883416c88SRandall Stewart #ifndef INVARIANTS 689df6e0cc3SRandall Stewart start_again: 69083416c88SRandall Stewart #endif 691f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 692f8829a4aSRandall Stewart for (; chk != NULL; chk = tp2) { 693f8829a4aSRandall Stewart tp2 = TAILQ_NEXT(chk, sctp_next); 694f8829a4aSRandall Stewart if ((compare_with_wrap(stcb->asoc.last_acked_seq, 695f8829a4aSRandall Stewart chk->rec.data.TSN_seq, 696f8829a4aSRandall Stewart MAX_TSN)) || 697f8829a4aSRandall Stewart (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) { 698f8829a4aSRandall Stewart /* Strange case our list got out of order? */ 699df6e0cc3SRandall Stewart SCTP_PRINTF("Our list is out of order? last_acked:%x chk:%x", 700df6e0cc3SRandall Stewart (unsigned int)stcb->asoc.last_acked_seq, (unsigned int)chk->rec.data.TSN_seq); 701df6e0cc3SRandall Stewart recovery_cnt++; 702df6e0cc3SRandall Stewart #ifdef INVARIANTS 703df6e0cc3SRandall Stewart panic("last acked >= chk on sent-Q"); 704df6e0cc3SRandall Stewart #else 705df6e0cc3SRandall Stewart SCTP_PRINTF("Recover attempts a restart cnt:%d\n", recovery_cnt); 706df6e0cc3SRandall Stewart sctp_recover_sent_list(stcb); 707df6e0cc3SRandall Stewart if (recovery_cnt < 10) { 708df6e0cc3SRandall Stewart goto start_again; 709df6e0cc3SRandall Stewart } else { 710df6e0cc3SRandall Stewart SCTP_PRINTF("Recovery fails %d times??\n", recovery_cnt); 711df6e0cc3SRandall Stewart } 712df6e0cc3SRandall Stewart #endif 713f8829a4aSRandall Stewart } 714f8829a4aSRandall Stewart if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) { 715f8829a4aSRandall Stewart /* 716f8829a4aSRandall Stewart * found one to mark: If it is less than 717f8829a4aSRandall Stewart * DATAGRAM_ACKED it MUST not be a skipped or marked 718f8829a4aSRandall Stewart * TSN but instead one that is either already set 719f8829a4aSRandall Stewart * for retransmission OR one that needs 720f8829a4aSRandall Stewart * retransmission. 721f8829a4aSRandall Stewart */ 722f8829a4aSRandall Stewart 723f8829a4aSRandall Stewart /* validate its been outstanding long enough */ 724b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 725f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, 726f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 727f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 728f8829a4aSRandall Stewart SCTP_FR_T3_MARK_TIME); 72980fefe0aSRandall Stewart } 730f8829a4aSRandall Stewart if ((chk->sent_rcv_time.tv_sec > min_wait.tv_sec) && (window_probe == 0)) { 731f8829a4aSRandall Stewart /* 732f8829a4aSRandall Stewart * we have reached a chunk that was sent 733f8829a4aSRandall Stewart * some seconds past our min.. forget it we 734f8829a4aSRandall Stewart * will find no more to send. 735f8829a4aSRandall Stewart */ 736b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 737f8829a4aSRandall Stewart sctp_log_fr(0, 738f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 739f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 740f8829a4aSRandall Stewart SCTP_FR_T3_STOPPED); 74180fefe0aSRandall Stewart } 742f8829a4aSRandall Stewart continue; 743f8829a4aSRandall Stewart } else if ((chk->sent_rcv_time.tv_sec == min_wait.tv_sec) && 744f8829a4aSRandall Stewart (window_probe == 0)) { 745f8829a4aSRandall Stewart /* 746f8829a4aSRandall Stewart * we must look at the micro seconds to 747f8829a4aSRandall Stewart * know. 748f8829a4aSRandall Stewart */ 749f8829a4aSRandall Stewart if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { 750f8829a4aSRandall Stewart /* 751f8829a4aSRandall Stewart * ok it was sent after our boundary 752f8829a4aSRandall Stewart * time. 753f8829a4aSRandall Stewart */ 754b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 755f8829a4aSRandall Stewart sctp_log_fr(0, 756f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 757f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 758f8829a4aSRandall Stewart SCTP_FR_T3_STOPPED); 75980fefe0aSRandall Stewart } 760f8829a4aSRandall Stewart continue; 761f8829a4aSRandall Stewart } 762f8829a4aSRandall Stewart } 763810ec536SMichael Tuexen if (stcb->asoc.peer_supports_prsctp && PR_SCTP_TTL_ENABLED(chk->flags)) { 764f8829a4aSRandall Stewart /* Is it expired? */ 765f8829a4aSRandall Stewart if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) || 766f8829a4aSRandall Stewart ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) && 767f8829a4aSRandall Stewart (now.tv_usec > chk->rec.data.timetodrop.tv_usec))) { 768f8829a4aSRandall Stewart /* Yes so drop it */ 769f8829a4aSRandall Stewart if (chk->data) { 770ad81507eSRandall Stewart (void)sctp_release_pr_sctp_chunk(stcb, 771f8829a4aSRandall Stewart chk, 772f8829a4aSRandall Stewart (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), 7730c0982b8SRandall Stewart SCTP_SO_NOT_LOCKED); 774*44fbe462SRandall Stewart cnt_abandoned++; 775f8829a4aSRandall Stewart } 776f8829a4aSRandall Stewart continue; 777f8829a4aSRandall Stewart } 778830d754dSRandall Stewart } 779810ec536SMichael Tuexen if (stcb->asoc.peer_supports_prsctp && PR_SCTP_RTX_ENABLED(chk->flags)) { 780f8829a4aSRandall Stewart /* Has it been retransmitted tv_sec times? */ 781f8829a4aSRandall Stewart if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) { 782f8829a4aSRandall Stewart if (chk->data) { 783ad81507eSRandall Stewart (void)sctp_release_pr_sctp_chunk(stcb, 784f8829a4aSRandall Stewart chk, 785f8829a4aSRandall Stewart (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), 7860c0982b8SRandall Stewart SCTP_SO_NOT_LOCKED); 787*44fbe462SRandall Stewart cnt_abandoned++; 788f8829a4aSRandall Stewart } 789f8829a4aSRandall Stewart continue; 790f8829a4aSRandall Stewart } 791830d754dSRandall Stewart } 792c105859eSRandall Stewart if (chk->sent < SCTP_DATAGRAM_RESEND) { 793f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 794f8829a4aSRandall Stewart num_mk++; 795f8829a4aSRandall Stewart if (fir == 0) { 796f8829a4aSRandall Stewart fir = 1; 797f8829a4aSRandall Stewart tsnfirst = chk->rec.data.TSN_seq; 798f8829a4aSRandall Stewart } 799f8829a4aSRandall Stewart tsnlast = chk->rec.data.TSN_seq; 800b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 801f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, 802f8829a4aSRandall Stewart 0, SCTP_FR_T3_MARKED); 80380fefe0aSRandall Stewart } 80442551e99SRandall Stewart if (chk->rec.data.chunk_was_revoked) { 80542551e99SRandall Stewart /* deflate the cwnd */ 80642551e99SRandall Stewart chk->whoTo->cwnd -= chk->book_size; 80742551e99SRandall Stewart chk->rec.data.chunk_was_revoked = 0; 80842551e99SRandall Stewart } 809f42a358aSRandall Stewart net->marked_retrans++; 810f42a358aSRandall Stewart stcb->asoc.marked_retrans++; 811b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 812c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO, 813a5d547adSRandall Stewart chk->whoTo->flight_size, 814a5d547adSRandall Stewart chk->book_size, 815c105859eSRandall Stewart (uintptr_t) chk->whoTo, 816a5d547adSRandall Stewart chk->rec.data.TSN_seq); 81780fefe0aSRandall Stewart } 818c105859eSRandall Stewart sctp_flight_size_decrease(chk); 819c105859eSRandall Stewart sctp_total_flight_decrease(stcb, chk); 820f8829a4aSRandall Stewart stcb->asoc.peers_rwnd += chk->send_size; 821b3f1ea41SRandall Stewart stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); 822c105859eSRandall Stewart } 823c105859eSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 824c105859eSRandall Stewart SCTP_STAT_INCR(sctps_markedretrans); 825f8829a4aSRandall Stewart 826f8829a4aSRandall Stewart /* reset the TSN for striking and other FR stuff */ 827f8829a4aSRandall Stewart chk->rec.data.doing_fast_retransmit = 0; 828f8829a4aSRandall Stewart /* Clear any time so NO RTT is being done */ 829f8829a4aSRandall Stewart chk->do_rtt = 0; 830f8829a4aSRandall Stewart if (alt != net) { 831f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 832f8829a4aSRandall Stewart chk->no_fr_allowed = 1; 833f8829a4aSRandall Stewart chk->whoTo = alt; 834f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 835f8829a4aSRandall Stewart } else { 836f8829a4aSRandall Stewart chk->no_fr_allowed = 0; 837f8829a4aSRandall Stewart if (TAILQ_EMPTY(&stcb->asoc.send_queue)) { 838f8829a4aSRandall Stewart chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq; 839f8829a4aSRandall Stewart } else { 840f8829a4aSRandall Stewart chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq; 841f8829a4aSRandall Stewart } 842f8829a4aSRandall Stewart } 843ad21a364SRandall Stewart /* 844ad21a364SRandall Stewart * CMT: Do not allow FRs on retransmitted TSNs. 845ad21a364SRandall Stewart */ 846b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 1) { 847f8829a4aSRandall Stewart chk->no_fr_allowed = 1; 848f8829a4aSRandall Stewart } 849*44fbe462SRandall Stewart #ifdef THIS_SHOULD_NOT_BE_DONE 850f8829a4aSRandall Stewart } else if (chk->sent == SCTP_DATAGRAM_ACKED) { 851f8829a4aSRandall Stewart /* remember highest acked one */ 852f8829a4aSRandall Stewart could_be_sent = chk; 853*44fbe462SRandall Stewart #endif 854f8829a4aSRandall Stewart } 855f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 856f8829a4aSRandall Stewart cnt_mk++; 857f8829a4aSRandall Stewart } 858f8829a4aSRandall Stewart } 859c105859eSRandall Stewart if ((orig_flight - net->flight_size) != (orig_tf - stcb->asoc.total_flight)) { 860c105859eSRandall Stewart /* we did not subtract the same things? */ 861c105859eSRandall Stewart audit_tf = 1; 862c105859eSRandall Stewart } 863b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 864f8829a4aSRandall Stewart sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT); 86580fefe0aSRandall Stewart } 866f8829a4aSRandall Stewart #ifdef SCTP_DEBUG 867f8829a4aSRandall Stewart if (num_mk) { 868ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", 869ad81507eSRandall Stewart tsnlast); 870ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%ld\n", 871f8829a4aSRandall Stewart num_mk, (u_long)stcb->asoc.peers_rwnd); 872ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", 873ad81507eSRandall Stewart tsnlast); 874ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%d\n", 875f8829a4aSRandall Stewart num_mk, 876ad81507eSRandall Stewart (int)stcb->asoc.peers_rwnd); 877f8829a4aSRandall Stewart } 878f8829a4aSRandall Stewart #endif 879f8829a4aSRandall Stewart *num_marked = num_mk; 880*44fbe462SRandall Stewart *num_abandoned = cnt_abandoned; 8816c065bbeSRandall Stewart /* 8826c065bbeSRandall Stewart * Now check for a ECN Echo that may be stranded And include the 8836c065bbeSRandall Stewart * cnt_mk'd to have all resends in the control queue. 8846c065bbeSRandall Stewart */ 8856c065bbeSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 8866c065bbeSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 8876c065bbeSRandall Stewart cnt_mk++; 8886c065bbeSRandall Stewart } 8896c065bbeSRandall Stewart if ((chk->whoTo == net) && 8906c065bbeSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 8916c065bbeSRandall Stewart sctp_free_remote_addr(chk->whoTo); 8926c065bbeSRandall Stewart chk->whoTo = alt; 8936c065bbeSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 8946c065bbeSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 8956c065bbeSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 8966c065bbeSRandall Stewart cnt_mk++; 8976c065bbeSRandall Stewart } 8986c065bbeSRandall Stewart atomic_add_int(&alt->ref_count, 1); 8996c065bbeSRandall Stewart } 9006c065bbeSRandall Stewart } 901*44fbe462SRandall Stewart #ifdef THIS_SHOULD_NOT_BE_DONE 902f8829a4aSRandall Stewart if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) { 903f8829a4aSRandall Stewart /* fix it so we retransmit the highest acked anyway */ 904f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 905f8829a4aSRandall Stewart cnt_mk++; 906f8829a4aSRandall Stewart could_be_sent->sent = SCTP_DATAGRAM_RESEND; 907f8829a4aSRandall Stewart } 908*44fbe462SRandall Stewart #endif 909f8829a4aSRandall Stewart if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { 910a5d547adSRandall Stewart #ifdef INVARIANTS 91118e198d3SRandall Stewart SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d we marked:%d this time\n", 91218e198d3SRandall Stewart cnt_mk, stcb->asoc.sent_queue_retran_cnt, num_mk); 913f8829a4aSRandall Stewart #endif 914f8829a4aSRandall Stewart #ifndef SCTP_AUDITING_ENABLED 915f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = cnt_mk; 916f8829a4aSRandall Stewart #endif 917f8829a4aSRandall Stewart } 918f8829a4aSRandall Stewart if (audit_tf) { 919ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, 920ad81507eSRandall Stewart "Audit total flight due to negative value net:%p\n", 921f8829a4aSRandall Stewart net); 922f8829a4aSRandall Stewart stcb->asoc.total_flight = 0; 923f8829a4aSRandall Stewart stcb->asoc.total_flight_count = 0; 924f8829a4aSRandall Stewart /* Clear all networks flight size */ 925f8829a4aSRandall Stewart TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) { 926f8829a4aSRandall Stewart lnets->flight_size = 0; 927ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, 928ad81507eSRandall Stewart "Net:%p c-f cwnd:%d ssthresh:%d\n", 929f8829a4aSRandall Stewart lnets, lnets->cwnd, lnets->ssthresh); 930f8829a4aSRandall Stewart } 931f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 932f8829a4aSRandall Stewart if (chk->sent < SCTP_DATAGRAM_RESEND) { 933b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 934a5d547adSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_UP, 935a5d547adSRandall Stewart chk->whoTo->flight_size, 936a5d547adSRandall Stewart chk->book_size, 937c105859eSRandall Stewart (uintptr_t) chk->whoTo, 938a5d547adSRandall Stewart chk->rec.data.TSN_seq); 93980fefe0aSRandall Stewart } 940c105859eSRandall Stewart sctp_flight_size_increase(chk); 941c105859eSRandall Stewart sctp_total_flight_increase(stcb, chk); 942f8829a4aSRandall Stewart } 943f8829a4aSRandall Stewart } 944f8829a4aSRandall Stewart } 945f8829a4aSRandall Stewart /* 946f8829a4aSRandall Stewart * Setup the ecn nonce re-sync point. We do this since 947f8829a4aSRandall Stewart * retranmissions are NOT setup for ECN. This means that do to 948f8829a4aSRandall Stewart * Karn's rule, we don't know the total of the peers ecn bits. 949f8829a4aSRandall Stewart */ 950f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.send_queue); 951f8829a4aSRandall Stewart if (chk == NULL) { 952f8829a4aSRandall Stewart stcb->asoc.nonce_resync_tsn = stcb->asoc.sending_seq; 953f8829a4aSRandall Stewart } else { 954f8829a4aSRandall Stewart stcb->asoc.nonce_resync_tsn = chk->rec.data.TSN_seq; 955f8829a4aSRandall Stewart } 956f8829a4aSRandall Stewart stcb->asoc.nonce_wait_for_ecne = 0; 957f8829a4aSRandall Stewart stcb->asoc.nonce_sum_check = 0; 958f8829a4aSRandall Stewart /* We return 1 if we only have a window probe outstanding */ 959f8829a4aSRandall Stewart return (0); 960f8829a4aSRandall Stewart } 961f8829a4aSRandall Stewart 962f8829a4aSRandall Stewart static void 963f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb, 964f8829a4aSRandall Stewart struct sctp_nets *net, 965f8829a4aSRandall Stewart struct sctp_nets *alt) 966f8829a4aSRandall Stewart { 967f8829a4aSRandall Stewart struct sctp_association *asoc; 968f8829a4aSRandall Stewart struct sctp_stream_out *outs; 969f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 970f8829a4aSRandall Stewart struct sctp_stream_queue_pending *sp; 971f8829a4aSRandall Stewart 972f8829a4aSRandall Stewart if (net == alt) 973f8829a4aSRandall Stewart /* nothing to do */ 974f8829a4aSRandall Stewart return; 975f8829a4aSRandall Stewart 976f8829a4aSRandall Stewart asoc = &stcb->asoc; 977f8829a4aSRandall Stewart 978f8829a4aSRandall Stewart /* 979f8829a4aSRandall Stewart * now through all the streams checking for chunks sent to our bad 980f8829a4aSRandall Stewart * network. 981f8829a4aSRandall Stewart */ 982f8829a4aSRandall Stewart TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { 983f8829a4aSRandall Stewart /* now clean up any chunks here */ 984f8829a4aSRandall Stewart TAILQ_FOREACH(sp, &outs->outqueue, next) { 985f8829a4aSRandall Stewart if (sp->net == net) { 986f8829a4aSRandall Stewart sctp_free_remote_addr(sp->net); 987f8829a4aSRandall Stewart sp->net = alt; 988f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 989f8829a4aSRandall Stewart } 990f8829a4aSRandall Stewart } 991f8829a4aSRandall Stewart } 992f8829a4aSRandall Stewart /* Now check the pending queue */ 993f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { 994f8829a4aSRandall Stewart if (chk->whoTo == net) { 995f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 996f8829a4aSRandall Stewart chk->whoTo = alt; 997f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 998f8829a4aSRandall Stewart } 999f8829a4aSRandall Stewart } 1000f8829a4aSRandall Stewart 1001f8829a4aSRandall Stewart } 1002f8829a4aSRandall Stewart 1003f8829a4aSRandall Stewart int 1004f8829a4aSRandall Stewart sctp_t3rxt_timer(struct sctp_inpcb *inp, 1005f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1006f8829a4aSRandall Stewart struct sctp_nets *net) 1007f8829a4aSRandall Stewart { 1008f8829a4aSRandall Stewart struct sctp_nets *alt; 1009*44fbe462SRandall Stewart int win_probe, num_mk, num_abandoned; 1010f8829a4aSRandall Stewart 1011b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { 1012562a89b5SRandall Stewart sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT); 101380fefe0aSRandall Stewart } 1014b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { 1015f8829a4aSRandall Stewart struct sctp_nets *lnet; 1016f8829a4aSRandall Stewart 1017f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 1018f8829a4aSRandall Stewart if (net == lnet) { 1019f8829a4aSRandall Stewart sctp_log_cwnd(stcb, lnet, 1, SCTP_CWND_LOG_FROM_T3); 1020f8829a4aSRandall Stewart } else { 1021f8829a4aSRandall Stewart sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_LOG_FROM_T3); 1022f8829a4aSRandall Stewart } 1023f8829a4aSRandall Stewart } 1024f8829a4aSRandall Stewart } 1025f8829a4aSRandall Stewart /* Find an alternate and mark those for retransmission */ 1026f8829a4aSRandall Stewart if ((stcb->asoc.peers_rwnd == 0) && 1027f8829a4aSRandall Stewart (stcb->asoc.total_flight < net->mtu)) { 1028f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timowindowprobe); 1029f8829a4aSRandall Stewart win_probe = 1; 1030f8829a4aSRandall Stewart } else { 1031f8829a4aSRandall Stewart win_probe = 0; 1032f8829a4aSRandall Stewart } 1033c105859eSRandall Stewart 1034b54d3a6cSRandall Stewart /* 1035b54d3a6cSRandall Stewart * JRS 5/14/07 - If CMT PF is on and the destination if not already 1036b54d3a6cSRandall Stewart * in PF state, set the destination to PF state and store the 1037b54d3a6cSRandall Stewart * current time as the time that the destination was last active. In 1038b54d3a6cSRandall Stewart * addition, find an alternate destination with PF-based 1039b54d3a6cSRandall Stewart * find_alt_net(). 1040b54d3a6cSRandall Stewart */ 1041b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { 1042b54d3a6cSRandall Stewart if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) { 1043b54d3a6cSRandall Stewart net->dest_state |= SCTP_ADDR_PF; 104418e198d3SRandall Stewart net->last_active = sctp_get_tick_count(); 1045b54d3a6cSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from active to PF.\n", 1046b54d3a6cSRandall Stewart net); 1047b54d3a6cSRandall Stewart } 1048b54d3a6cSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 2); 1049b3f1ea41SRandall Stewart } else if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { 1050c105859eSRandall Stewart /* 1051c105859eSRandall Stewart * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being 1052c105859eSRandall Stewart * used, then pick dest with largest ssthresh for any 1053c105859eSRandall Stewart * retransmission. 1054c105859eSRandall Stewart */ 1055c105859eSRandall Stewart alt = net; 1056c105859eSRandall Stewart alt = sctp_find_alternate_net(stcb, alt, 1); 1057c105859eSRandall Stewart /* 1058c105859eSRandall Stewart * CUCv2: If a different dest is picked for the 1059c105859eSRandall Stewart * retransmission, then new (rtx-)pseudo_cumack needs to be 1060c105859eSRandall Stewart * tracked for orig dest. Let CUCv2 track new (rtx-) 1061c105859eSRandall Stewart * pseudo-cumack always. 1062c105859eSRandall Stewart */ 1063c105859eSRandall Stewart net->find_pseudo_cumack = 1; 1064c105859eSRandall Stewart net->find_rtx_pseudo_cumack = 1; 1065c105859eSRandall Stewart } else { /* CMT is OFF */ 1066f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 1067c105859eSRandall Stewart } 1068*44fbe462SRandall Stewart num_mk = 0; 1069*44fbe462SRandall Stewart num_abandoned = 0; 1070*44fbe462SRandall Stewart (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, 1071*44fbe462SRandall Stewart &num_mk, &num_abandoned); 1072f8829a4aSRandall Stewart /* FR Loss recovery just ended with the T3. */ 1073f8829a4aSRandall Stewart stcb->asoc.fast_retran_loss_recovery = 0; 1074f8829a4aSRandall Stewart 1075f8829a4aSRandall Stewart /* CMT FR loss recovery ended with the T3 */ 1076f8829a4aSRandall Stewart net->fast_retran_loss_recovery = 0; 1077f8829a4aSRandall Stewart 1078f8829a4aSRandall Stewart /* 1079f8829a4aSRandall Stewart * setup the sat loss recovery that prevents satellite cwnd advance. 1080f8829a4aSRandall Stewart */ 1081f8829a4aSRandall Stewart stcb->asoc.sat_t3_loss_recovery = 1; 1082f8829a4aSRandall Stewart stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; 1083f8829a4aSRandall Stewart 1084f8829a4aSRandall Stewart /* Backoff the timer and cwnd */ 1085*44fbe462SRandall Stewart sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); 1086f8829a4aSRandall Stewart if (win_probe == 0) { 1087f8829a4aSRandall Stewart /* We don't do normal threshold management on window probes */ 1088f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, 1089f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1090f8829a4aSRandall Stewart /* Association was destroyed */ 1091f8829a4aSRandall Stewart return (1); 1092f8829a4aSRandall Stewart } else { 1093f8829a4aSRandall Stewart if (net != stcb->asoc.primary_destination) { 1094f8829a4aSRandall Stewart /* send a immediate HB if our RTO is stale */ 1095f8829a4aSRandall Stewart struct timeval now; 1096f8829a4aSRandall Stewart unsigned int ms_goneby; 1097f8829a4aSRandall Stewart 10986e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 1099f8829a4aSRandall Stewart if (net->last_sent_time.tv_sec) { 1100f8829a4aSRandall Stewart ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000; 1101f8829a4aSRandall Stewart } else { 1102f8829a4aSRandall Stewart ms_goneby = 0; 1103f8829a4aSRandall Stewart } 1104f8829a4aSRandall Stewart if ((ms_goneby > net->RTO) || (net->RTO == 0)) { 1105f8829a4aSRandall Stewart /* 1106f8829a4aSRandall Stewart * no recent feed back in an RTO or 1107f8829a4aSRandall Stewart * more, request a RTT update 1108f8829a4aSRandall Stewart */ 1109b54d3a6cSRandall Stewart if (sctp_send_hb(stcb, 1, net) < 0) 1110830d754dSRandall Stewart /* 1111830d754dSRandall Stewart * Less than 0 means we lost 1112830d754dSRandall Stewart * the assoc 1113830d754dSRandall Stewart */ 1114830d754dSRandall Stewart return (1); 1115f8829a4aSRandall Stewart } 1116f8829a4aSRandall Stewart } 1117f8829a4aSRandall Stewart } 1118f8829a4aSRandall Stewart } else { 1119f8829a4aSRandall Stewart /* 1120f8829a4aSRandall Stewart * For a window probe we don't penalize the net's but only 1121f8829a4aSRandall Stewart * the association. This may fail it if SACKs are not coming 1122f8829a4aSRandall Stewart * back. If sack's are coming with rwnd locked at 0, we will 1123f8829a4aSRandall Stewart * continue to hold things waiting for rwnd to raise 1124f8829a4aSRandall Stewart */ 1125f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, NULL, 1126f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1127f8829a4aSRandall Stewart /* Association was destroyed */ 1128f8829a4aSRandall Stewart return (1); 1129f8829a4aSRandall Stewart } 1130f8829a4aSRandall Stewart } 1131f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 1132f8829a4aSRandall Stewart /* Move all pending over too */ 1133f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 113417205eccSRandall Stewart 113517205eccSRandall Stewart /* 113617205eccSRandall Stewart * Get the address that failed, to force a new src address 113717205eccSRandall Stewart * selecton and a route allocation. 113817205eccSRandall Stewart */ 113917205eccSRandall Stewart if (net->ro._s_addr) { 114017205eccSRandall Stewart sctp_free_ifa(net->ro._s_addr); 114117205eccSRandall Stewart net->ro._s_addr = NULL; 114217205eccSRandall Stewart } 114317205eccSRandall Stewart net->src_addr_selected = 0; 114417205eccSRandall Stewart 114517205eccSRandall Stewart /* Force a route allocation too */ 114617205eccSRandall Stewart if (net->ro.ro_rt) { 114717205eccSRandall Stewart RTFREE(net->ro.ro_rt); 114817205eccSRandall Stewart net->ro.ro_rt = NULL; 114917205eccSRandall Stewart } 1150f8829a4aSRandall Stewart /* Was it our primary? */ 1151f8829a4aSRandall Stewart if ((stcb->asoc.primary_destination == net) && (alt != net)) { 1152f8829a4aSRandall Stewart /* 1153f8829a4aSRandall Stewart * Yes, note it as such and find an alternate note: 1154f8829a4aSRandall Stewart * this means HB code must use this to resent the 1155f8829a4aSRandall Stewart * primary if it goes active AND if someone does a 1156f8829a4aSRandall Stewart * change-primary then this flag must be cleared 1157f8829a4aSRandall Stewart * from any net structures. 1158f8829a4aSRandall Stewart */ 1159f8829a4aSRandall Stewart if (sctp_set_primary_addr(stcb, 1160f8829a4aSRandall Stewart (struct sockaddr *)NULL, 1161f8829a4aSRandall Stewart alt) == 0) { 1162f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_WAS_PRIMARY; 1163f8829a4aSRandall Stewart } 1164f8829a4aSRandall Stewart } 1165b3f1ea41SRandall Stewart } else if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf) && (net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) { 1166b54d3a6cSRandall Stewart /* 1167b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination hasn't failed completely 1168b54d3a6cSRandall Stewart * but is in PF state, a PF-heartbeat needs to be sent 1169b54d3a6cSRandall Stewart * manually. 1170b54d3a6cSRandall Stewart */ 1171b54d3a6cSRandall Stewart if (sctp_send_hb(stcb, 1, net) < 0) 1172830d754dSRandall Stewart /* Return less than 0 means we lost the association */ 1173830d754dSRandall Stewart return (1); 1174f8829a4aSRandall Stewart } 1175f8829a4aSRandall Stewart /* 1176f8829a4aSRandall Stewart * Special case for cookie-echo'ed case, we don't do output but must 1177f8829a4aSRandall Stewart * await the COOKIE-ACK before retransmission 1178f8829a4aSRandall Stewart */ 1179f8829a4aSRandall Stewart if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { 1180f8829a4aSRandall Stewart /* 1181f8829a4aSRandall Stewart * Here we just reset the timer and start again since we 1182f8829a4aSRandall Stewart * have not established the asoc 1183f8829a4aSRandall Stewart */ 1184f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); 1185f8829a4aSRandall Stewart return (0); 1186f8829a4aSRandall Stewart } 1187f8829a4aSRandall Stewart if (stcb->asoc.peer_supports_prsctp) { 1188f8829a4aSRandall Stewart struct sctp_tmit_chunk *lchk; 1189f8829a4aSRandall Stewart 1190f8829a4aSRandall Stewart lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc); 1191f8829a4aSRandall Stewart /* C3. See if we need to send a Fwd-TSN */ 1192f8829a4aSRandall Stewart if (compare_with_wrap(stcb->asoc.advanced_peer_ack_point, 1193f8829a4aSRandall Stewart stcb->asoc.last_acked_seq, MAX_TSN)) { 1194f8829a4aSRandall Stewart /* 1195f8829a4aSRandall Stewart * ISSUE with ECN, see FWD-TSN processing for notes 1196f8829a4aSRandall Stewart * on issues that will occur when the ECN NONCE 1197f8829a4aSRandall Stewart * stuff is put into SCTP for cross checking. 1198f8829a4aSRandall Stewart */ 1199f8829a4aSRandall Stewart send_forward_tsn(stcb, &stcb->asoc); 1200f8829a4aSRandall Stewart if (lchk) { 1201f8829a4aSRandall Stewart /* Assure a timer is up */ 1202f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo); 1203f8829a4aSRandall Stewart } 1204f8829a4aSRandall Stewart } 1205f8829a4aSRandall Stewart } 1206b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { 1207f8829a4aSRandall Stewart sctp_log_cwnd(stcb, net, net->cwnd, SCTP_CWND_LOG_FROM_RTX); 120880fefe0aSRandall Stewart } 1209f8829a4aSRandall Stewart return (0); 1210f8829a4aSRandall Stewart } 1211f8829a4aSRandall Stewart 1212f8829a4aSRandall Stewart int 1213f8829a4aSRandall Stewart sctp_t1init_timer(struct sctp_inpcb *inp, 1214f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1215f8829a4aSRandall Stewart struct sctp_nets *net) 1216f8829a4aSRandall Stewart { 1217f8829a4aSRandall Stewart /* bump the thresholds */ 1218f8829a4aSRandall Stewart if (stcb->asoc.delayed_connection) { 1219f8829a4aSRandall Stewart /* 1220f8829a4aSRandall Stewart * special hook for delayed connection. The library did NOT 1221f8829a4aSRandall Stewart * complete the rest of its sends. 1222f8829a4aSRandall Stewart */ 1223f8829a4aSRandall Stewart stcb->asoc.delayed_connection = 0; 1224ceaad40aSRandall Stewart sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); 1225f8829a4aSRandall Stewart return (0); 1226f8829a4aSRandall Stewart } 1227f8829a4aSRandall Stewart if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) { 1228f8829a4aSRandall Stewart return (0); 1229f8829a4aSRandall Stewart } 1230f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, 1231f8829a4aSRandall Stewart stcb->asoc.max_init_times)) { 1232f8829a4aSRandall Stewart /* Association was destroyed */ 1233f8829a4aSRandall Stewart return (1); 1234f8829a4aSRandall Stewart } 1235f8829a4aSRandall Stewart stcb->asoc.dropped_special_cnt = 0; 1236*44fbe462SRandall Stewart sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0, 0); 1237f8829a4aSRandall Stewart if (stcb->asoc.initial_init_rto_max < net->RTO) { 1238f8829a4aSRandall Stewart net->RTO = stcb->asoc.initial_init_rto_max; 1239f8829a4aSRandall Stewart } 1240f8829a4aSRandall Stewart if (stcb->asoc.numnets > 1) { 1241f8829a4aSRandall Stewart /* If we have more than one addr use it */ 1242f8829a4aSRandall Stewart struct sctp_nets *alt; 1243f8829a4aSRandall Stewart 1244f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0); 1245f8829a4aSRandall Stewart if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) { 1246f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt); 1247f8829a4aSRandall Stewart stcb->asoc.primary_destination = alt; 1248f8829a4aSRandall Stewart } 1249f8829a4aSRandall Stewart } 1250f8829a4aSRandall Stewart /* Send out a new init */ 1251ceaad40aSRandall Stewart sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); 1252f8829a4aSRandall Stewart return (0); 1253f8829a4aSRandall Stewart } 1254f8829a4aSRandall Stewart 1255f8829a4aSRandall Stewart /* 1256f8829a4aSRandall Stewart * For cookie and asconf we actually need to find and mark for resend, then 1257f8829a4aSRandall Stewart * increment the resend counter (after all the threshold management stuff of 1258f8829a4aSRandall Stewart * course). 1259f8829a4aSRandall Stewart */ 1260f8829a4aSRandall Stewart int 1261f8829a4aSRandall Stewart sctp_cookie_timer(struct sctp_inpcb *inp, 1262f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1263f8829a4aSRandall Stewart struct sctp_nets *net) 1264f8829a4aSRandall Stewart { 1265f8829a4aSRandall Stewart struct sctp_nets *alt; 1266f8829a4aSRandall Stewart struct sctp_tmit_chunk *cookie; 1267f8829a4aSRandall Stewart 1268f8829a4aSRandall Stewart /* first before all else we must find the cookie */ 1269f8829a4aSRandall Stewart TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) { 1270f8829a4aSRandall Stewart if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) { 1271f8829a4aSRandall Stewart break; 1272f8829a4aSRandall Stewart } 1273f8829a4aSRandall Stewart } 1274f8829a4aSRandall Stewart if (cookie == NULL) { 1275f8829a4aSRandall Stewart if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { 1276f8829a4aSRandall Stewart /* FOOBAR! */ 1277f8829a4aSRandall Stewart struct mbuf *oper; 1278f8829a4aSRandall Stewart 1279f8829a4aSRandall Stewart oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 1280f8829a4aSRandall Stewart 0, M_DONTWAIT, 1, MT_DATA); 1281f8829a4aSRandall Stewart if (oper) { 1282f8829a4aSRandall Stewart struct sctp_paramhdr *ph; 1283f8829a4aSRandall Stewart uint32_t *ippp; 1284f8829a4aSRandall Stewart 1285139bc87fSRandall Stewart SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) + 1286f8829a4aSRandall Stewart sizeof(uint32_t); 1287f8829a4aSRandall Stewart ph = mtod(oper, struct sctp_paramhdr *); 1288f8829a4aSRandall Stewart ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1289139bc87fSRandall Stewart ph->param_length = htons(SCTP_BUF_LEN(oper)); 1290f8829a4aSRandall Stewart ippp = (uint32_t *) (ph + 1); 1291b54d3a6cSRandall Stewart *ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 1292f8829a4aSRandall Stewart } 1293b54d3a6cSRandall Stewart inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_4; 1294f8829a4aSRandall Stewart sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR, 1295ceaad40aSRandall Stewart oper, SCTP_SO_NOT_LOCKED); 1296f8829a4aSRandall Stewart } else { 1297a5d547adSRandall Stewart #ifdef INVARIANTS 1298f8829a4aSRandall Stewart panic("Cookie timer expires in wrong state?"); 1299f8829a4aSRandall Stewart #else 1300ad81507eSRandall Stewart SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc)); 1301f8829a4aSRandall Stewart return (0); 1302f8829a4aSRandall Stewart #endif 1303f8829a4aSRandall Stewart } 1304f8829a4aSRandall Stewart return (0); 1305f8829a4aSRandall Stewart } 1306f8829a4aSRandall Stewart /* Ok we found the cookie, threshold management next */ 1307f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, cookie->whoTo, 1308f8829a4aSRandall Stewart stcb->asoc.max_init_times)) { 1309f8829a4aSRandall Stewart /* Assoc is over */ 1310f8829a4aSRandall Stewart return (1); 1311f8829a4aSRandall Stewart } 1312f8829a4aSRandall Stewart /* 1313f8829a4aSRandall Stewart * cleared theshold management now lets backoff the address & select 1314f8829a4aSRandall Stewart * an alternate 1315f8829a4aSRandall Stewart */ 1316f8829a4aSRandall Stewart stcb->asoc.dropped_special_cnt = 0; 1317*44fbe462SRandall Stewart sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0); 1318f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0); 1319f8829a4aSRandall Stewart if (alt != cookie->whoTo) { 1320f8829a4aSRandall Stewart sctp_free_remote_addr(cookie->whoTo); 1321f8829a4aSRandall Stewart cookie->whoTo = alt; 1322f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1323f8829a4aSRandall Stewart } 1324f8829a4aSRandall Stewart /* Now mark the retran info */ 1325f8829a4aSRandall Stewart if (cookie->sent != SCTP_DATAGRAM_RESEND) { 1326f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1327f8829a4aSRandall Stewart } 1328f8829a4aSRandall Stewart cookie->sent = SCTP_DATAGRAM_RESEND; 1329f8829a4aSRandall Stewart /* 1330f8829a4aSRandall Stewart * Now call the output routine to kick out the cookie again, Note we 1331f8829a4aSRandall Stewart * don't mark any chunks for retran so that FR will need to kick in 1332f8829a4aSRandall Stewart * to move these (or a send timer). 1333f8829a4aSRandall Stewart */ 1334f8829a4aSRandall Stewart return (0); 1335f8829a4aSRandall Stewart } 1336f8829a4aSRandall Stewart 1337f8829a4aSRandall Stewart int 1338f8829a4aSRandall Stewart sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1339f8829a4aSRandall Stewart struct sctp_nets *net) 1340f8829a4aSRandall Stewart { 1341f8829a4aSRandall Stewart struct sctp_nets *alt; 1342f8829a4aSRandall Stewart struct sctp_tmit_chunk *strrst = NULL, *chk = NULL; 1343f8829a4aSRandall Stewart 1344f8829a4aSRandall Stewart if (stcb->asoc.stream_reset_outstanding == 0) { 1345f8829a4aSRandall Stewart return (0); 1346f8829a4aSRandall Stewart } 1347f8829a4aSRandall Stewart /* find the existing STRRESET, we use the seq number we sent out on */ 1348ad81507eSRandall Stewart (void)sctp_find_stream_reset(stcb, stcb->asoc.str_reset_seq_out, &strrst); 1349f8829a4aSRandall Stewart if (strrst == NULL) { 1350f8829a4aSRandall Stewart return (0); 1351f8829a4aSRandall Stewart } 1352f8829a4aSRandall Stewart /* do threshold management */ 1353f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, strrst->whoTo, 1354f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1355f8829a4aSRandall Stewart /* Assoc is over */ 1356f8829a4aSRandall Stewart return (1); 1357f8829a4aSRandall Stewart } 1358f8829a4aSRandall Stewart /* 1359f8829a4aSRandall Stewart * cleared theshold management now lets backoff the address & select 1360f8829a4aSRandall Stewart * an alternate 1361f8829a4aSRandall Stewart */ 1362*44fbe462SRandall Stewart sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0, 0); 1363f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0); 1364f8829a4aSRandall Stewart sctp_free_remote_addr(strrst->whoTo); 1365f8829a4aSRandall Stewart strrst->whoTo = alt; 1366f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1367f8829a4aSRandall Stewart 1368f8829a4aSRandall Stewart /* See if a ECN Echo is also stranded */ 1369f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 1370f8829a4aSRandall Stewart if ((chk->whoTo == net) && 1371f8829a4aSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 1372f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 1373f8829a4aSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 1374f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 1375f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1376f8829a4aSRandall Stewart } 1377f8829a4aSRandall Stewart chk->whoTo = alt; 1378f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1379f8829a4aSRandall Stewart } 1380f8829a4aSRandall Stewart } 1381f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 1382f8829a4aSRandall Stewart /* 1383f8829a4aSRandall Stewart * If the address went un-reachable, we need to move to 1384f8829a4aSRandall Stewart * alternates for ALL chk's in queue 1385f8829a4aSRandall Stewart */ 1386f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 1387f8829a4aSRandall Stewart } 1388f8829a4aSRandall Stewart /* mark the retran info */ 1389f8829a4aSRandall Stewart if (strrst->sent != SCTP_DATAGRAM_RESEND) 1390f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1391f8829a4aSRandall Stewart strrst->sent = SCTP_DATAGRAM_RESEND; 1392f8829a4aSRandall Stewart 1393f8829a4aSRandall Stewart /* restart the timer */ 1394f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo); 1395f8829a4aSRandall Stewart return (0); 1396f8829a4aSRandall Stewart } 1397f8829a4aSRandall Stewart 1398f8829a4aSRandall Stewart int 1399f8829a4aSRandall Stewart sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1400f8829a4aSRandall Stewart struct sctp_nets *net) 1401f8829a4aSRandall Stewart { 1402f8829a4aSRandall Stewart struct sctp_nets *alt; 1403c54a18d2SRandall Stewart struct sctp_tmit_chunk *asconf, *chk, *nchk; 1404f8829a4aSRandall Stewart 14051b649582SRandall Stewart /* is this a first send, or a retransmission? */ 1406c54a18d2SRandall Stewart if (TAILQ_EMPTY(&stcb->asoc.asconf_send_queue)) { 1407f8829a4aSRandall Stewart /* compose a new ASCONF chunk and send it */ 14083232788eSRandall Stewart sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); 1409f8829a4aSRandall Stewart } else { 14101b649582SRandall Stewart /* 14111b649582SRandall Stewart * Retransmission of the existing ASCONF is needed 14121b649582SRandall Stewart */ 1413f8829a4aSRandall Stewart 1414f8829a4aSRandall Stewart /* find the existing ASCONF */ 1415c54a18d2SRandall Stewart asconf = TAILQ_FIRST(&stcb->asoc.asconf_send_queue); 1416f8829a4aSRandall Stewart if (asconf == NULL) { 1417f8829a4aSRandall Stewart return (0); 1418f8829a4aSRandall Stewart } 1419f8829a4aSRandall Stewart /* do threshold management */ 1420f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, asconf->whoTo, 1421f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1422f8829a4aSRandall Stewart /* Assoc is over */ 1423f8829a4aSRandall Stewart return (1); 1424f8829a4aSRandall Stewart } 1425f8829a4aSRandall Stewart if (asconf->snd_count > stcb->asoc.max_send_times) { 1426f8829a4aSRandall Stewart /* 14271b649582SRandall Stewart * Something is rotten: our peer is not responding 14281b649582SRandall Stewart * to ASCONFs but apparently is to other chunks. 14291b649582SRandall Stewart * i.e. it is not properly handling the chunk type 14301b649582SRandall Stewart * upper bits. Mark this peer as ASCONF incapable 14311b649582SRandall Stewart * and cleanup. 1432f8829a4aSRandall Stewart */ 1433ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n"); 1434f8829a4aSRandall Stewart sctp_asconf_cleanup(stcb, net); 1435f8829a4aSRandall Stewart return (0); 1436f8829a4aSRandall Stewart } 1437f8829a4aSRandall Stewart /* 14381b649582SRandall Stewart * cleared threshold management, so now backoff the net and 14391b649582SRandall Stewart * select an alternate 1440f8829a4aSRandall Stewart */ 1441*44fbe462SRandall Stewart sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0, 0); 1442f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0); 1443c54a18d2SRandall Stewart if (asconf->whoTo != alt) { 1444f8829a4aSRandall Stewart sctp_free_remote_addr(asconf->whoTo); 1445f8829a4aSRandall Stewart asconf->whoTo = alt; 1446f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1447c54a18d2SRandall Stewart } 14481b649582SRandall Stewart /* See if an ECN Echo is also stranded */ 1449f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 1450f8829a4aSRandall Stewart if ((chk->whoTo == net) && 1451f8829a4aSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 1452f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 1453f8829a4aSRandall Stewart chk->whoTo = alt; 1454f8829a4aSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 1455f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 1456f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1457f8829a4aSRandall Stewart } 1458f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1459f8829a4aSRandall Stewart } 1460f8829a4aSRandall Stewart } 1461c54a18d2SRandall Stewart for (chk = asconf; chk; chk = nchk) { 1462c54a18d2SRandall Stewart nchk = TAILQ_NEXT(chk, sctp_next); 1463c54a18d2SRandall Stewart if (chk->whoTo != alt) { 1464c54a18d2SRandall Stewart sctp_free_remote_addr(chk->whoTo); 1465c54a18d2SRandall Stewart chk->whoTo = alt; 1466c54a18d2SRandall Stewart atomic_add_int(&alt->ref_count, 1); 1467c54a18d2SRandall Stewart } 1468c54a18d2SRandall Stewart if (asconf->sent != SCTP_DATAGRAM_RESEND && chk->sent != SCTP_DATAGRAM_UNSENT) 1469c54a18d2SRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1470c54a18d2SRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 1471c54a18d2SRandall Stewart } 1472f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 1473f8829a4aSRandall Stewart /* 1474f8829a4aSRandall Stewart * If the address went un-reachable, we need to move 14751b649582SRandall Stewart * to the alternate for ALL chunks in queue 1476f8829a4aSRandall Stewart */ 1477f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 1478c54a18d2SRandall Stewart net = alt; 1479f8829a4aSRandall Stewart } 1480f8829a4aSRandall Stewart /* mark the retran info */ 1481f8829a4aSRandall Stewart if (asconf->sent != SCTP_DATAGRAM_RESEND) 1482f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1483f8829a4aSRandall Stewart asconf->sent = SCTP_DATAGRAM_RESEND; 1484c54a18d2SRandall Stewart 1485c54a18d2SRandall Stewart /* send another ASCONF if any and we can do */ 1486c54a18d2SRandall Stewart sctp_send_asconf(stcb, alt, SCTP_ADDR_NOT_LOCKED); 1487f8829a4aSRandall Stewart } 1488f8829a4aSRandall Stewart return (0); 1489f8829a4aSRandall Stewart } 1490f8829a4aSRandall Stewart 1491851b7298SRandall Stewart /* Mobility adaptation */ 149204ee05e8SRandall Stewart void 1493851b7298SRandall Stewart sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1494851b7298SRandall Stewart struct sctp_nets *net) 1495851b7298SRandall Stewart { 1496851b7298SRandall Stewart if (stcb->asoc.deleted_primary == NULL) { 1497851b7298SRandall Stewart SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n"); 1498851b7298SRandall Stewart sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); 149904ee05e8SRandall Stewart return; 1500851b7298SRandall Stewart } 1501851b7298SRandall Stewart SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: finished to keep deleted primary "); 1502851b7298SRandall Stewart SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); 1503851b7298SRandall Stewart sctp_free_remote_addr(stcb->asoc.deleted_primary); 1504851b7298SRandall Stewart stcb->asoc.deleted_primary = NULL; 1505851b7298SRandall Stewart sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); 150604ee05e8SRandall Stewart return; 1507851b7298SRandall Stewart } 1508851b7298SRandall Stewart 1509f8829a4aSRandall Stewart /* 1510f8829a4aSRandall Stewart * For the shutdown and shutdown-ack, we do not keep one around on the 1511f8829a4aSRandall Stewart * control queue. This means we must generate a new one and call the general 1512f8829a4aSRandall Stewart * chunk output routine, AFTER having done threshold management. 1513f8829a4aSRandall Stewart */ 1514f8829a4aSRandall Stewart int 1515f8829a4aSRandall Stewart sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1516f8829a4aSRandall Stewart struct sctp_nets *net) 1517f8829a4aSRandall Stewart { 1518f8829a4aSRandall Stewart struct sctp_nets *alt; 1519f8829a4aSRandall Stewart 1520f8829a4aSRandall Stewart /* first threshold managment */ 1521f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { 1522f8829a4aSRandall Stewart /* Assoc is over */ 1523f8829a4aSRandall Stewart return (1); 1524f8829a4aSRandall Stewart } 1525f8829a4aSRandall Stewart /* second select an alternative */ 1526f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 1527f8829a4aSRandall Stewart 1528f8829a4aSRandall Stewart /* third generate a shutdown into the queue for out net */ 1529f8829a4aSRandall Stewart if (alt) { 1530f8829a4aSRandall Stewart sctp_send_shutdown(stcb, alt); 1531f8829a4aSRandall Stewart } else { 1532f8829a4aSRandall Stewart /* 1533f8829a4aSRandall Stewart * if alt is NULL, there is no dest to send to?? 1534f8829a4aSRandall Stewart */ 1535f8829a4aSRandall Stewart return (0); 1536f8829a4aSRandall Stewart } 1537f8829a4aSRandall Stewart /* fourth restart timer */ 1538f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt); 1539f8829a4aSRandall Stewart return (0); 1540f8829a4aSRandall Stewart } 1541f8829a4aSRandall Stewart 1542f8829a4aSRandall Stewart int 1543f8829a4aSRandall Stewart sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1544f8829a4aSRandall Stewart struct sctp_nets *net) 1545f8829a4aSRandall Stewart { 1546f8829a4aSRandall Stewart struct sctp_nets *alt; 1547f8829a4aSRandall Stewart 1548f8829a4aSRandall Stewart /* first threshold managment */ 1549f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { 1550f8829a4aSRandall Stewart /* Assoc is over */ 1551f8829a4aSRandall Stewart return (1); 1552f8829a4aSRandall Stewart } 1553f8829a4aSRandall Stewart /* second select an alternative */ 1554f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 1555f8829a4aSRandall Stewart 1556f8829a4aSRandall Stewart /* third generate a shutdown into the queue for out net */ 1557f8829a4aSRandall Stewart sctp_send_shutdown_ack(stcb, alt); 1558f8829a4aSRandall Stewart 1559f8829a4aSRandall Stewart /* fourth restart timer */ 1560f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt); 1561f8829a4aSRandall Stewart return (0); 1562f8829a4aSRandall Stewart } 1563f8829a4aSRandall Stewart 1564f8829a4aSRandall Stewart static void 1565f8829a4aSRandall Stewart sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, 1566f8829a4aSRandall Stewart struct sctp_tcb *stcb) 1567f8829a4aSRandall Stewart { 1568f8829a4aSRandall Stewart struct sctp_stream_out *outs; 1569f8829a4aSRandall Stewart struct sctp_stream_queue_pending *sp; 1570f8829a4aSRandall Stewart unsigned int chks_in_queue = 0; 1571f8829a4aSRandall Stewart int being_filled = 0; 1572f8829a4aSRandall Stewart 1573f8829a4aSRandall Stewart /* 1574f8829a4aSRandall Stewart * This function is ONLY called when the send/sent queues are empty. 1575f8829a4aSRandall Stewart */ 1576f8829a4aSRandall Stewart if ((stcb == NULL) || (inp == NULL)) 1577f8829a4aSRandall Stewart return; 1578f8829a4aSRandall Stewart 1579f8829a4aSRandall Stewart if (stcb->asoc.sent_queue_retran_cnt) { 1580ad81507eSRandall Stewart SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n", 1581f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt); 1582f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = 0; 1583f8829a4aSRandall Stewart } 1584f8829a4aSRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 1585f8829a4aSRandall Stewart if (TAILQ_EMPTY(&stcb->asoc.out_wheel)) { 1586f8829a4aSRandall Stewart int i, cnt = 0; 1587f8829a4aSRandall Stewart 1588f8829a4aSRandall Stewart /* Check to see if a spoke fell off the wheel */ 1589f8829a4aSRandall Stewart for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 1590f8829a4aSRandall Stewart if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 1591f8829a4aSRandall Stewart sctp_insert_on_wheel(stcb, &stcb->asoc, &stcb->asoc.strmout[i], 1); 1592f8829a4aSRandall Stewart cnt++; 1593f8829a4aSRandall Stewart } 1594f8829a4aSRandall Stewart } 1595f8829a4aSRandall Stewart if (cnt) { 1596f8829a4aSRandall Stewart /* yep, we lost a spoke or two */ 1597ad81507eSRandall Stewart SCTP_PRINTF("Found an additional %d streams NOT on outwheel, corrected\n", cnt); 1598f8829a4aSRandall Stewart } else { 1599f8829a4aSRandall Stewart /* no spokes lost, */ 1600f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size = 0; 1601f8829a4aSRandall Stewart } 1602f8829a4aSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 1603f8829a4aSRandall Stewart return; 1604f8829a4aSRandall Stewart } 1605f8829a4aSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 1606f8829a4aSRandall Stewart /* Check to see if some data queued, if so report it */ 1607f8829a4aSRandall Stewart TAILQ_FOREACH(outs, &stcb->asoc.out_wheel, next_spoke) { 1608f8829a4aSRandall Stewart if (!TAILQ_EMPTY(&outs->outqueue)) { 1609f8829a4aSRandall Stewart TAILQ_FOREACH(sp, &outs->outqueue, next) { 1610f8829a4aSRandall Stewart if (sp->msg_is_complete) 1611f8829a4aSRandall Stewart being_filled++; 1612f8829a4aSRandall Stewart chks_in_queue++; 1613f8829a4aSRandall Stewart } 1614f8829a4aSRandall Stewart } 1615f8829a4aSRandall Stewart } 1616f8829a4aSRandall Stewart if (chks_in_queue != stcb->asoc.stream_queue_cnt) { 1617ad81507eSRandall Stewart SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n", 1618f8829a4aSRandall Stewart stcb->asoc.stream_queue_cnt, chks_in_queue); 1619f8829a4aSRandall Stewart } 1620f8829a4aSRandall Stewart if (chks_in_queue) { 1621f8829a4aSRandall Stewart /* call the output queue function */ 1622ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1623f8829a4aSRandall Stewart if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) && 1624f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { 1625f8829a4aSRandall Stewart /* 1626f8829a4aSRandall Stewart * Probably should go in and make it go back through 1627f8829a4aSRandall Stewart * and add fragments allowed 1628f8829a4aSRandall Stewart */ 1629f8829a4aSRandall Stewart if (being_filled == 0) { 1630ad81507eSRandall Stewart SCTP_PRINTF("Still nothing moved %d chunks are stuck\n", 1631f8829a4aSRandall Stewart chks_in_queue); 1632f8829a4aSRandall Stewart } 1633f8829a4aSRandall Stewart } 1634f8829a4aSRandall Stewart } else { 1635ad81507eSRandall Stewart SCTP_PRINTF("Found no chunks on any queue tot:%lu\n", 1636f8829a4aSRandall Stewart (u_long)stcb->asoc.total_output_queue_size); 1637f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size = 0; 1638f8829a4aSRandall Stewart } 1639f8829a4aSRandall Stewart } 1640f8829a4aSRandall Stewart 1641f8829a4aSRandall Stewart int 1642f8829a4aSRandall Stewart sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1643f8829a4aSRandall Stewart struct sctp_nets *net, int cnt_of_unconf) 1644f8829a4aSRandall Stewart { 1645b54d3a6cSRandall Stewart int ret; 1646b54d3a6cSRandall Stewart 1647f8829a4aSRandall Stewart if (net) { 1648f8829a4aSRandall Stewart if (net->hb_responded == 0) { 164942551e99SRandall Stewart if (net->ro._s_addr) { 165042551e99SRandall Stewart /* 165142551e99SRandall Stewart * Invalidate the src address if we did not 165242551e99SRandall Stewart * get a response last time. 165342551e99SRandall Stewart */ 165442551e99SRandall Stewart sctp_free_ifa(net->ro._s_addr); 165542551e99SRandall Stewart net->ro._s_addr = NULL; 165642551e99SRandall Stewart net->src_addr_selected = 0; 165742551e99SRandall Stewart } 1658*44fbe462SRandall Stewart sctp_backoff_on_timeout(stcb, net, 1, 0, 0); 1659f8829a4aSRandall Stewart } 1660f8829a4aSRandall Stewart /* Zero PBA, if it needs it */ 1661f8829a4aSRandall Stewart if (net->partial_bytes_acked) { 1662f8829a4aSRandall Stewart net->partial_bytes_acked = 0; 1663f8829a4aSRandall Stewart } 1664f8829a4aSRandall Stewart } 1665f8829a4aSRandall Stewart if ((stcb->asoc.total_output_queue_size > 0) && 1666f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.send_queue)) && 1667f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { 1668f8829a4aSRandall Stewart sctp_audit_stream_queues_for_size(inp, stcb); 1669f8829a4aSRandall Stewart } 1670f8829a4aSRandall Stewart /* Send a new HB, this will do threshold managment, pick a new dest */ 1671f8829a4aSRandall Stewart if (cnt_of_unconf == 0) { 1672f8829a4aSRandall Stewart if (sctp_send_hb(stcb, 0, NULL) < 0) { 1673f8829a4aSRandall Stewart return (1); 1674f8829a4aSRandall Stewart } 1675f8829a4aSRandall Stewart } else { 1676f8829a4aSRandall Stewart /* 1677f8829a4aSRandall Stewart * this will send out extra hb's up to maxburst if there are 1678f8829a4aSRandall Stewart * any unconfirmed addresses. 1679f8829a4aSRandall Stewart */ 1680d61a0ae0SRandall Stewart uint32_t cnt_sent = 0; 1681f8829a4aSRandall Stewart 1682f8829a4aSRandall Stewart TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1683f8829a4aSRandall Stewart if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) && 1684f8829a4aSRandall Stewart (net->dest_state & SCTP_ADDR_REACHABLE)) { 1685f8829a4aSRandall Stewart cnt_sent++; 168642551e99SRandall Stewart if (net->hb_responded == 0) { 168742551e99SRandall Stewart /* Did we respond last time? */ 168842551e99SRandall Stewart if (net->ro._s_addr) { 168942551e99SRandall Stewart sctp_free_ifa(net->ro._s_addr); 169042551e99SRandall Stewart net->ro._s_addr = NULL; 169142551e99SRandall Stewart net->src_addr_selected = 0; 169242551e99SRandall Stewart } 169342551e99SRandall Stewart } 1694b54d3a6cSRandall Stewart ret = sctp_send_hb(stcb, 1, net); 1695b54d3a6cSRandall Stewart if (ret < 0) 1696b54d3a6cSRandall Stewart return 1; 1697b54d3a6cSRandall Stewart else if (ret == 0) { 1698f8829a4aSRandall Stewart break; 1699f8829a4aSRandall Stewart } 1700b3f1ea41SRandall Stewart if (cnt_sent >= SCTP_BASE_SYSCTL(sctp_hb_maxburst)) 1701f8829a4aSRandall Stewart break; 1702f8829a4aSRandall Stewart } 1703f8829a4aSRandall Stewart } 1704f8829a4aSRandall Stewart } 1705f8829a4aSRandall Stewart return (0); 1706f8829a4aSRandall Stewart } 1707f8829a4aSRandall Stewart 1708f8829a4aSRandall Stewart int 1709f8829a4aSRandall Stewart sctp_is_hb_timer_running(struct sctp_tcb *stcb) 1710f8829a4aSRandall Stewart { 1711139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&stcb->asoc.hb_timer.timer)) { 1712f8829a4aSRandall Stewart /* its running */ 1713f8829a4aSRandall Stewart return (1); 1714f8829a4aSRandall Stewart } else { 1715f8829a4aSRandall Stewart /* nope */ 1716f8829a4aSRandall Stewart return (0); 1717f8829a4aSRandall Stewart } 1718f8829a4aSRandall Stewart } 1719f8829a4aSRandall Stewart 1720f8829a4aSRandall Stewart int 1721f8829a4aSRandall Stewart sctp_is_sack_timer_running(struct sctp_tcb *stcb) 1722f8829a4aSRandall Stewart { 1723139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { 1724f8829a4aSRandall Stewart /* its running */ 1725f8829a4aSRandall Stewart return (1); 1726f8829a4aSRandall Stewart } else { 1727f8829a4aSRandall Stewart /* nope */ 1728f8829a4aSRandall Stewart return (0); 1729f8829a4aSRandall Stewart } 1730f8829a4aSRandall Stewart } 1731f8829a4aSRandall Stewart 1732f8829a4aSRandall Stewart #define SCTP_NUMBER_OF_MTU_SIZES 18 1733f8829a4aSRandall Stewart static uint32_t mtu_sizes[] = { 1734f8829a4aSRandall Stewart 68, 1735f8829a4aSRandall Stewart 296, 1736f8829a4aSRandall Stewart 508, 1737f8829a4aSRandall Stewart 512, 1738f8829a4aSRandall Stewart 544, 1739f8829a4aSRandall Stewart 576, 1740f8829a4aSRandall Stewart 1006, 1741f8829a4aSRandall Stewart 1492, 1742f8829a4aSRandall Stewart 1500, 1743f8829a4aSRandall Stewart 1536, 1744f8829a4aSRandall Stewart 2002, 1745f8829a4aSRandall Stewart 2048, 1746f8829a4aSRandall Stewart 4352, 1747f8829a4aSRandall Stewart 4464, 1748f8829a4aSRandall Stewart 8166, 1749f8829a4aSRandall Stewart 17914, 1750f8829a4aSRandall Stewart 32000, 1751f8829a4aSRandall Stewart 65535 1752f8829a4aSRandall Stewart }; 1753f8829a4aSRandall Stewart 1754f8829a4aSRandall Stewart 1755f8829a4aSRandall Stewart static uint32_t 1756f8829a4aSRandall Stewart sctp_getnext_mtu(struct sctp_inpcb *inp, uint32_t cur_mtu) 1757f8829a4aSRandall Stewart { 1758f8829a4aSRandall Stewart /* select another MTU that is just bigger than this one */ 1759f8829a4aSRandall Stewart int i; 1760f8829a4aSRandall Stewart 1761f8829a4aSRandall Stewart for (i = 0; i < SCTP_NUMBER_OF_MTU_SIZES; i++) { 1762f8829a4aSRandall Stewart if (cur_mtu < mtu_sizes[i]) { 1763f8829a4aSRandall Stewart /* no max_mtu is bigger than this one */ 1764f8829a4aSRandall Stewart return (mtu_sizes[i]); 1765f8829a4aSRandall Stewart } 1766f8829a4aSRandall Stewart } 1767f8829a4aSRandall Stewart /* here return the highest allowable */ 1768f8829a4aSRandall Stewart return (cur_mtu); 1769f8829a4aSRandall Stewart } 1770f8829a4aSRandall Stewart 1771f8829a4aSRandall Stewart 1772f8829a4aSRandall Stewart void 1773f8829a4aSRandall Stewart sctp_pathmtu_timer(struct sctp_inpcb *inp, 1774f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1775f8829a4aSRandall Stewart struct sctp_nets *net) 1776f8829a4aSRandall Stewart { 1777c54a18d2SRandall Stewart uint32_t next_mtu, mtu; 1778f8829a4aSRandall Stewart 1779f8829a4aSRandall Stewart next_mtu = sctp_getnext_mtu(inp, net->mtu); 178017205eccSRandall Stewart 1781c54a18d2SRandall Stewart if ((next_mtu > net->mtu) && (net->port == 0)) { 178217205eccSRandall Stewart if ((net->src_addr_selected == 0) || 178317205eccSRandall Stewart (net->ro._s_addr == NULL) || 178417205eccSRandall Stewart (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { 1785ad81507eSRandall Stewart if ((net->ro._s_addr != NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { 178617205eccSRandall Stewart sctp_free_ifa(net->ro._s_addr); 178717205eccSRandall Stewart net->ro._s_addr = NULL; 178817205eccSRandall Stewart net->src_addr_selected = 0; 1789ad81507eSRandall Stewart } else if (net->ro._s_addr == NULL) { 1790c54a18d2SRandall Stewart #if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE) 1791c54a18d2SRandall Stewart if (net->ro._l_addr.sa.sa_family == AF_INET6) { 1792c54a18d2SRandall Stewart struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1793c54a18d2SRandall Stewart 1794c54a18d2SRandall Stewart /* KAME hack: embed scopeid */ 1795482444b4SRandall Stewart (void)sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)); 1796c54a18d2SRandall Stewart } 1797c54a18d2SRandall Stewart #endif 1798c54a18d2SRandall Stewart 179917205eccSRandall Stewart net->ro._s_addr = sctp_source_address_selection(inp, 180017205eccSRandall Stewart stcb, 180117205eccSRandall Stewart (sctp_route_t *) & net->ro, 180217205eccSRandall Stewart net, 0, stcb->asoc.vrf_id); 1803c54a18d2SRandall Stewart #if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE) 1804c54a18d2SRandall Stewart if (net->ro._l_addr.sa.sa_family == AF_INET6) { 1805c54a18d2SRandall Stewart struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1806c54a18d2SRandall Stewart 1807c54a18d2SRandall Stewart (void)sa6_recoverscope(sin6); 1808c54a18d2SRandall Stewart } 1809c54a18d2SRandall Stewart #endif /* INET6 */ 1810ad81507eSRandall Stewart } 181117205eccSRandall Stewart if (net->ro._s_addr) 181217205eccSRandall Stewart net->src_addr_selected = 1; 181317205eccSRandall Stewart } 181417205eccSRandall Stewart if (net->ro._s_addr) { 181517205eccSRandall Stewart mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt); 1816830d754dSRandall Stewart if (net->port) { 1817830d754dSRandall Stewart mtu -= sizeof(struct udphdr); 1818830d754dSRandall Stewart } 181917205eccSRandall Stewart if (mtu > next_mtu) { 1820f8829a4aSRandall Stewart net->mtu = next_mtu; 1821f8829a4aSRandall Stewart } 1822f8829a4aSRandall Stewart } 1823f8829a4aSRandall Stewart } 1824f8829a4aSRandall Stewart /* restart the timer */ 1825f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 1826f8829a4aSRandall Stewart } 1827f8829a4aSRandall Stewart 1828f8829a4aSRandall Stewart void 1829f8829a4aSRandall Stewart sctp_autoclose_timer(struct sctp_inpcb *inp, 1830f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1831f8829a4aSRandall Stewart struct sctp_nets *net) 1832f8829a4aSRandall Stewart { 1833f8829a4aSRandall Stewart struct timeval tn, *tim_touse; 1834f8829a4aSRandall Stewart struct sctp_association *asoc; 1835f8829a4aSRandall Stewart int ticks_gone_by; 1836f8829a4aSRandall Stewart 18376e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&tn); 1838f8829a4aSRandall Stewart if (stcb->asoc.sctp_autoclose_ticks && 1839f8829a4aSRandall Stewart sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { 1840f8829a4aSRandall Stewart /* Auto close is on */ 1841f8829a4aSRandall Stewart asoc = &stcb->asoc; 1842f8829a4aSRandall Stewart /* pick the time to use */ 1843f8829a4aSRandall Stewart if (asoc->time_last_rcvd.tv_sec > 1844f8829a4aSRandall Stewart asoc->time_last_sent.tv_sec) { 1845f8829a4aSRandall Stewart tim_touse = &asoc->time_last_rcvd; 1846f8829a4aSRandall Stewart } else { 1847f8829a4aSRandall Stewart tim_touse = &asoc->time_last_sent; 1848f8829a4aSRandall Stewart } 1849f8829a4aSRandall Stewart /* Now has long enough transpired to autoclose? */ 1850f8829a4aSRandall Stewart ticks_gone_by = SEC_TO_TICKS(tn.tv_sec - tim_touse->tv_sec); 1851f8829a4aSRandall Stewart if ((ticks_gone_by > 0) && 1852f8829a4aSRandall Stewart (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) { 1853f8829a4aSRandall Stewart /* 1854f8829a4aSRandall Stewart * autoclose time has hit, call the output routine, 1855f8829a4aSRandall Stewart * which should do nothing just to be SURE we don't 1856f8829a4aSRandall Stewart * have hanging data. We can then safely check the 1857f8829a4aSRandall Stewart * queues and know that we are clear to send 1858f8829a4aSRandall Stewart * shutdown 1859f8829a4aSRandall Stewart */ 1860ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); 1861f8829a4aSRandall Stewart /* Are we clean? */ 1862f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue) && 1863f8829a4aSRandall Stewart TAILQ_EMPTY(&asoc->sent_queue)) { 1864f8829a4aSRandall Stewart /* 1865f8829a4aSRandall Stewart * there is nothing queued to send, so I'm 1866f8829a4aSRandall Stewart * done... 1867f8829a4aSRandall Stewart */ 1868f42a358aSRandall Stewart if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 1869f8829a4aSRandall Stewart /* only send SHUTDOWN 1st time thru */ 1870f8829a4aSRandall Stewart sctp_send_shutdown(stcb, stcb->asoc.primary_destination); 1871f42a358aSRandall Stewart if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 1872f42a358aSRandall Stewart (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 1873f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 1874f42a358aSRandall Stewart } 1875c4739e2fSRandall Stewart SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 1876b201f536SRandall Stewart SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 1877f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 1878f8829a4aSRandall Stewart stcb->sctp_ep, stcb, 1879f8829a4aSRandall Stewart asoc->primary_destination); 1880f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 1881f8829a4aSRandall Stewart stcb->sctp_ep, stcb, 1882f8829a4aSRandall Stewart asoc->primary_destination); 1883f8829a4aSRandall Stewart } 1884f8829a4aSRandall Stewart } 1885f8829a4aSRandall Stewart } else { 1886f8829a4aSRandall Stewart /* 1887f8829a4aSRandall Stewart * No auto close at this time, reset t-o to check 1888f8829a4aSRandall Stewart * later 1889f8829a4aSRandall Stewart */ 1890f8829a4aSRandall Stewart int tmp; 1891f8829a4aSRandall Stewart 1892f8829a4aSRandall Stewart /* fool the timer startup to use the time left */ 1893f8829a4aSRandall Stewart tmp = asoc->sctp_autoclose_ticks; 1894f8829a4aSRandall Stewart asoc->sctp_autoclose_ticks -= ticks_gone_by; 1895f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, 1896f8829a4aSRandall Stewart net); 1897f8829a4aSRandall Stewart /* restore the real tick value */ 1898f8829a4aSRandall Stewart asoc->sctp_autoclose_ticks = tmp; 1899f8829a4aSRandall Stewart } 1900f8829a4aSRandall Stewart } 1901f8829a4aSRandall Stewart } 1902