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 #include <netinet6/sctp6_var.h> 41f8829a4aSRandall Stewart #endif 42f8829a4aSRandall Stewart #include <netinet/sctp_var.h> 4342551e99SRandall Stewart #include <netinet/sctp_sysctl.h> 44f8829a4aSRandall Stewart #include <netinet/sctp_timer.h> 45f8829a4aSRandall Stewart #include <netinet/sctputil.h> 46f8829a4aSRandall Stewart #include <netinet/sctp_output.h> 47f8829a4aSRandall Stewart #include <netinet/sctp_header.h> 48f8829a4aSRandall Stewart #include <netinet/sctp_indata.h> 49f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h> 50f8829a4aSRandall Stewart #include <netinet/sctp_input.h> 51f8829a4aSRandall Stewart #include <netinet/sctp.h> 52f8829a4aSRandall Stewart #include <netinet/sctp_uio.h> 53f8829a4aSRandall Stewart 54f8829a4aSRandall Stewart 55f8829a4aSRandall Stewart 56f8829a4aSRandall Stewart void 57f8829a4aSRandall Stewart sctp_early_fr_timer(struct sctp_inpcb *inp, 58f8829a4aSRandall Stewart struct sctp_tcb *stcb, 59f8829a4aSRandall Stewart struct sctp_nets *net) 60f8829a4aSRandall Stewart { 61f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk, *tp2; 62f8829a4aSRandall Stewart struct timeval now, min_wait, tv; 63f8829a4aSRandall Stewart unsigned int cur_rtt, cnt = 0, cnt_resend = 0; 64f8829a4aSRandall Stewart 65f8829a4aSRandall Stewart /* an early FR is occuring. */ 666e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 67f8829a4aSRandall Stewart /* get cur rto in micro-seconds */ 68f8829a4aSRandall Stewart if (net->lastsa == 0) { 69f8829a4aSRandall Stewart /* Hmm no rtt estimate yet? */ 70f8829a4aSRandall Stewart cur_rtt = stcb->asoc.initial_rto >> 2; 71f8829a4aSRandall Stewart } else { 72f8829a4aSRandall Stewart 73f8829a4aSRandall Stewart cur_rtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 74f8829a4aSRandall Stewart } 75f8829a4aSRandall Stewart if (cur_rtt < sctp_early_fr_msec) { 76f8829a4aSRandall Stewart cur_rtt = sctp_early_fr_msec; 77f8829a4aSRandall Stewart } 78f8829a4aSRandall Stewart cur_rtt *= 1000; 79f8829a4aSRandall Stewart tv.tv_sec = cur_rtt / 1000000; 80f8829a4aSRandall Stewart tv.tv_usec = cur_rtt % 1000000; 81f8829a4aSRandall Stewart min_wait = now; 82f8829a4aSRandall Stewart timevalsub(&min_wait, &tv); 83f8829a4aSRandall Stewart if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { 84f8829a4aSRandall Stewart /* 85f8829a4aSRandall Stewart * if we hit here, we don't have enough seconds on the clock 86f8829a4aSRandall Stewart * to account for the RTO. We just let the lower seconds be 87f8829a4aSRandall Stewart * the bounds and don't worry about it. This may mean we 88f8829a4aSRandall Stewart * will mark a lot more than we should. 89f8829a4aSRandall Stewart */ 90f8829a4aSRandall Stewart min_wait.tv_sec = min_wait.tv_usec = 0; 91f8829a4aSRandall Stewart } 92f8829a4aSRandall Stewart chk = TAILQ_LAST(&stcb->asoc.sent_queue, sctpchunk_listhead); 93f8829a4aSRandall Stewart for (; chk != NULL; chk = tp2) { 94f8829a4aSRandall Stewart tp2 = TAILQ_PREV(chk, sctpchunk_listhead, sctp_next); 95f8829a4aSRandall Stewart if (chk->whoTo != net) { 96f8829a4aSRandall Stewart continue; 97f8829a4aSRandall Stewart } 98f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) 99f8829a4aSRandall Stewart cnt_resend++; 100f8829a4aSRandall Stewart else if ((chk->sent > SCTP_DATAGRAM_UNSENT) && 101f8829a4aSRandall Stewart (chk->sent < SCTP_DATAGRAM_RESEND)) { 102f8829a4aSRandall Stewart /* pending, may need retran */ 103f8829a4aSRandall Stewart if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) { 104f8829a4aSRandall Stewart /* 105f8829a4aSRandall Stewart * we have reached a chunk that was sent 106f8829a4aSRandall Stewart * some seconds past our min.. forget it we 107f8829a4aSRandall Stewart * will find no more to send. 108f8829a4aSRandall Stewart */ 109f8829a4aSRandall Stewart continue; 110f8829a4aSRandall Stewart } else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) { 111f8829a4aSRandall Stewart /* 112f8829a4aSRandall Stewart * we must look at the micro seconds to 113f8829a4aSRandall Stewart * know. 114f8829a4aSRandall Stewart */ 115f8829a4aSRandall Stewart if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { 116f8829a4aSRandall Stewart /* 117f8829a4aSRandall Stewart * ok it was sent after our boundary 118f8829a4aSRandall Stewart * time. 119f8829a4aSRandall Stewart */ 120f8829a4aSRandall Stewart continue; 121f8829a4aSRandall Stewart } 122f8829a4aSRandall Stewart } 12380fefe0aSRandall Stewart if (sctp_logging_level & SCTP_EARLYFR_LOGGING_ENABLE) { 124f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, 125f8829a4aSRandall Stewart 4, SCTP_FR_MARKED_EARLY); 12680fefe0aSRandall Stewart } 127f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_earlyfrmrkretrans); 128f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 129f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 130f8829a4aSRandall Stewart /* double book size since we are doing an early FR */ 131f8829a4aSRandall Stewart chk->book_size_scale++; 132f8829a4aSRandall Stewart cnt += chk->send_size; 133f8829a4aSRandall Stewart if ((cnt + net->flight_size) > net->cwnd) { 134f8829a4aSRandall Stewart /* Mark all we could possibly resend */ 135f8829a4aSRandall Stewart break; 136f8829a4aSRandall Stewart } 137f8829a4aSRandall Stewart } 138f8829a4aSRandall Stewart } 139f8829a4aSRandall Stewart if (cnt) { 140f8829a4aSRandall Stewart /* 141b54d3a6cSRandall Stewart * JRS - Use the congestion control given in the congestion 142b54d3a6cSRandall Stewart * control module 143f8829a4aSRandall Stewart */ 144b54d3a6cSRandall Stewart stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer(inp, stcb, net); 145f8829a4aSRandall Stewart } else if (cnt_resend) { 146ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED); 147f8829a4aSRandall Stewart } 148f8829a4aSRandall Stewart /* Restart it? */ 149f8829a4aSRandall Stewart if (net->flight_size < net->cwnd) { 150f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_earlyfrstrtmr); 151f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 152f8829a4aSRandall Stewart } 153f8829a4aSRandall Stewart } 154f8829a4aSRandall Stewart 155f8829a4aSRandall Stewart void 156f8829a4aSRandall Stewart sctp_audit_retranmission_queue(struct sctp_association *asoc) 157f8829a4aSRandall Stewart { 158f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 159f8829a4aSRandall Stewart 160ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Audit invoked on send queue cnt:%d onqueue:%d\n", 161f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt, 162f8829a4aSRandall Stewart asoc->sent_queue_cnt); 163f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0; 164f8829a4aSRandall Stewart asoc->sent_queue_cnt = 0; 165f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 166f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 167f8829a4aSRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 168f8829a4aSRandall Stewart } 169f8829a4aSRandall Stewart asoc->sent_queue_cnt++; 170f8829a4aSRandall Stewart } 171f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { 172f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 173f8829a4aSRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 174f8829a4aSRandall Stewart } 175f8829a4aSRandall Stewart } 176ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n", 177f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt, 178f8829a4aSRandall Stewart asoc->sent_queue_cnt); 179f8829a4aSRandall Stewart } 180f8829a4aSRandall Stewart 181f8829a4aSRandall Stewart int 182f8829a4aSRandall Stewart sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 183f8829a4aSRandall Stewart struct sctp_nets *net, uint16_t threshold) 184f8829a4aSRandall Stewart { 185f8829a4aSRandall Stewart if (net) { 186f8829a4aSRandall Stewart net->error_count++; 187ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n", 188f8829a4aSRandall Stewart net, net->error_count, 189f8829a4aSRandall Stewart net->failure_threshold); 190f8829a4aSRandall Stewart if (net->error_count > net->failure_threshold) { 191f8829a4aSRandall Stewart /* We had a threshold failure */ 192f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_REACHABLE) { 193f8829a4aSRandall Stewart net->dest_state &= ~SCTP_ADDR_REACHABLE; 194f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 19542551e99SRandall Stewart net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; 196f8829a4aSRandall Stewart if (net == stcb->asoc.primary_destination) { 197f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_WAS_PRIMARY; 198f8829a4aSRandall Stewart } 199b54d3a6cSRandall Stewart /* 200b54d3a6cSRandall Stewart * JRS 5/14/07 - If a destination is 201b54d3a6cSRandall Stewart * unreachable, the PF bit is turned off. 202b54d3a6cSRandall Stewart * This allows an unambiguous use of the PF 203b54d3a6cSRandall Stewart * bit for destinations that are reachable 204b54d3a6cSRandall Stewart * but potentially failed. If the 205b54d3a6cSRandall Stewart * destination is set to the unreachable 206b54d3a6cSRandall Stewart * state, also set the destination to the PF 207b54d3a6cSRandall Stewart * state. 208b54d3a6cSRandall Stewart */ 209b54d3a6cSRandall Stewart /* 210b54d3a6cSRandall Stewart * Add debug message here if destination is 211b54d3a6cSRandall Stewart * not in PF state. 212b54d3a6cSRandall Stewart */ 213b54d3a6cSRandall Stewart /* Stop any running T3 timers here? */ 21418e198d3SRandall Stewart if (sctp_cmt_on_off && sctp_cmt_pf) { 215b54d3a6cSRandall Stewart net->dest_state &= ~SCTP_ADDR_PF; 216b54d3a6cSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", 217b54d3a6cSRandall Stewart net); 218b54d3a6cSRandall Stewart } 219f8829a4aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 220f8829a4aSRandall Stewart stcb, 221f8829a4aSRandall Stewart SCTP_FAILED_THRESHOLD, 222ceaad40aSRandall Stewart (void *)net, SCTP_SO_NOT_LOCKED); 223f8829a4aSRandall Stewart } 224f8829a4aSRandall Stewart } 225f8829a4aSRandall Stewart /*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE 226f8829a4aSRandall Stewart *********ROUTING CODE 227f8829a4aSRandall Stewart */ 228f8829a4aSRandall Stewart /*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE 229f8829a4aSRandall Stewart *********ROUTING CODE 230f8829a4aSRandall Stewart */ 231f8829a4aSRandall Stewart } 232f8829a4aSRandall Stewart if (stcb == NULL) 233f8829a4aSRandall Stewart return (0); 234f8829a4aSRandall Stewart 235f8829a4aSRandall Stewart if (net) { 236f8829a4aSRandall Stewart if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { 237c4739e2fSRandall Stewart if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { 238c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_INCR, 239c4739e2fSRandall Stewart stcb->asoc.overall_error_count, 240c4739e2fSRandall Stewart (stcb->asoc.overall_error_count + 1), 241c4739e2fSRandall Stewart SCTP_FROM_SCTP_TIMER, 242c4739e2fSRandall Stewart __LINE__); 243c4739e2fSRandall Stewart } 244f8829a4aSRandall Stewart stcb->asoc.overall_error_count++; 245f8829a4aSRandall Stewart } 246f8829a4aSRandall Stewart } else { 247c4739e2fSRandall Stewart if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { 248c4739e2fSRandall Stewart sctp_misc_ints(SCTP_THRESHOLD_INCR, 249c4739e2fSRandall Stewart stcb->asoc.overall_error_count, 250c4739e2fSRandall Stewart (stcb->asoc.overall_error_count + 1), 251c4739e2fSRandall Stewart SCTP_FROM_SCTP_TIMER, 252c4739e2fSRandall Stewart __LINE__); 253c4739e2fSRandall Stewart } 254f8829a4aSRandall Stewart stcb->asoc.overall_error_count++; 255f8829a4aSRandall Stewart } 256ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n", 257ad81507eSRandall Stewart &stcb->asoc, stcb->asoc.overall_error_count, 258f8829a4aSRandall Stewart (uint32_t) threshold, 259f8829a4aSRandall Stewart ((net == NULL) ? (uint32_t) 0 : (uint32_t) net->dest_state)); 260f8829a4aSRandall Stewart /* 261f8829a4aSRandall Stewart * We specifically do not do >= to give the assoc one more change 262f8829a4aSRandall Stewart * before we fail it. 263f8829a4aSRandall Stewart */ 264f8829a4aSRandall Stewart if (stcb->asoc.overall_error_count > threshold) { 265f8829a4aSRandall Stewart /* Abort notification sends a ULP notify */ 266f8829a4aSRandall Stewart struct mbuf *oper; 267f8829a4aSRandall Stewart 268f8829a4aSRandall Stewart oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 269f8829a4aSRandall Stewart 0, M_DONTWAIT, 1, MT_DATA); 270f8829a4aSRandall Stewart if (oper) { 271f8829a4aSRandall Stewart struct sctp_paramhdr *ph; 272f8829a4aSRandall Stewart uint32_t *ippp; 273f8829a4aSRandall Stewart 274139bc87fSRandall Stewart SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) + 275f8829a4aSRandall Stewart sizeof(uint32_t); 276f8829a4aSRandall Stewart ph = mtod(oper, struct sctp_paramhdr *); 277f8829a4aSRandall Stewart ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 278139bc87fSRandall Stewart ph->param_length = htons(SCTP_BUF_LEN(oper)); 279f8829a4aSRandall Stewart ippp = (uint32_t *) (ph + 1); 280a5d547adSRandall Stewart *ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); 281f8829a4aSRandall Stewart } 282a5d547adSRandall Stewart inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1; 283ceaad40aSRandall Stewart sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper, SCTP_SO_NOT_LOCKED); 284f8829a4aSRandall Stewart return (1); 285f8829a4aSRandall Stewart } 286f8829a4aSRandall Stewart return (0); 287f8829a4aSRandall Stewart } 288f8829a4aSRandall Stewart 289f8829a4aSRandall Stewart struct sctp_nets * 290f8829a4aSRandall Stewart sctp_find_alternate_net(struct sctp_tcb *stcb, 291f8829a4aSRandall Stewart struct sctp_nets *net, 292b54d3a6cSRandall Stewart int mode) 293f8829a4aSRandall Stewart { 294f8829a4aSRandall Stewart /* Find and return an alternate network if possible */ 295b54d3a6cSRandall Stewart struct sctp_nets *alt, *mnet, *min_errors_net = NULL, *max_cwnd_net = NULL; 296f8829a4aSRandall Stewart int once; 297b54d3a6cSRandall Stewart 298b54d3a6cSRandall Stewart /* JRS 5/14/07 - Initialize min_errors to an impossible value. */ 299b54d3a6cSRandall Stewart int min_errors = -1; 300b54d3a6cSRandall Stewart uint32_t max_cwnd = 0; 301f8829a4aSRandall Stewart 302f8829a4aSRandall Stewart if (stcb->asoc.numnets == 1) { 303f8829a4aSRandall Stewart /* No others but net */ 304f8829a4aSRandall Stewart return (TAILQ_FIRST(&stcb->asoc.nets)); 305f8829a4aSRandall Stewart } 306b54d3a6cSRandall Stewart /* 307b54d3a6cSRandall Stewart * JRS 5/14/07 - If mode is set to 2, use the CMT PF find alternate 308b54d3a6cSRandall Stewart * net algorithm. This algorithm chooses the active destination (not 309b54d3a6cSRandall Stewart * in PF state) with the largest cwnd value. If all destinations are 310b54d3a6cSRandall Stewart * in PF state, unreachable, or unconfirmed, choose the desination 311b54d3a6cSRandall Stewart * that is in PF state with the lowest error count. In case of a 312b54d3a6cSRandall Stewart * tie, choose the destination that was most recently active. 313b54d3a6cSRandall Stewart */ 314b54d3a6cSRandall Stewart if (mode == 2) { 315b54d3a6cSRandall Stewart TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { 316b54d3a6cSRandall Stewart /* 317b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination is unreachable 318b54d3a6cSRandall Stewart * or unconfirmed, skip it. 319b54d3a6cSRandall Stewart */ 320b54d3a6cSRandall Stewart if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || 321b54d3a6cSRandall Stewart (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) { 322b54d3a6cSRandall Stewart continue; 323b54d3a6cSRandall Stewart } 324b54d3a6cSRandall Stewart /* 325b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination is reachable 326b54d3a6cSRandall Stewart * but in PF state, compare the error count of the 327b54d3a6cSRandall Stewart * destination to the minimum error count seen thus 328b54d3a6cSRandall Stewart * far. Store the destination with the lower error 329b54d3a6cSRandall Stewart * count. If the error counts are equal, store the 330b54d3a6cSRandall Stewart * destination that was most recently active. 331b54d3a6cSRandall Stewart */ 332b54d3a6cSRandall Stewart if (mnet->dest_state & SCTP_ADDR_PF) { 333b54d3a6cSRandall Stewart /* 334b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination under 335b54d3a6cSRandall Stewart * consideration is the current destination, 336b54d3a6cSRandall Stewart * work as if the error count is one higher. 337b54d3a6cSRandall Stewart * The actual error count will not be 338b54d3a6cSRandall Stewart * incremented until later in the t3 339b54d3a6cSRandall Stewart * handler. 340b54d3a6cSRandall Stewart */ 341b54d3a6cSRandall Stewart if (mnet == net) { 342b54d3a6cSRandall Stewart if (min_errors == -1) { 343b54d3a6cSRandall Stewart min_errors = mnet->error_count + 1; 344b54d3a6cSRandall Stewart min_errors_net = mnet; 345b54d3a6cSRandall Stewart } else if (mnet->error_count + 1 < min_errors) { 346b54d3a6cSRandall Stewart min_errors = mnet->error_count + 1; 347b54d3a6cSRandall Stewart min_errors_net = mnet; 348b54d3a6cSRandall Stewart } else if (mnet->error_count + 1 == min_errors 349b54d3a6cSRandall Stewart && mnet->last_active > min_errors_net->last_active) { 350b54d3a6cSRandall Stewart min_errors_net = mnet; 351b54d3a6cSRandall Stewart min_errors = mnet->error_count + 1; 352b54d3a6cSRandall Stewart } 353b54d3a6cSRandall Stewart continue; 354b54d3a6cSRandall Stewart } else { 355b54d3a6cSRandall Stewart if (min_errors == -1) { 356b54d3a6cSRandall Stewart min_errors = mnet->error_count; 357b54d3a6cSRandall Stewart min_errors_net = mnet; 358b54d3a6cSRandall Stewart } else if (mnet->error_count < min_errors) { 359b54d3a6cSRandall Stewart min_errors = mnet->error_count; 360b54d3a6cSRandall Stewart min_errors_net = mnet; 361b54d3a6cSRandall Stewart } else if (mnet->error_count == min_errors 362b54d3a6cSRandall Stewart && mnet->last_active > min_errors_net->last_active) { 363b54d3a6cSRandall Stewart min_errors_net = mnet; 364b54d3a6cSRandall Stewart min_errors = mnet->error_count; 365b54d3a6cSRandall Stewart } 366b54d3a6cSRandall Stewart continue; 367b54d3a6cSRandall Stewart } 368b54d3a6cSRandall Stewart } 369b54d3a6cSRandall Stewart /* 370b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination is reachable and 371b54d3a6cSRandall Stewart * not in PF state, compare the cwnd of the 372b54d3a6cSRandall Stewart * destination to the highest cwnd seen thus far. 373b54d3a6cSRandall Stewart * Store the destination with the higher cwnd value. 374b54d3a6cSRandall Stewart * If the cwnd values are equal, randomly choose one 375b54d3a6cSRandall Stewart * of the two destinations. 376b54d3a6cSRandall Stewart */ 377b54d3a6cSRandall Stewart if (max_cwnd < mnet->cwnd) { 378b54d3a6cSRandall Stewart max_cwnd_net = mnet; 379b54d3a6cSRandall Stewart max_cwnd = mnet->cwnd; 380b54d3a6cSRandall Stewart } else if (max_cwnd == mnet->cwnd) { 381b54d3a6cSRandall Stewart uint32_t rndval; 382b54d3a6cSRandall Stewart uint8_t this_random; 383b54d3a6cSRandall Stewart 384b54d3a6cSRandall Stewart if (stcb->asoc.hb_random_idx > 3) { 385b54d3a6cSRandall Stewart rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); 386b54d3a6cSRandall Stewart memcpy(stcb->asoc.hb_random_values, &rndval, sizeof(stcb->asoc.hb_random_values)); 387b54d3a6cSRandall Stewart this_random = stcb->asoc.hb_random_values[0]; 388b54d3a6cSRandall Stewart stcb->asoc.hb_random_idx++; 389b54d3a6cSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 390b54d3a6cSRandall Stewart } else { 391b54d3a6cSRandall Stewart this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; 392b54d3a6cSRandall Stewart stcb->asoc.hb_random_idx++; 393b54d3a6cSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 394b54d3a6cSRandall Stewart } 395b54d3a6cSRandall Stewart if (this_random % 2 == 1) { 396b54d3a6cSRandall Stewart max_cwnd_net = mnet; 397b54d3a6cSRandall Stewart max_cwnd = mnet->cwnd; 398b54d3a6cSRandall Stewart //Useless ? 399b54d3a6cSRandall Stewart } 400b54d3a6cSRandall Stewart } 401b54d3a6cSRandall Stewart } 402b54d3a6cSRandall Stewart /* 403b54d3a6cSRandall Stewart * JRS 5/14/07 - After all destination have been considered 404b54d3a6cSRandall Stewart * as alternates, check to see if there was some active 405b54d3a6cSRandall Stewart * destination (not in PF state). If not, check to see if 406b54d3a6cSRandall Stewart * there was some PF destination with the minimum number of 407b54d3a6cSRandall Stewart * errors. If not, return the original destination. If 408b54d3a6cSRandall Stewart * there is a min_errors_net, remove the PF flag from that 409b54d3a6cSRandall Stewart * destination, set the cwnd to one or two MTUs, and return 410b54d3a6cSRandall Stewart * the destination as an alt. If there was some active 411b54d3a6cSRandall Stewart * destination with a highest cwnd, return the destination 412b54d3a6cSRandall Stewart * as an alt. 413b54d3a6cSRandall Stewart */ 414b54d3a6cSRandall Stewart if (max_cwnd_net == NULL) { 415b54d3a6cSRandall Stewart if (min_errors_net == NULL) { 416b54d3a6cSRandall Stewart return (net); 417b54d3a6cSRandall Stewart } 418b54d3a6cSRandall Stewart min_errors_net->dest_state &= ~SCTP_ADDR_PF; 419b54d3a6cSRandall Stewart min_errors_net->cwnd = min_errors_net->mtu * sctp_cmt_pf; 420b54d3a6cSRandall Stewart if (SCTP_OS_TIMER_PENDING(&min_errors_net->rxt_timer.timer)) { 421b54d3a6cSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, 422b54d3a6cSRandall Stewart stcb, min_errors_net, 423b54d3a6cSRandall Stewart SCTP_FROM_SCTP_TIMER + SCTP_LOC_2); 424b54d3a6cSRandall Stewart } 425b54d3a6cSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to active with %d errors.\n", 426b54d3a6cSRandall Stewart min_errors_net, min_errors_net->error_count); 427b54d3a6cSRandall Stewart return (min_errors_net); 428b54d3a6cSRandall Stewart } else { 429b54d3a6cSRandall Stewart return (max_cwnd_net); 430b54d3a6cSRandall Stewart } 431b54d3a6cSRandall Stewart } 432b54d3a6cSRandall Stewart /* 433b54d3a6cSRandall Stewart * JRS 5/14/07 - If mode is set to 1, use the CMT policy for 434b54d3a6cSRandall Stewart * choosing an alternate net. 435b54d3a6cSRandall Stewart */ 436b54d3a6cSRandall Stewart else if (mode == 1) { 437f8829a4aSRandall Stewart TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { 438f8829a4aSRandall Stewart if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || 439f8829a4aSRandall Stewart (mnet->dest_state & SCTP_ADDR_UNCONFIRMED) 440f8829a4aSRandall Stewart ) { 441f8829a4aSRandall Stewart /* 442f8829a4aSRandall Stewart * will skip ones that are not-reachable or 443f8829a4aSRandall Stewart * unconfirmed 444f8829a4aSRandall Stewart */ 445f8829a4aSRandall Stewart continue; 446f8829a4aSRandall Stewart } 447b54d3a6cSRandall Stewart if (max_cwnd < mnet->cwnd) { 448b54d3a6cSRandall Stewart max_cwnd_net = mnet; 449b54d3a6cSRandall Stewart max_cwnd = mnet->cwnd; 450b54d3a6cSRandall Stewart } else if (max_cwnd == mnet->cwnd) { 451f8829a4aSRandall Stewart uint32_t rndval; 452f8829a4aSRandall Stewart uint8_t this_random; 453f8829a4aSRandall Stewart 454f8829a4aSRandall Stewart if (stcb->asoc.hb_random_idx > 3) { 455f8829a4aSRandall Stewart rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); 456f8829a4aSRandall Stewart memcpy(stcb->asoc.hb_random_values, &rndval, 457f8829a4aSRandall Stewart sizeof(stcb->asoc.hb_random_values)); 458f8829a4aSRandall Stewart this_random = stcb->asoc.hb_random_values[0]; 459f8829a4aSRandall Stewart stcb->asoc.hb_random_idx = 0; 460f8829a4aSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 461f8829a4aSRandall Stewart } else { 462f8829a4aSRandall Stewart this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; 463f8829a4aSRandall Stewart stcb->asoc.hb_random_idx++; 464f8829a4aSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 465f8829a4aSRandall Stewart } 466f8829a4aSRandall Stewart if (this_random % 2) { 467b54d3a6cSRandall Stewart max_cwnd_net = mnet; 468b54d3a6cSRandall Stewart max_cwnd = mnet->cwnd; 469f8829a4aSRandall Stewart } 470f8829a4aSRandall Stewart } 471f8829a4aSRandall Stewart } 472b54d3a6cSRandall Stewart if (max_cwnd_net) { 473b54d3a6cSRandall Stewart return (max_cwnd_net); 474f8829a4aSRandall Stewart } 475f8829a4aSRandall Stewart } 476f8829a4aSRandall Stewart mnet = net; 477f8829a4aSRandall Stewart once = 0; 478f8829a4aSRandall Stewart 479f8829a4aSRandall Stewart if (mnet == NULL) { 480f8829a4aSRandall Stewart mnet = TAILQ_FIRST(&stcb->asoc.nets); 481f8829a4aSRandall Stewart } 482f8829a4aSRandall Stewart do { 483f8829a4aSRandall Stewart alt = TAILQ_NEXT(mnet, sctp_next); 484f8829a4aSRandall Stewart if (alt == NULL) { 485f8829a4aSRandall Stewart once++; 486f8829a4aSRandall Stewart if (once > 1) { 487f8829a4aSRandall Stewart break; 488f8829a4aSRandall Stewart } 489f8829a4aSRandall Stewart alt = TAILQ_FIRST(&stcb->asoc.nets); 490f8829a4aSRandall Stewart } 491f8829a4aSRandall Stewart if (alt->ro.ro_rt == NULL) { 49242551e99SRandall Stewart if (alt->ro._s_addr) { 49342551e99SRandall Stewart sctp_free_ifa(alt->ro._s_addr); 49442551e99SRandall Stewart alt->ro._s_addr = NULL; 49542551e99SRandall Stewart } 496f8829a4aSRandall Stewart alt->src_addr_selected = 0; 497f8829a4aSRandall Stewart } 498f8829a4aSRandall Stewart if ( 499f8829a4aSRandall Stewart ((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) && 500f8829a4aSRandall Stewart (alt->ro.ro_rt != NULL) && 5013c503c28SRandall Stewart /* sa_ignore NO_NULL_CHK */ 502f8829a4aSRandall Stewart (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) 503f8829a4aSRandall Stewart ) { 504f8829a4aSRandall Stewart /* Found a reachable address */ 505f8829a4aSRandall Stewart break; 506f8829a4aSRandall Stewart } 507f8829a4aSRandall Stewart mnet = alt; 508f8829a4aSRandall Stewart } while (alt != NULL); 509f8829a4aSRandall Stewart 510f8829a4aSRandall Stewart if (alt == NULL) { 511f8829a4aSRandall Stewart /* Case where NO insv network exists (dormant state) */ 512f8829a4aSRandall Stewart /* we rotate destinations */ 513f8829a4aSRandall Stewart once = 0; 514f8829a4aSRandall Stewart mnet = net; 515f8829a4aSRandall Stewart do { 516f8829a4aSRandall Stewart alt = TAILQ_NEXT(mnet, sctp_next); 517f8829a4aSRandall Stewart if (alt == NULL) { 518f8829a4aSRandall Stewart once++; 519f8829a4aSRandall Stewart if (once > 1) { 520f8829a4aSRandall Stewart break; 521f8829a4aSRandall Stewart } 522f8829a4aSRandall Stewart alt = TAILQ_FIRST(&stcb->asoc.nets); 523f8829a4aSRandall Stewart } 5243c503c28SRandall Stewart /* sa_ignore NO_NULL_CHK */ 525f8829a4aSRandall Stewart if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) && 526f8829a4aSRandall Stewart (alt != net)) { 527f8829a4aSRandall Stewart /* Found an alternate address */ 528f8829a4aSRandall Stewart break; 529f8829a4aSRandall Stewart } 530f8829a4aSRandall Stewart mnet = alt; 531f8829a4aSRandall Stewart } while (alt != NULL); 532f8829a4aSRandall Stewart } 533f8829a4aSRandall Stewart if (alt == NULL) { 534f8829a4aSRandall Stewart return (net); 535f8829a4aSRandall Stewart } 536f8829a4aSRandall Stewart return (alt); 537f8829a4aSRandall Stewart } 538f8829a4aSRandall Stewart 539b54d3a6cSRandall Stewart 540b54d3a6cSRandall Stewart 541f8829a4aSRandall Stewart static void 542f8829a4aSRandall Stewart sctp_backoff_on_timeout(struct sctp_tcb *stcb, 543f8829a4aSRandall Stewart struct sctp_nets *net, 544f8829a4aSRandall Stewart int win_probe, 545f8829a4aSRandall Stewart int num_marked) 546f8829a4aSRandall Stewart { 5479a972525SRandall Stewart if (net->RTO == 0) { 5489a972525SRandall Stewart net->RTO = stcb->asoc.minrto; 5499a972525SRandall Stewart } 550f8829a4aSRandall Stewart net->RTO <<= 1; 551f8829a4aSRandall Stewart if (net->RTO > stcb->asoc.maxrto) { 552f8829a4aSRandall Stewart net->RTO = stcb->asoc.maxrto; 553f8829a4aSRandall Stewart } 554f8829a4aSRandall Stewart if ((win_probe == 0) && num_marked) { 555f8829a4aSRandall Stewart /* We don't apply penalty to window probe scenarios */ 556b54d3a6cSRandall Stewart /* JRS - Use the congestion control given in the CC module */ 557b54d3a6cSRandall Stewart stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net); 558f8829a4aSRandall Stewart } 559f8829a4aSRandall Stewart } 560f8829a4aSRandall Stewart 561f8829a4aSRandall Stewart static int 562f8829a4aSRandall Stewart sctp_mark_all_for_resend(struct sctp_tcb *stcb, 563f8829a4aSRandall Stewart struct sctp_nets *net, 564f8829a4aSRandall Stewart struct sctp_nets *alt, 565f8829a4aSRandall Stewart int window_probe, 566f8829a4aSRandall Stewart int *num_marked) 567f8829a4aSRandall Stewart { 568f8829a4aSRandall Stewart 569f8829a4aSRandall Stewart /* 570f8829a4aSRandall Stewart * Mark all chunks (well not all) that were sent to *net for 571f8829a4aSRandall Stewart * retransmission. Move them to alt for there destination as well... 572f8829a4aSRandall Stewart * We only mark chunks that have been outstanding long enough to 573f8829a4aSRandall Stewart * have received feed-back. 574f8829a4aSRandall Stewart */ 575f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk, *tp2, *could_be_sent = NULL; 576f8829a4aSRandall Stewart struct sctp_nets *lnets; 577f8829a4aSRandall Stewart struct timeval now, min_wait, tv; 578f8829a4aSRandall Stewart int cur_rtt; 579c105859eSRandall Stewart int audit_tf, num_mk, fir; 580f8829a4aSRandall Stewart unsigned int cnt_mk; 581c105859eSRandall Stewart uint32_t orig_flight, orig_tf; 582f8829a4aSRandall Stewart uint32_t tsnlast, tsnfirst; 583f8829a4aSRandall Stewart 584b54d3a6cSRandall Stewart 585f8829a4aSRandall Stewart /* none in flight now */ 586f8829a4aSRandall Stewart audit_tf = 0; 587f8829a4aSRandall Stewart fir = 0; 588f8829a4aSRandall Stewart /* 589f8829a4aSRandall Stewart * figure out how long a data chunk must be pending before we can 590f8829a4aSRandall Stewart * mark it .. 591f8829a4aSRandall Stewart */ 5926e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 593f8829a4aSRandall Stewart /* get cur rto in micro-seconds */ 594f8829a4aSRandall Stewart cur_rtt = (((net->lastsa >> 2) + net->lastsv) >> 1); 595f8829a4aSRandall Stewart cur_rtt *= 1000; 59680fefe0aSRandall Stewart if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 597f8829a4aSRandall Stewart sctp_log_fr(cur_rtt, 598f8829a4aSRandall Stewart stcb->asoc.peers_rwnd, 599f8829a4aSRandall Stewart window_probe, 600f8829a4aSRandall Stewart SCTP_FR_T3_MARK_TIME); 601f8829a4aSRandall Stewart sctp_log_fr(net->flight_size, 602139bc87fSRandall Stewart SCTP_OS_TIMER_PENDING(&net->fr_timer.timer), 603139bc87fSRandall Stewart SCTP_OS_TIMER_ACTIVE(&net->fr_timer.timer), 604f8829a4aSRandall Stewart SCTP_FR_CWND_REPORT); 605f8829a4aSRandall Stewart sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT); 60680fefe0aSRandall Stewart } 607f8829a4aSRandall Stewart tv.tv_sec = cur_rtt / 1000000; 608f8829a4aSRandall Stewart tv.tv_usec = cur_rtt % 1000000; 609f8829a4aSRandall Stewart min_wait = now; 610f8829a4aSRandall Stewart timevalsub(&min_wait, &tv); 611f8829a4aSRandall Stewart if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { 612f8829a4aSRandall Stewart /* 613f8829a4aSRandall Stewart * if we hit here, we don't have enough seconds on the clock 614f8829a4aSRandall Stewart * to account for the RTO. We just let the lower seconds be 615f8829a4aSRandall Stewart * the bounds and don't worry about it. This may mean we 616f8829a4aSRandall Stewart * will mark a lot more than we should. 617f8829a4aSRandall Stewart */ 618f8829a4aSRandall Stewart min_wait.tv_sec = min_wait.tv_usec = 0; 619f8829a4aSRandall Stewart } 62080fefe0aSRandall Stewart if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 621f8829a4aSRandall Stewart sctp_log_fr(cur_rtt, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); 622f8829a4aSRandall Stewart sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); 62380fefe0aSRandall Stewart } 624f8829a4aSRandall Stewart /* 625f8829a4aSRandall Stewart * Our rwnd will be incorrect here since we are not adding back the 626f8829a4aSRandall Stewart * cnt * mbuf but we will fix that down below. 627f8829a4aSRandall Stewart */ 628f8829a4aSRandall Stewart orig_flight = net->flight_size; 629c105859eSRandall Stewart orig_tf = stcb->asoc.total_flight; 630c105859eSRandall Stewart 631f8829a4aSRandall Stewart net->fast_retran_ip = 0; 632f8829a4aSRandall Stewart /* Now on to each chunk */ 633f8829a4aSRandall Stewart num_mk = cnt_mk = 0; 634f8829a4aSRandall Stewart tsnfirst = tsnlast = 0; 635f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 636f8829a4aSRandall Stewart for (; chk != NULL; chk = tp2) { 637f8829a4aSRandall Stewart tp2 = TAILQ_NEXT(chk, sctp_next); 638f8829a4aSRandall Stewart if ((compare_with_wrap(stcb->asoc.last_acked_seq, 639f8829a4aSRandall Stewart chk->rec.data.TSN_seq, 640f8829a4aSRandall Stewart MAX_TSN)) || 641f8829a4aSRandall Stewart (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) { 642f8829a4aSRandall Stewart /* Strange case our list got out of order? */ 643ad81507eSRandall Stewart SCTP_PRINTF("Our list is out of order?\n"); 644f8829a4aSRandall Stewart panic("Out of order list"); 645f8829a4aSRandall Stewart } 646f8829a4aSRandall Stewart if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) { 647f8829a4aSRandall Stewart /* 648f8829a4aSRandall Stewart * found one to mark: If it is less than 649f8829a4aSRandall Stewart * DATAGRAM_ACKED it MUST not be a skipped or marked 650f8829a4aSRandall Stewart * TSN but instead one that is either already set 651f8829a4aSRandall Stewart * for retransmission OR one that needs 652f8829a4aSRandall Stewart * retransmission. 653f8829a4aSRandall Stewart */ 654f8829a4aSRandall Stewart 655f8829a4aSRandall Stewart /* validate its been outstanding long enough */ 65680fefe0aSRandall Stewart if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 657f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, 658f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 659f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 660f8829a4aSRandall Stewart SCTP_FR_T3_MARK_TIME); 66180fefe0aSRandall Stewart } 662f8829a4aSRandall Stewart if ((chk->sent_rcv_time.tv_sec > min_wait.tv_sec) && (window_probe == 0)) { 663f8829a4aSRandall Stewart /* 664f8829a4aSRandall Stewart * we have reached a chunk that was sent 665f8829a4aSRandall Stewart * some seconds past our min.. forget it we 666f8829a4aSRandall Stewart * will find no more to send. 667f8829a4aSRandall Stewart */ 66880fefe0aSRandall Stewart if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 669f8829a4aSRandall Stewart sctp_log_fr(0, 670f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 671f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 672f8829a4aSRandall Stewart SCTP_FR_T3_STOPPED); 67380fefe0aSRandall Stewart } 674f8829a4aSRandall Stewart continue; 675f8829a4aSRandall Stewart } else if ((chk->sent_rcv_time.tv_sec == min_wait.tv_sec) && 676f8829a4aSRandall Stewart (window_probe == 0)) { 677f8829a4aSRandall Stewart /* 678f8829a4aSRandall Stewart * we must look at the micro seconds to 679f8829a4aSRandall Stewart * know. 680f8829a4aSRandall Stewart */ 681f8829a4aSRandall Stewart if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { 682f8829a4aSRandall Stewart /* 683f8829a4aSRandall Stewart * ok it was sent after our boundary 684f8829a4aSRandall Stewart * time. 685f8829a4aSRandall Stewart */ 68680fefe0aSRandall Stewart if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 687f8829a4aSRandall Stewart sctp_log_fr(0, 688f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 689f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 690f8829a4aSRandall Stewart SCTP_FR_T3_STOPPED); 69180fefe0aSRandall Stewart } 692f8829a4aSRandall Stewart continue; 693f8829a4aSRandall Stewart } 694f8829a4aSRandall Stewart } 695f8829a4aSRandall Stewart if (PR_SCTP_TTL_ENABLED(chk->flags)) { 696f8829a4aSRandall Stewart /* Is it expired? */ 697f8829a4aSRandall Stewart if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) || 698f8829a4aSRandall Stewart ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) && 699f8829a4aSRandall Stewart (now.tv_usec > chk->rec.data.timetodrop.tv_usec))) { 700f8829a4aSRandall Stewart /* Yes so drop it */ 701f8829a4aSRandall Stewart if (chk->data) { 702ad81507eSRandall Stewart (void)sctp_release_pr_sctp_chunk(stcb, 703f8829a4aSRandall Stewart chk, 704f8829a4aSRandall Stewart (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), 705ceaad40aSRandall Stewart &stcb->asoc.sent_queue, SCTP_SO_NOT_LOCKED); 706f8829a4aSRandall Stewart } 707f8829a4aSRandall Stewart } 708f8829a4aSRandall Stewart continue; 709f8829a4aSRandall Stewart } 710f8829a4aSRandall Stewart if (PR_SCTP_RTX_ENABLED(chk->flags)) { 711f8829a4aSRandall Stewart /* Has it been retransmitted tv_sec times? */ 712f8829a4aSRandall Stewart if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) { 713f8829a4aSRandall Stewart if (chk->data) { 714ad81507eSRandall Stewart (void)sctp_release_pr_sctp_chunk(stcb, 715f8829a4aSRandall Stewart chk, 716f8829a4aSRandall Stewart (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), 717ceaad40aSRandall Stewart &stcb->asoc.sent_queue, SCTP_SO_NOT_LOCKED); 718f8829a4aSRandall Stewart } 719f8829a4aSRandall Stewart } 720f8829a4aSRandall Stewart continue; 721f8829a4aSRandall Stewart } 722c105859eSRandall Stewart if (chk->sent < SCTP_DATAGRAM_RESEND) { 723f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 724f8829a4aSRandall Stewart num_mk++; 725f8829a4aSRandall Stewart if (fir == 0) { 726f8829a4aSRandall Stewart fir = 1; 727f8829a4aSRandall Stewart tsnfirst = chk->rec.data.TSN_seq; 728f8829a4aSRandall Stewart } 729f8829a4aSRandall Stewart tsnlast = chk->rec.data.TSN_seq; 73080fefe0aSRandall Stewart if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 731f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, 732f8829a4aSRandall Stewart 0, SCTP_FR_T3_MARKED); 73380fefe0aSRandall Stewart } 73442551e99SRandall Stewart if (chk->rec.data.chunk_was_revoked) { 73542551e99SRandall Stewart /* deflate the cwnd */ 73642551e99SRandall Stewart chk->whoTo->cwnd -= chk->book_size; 73742551e99SRandall Stewart chk->rec.data.chunk_was_revoked = 0; 73842551e99SRandall Stewart } 739f42a358aSRandall Stewart net->marked_retrans++; 740f42a358aSRandall Stewart stcb->asoc.marked_retrans++; 74180fefe0aSRandall Stewart if (sctp_logging_level & SCTP_FLIGHT_LOGGING_ENABLE) { 742c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO, 743a5d547adSRandall Stewart chk->whoTo->flight_size, 744a5d547adSRandall Stewart chk->book_size, 745c105859eSRandall Stewart (uintptr_t) chk->whoTo, 746a5d547adSRandall Stewart chk->rec.data.TSN_seq); 74780fefe0aSRandall Stewart } 748c105859eSRandall Stewart sctp_flight_size_decrease(chk); 749c105859eSRandall Stewart sctp_total_flight_decrease(stcb, chk); 750f8829a4aSRandall Stewart stcb->asoc.peers_rwnd += chk->send_size; 751f8829a4aSRandall Stewart stcb->asoc.peers_rwnd += sctp_peer_chunk_oh; 752c105859eSRandall Stewart } 753c105859eSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 754c105859eSRandall Stewart SCTP_STAT_INCR(sctps_markedretrans); 755f8829a4aSRandall Stewart 756f8829a4aSRandall Stewart /* reset the TSN for striking and other FR stuff */ 757f8829a4aSRandall Stewart chk->rec.data.doing_fast_retransmit = 0; 758f8829a4aSRandall Stewart /* Clear any time so NO RTT is being done */ 759f8829a4aSRandall Stewart chk->do_rtt = 0; 760f8829a4aSRandall Stewart if (alt != net) { 761f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 762f8829a4aSRandall Stewart chk->no_fr_allowed = 1; 763f8829a4aSRandall Stewart chk->whoTo = alt; 764f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 765f8829a4aSRandall Stewart } else { 766f8829a4aSRandall Stewart chk->no_fr_allowed = 0; 767f8829a4aSRandall Stewart if (TAILQ_EMPTY(&stcb->asoc.send_queue)) { 768f8829a4aSRandall Stewart chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq; 769f8829a4aSRandall Stewart } else { 770f8829a4aSRandall Stewart chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq; 771f8829a4aSRandall Stewart } 772f8829a4aSRandall Stewart } 773ad21a364SRandall Stewart /* 774ad21a364SRandall Stewart * CMT: Do not allow FRs on retransmitted TSNs. 775ad21a364SRandall Stewart */ 776f8829a4aSRandall Stewart if (sctp_cmt_on_off == 1) { 777f8829a4aSRandall Stewart chk->no_fr_allowed = 1; 778f8829a4aSRandall Stewart } 779f8829a4aSRandall Stewart } else if (chk->sent == SCTP_DATAGRAM_ACKED) { 780f8829a4aSRandall Stewart /* remember highest acked one */ 781f8829a4aSRandall Stewart could_be_sent = chk; 782f8829a4aSRandall Stewart } 783f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 784f8829a4aSRandall Stewart cnt_mk++; 785f8829a4aSRandall Stewart } 786f8829a4aSRandall Stewart } 787c105859eSRandall Stewart if ((orig_flight - net->flight_size) != (orig_tf - stcb->asoc.total_flight)) { 788c105859eSRandall Stewart /* we did not subtract the same things? */ 789c105859eSRandall Stewart audit_tf = 1; 790c105859eSRandall Stewart } 79180fefe0aSRandall Stewart if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) { 792f8829a4aSRandall Stewart sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT); 79380fefe0aSRandall Stewart } 794f8829a4aSRandall Stewart #ifdef SCTP_DEBUG 795f8829a4aSRandall Stewart if (num_mk) { 796ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", 797ad81507eSRandall Stewart tsnlast); 798ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%ld\n", 799f8829a4aSRandall Stewart num_mk, (u_long)stcb->asoc.peers_rwnd); 800ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", 801ad81507eSRandall Stewart tsnlast); 802ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%d\n", 803f8829a4aSRandall Stewart num_mk, 804ad81507eSRandall Stewart (int)stcb->asoc.peers_rwnd); 805f8829a4aSRandall Stewart } 806f8829a4aSRandall Stewart #endif 807f8829a4aSRandall Stewart *num_marked = num_mk; 808f8829a4aSRandall Stewart if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) { 809f8829a4aSRandall Stewart /* fix it so we retransmit the highest acked anyway */ 810f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 811f8829a4aSRandall Stewart cnt_mk++; 812f8829a4aSRandall Stewart could_be_sent->sent = SCTP_DATAGRAM_RESEND; 813f8829a4aSRandall Stewart } 814f8829a4aSRandall Stewart if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { 815a5d547adSRandall Stewart #ifdef INVARIANTS 81618e198d3SRandall Stewart SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d we marked:%d this time\n", 81718e198d3SRandall Stewart cnt_mk, stcb->asoc.sent_queue_retran_cnt, num_mk); 818f8829a4aSRandall Stewart #endif 819f8829a4aSRandall Stewart #ifndef SCTP_AUDITING_ENABLED 820f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = cnt_mk; 821f8829a4aSRandall Stewart #endif 822f8829a4aSRandall Stewart } 823f8829a4aSRandall Stewart /* Now check for a ECN Echo that may be stranded */ 824f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 825f8829a4aSRandall Stewart if ((chk->whoTo == net) && 826f8829a4aSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 827f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 828f8829a4aSRandall Stewart chk->whoTo = alt; 829f8829a4aSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 830f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 831f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 832f8829a4aSRandall Stewart } 833f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 834f8829a4aSRandall Stewart } 835f8829a4aSRandall Stewart } 836f8829a4aSRandall Stewart if (audit_tf) { 837ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, 838ad81507eSRandall Stewart "Audit total flight due to negative value net:%p\n", 839f8829a4aSRandall Stewart net); 840f8829a4aSRandall Stewart stcb->asoc.total_flight = 0; 841f8829a4aSRandall Stewart stcb->asoc.total_flight_count = 0; 842f8829a4aSRandall Stewart /* Clear all networks flight size */ 843f8829a4aSRandall Stewart TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) { 844f8829a4aSRandall Stewart lnets->flight_size = 0; 845ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, 846ad81507eSRandall Stewart "Net:%p c-f cwnd:%d ssthresh:%d\n", 847f8829a4aSRandall Stewart lnets, lnets->cwnd, lnets->ssthresh); 848f8829a4aSRandall Stewart } 849f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 850f8829a4aSRandall Stewart if (chk->sent < SCTP_DATAGRAM_RESEND) { 85180fefe0aSRandall Stewart if (sctp_logging_level & SCTP_FLIGHT_LOGGING_ENABLE) { 852a5d547adSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_UP, 853a5d547adSRandall Stewart chk->whoTo->flight_size, 854a5d547adSRandall Stewart chk->book_size, 855c105859eSRandall Stewart (uintptr_t) chk->whoTo, 856a5d547adSRandall Stewart chk->rec.data.TSN_seq); 85780fefe0aSRandall Stewart } 858c105859eSRandall Stewart sctp_flight_size_increase(chk); 859c105859eSRandall Stewart sctp_total_flight_increase(stcb, chk); 860f8829a4aSRandall Stewart } 861f8829a4aSRandall Stewart } 862f8829a4aSRandall Stewart } 863f8829a4aSRandall Stewart /* 864f8829a4aSRandall Stewart * Setup the ecn nonce re-sync point. We do this since 865f8829a4aSRandall Stewart * retranmissions are NOT setup for ECN. This means that do to 866f8829a4aSRandall Stewart * Karn's rule, we don't know the total of the peers ecn bits. 867f8829a4aSRandall Stewart */ 868f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.send_queue); 869f8829a4aSRandall Stewart if (chk == NULL) { 870f8829a4aSRandall Stewart stcb->asoc.nonce_resync_tsn = stcb->asoc.sending_seq; 871f8829a4aSRandall Stewart } else { 872f8829a4aSRandall Stewart stcb->asoc.nonce_resync_tsn = chk->rec.data.TSN_seq; 873f8829a4aSRandall Stewart } 874f8829a4aSRandall Stewart stcb->asoc.nonce_wait_for_ecne = 0; 875f8829a4aSRandall Stewart stcb->asoc.nonce_sum_check = 0; 876f8829a4aSRandall Stewart /* We return 1 if we only have a window probe outstanding */ 877f8829a4aSRandall Stewart return (0); 878f8829a4aSRandall Stewart } 879f8829a4aSRandall Stewart 880f8829a4aSRandall Stewart static void 881f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb, 882f8829a4aSRandall Stewart struct sctp_nets *net, 883f8829a4aSRandall Stewart struct sctp_nets *alt) 884f8829a4aSRandall Stewart { 885f8829a4aSRandall Stewart struct sctp_association *asoc; 886f8829a4aSRandall Stewart struct sctp_stream_out *outs; 887f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 888f8829a4aSRandall Stewart struct sctp_stream_queue_pending *sp; 889f8829a4aSRandall Stewart 890f8829a4aSRandall Stewart if (net == alt) 891f8829a4aSRandall Stewart /* nothing to do */ 892f8829a4aSRandall Stewart return; 893f8829a4aSRandall Stewart 894f8829a4aSRandall Stewart asoc = &stcb->asoc; 895f8829a4aSRandall Stewart 896f8829a4aSRandall Stewart /* 897f8829a4aSRandall Stewart * now through all the streams checking for chunks sent to our bad 898f8829a4aSRandall Stewart * network. 899f8829a4aSRandall Stewart */ 900f8829a4aSRandall Stewart TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { 901f8829a4aSRandall Stewart /* now clean up any chunks here */ 902f8829a4aSRandall Stewart TAILQ_FOREACH(sp, &outs->outqueue, next) { 903f8829a4aSRandall Stewart if (sp->net == net) { 904f8829a4aSRandall Stewart sctp_free_remote_addr(sp->net); 905f8829a4aSRandall Stewart sp->net = alt; 906f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 907f8829a4aSRandall Stewart } 908f8829a4aSRandall Stewart } 909f8829a4aSRandall Stewart } 910f8829a4aSRandall Stewart /* Now check the pending queue */ 911f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { 912f8829a4aSRandall Stewart if (chk->whoTo == net) { 913f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 914f8829a4aSRandall Stewart chk->whoTo = alt; 915f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 916f8829a4aSRandall Stewart } 917f8829a4aSRandall Stewart } 918f8829a4aSRandall Stewart 919f8829a4aSRandall Stewart } 920f8829a4aSRandall Stewart 921f8829a4aSRandall Stewart int 922f8829a4aSRandall Stewart sctp_t3rxt_timer(struct sctp_inpcb *inp, 923f8829a4aSRandall Stewart struct sctp_tcb *stcb, 924f8829a4aSRandall Stewart struct sctp_nets *net) 925f8829a4aSRandall Stewart { 926f8829a4aSRandall Stewart struct sctp_nets *alt; 927f8829a4aSRandall Stewart int win_probe, num_mk; 928f8829a4aSRandall Stewart 92980fefe0aSRandall Stewart if (sctp_logging_level & SCTP_FR_LOGGING_ENABLE) { 930562a89b5SRandall Stewart sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT); 93180fefe0aSRandall Stewart } 93280fefe0aSRandall Stewart if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) { 933f8829a4aSRandall Stewart struct sctp_nets *lnet; 934f8829a4aSRandall Stewart 935f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 936f8829a4aSRandall Stewart if (net == lnet) { 937f8829a4aSRandall Stewart sctp_log_cwnd(stcb, lnet, 1, SCTP_CWND_LOG_FROM_T3); 938f8829a4aSRandall Stewart } else { 939f8829a4aSRandall Stewart sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_LOG_FROM_T3); 940f8829a4aSRandall Stewart } 941f8829a4aSRandall Stewart } 942f8829a4aSRandall Stewart } 943f8829a4aSRandall Stewart /* Find an alternate and mark those for retransmission */ 944f8829a4aSRandall Stewart if ((stcb->asoc.peers_rwnd == 0) && 945f8829a4aSRandall Stewart (stcb->asoc.total_flight < net->mtu)) { 946f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timowindowprobe); 947f8829a4aSRandall Stewart win_probe = 1; 948f8829a4aSRandall Stewart } else { 949f8829a4aSRandall Stewart win_probe = 0; 950f8829a4aSRandall Stewart } 951c105859eSRandall Stewart 952b54d3a6cSRandall Stewart /* 953b54d3a6cSRandall Stewart * JRS 5/14/07 - If CMT PF is on and the destination if not already 954b54d3a6cSRandall Stewart * in PF state, set the destination to PF state and store the 955b54d3a6cSRandall Stewart * current time as the time that the destination was last active. In 956b54d3a6cSRandall Stewart * addition, find an alternate destination with PF-based 957b54d3a6cSRandall Stewart * find_alt_net(). 958b54d3a6cSRandall Stewart */ 95918e198d3SRandall Stewart if (sctp_cmt_on_off && sctp_cmt_pf) { 960b54d3a6cSRandall Stewart if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) { 961b54d3a6cSRandall Stewart net->dest_state |= SCTP_ADDR_PF; 96218e198d3SRandall Stewart net->last_active = sctp_get_tick_count(); 963b54d3a6cSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from active to PF.\n", 964b54d3a6cSRandall Stewart net); 965b54d3a6cSRandall Stewart } 966b54d3a6cSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 2); 967b54d3a6cSRandall Stewart } else if (sctp_cmt_on_off) { 968c105859eSRandall Stewart /* 969c105859eSRandall Stewart * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being 970c105859eSRandall Stewart * used, then pick dest with largest ssthresh for any 971c105859eSRandall Stewart * retransmission. 972c105859eSRandall Stewart */ 973c105859eSRandall Stewart alt = net; 974c105859eSRandall Stewart alt = sctp_find_alternate_net(stcb, alt, 1); 975c105859eSRandall Stewart /* 976c105859eSRandall Stewart * CUCv2: If a different dest is picked for the 977c105859eSRandall Stewart * retransmission, then new (rtx-)pseudo_cumack needs to be 978c105859eSRandall Stewart * tracked for orig dest. Let CUCv2 track new (rtx-) 979c105859eSRandall Stewart * pseudo-cumack always. 980c105859eSRandall Stewart */ 981c105859eSRandall Stewart net->find_pseudo_cumack = 1; 982c105859eSRandall Stewart net->find_rtx_pseudo_cumack = 1; 983c105859eSRandall Stewart } else { /* CMT is OFF */ 984f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 985c105859eSRandall Stewart } 986c105859eSRandall Stewart 987ad81507eSRandall Stewart (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, &num_mk); 988f8829a4aSRandall Stewart /* FR Loss recovery just ended with the T3. */ 989f8829a4aSRandall Stewart stcb->asoc.fast_retran_loss_recovery = 0; 990f8829a4aSRandall Stewart 991f8829a4aSRandall Stewart /* CMT FR loss recovery ended with the T3 */ 992f8829a4aSRandall Stewart net->fast_retran_loss_recovery = 0; 993f8829a4aSRandall Stewart 994f8829a4aSRandall Stewart /* 995f8829a4aSRandall Stewart * setup the sat loss recovery that prevents satellite cwnd advance. 996f8829a4aSRandall Stewart */ 997f8829a4aSRandall Stewart stcb->asoc.sat_t3_loss_recovery = 1; 998f8829a4aSRandall Stewart stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; 999f8829a4aSRandall Stewart 1000f8829a4aSRandall Stewart /* Backoff the timer and cwnd */ 1001f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, net, win_probe, num_mk); 1002f8829a4aSRandall Stewart if (win_probe == 0) { 1003f8829a4aSRandall Stewart /* We don't do normal threshold management on window probes */ 1004f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, 1005f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1006f8829a4aSRandall Stewart /* Association was destroyed */ 1007f8829a4aSRandall Stewart return (1); 1008f8829a4aSRandall Stewart } else { 1009f8829a4aSRandall Stewart if (net != stcb->asoc.primary_destination) { 1010f8829a4aSRandall Stewart /* send a immediate HB if our RTO is stale */ 1011f8829a4aSRandall Stewart struct timeval now; 1012f8829a4aSRandall Stewart unsigned int ms_goneby; 1013f8829a4aSRandall Stewart 10146e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 1015f8829a4aSRandall Stewart if (net->last_sent_time.tv_sec) { 1016f8829a4aSRandall Stewart ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000; 1017f8829a4aSRandall Stewart } else { 1018f8829a4aSRandall Stewart ms_goneby = 0; 1019f8829a4aSRandall Stewart } 1020f8829a4aSRandall Stewart if ((ms_goneby > net->RTO) || (net->RTO == 0)) { 1021f8829a4aSRandall Stewart /* 1022f8829a4aSRandall Stewart * no recent feed back in an RTO or 1023f8829a4aSRandall Stewart * more, request a RTT update 1024f8829a4aSRandall Stewart */ 1025b54d3a6cSRandall Stewart if (sctp_send_hb(stcb, 1, net) < 0) 1026b54d3a6cSRandall Stewart return 1; 1027f8829a4aSRandall Stewart } 1028f8829a4aSRandall Stewart } 1029f8829a4aSRandall Stewart } 1030f8829a4aSRandall Stewart } else { 1031f8829a4aSRandall Stewart /* 1032f8829a4aSRandall Stewart * For a window probe we don't penalize the net's but only 1033f8829a4aSRandall Stewart * the association. This may fail it if SACKs are not coming 1034f8829a4aSRandall Stewart * back. If sack's are coming with rwnd locked at 0, we will 1035f8829a4aSRandall Stewart * continue to hold things waiting for rwnd to raise 1036f8829a4aSRandall Stewart */ 1037f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, NULL, 1038f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1039f8829a4aSRandall Stewart /* Association was destroyed */ 1040f8829a4aSRandall Stewart return (1); 1041f8829a4aSRandall Stewart } 1042f8829a4aSRandall Stewart } 1043f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 1044f8829a4aSRandall Stewart /* Move all pending over too */ 1045f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 104617205eccSRandall Stewart 104717205eccSRandall Stewart /* 104817205eccSRandall Stewart * Get the address that failed, to force a new src address 104917205eccSRandall Stewart * selecton and a route allocation. 105017205eccSRandall Stewart */ 105117205eccSRandall Stewart if (net->ro._s_addr) { 105217205eccSRandall Stewart sctp_free_ifa(net->ro._s_addr); 105317205eccSRandall Stewart net->ro._s_addr = NULL; 105417205eccSRandall Stewart } 105517205eccSRandall Stewart net->src_addr_selected = 0; 105617205eccSRandall Stewart 105717205eccSRandall Stewart /* Force a route allocation too */ 105817205eccSRandall Stewart if (net->ro.ro_rt) { 105917205eccSRandall Stewart RTFREE(net->ro.ro_rt); 106017205eccSRandall Stewart net->ro.ro_rt = NULL; 106117205eccSRandall Stewart } 1062f8829a4aSRandall Stewart /* Was it our primary? */ 1063f8829a4aSRandall Stewart if ((stcb->asoc.primary_destination == net) && (alt != net)) { 1064f8829a4aSRandall Stewart /* 1065f8829a4aSRandall Stewart * Yes, note it as such and find an alternate note: 1066f8829a4aSRandall Stewart * this means HB code must use this to resent the 1067f8829a4aSRandall Stewart * primary if it goes active AND if someone does a 1068f8829a4aSRandall Stewart * change-primary then this flag must be cleared 1069f8829a4aSRandall Stewart * from any net structures. 1070f8829a4aSRandall Stewart */ 1071f8829a4aSRandall Stewart if (sctp_set_primary_addr(stcb, 1072f8829a4aSRandall Stewart (struct sockaddr *)NULL, 1073f8829a4aSRandall Stewart alt) == 0) { 1074f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_WAS_PRIMARY; 1075f8829a4aSRandall Stewart } 1076f8829a4aSRandall Stewart } 107718e198d3SRandall Stewart } else if (sctp_cmt_on_off && sctp_cmt_pf && (net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) { 1078b54d3a6cSRandall Stewart /* 1079b54d3a6cSRandall Stewart * JRS 5/14/07 - If the destination hasn't failed completely 1080b54d3a6cSRandall Stewart * but is in PF state, a PF-heartbeat needs to be sent 1081b54d3a6cSRandall Stewart * manually. 1082b54d3a6cSRandall Stewart */ 1083b54d3a6cSRandall Stewart if (sctp_send_hb(stcb, 1, net) < 0) 1084b54d3a6cSRandall Stewart return 1; 1085f8829a4aSRandall Stewart } 1086f8829a4aSRandall Stewart /* 1087f8829a4aSRandall Stewart * Special case for cookie-echo'ed case, we don't do output but must 1088f8829a4aSRandall Stewart * await the COOKIE-ACK before retransmission 1089f8829a4aSRandall Stewart */ 1090f8829a4aSRandall Stewart if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { 1091f8829a4aSRandall Stewart /* 1092f8829a4aSRandall Stewart * Here we just reset the timer and start again since we 1093f8829a4aSRandall Stewart * have not established the asoc 1094f8829a4aSRandall Stewart */ 1095f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); 1096f8829a4aSRandall Stewart return (0); 1097f8829a4aSRandall Stewart } 1098f8829a4aSRandall Stewart if (stcb->asoc.peer_supports_prsctp) { 1099f8829a4aSRandall Stewart struct sctp_tmit_chunk *lchk; 1100f8829a4aSRandall Stewart 1101f8829a4aSRandall Stewart lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc); 1102f8829a4aSRandall Stewart /* C3. See if we need to send a Fwd-TSN */ 1103f8829a4aSRandall Stewart if (compare_with_wrap(stcb->asoc.advanced_peer_ack_point, 1104f8829a4aSRandall Stewart stcb->asoc.last_acked_seq, MAX_TSN)) { 1105f8829a4aSRandall Stewart /* 1106f8829a4aSRandall Stewart * ISSUE with ECN, see FWD-TSN processing for notes 1107f8829a4aSRandall Stewart * on issues that will occur when the ECN NONCE 1108f8829a4aSRandall Stewart * stuff is put into SCTP for cross checking. 1109f8829a4aSRandall Stewart */ 1110f8829a4aSRandall Stewart send_forward_tsn(stcb, &stcb->asoc); 1111f8829a4aSRandall Stewart if (lchk) { 1112f8829a4aSRandall Stewart /* Assure a timer is up */ 1113f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo); 1114f8829a4aSRandall Stewart } 1115f8829a4aSRandall Stewart } 1116f8829a4aSRandall Stewart } 111780fefe0aSRandall Stewart if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) { 1118f8829a4aSRandall Stewart sctp_log_cwnd(stcb, net, net->cwnd, SCTP_CWND_LOG_FROM_RTX); 111980fefe0aSRandall Stewart } 1120f8829a4aSRandall Stewart return (0); 1121f8829a4aSRandall Stewart } 1122f8829a4aSRandall Stewart 1123f8829a4aSRandall Stewart int 1124f8829a4aSRandall Stewart sctp_t1init_timer(struct sctp_inpcb *inp, 1125f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1126f8829a4aSRandall Stewart struct sctp_nets *net) 1127f8829a4aSRandall Stewart { 1128f8829a4aSRandall Stewart /* bump the thresholds */ 1129f8829a4aSRandall Stewart if (stcb->asoc.delayed_connection) { 1130f8829a4aSRandall Stewart /* 1131f8829a4aSRandall Stewart * special hook for delayed connection. The library did NOT 1132f8829a4aSRandall Stewart * complete the rest of its sends. 1133f8829a4aSRandall Stewart */ 1134f8829a4aSRandall Stewart stcb->asoc.delayed_connection = 0; 1135ceaad40aSRandall Stewart sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); 1136f8829a4aSRandall Stewart return (0); 1137f8829a4aSRandall Stewart } 1138f8829a4aSRandall Stewart if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) { 1139f8829a4aSRandall Stewart return (0); 1140f8829a4aSRandall Stewart } 1141f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, 1142f8829a4aSRandall Stewart stcb->asoc.max_init_times)) { 1143f8829a4aSRandall Stewart /* Association was destroyed */ 1144f8829a4aSRandall Stewart return (1); 1145f8829a4aSRandall Stewart } 1146f8829a4aSRandall Stewart stcb->asoc.dropped_special_cnt = 0; 1147f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0); 1148f8829a4aSRandall Stewart if (stcb->asoc.initial_init_rto_max < net->RTO) { 1149f8829a4aSRandall Stewart net->RTO = stcb->asoc.initial_init_rto_max; 1150f8829a4aSRandall Stewart } 1151f8829a4aSRandall Stewart if (stcb->asoc.numnets > 1) { 1152f8829a4aSRandall Stewart /* If we have more than one addr use it */ 1153f8829a4aSRandall Stewart struct sctp_nets *alt; 1154f8829a4aSRandall Stewart 1155f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0); 1156f8829a4aSRandall Stewart if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) { 1157f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt); 1158f8829a4aSRandall Stewart stcb->asoc.primary_destination = alt; 1159f8829a4aSRandall Stewart } 1160f8829a4aSRandall Stewart } 1161f8829a4aSRandall Stewart /* Send out a new init */ 1162ceaad40aSRandall Stewart sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); 1163f8829a4aSRandall Stewart return (0); 1164f8829a4aSRandall Stewart } 1165f8829a4aSRandall Stewart 1166f8829a4aSRandall Stewart /* 1167f8829a4aSRandall Stewart * For cookie and asconf we actually need to find and mark for resend, then 1168f8829a4aSRandall Stewart * increment the resend counter (after all the threshold management stuff of 1169f8829a4aSRandall Stewart * course). 1170f8829a4aSRandall Stewart */ 1171f8829a4aSRandall Stewart int 1172f8829a4aSRandall Stewart sctp_cookie_timer(struct sctp_inpcb *inp, 1173f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1174f8829a4aSRandall Stewart struct sctp_nets *net) 1175f8829a4aSRandall Stewart { 1176f8829a4aSRandall Stewart struct sctp_nets *alt; 1177f8829a4aSRandall Stewart struct sctp_tmit_chunk *cookie; 1178f8829a4aSRandall Stewart 1179f8829a4aSRandall Stewart /* first before all else we must find the cookie */ 1180f8829a4aSRandall Stewart TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) { 1181f8829a4aSRandall Stewart if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) { 1182f8829a4aSRandall Stewart break; 1183f8829a4aSRandall Stewart } 1184f8829a4aSRandall Stewart } 1185f8829a4aSRandall Stewart if (cookie == NULL) { 1186f8829a4aSRandall Stewart if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { 1187f8829a4aSRandall Stewart /* FOOBAR! */ 1188f8829a4aSRandall Stewart struct mbuf *oper; 1189f8829a4aSRandall Stewart 1190f8829a4aSRandall Stewart oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 1191f8829a4aSRandall Stewart 0, M_DONTWAIT, 1, MT_DATA); 1192f8829a4aSRandall Stewart if (oper) { 1193f8829a4aSRandall Stewart struct sctp_paramhdr *ph; 1194f8829a4aSRandall Stewart uint32_t *ippp; 1195f8829a4aSRandall Stewart 1196139bc87fSRandall Stewart SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) + 1197f8829a4aSRandall Stewart sizeof(uint32_t); 1198f8829a4aSRandall Stewart ph = mtod(oper, struct sctp_paramhdr *); 1199f8829a4aSRandall Stewart ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1200139bc87fSRandall Stewart ph->param_length = htons(SCTP_BUF_LEN(oper)); 1201f8829a4aSRandall Stewart ippp = (uint32_t *) (ph + 1); 1202b54d3a6cSRandall Stewart *ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 1203f8829a4aSRandall Stewart } 1204b54d3a6cSRandall Stewart inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_4; 1205f8829a4aSRandall Stewart sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR, 1206ceaad40aSRandall Stewart oper, SCTP_SO_NOT_LOCKED); 1207f8829a4aSRandall Stewart } else { 1208a5d547adSRandall Stewart #ifdef INVARIANTS 1209f8829a4aSRandall Stewart panic("Cookie timer expires in wrong state?"); 1210f8829a4aSRandall Stewart #else 1211ad81507eSRandall Stewart SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc)); 1212f8829a4aSRandall Stewart return (0); 1213f8829a4aSRandall Stewart #endif 1214f8829a4aSRandall Stewart } 1215f8829a4aSRandall Stewart return (0); 1216f8829a4aSRandall Stewart } 1217f8829a4aSRandall Stewart /* Ok we found the cookie, threshold management next */ 1218f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, cookie->whoTo, 1219f8829a4aSRandall Stewart stcb->asoc.max_init_times)) { 1220f8829a4aSRandall Stewart /* Assoc is over */ 1221f8829a4aSRandall Stewart return (1); 1222f8829a4aSRandall Stewart } 1223f8829a4aSRandall Stewart /* 1224f8829a4aSRandall Stewart * cleared theshold management now lets backoff the address & select 1225f8829a4aSRandall Stewart * an alternate 1226f8829a4aSRandall Stewart */ 1227f8829a4aSRandall Stewart stcb->asoc.dropped_special_cnt = 0; 1228f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0); 1229f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0); 1230f8829a4aSRandall Stewart if (alt != cookie->whoTo) { 1231f8829a4aSRandall Stewart sctp_free_remote_addr(cookie->whoTo); 1232f8829a4aSRandall Stewart cookie->whoTo = alt; 1233f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1234f8829a4aSRandall Stewart } 1235f8829a4aSRandall Stewart /* Now mark the retran info */ 1236f8829a4aSRandall Stewart if (cookie->sent != SCTP_DATAGRAM_RESEND) { 1237f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1238f8829a4aSRandall Stewart } 1239f8829a4aSRandall Stewart cookie->sent = SCTP_DATAGRAM_RESEND; 1240f8829a4aSRandall Stewart /* 1241f8829a4aSRandall Stewart * Now call the output routine to kick out the cookie again, Note we 1242f8829a4aSRandall Stewart * don't mark any chunks for retran so that FR will need to kick in 1243f8829a4aSRandall Stewart * to move these (or a send timer). 1244f8829a4aSRandall Stewart */ 1245f8829a4aSRandall Stewart return (0); 1246f8829a4aSRandall Stewart } 1247f8829a4aSRandall Stewart 1248f8829a4aSRandall Stewart int 1249f8829a4aSRandall Stewart sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1250f8829a4aSRandall Stewart struct sctp_nets *net) 1251f8829a4aSRandall Stewart { 1252f8829a4aSRandall Stewart struct sctp_nets *alt; 1253f8829a4aSRandall Stewart struct sctp_tmit_chunk *strrst = NULL, *chk = NULL; 1254f8829a4aSRandall Stewart 1255f8829a4aSRandall Stewart if (stcb->asoc.stream_reset_outstanding == 0) { 1256f8829a4aSRandall Stewart return (0); 1257f8829a4aSRandall Stewart } 1258f8829a4aSRandall Stewart /* find the existing STRRESET, we use the seq number we sent out on */ 1259ad81507eSRandall Stewart (void)sctp_find_stream_reset(stcb, stcb->asoc.str_reset_seq_out, &strrst); 1260f8829a4aSRandall Stewart if (strrst == NULL) { 1261f8829a4aSRandall Stewart return (0); 1262f8829a4aSRandall Stewart } 1263f8829a4aSRandall Stewart /* do threshold management */ 1264f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, strrst->whoTo, 1265f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1266f8829a4aSRandall Stewart /* Assoc is over */ 1267f8829a4aSRandall Stewart return (1); 1268f8829a4aSRandall Stewart } 1269f8829a4aSRandall Stewart /* 1270f8829a4aSRandall Stewart * cleared theshold management now lets backoff the address & select 1271f8829a4aSRandall Stewart * an alternate 1272f8829a4aSRandall Stewart */ 1273f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0); 1274f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0); 1275f8829a4aSRandall Stewart sctp_free_remote_addr(strrst->whoTo); 1276f8829a4aSRandall Stewart strrst->whoTo = alt; 1277f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1278f8829a4aSRandall Stewart 1279f8829a4aSRandall Stewart /* See if a ECN Echo is also stranded */ 1280f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 1281f8829a4aSRandall Stewart if ((chk->whoTo == net) && 1282f8829a4aSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 1283f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 1284f8829a4aSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 1285f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 1286f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1287f8829a4aSRandall Stewart } 1288f8829a4aSRandall Stewart chk->whoTo = alt; 1289f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1290f8829a4aSRandall Stewart } 1291f8829a4aSRandall Stewart } 1292f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 1293f8829a4aSRandall Stewart /* 1294f8829a4aSRandall Stewart * If the address went un-reachable, we need to move to 1295f8829a4aSRandall Stewart * alternates for ALL chk's in queue 1296f8829a4aSRandall Stewart */ 1297f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 1298f8829a4aSRandall Stewart } 1299f8829a4aSRandall Stewart /* mark the retran info */ 1300f8829a4aSRandall Stewart if (strrst->sent != SCTP_DATAGRAM_RESEND) 1301f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1302f8829a4aSRandall Stewart strrst->sent = SCTP_DATAGRAM_RESEND; 1303f8829a4aSRandall Stewart 1304f8829a4aSRandall Stewart /* restart the timer */ 1305f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo); 1306f8829a4aSRandall Stewart return (0); 1307f8829a4aSRandall Stewart } 1308f8829a4aSRandall Stewart 1309f8829a4aSRandall Stewart int 1310f8829a4aSRandall Stewart sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1311f8829a4aSRandall Stewart struct sctp_nets *net) 1312f8829a4aSRandall Stewart { 1313f8829a4aSRandall Stewart struct sctp_nets *alt; 1314f8829a4aSRandall Stewart struct sctp_tmit_chunk *asconf, *chk; 1315f8829a4aSRandall Stewart 13161b649582SRandall Stewart /* is this a first send, or a retransmission? */ 1317f8829a4aSRandall Stewart if (stcb->asoc.asconf_sent == 0) { 1318f8829a4aSRandall Stewart /* compose a new ASCONF chunk and send it */ 13193232788eSRandall Stewart sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); 1320f8829a4aSRandall Stewart } else { 13211b649582SRandall Stewart /* 13221b649582SRandall Stewart * Retransmission of the existing ASCONF is needed 13231b649582SRandall Stewart */ 1324f8829a4aSRandall Stewart 1325f8829a4aSRandall Stewart /* find the existing ASCONF */ 1326f8829a4aSRandall Stewart TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue, 1327f8829a4aSRandall Stewart sctp_next) { 1328f8829a4aSRandall Stewart if (asconf->rec.chunk_id.id == SCTP_ASCONF) { 1329f8829a4aSRandall Stewart break; 1330f8829a4aSRandall Stewart } 1331f8829a4aSRandall Stewart } 1332f8829a4aSRandall Stewart if (asconf == NULL) { 1333f8829a4aSRandall Stewart return (0); 1334f8829a4aSRandall Stewart } 1335f8829a4aSRandall Stewart /* do threshold management */ 1336f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, asconf->whoTo, 1337f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1338f8829a4aSRandall Stewart /* Assoc is over */ 1339f8829a4aSRandall Stewart return (1); 1340f8829a4aSRandall Stewart } 1341f8829a4aSRandall Stewart if (asconf->snd_count > stcb->asoc.max_send_times) { 1342f8829a4aSRandall Stewart /* 13431b649582SRandall Stewart * Something is rotten: our peer is not responding 13441b649582SRandall Stewart * to ASCONFs but apparently is to other chunks. 13451b649582SRandall Stewart * i.e. it is not properly handling the chunk type 13461b649582SRandall Stewart * upper bits. Mark this peer as ASCONF incapable 13471b649582SRandall Stewart * and cleanup. 1348f8829a4aSRandall Stewart */ 1349ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n"); 1350f8829a4aSRandall Stewart sctp_asconf_cleanup(stcb, net); 1351f8829a4aSRandall Stewart return (0); 1352f8829a4aSRandall Stewart } 1353f8829a4aSRandall Stewart /* 13541b649582SRandall Stewart * cleared threshold management, so now backoff the net and 13551b649582SRandall Stewart * select an alternate 1356f8829a4aSRandall Stewart */ 1357f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0); 1358f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0); 1359f8829a4aSRandall Stewart sctp_free_remote_addr(asconf->whoTo); 1360f8829a4aSRandall Stewart asconf->whoTo = alt; 1361f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1362f8829a4aSRandall Stewart 13631b649582SRandall Stewart /* See if an ECN Echo is also stranded */ 1364f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 1365f8829a4aSRandall Stewart if ((chk->whoTo == net) && 1366f8829a4aSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 1367f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 1368f8829a4aSRandall Stewart chk->whoTo = alt; 1369f8829a4aSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 1370f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 1371f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1372f8829a4aSRandall Stewart } 1373f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1374f8829a4aSRandall Stewart } 1375f8829a4aSRandall Stewart } 1376f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 1377f8829a4aSRandall Stewart /* 1378f8829a4aSRandall Stewart * If the address went un-reachable, we need to move 13791b649582SRandall Stewart * to the alternate for ALL chunks in queue 1380f8829a4aSRandall Stewart */ 1381f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 1382f8829a4aSRandall Stewart } 1383f8829a4aSRandall Stewart /* mark the retran info */ 1384f8829a4aSRandall Stewart if (asconf->sent != SCTP_DATAGRAM_RESEND) 1385f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1386f8829a4aSRandall Stewart asconf->sent = SCTP_DATAGRAM_RESEND; 1387f8829a4aSRandall Stewart } 1388f8829a4aSRandall Stewart return (0); 1389f8829a4aSRandall Stewart } 1390f8829a4aSRandall Stewart 1391851b7298SRandall Stewart /* Mobility adaptation */ 139204ee05e8SRandall Stewart void 1393851b7298SRandall Stewart sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1394851b7298SRandall Stewart struct sctp_nets *net) 1395851b7298SRandall Stewart { 1396851b7298SRandall Stewart if (stcb->asoc.deleted_primary == NULL) { 1397851b7298SRandall Stewart SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n"); 1398851b7298SRandall Stewart sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); 139904ee05e8SRandall Stewart return; 1400851b7298SRandall Stewart } 1401851b7298SRandall Stewart SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: finished to keep deleted primary "); 1402851b7298SRandall Stewart SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); 1403851b7298SRandall Stewart sctp_free_remote_addr(stcb->asoc.deleted_primary); 1404851b7298SRandall Stewart stcb->asoc.deleted_primary = NULL; 1405851b7298SRandall Stewart sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); 140604ee05e8SRandall Stewart return; 1407851b7298SRandall Stewart } 1408851b7298SRandall Stewart 1409f8829a4aSRandall Stewart /* 1410f8829a4aSRandall Stewart * For the shutdown and shutdown-ack, we do not keep one around on the 1411f8829a4aSRandall Stewart * control queue. This means we must generate a new one and call the general 1412f8829a4aSRandall Stewart * chunk output routine, AFTER having done threshold management. 1413f8829a4aSRandall Stewart */ 1414f8829a4aSRandall Stewart int 1415f8829a4aSRandall Stewart sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1416f8829a4aSRandall Stewart struct sctp_nets *net) 1417f8829a4aSRandall Stewart { 1418f8829a4aSRandall Stewart struct sctp_nets *alt; 1419f8829a4aSRandall Stewart 1420f8829a4aSRandall Stewart /* first threshold managment */ 1421f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { 1422f8829a4aSRandall Stewart /* Assoc is over */ 1423f8829a4aSRandall Stewart return (1); 1424f8829a4aSRandall Stewart } 1425f8829a4aSRandall Stewart /* second select an alternative */ 1426f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 1427f8829a4aSRandall Stewart 1428f8829a4aSRandall Stewart /* third generate a shutdown into the queue for out net */ 1429f8829a4aSRandall Stewart if (alt) { 1430f8829a4aSRandall Stewart sctp_send_shutdown(stcb, alt); 1431f8829a4aSRandall Stewart } else { 1432f8829a4aSRandall Stewart /* 1433f8829a4aSRandall Stewart * if alt is NULL, there is no dest to send to?? 1434f8829a4aSRandall Stewart */ 1435f8829a4aSRandall Stewart return (0); 1436f8829a4aSRandall Stewart } 1437f8829a4aSRandall Stewart /* fourth restart timer */ 1438f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt); 1439f8829a4aSRandall Stewart return (0); 1440f8829a4aSRandall Stewart } 1441f8829a4aSRandall Stewart 1442f8829a4aSRandall Stewart int 1443f8829a4aSRandall Stewart sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1444f8829a4aSRandall Stewart struct sctp_nets *net) 1445f8829a4aSRandall Stewart { 1446f8829a4aSRandall Stewart struct sctp_nets *alt; 1447f8829a4aSRandall Stewart 1448f8829a4aSRandall Stewart /* first threshold managment */ 1449f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { 1450f8829a4aSRandall Stewart /* Assoc is over */ 1451f8829a4aSRandall Stewart return (1); 1452f8829a4aSRandall Stewart } 1453f8829a4aSRandall Stewart /* second select an alternative */ 1454f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 1455f8829a4aSRandall Stewart 1456f8829a4aSRandall Stewart /* third generate a shutdown into the queue for out net */ 1457f8829a4aSRandall Stewart sctp_send_shutdown_ack(stcb, alt); 1458f8829a4aSRandall Stewart 1459f8829a4aSRandall Stewart /* fourth restart timer */ 1460f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt); 1461f8829a4aSRandall Stewart return (0); 1462f8829a4aSRandall Stewart } 1463f8829a4aSRandall Stewart 1464f8829a4aSRandall Stewart static void 1465f8829a4aSRandall Stewart sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, 1466f8829a4aSRandall Stewart struct sctp_tcb *stcb) 1467f8829a4aSRandall Stewart { 1468f8829a4aSRandall Stewart struct sctp_stream_out *outs; 1469f8829a4aSRandall Stewart struct sctp_stream_queue_pending *sp; 1470f8829a4aSRandall Stewart unsigned int chks_in_queue = 0; 1471f8829a4aSRandall Stewart int being_filled = 0; 1472f8829a4aSRandall Stewart 1473f8829a4aSRandall Stewart /* 1474f8829a4aSRandall Stewart * This function is ONLY called when the send/sent queues are empty. 1475f8829a4aSRandall Stewart */ 1476f8829a4aSRandall Stewart if ((stcb == NULL) || (inp == NULL)) 1477f8829a4aSRandall Stewart return; 1478f8829a4aSRandall Stewart 1479f8829a4aSRandall Stewart if (stcb->asoc.sent_queue_retran_cnt) { 1480ad81507eSRandall Stewart SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n", 1481f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt); 1482f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = 0; 1483f8829a4aSRandall Stewart } 1484f8829a4aSRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 1485f8829a4aSRandall Stewart if (TAILQ_EMPTY(&stcb->asoc.out_wheel)) { 1486f8829a4aSRandall Stewart int i, cnt = 0; 1487f8829a4aSRandall Stewart 1488f8829a4aSRandall Stewart /* Check to see if a spoke fell off the wheel */ 1489f8829a4aSRandall Stewart for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 1490f8829a4aSRandall Stewart if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 1491f8829a4aSRandall Stewart sctp_insert_on_wheel(stcb, &stcb->asoc, &stcb->asoc.strmout[i], 1); 1492f8829a4aSRandall Stewart cnt++; 1493f8829a4aSRandall Stewart } 1494f8829a4aSRandall Stewart } 1495f8829a4aSRandall Stewart if (cnt) { 1496f8829a4aSRandall Stewart /* yep, we lost a spoke or two */ 1497ad81507eSRandall Stewart SCTP_PRINTF("Found an additional %d streams NOT on outwheel, corrected\n", cnt); 1498f8829a4aSRandall Stewart } else { 1499f8829a4aSRandall Stewart /* no spokes lost, */ 1500f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size = 0; 1501f8829a4aSRandall Stewart } 1502f8829a4aSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 1503f8829a4aSRandall Stewart return; 1504f8829a4aSRandall Stewart } 1505f8829a4aSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 1506f8829a4aSRandall Stewart /* Check to see if some data queued, if so report it */ 1507f8829a4aSRandall Stewart TAILQ_FOREACH(outs, &stcb->asoc.out_wheel, next_spoke) { 1508f8829a4aSRandall Stewart if (!TAILQ_EMPTY(&outs->outqueue)) { 1509f8829a4aSRandall Stewart TAILQ_FOREACH(sp, &outs->outqueue, next) { 1510f8829a4aSRandall Stewart if (sp->msg_is_complete) 1511f8829a4aSRandall Stewart being_filled++; 1512f8829a4aSRandall Stewart chks_in_queue++; 1513f8829a4aSRandall Stewart } 1514f8829a4aSRandall Stewart } 1515f8829a4aSRandall Stewart } 1516f8829a4aSRandall Stewart if (chks_in_queue != stcb->asoc.stream_queue_cnt) { 1517ad81507eSRandall Stewart SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n", 1518f8829a4aSRandall Stewart stcb->asoc.stream_queue_cnt, chks_in_queue); 1519f8829a4aSRandall Stewart } 1520f8829a4aSRandall Stewart if (chks_in_queue) { 1521f8829a4aSRandall Stewart /* call the output queue function */ 1522ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1523f8829a4aSRandall Stewart if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) && 1524f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { 1525f8829a4aSRandall Stewart /* 1526f8829a4aSRandall Stewart * Probably should go in and make it go back through 1527f8829a4aSRandall Stewart * and add fragments allowed 1528f8829a4aSRandall Stewart */ 1529f8829a4aSRandall Stewart if (being_filled == 0) { 1530ad81507eSRandall Stewart SCTP_PRINTF("Still nothing moved %d chunks are stuck\n", 1531f8829a4aSRandall Stewart chks_in_queue); 1532f8829a4aSRandall Stewart } 1533f8829a4aSRandall Stewart } 1534f8829a4aSRandall Stewart } else { 1535ad81507eSRandall Stewart SCTP_PRINTF("Found no chunks on any queue tot:%lu\n", 1536f8829a4aSRandall Stewart (u_long)stcb->asoc.total_output_queue_size); 1537f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size = 0; 1538f8829a4aSRandall Stewart } 1539f8829a4aSRandall Stewart } 1540f8829a4aSRandall Stewart 1541f8829a4aSRandall Stewart int 1542f8829a4aSRandall Stewart sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1543f8829a4aSRandall Stewart struct sctp_nets *net, int cnt_of_unconf) 1544f8829a4aSRandall Stewart { 1545b54d3a6cSRandall Stewart int ret; 1546b54d3a6cSRandall Stewart 1547f8829a4aSRandall Stewart if (net) { 1548f8829a4aSRandall Stewart if (net->hb_responded == 0) { 154942551e99SRandall Stewart if (net->ro._s_addr) { 155042551e99SRandall Stewart /* 155142551e99SRandall Stewart * Invalidate the src address if we did not 155242551e99SRandall Stewart * get a response last time. 155342551e99SRandall Stewart */ 155442551e99SRandall Stewart sctp_free_ifa(net->ro._s_addr); 155542551e99SRandall Stewart net->ro._s_addr = NULL; 155642551e99SRandall Stewart net->src_addr_selected = 0; 155742551e99SRandall Stewart } 1558f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, net, 1, 0); 1559f8829a4aSRandall Stewart } 1560f8829a4aSRandall Stewart /* Zero PBA, if it needs it */ 1561f8829a4aSRandall Stewart if (net->partial_bytes_acked) { 1562f8829a4aSRandall Stewart net->partial_bytes_acked = 0; 1563f8829a4aSRandall Stewart } 1564f8829a4aSRandall Stewart } 1565f8829a4aSRandall Stewart if ((stcb->asoc.total_output_queue_size > 0) && 1566f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.send_queue)) && 1567f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { 1568f8829a4aSRandall Stewart sctp_audit_stream_queues_for_size(inp, stcb); 1569f8829a4aSRandall Stewart } 1570f8829a4aSRandall Stewart /* Send a new HB, this will do threshold managment, pick a new dest */ 1571f8829a4aSRandall Stewart if (cnt_of_unconf == 0) { 1572f8829a4aSRandall Stewart if (sctp_send_hb(stcb, 0, NULL) < 0) { 1573f8829a4aSRandall Stewart return (1); 1574f8829a4aSRandall Stewart } 1575f8829a4aSRandall Stewart } else { 1576f8829a4aSRandall Stewart /* 1577f8829a4aSRandall Stewart * this will send out extra hb's up to maxburst if there are 1578f8829a4aSRandall Stewart * any unconfirmed addresses. 1579f8829a4aSRandall Stewart */ 1580d61a0ae0SRandall Stewart uint32_t cnt_sent = 0; 1581f8829a4aSRandall Stewart 1582f8829a4aSRandall Stewart TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1583f8829a4aSRandall Stewart if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) && 1584f8829a4aSRandall Stewart (net->dest_state & SCTP_ADDR_REACHABLE)) { 1585f8829a4aSRandall Stewart cnt_sent++; 158642551e99SRandall Stewart if (net->hb_responded == 0) { 158742551e99SRandall Stewart /* Did we respond last time? */ 158842551e99SRandall Stewart if (net->ro._s_addr) { 158942551e99SRandall Stewart sctp_free_ifa(net->ro._s_addr); 159042551e99SRandall Stewart net->ro._s_addr = NULL; 159142551e99SRandall Stewart net->src_addr_selected = 0; 159242551e99SRandall Stewart } 159342551e99SRandall Stewart } 1594b54d3a6cSRandall Stewart ret = sctp_send_hb(stcb, 1, net); 1595b54d3a6cSRandall Stewart if (ret < 0) 1596b54d3a6cSRandall Stewart return 1; 1597b54d3a6cSRandall Stewart else if (ret == 0) { 1598f8829a4aSRandall Stewart break; 1599f8829a4aSRandall Stewart } 160042551e99SRandall Stewart if (cnt_sent >= sctp_hb_maxburst) 1601f8829a4aSRandall Stewart break; 1602f8829a4aSRandall Stewart } 1603f8829a4aSRandall Stewart } 1604f8829a4aSRandall Stewart } 1605f8829a4aSRandall Stewart return (0); 1606f8829a4aSRandall Stewart } 1607f8829a4aSRandall Stewart 1608f8829a4aSRandall Stewart int 1609f8829a4aSRandall Stewart sctp_is_hb_timer_running(struct sctp_tcb *stcb) 1610f8829a4aSRandall Stewart { 1611139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&stcb->asoc.hb_timer.timer)) { 1612f8829a4aSRandall Stewart /* its running */ 1613f8829a4aSRandall Stewart return (1); 1614f8829a4aSRandall Stewart } else { 1615f8829a4aSRandall Stewart /* nope */ 1616f8829a4aSRandall Stewart return (0); 1617f8829a4aSRandall Stewart } 1618f8829a4aSRandall Stewart } 1619f8829a4aSRandall Stewart 1620f8829a4aSRandall Stewart int 1621f8829a4aSRandall Stewart sctp_is_sack_timer_running(struct sctp_tcb *stcb) 1622f8829a4aSRandall Stewart { 1623139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { 1624f8829a4aSRandall Stewart /* its running */ 1625f8829a4aSRandall Stewart return (1); 1626f8829a4aSRandall Stewart } else { 1627f8829a4aSRandall Stewart /* nope */ 1628f8829a4aSRandall Stewart return (0); 1629f8829a4aSRandall Stewart } 1630f8829a4aSRandall Stewart } 1631f8829a4aSRandall Stewart 1632f8829a4aSRandall Stewart #define SCTP_NUMBER_OF_MTU_SIZES 18 1633f8829a4aSRandall Stewart static uint32_t mtu_sizes[] = { 1634f8829a4aSRandall Stewart 68, 1635f8829a4aSRandall Stewart 296, 1636f8829a4aSRandall Stewart 508, 1637f8829a4aSRandall Stewart 512, 1638f8829a4aSRandall Stewart 544, 1639f8829a4aSRandall Stewart 576, 1640f8829a4aSRandall Stewart 1006, 1641f8829a4aSRandall Stewart 1492, 1642f8829a4aSRandall Stewart 1500, 1643f8829a4aSRandall Stewart 1536, 1644f8829a4aSRandall Stewart 2002, 1645f8829a4aSRandall Stewart 2048, 1646f8829a4aSRandall Stewart 4352, 1647f8829a4aSRandall Stewart 4464, 1648f8829a4aSRandall Stewart 8166, 1649f8829a4aSRandall Stewart 17914, 1650f8829a4aSRandall Stewart 32000, 1651f8829a4aSRandall Stewart 65535 1652f8829a4aSRandall Stewart }; 1653f8829a4aSRandall Stewart 1654f8829a4aSRandall Stewart 1655f8829a4aSRandall Stewart static uint32_t 1656f8829a4aSRandall Stewart sctp_getnext_mtu(struct sctp_inpcb *inp, uint32_t cur_mtu) 1657f8829a4aSRandall Stewart { 1658f8829a4aSRandall Stewart /* select another MTU that is just bigger than this one */ 1659f8829a4aSRandall Stewart int i; 1660f8829a4aSRandall Stewart 1661f8829a4aSRandall Stewart for (i = 0; i < SCTP_NUMBER_OF_MTU_SIZES; i++) { 1662f8829a4aSRandall Stewart if (cur_mtu < mtu_sizes[i]) { 1663f8829a4aSRandall Stewart /* no max_mtu is bigger than this one */ 1664f8829a4aSRandall Stewart return (mtu_sizes[i]); 1665f8829a4aSRandall Stewart } 1666f8829a4aSRandall Stewart } 1667f8829a4aSRandall Stewart /* here return the highest allowable */ 1668f8829a4aSRandall Stewart return (cur_mtu); 1669f8829a4aSRandall Stewart } 1670f8829a4aSRandall Stewart 1671f8829a4aSRandall Stewart 1672f8829a4aSRandall Stewart void 1673f8829a4aSRandall Stewart sctp_pathmtu_timer(struct sctp_inpcb *inp, 1674f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1675f8829a4aSRandall Stewart struct sctp_nets *net) 1676f8829a4aSRandall Stewart { 1677f8829a4aSRandall Stewart uint32_t next_mtu; 1678f8829a4aSRandall Stewart 1679f8829a4aSRandall Stewart /* restart the timer in any case */ 1680f8829a4aSRandall Stewart next_mtu = sctp_getnext_mtu(inp, net->mtu); 1681f8829a4aSRandall Stewart if (next_mtu <= net->mtu) { 1682f8829a4aSRandall Stewart /* nothing to do */ 1683f8829a4aSRandall Stewart return; 168417205eccSRandall Stewart } { 168517205eccSRandall Stewart uint32_t mtu; 168617205eccSRandall Stewart 168717205eccSRandall Stewart if ((net->src_addr_selected == 0) || 168817205eccSRandall Stewart (net->ro._s_addr == NULL) || 168917205eccSRandall Stewart (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { 1690ad81507eSRandall Stewart if ((net->ro._s_addr != NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { 169117205eccSRandall Stewart sctp_free_ifa(net->ro._s_addr); 169217205eccSRandall Stewart net->ro._s_addr = NULL; 169317205eccSRandall Stewart net->src_addr_selected = 0; 1694ad81507eSRandall Stewart } else if (net->ro._s_addr == NULL) { 169517205eccSRandall Stewart net->ro._s_addr = sctp_source_address_selection(inp, 169617205eccSRandall Stewart stcb, 169717205eccSRandall Stewart (sctp_route_t *) & net->ro, 169817205eccSRandall Stewart net, 0, stcb->asoc.vrf_id); 1699ad81507eSRandall Stewart } 170017205eccSRandall Stewart if (net->ro._s_addr) 170117205eccSRandall Stewart net->src_addr_selected = 1; 170217205eccSRandall Stewart } 170317205eccSRandall Stewart if (net->ro._s_addr) { 170417205eccSRandall Stewart mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt); 170517205eccSRandall Stewart if (mtu > next_mtu) { 1706f8829a4aSRandall Stewart net->mtu = next_mtu; 1707f8829a4aSRandall Stewart } 1708f8829a4aSRandall Stewart } 1709f8829a4aSRandall Stewart } 1710f8829a4aSRandall Stewart /* restart the timer */ 1711f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 1712f8829a4aSRandall Stewart } 1713f8829a4aSRandall Stewart 1714f8829a4aSRandall Stewart void 1715f8829a4aSRandall Stewart sctp_autoclose_timer(struct sctp_inpcb *inp, 1716f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1717f8829a4aSRandall Stewart struct sctp_nets *net) 1718f8829a4aSRandall Stewart { 1719f8829a4aSRandall Stewart struct timeval tn, *tim_touse; 1720f8829a4aSRandall Stewart struct sctp_association *asoc; 1721f8829a4aSRandall Stewart int ticks_gone_by; 1722f8829a4aSRandall Stewart 17236e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&tn); 1724f8829a4aSRandall Stewart if (stcb->asoc.sctp_autoclose_ticks && 1725f8829a4aSRandall Stewart sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { 1726f8829a4aSRandall Stewart /* Auto close is on */ 1727f8829a4aSRandall Stewart asoc = &stcb->asoc; 1728f8829a4aSRandall Stewart /* pick the time to use */ 1729f8829a4aSRandall Stewart if (asoc->time_last_rcvd.tv_sec > 1730f8829a4aSRandall Stewart asoc->time_last_sent.tv_sec) { 1731f8829a4aSRandall Stewart tim_touse = &asoc->time_last_rcvd; 1732f8829a4aSRandall Stewart } else { 1733f8829a4aSRandall Stewart tim_touse = &asoc->time_last_sent; 1734f8829a4aSRandall Stewart } 1735f8829a4aSRandall Stewart /* Now has long enough transpired to autoclose? */ 1736f8829a4aSRandall Stewart ticks_gone_by = SEC_TO_TICKS(tn.tv_sec - tim_touse->tv_sec); 1737f8829a4aSRandall Stewart if ((ticks_gone_by > 0) && 1738f8829a4aSRandall Stewart (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) { 1739f8829a4aSRandall Stewart /* 1740f8829a4aSRandall Stewart * autoclose time has hit, call the output routine, 1741f8829a4aSRandall Stewart * which should do nothing just to be SURE we don't 1742f8829a4aSRandall Stewart * have hanging data. We can then safely check the 1743f8829a4aSRandall Stewart * queues and know that we are clear to send 1744f8829a4aSRandall Stewart * shutdown 1745f8829a4aSRandall Stewart */ 1746ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); 1747f8829a4aSRandall Stewart /* Are we clean? */ 1748f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue) && 1749f8829a4aSRandall Stewart TAILQ_EMPTY(&asoc->sent_queue)) { 1750f8829a4aSRandall Stewart /* 1751f8829a4aSRandall Stewart * there is nothing queued to send, so I'm 1752f8829a4aSRandall Stewart * done... 1753f8829a4aSRandall Stewart */ 1754f42a358aSRandall Stewart if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 1755f8829a4aSRandall Stewart /* only send SHUTDOWN 1st time thru */ 1756f8829a4aSRandall Stewart sctp_send_shutdown(stcb, stcb->asoc.primary_destination); 1757f42a358aSRandall Stewart if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 1758f42a358aSRandall Stewart (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 1759f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 1760f42a358aSRandall Stewart } 1761c4739e2fSRandall Stewart SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 1762f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 1763f8829a4aSRandall Stewart stcb->sctp_ep, stcb, 1764f8829a4aSRandall Stewart asoc->primary_destination); 1765f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 1766f8829a4aSRandall Stewart stcb->sctp_ep, stcb, 1767f8829a4aSRandall Stewart asoc->primary_destination); 1768f8829a4aSRandall Stewart } 1769f8829a4aSRandall Stewart } 1770f8829a4aSRandall Stewart } else { 1771f8829a4aSRandall Stewart /* 1772f8829a4aSRandall Stewart * No auto close at this time, reset t-o to check 1773f8829a4aSRandall Stewart * later 1774f8829a4aSRandall Stewart */ 1775f8829a4aSRandall Stewart int tmp; 1776f8829a4aSRandall Stewart 1777f8829a4aSRandall Stewart /* fool the timer startup to use the time left */ 1778f8829a4aSRandall Stewart tmp = asoc->sctp_autoclose_ticks; 1779f8829a4aSRandall Stewart asoc->sctp_autoclose_ticks -= ticks_gone_by; 1780f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, 1781f8829a4aSRandall Stewart net); 1782f8829a4aSRandall Stewart /* restore the real tick value */ 1783f8829a4aSRandall Stewart asoc->sctp_autoclose_ticks = tmp; 1784f8829a4aSRandall Stewart } 1785f8829a4aSRandall Stewart } 1786f8829a4aSRandall Stewart } 1787f8829a4aSRandall Stewart 1788f8829a4aSRandall Stewart void 1789f8829a4aSRandall Stewart sctp_iterator_timer(struct sctp_iterator *it) 1790f8829a4aSRandall Stewart { 1791f8829a4aSRandall Stewart int iteration_count = 0; 179242551e99SRandall Stewart int inp_skip = 0; 1793f8829a4aSRandall Stewart 1794f8829a4aSRandall Stewart /* 1795f8829a4aSRandall Stewart * only one iterator can run at a time. This is the only way we can 1796f8829a4aSRandall Stewart * cleanly pull ep's from underneath all the running interators when 1797f8829a4aSRandall Stewart * a ep is freed. 1798f8829a4aSRandall Stewart */ 1799f8829a4aSRandall Stewart SCTP_ITERATOR_LOCK(); 1800f8829a4aSRandall Stewart if (it->inp == NULL) { 1801f8829a4aSRandall Stewart /* iterator is complete */ 1802f8829a4aSRandall Stewart done_with_iterator: 1803f8829a4aSRandall Stewart SCTP_ITERATOR_UNLOCK(); 1804f8829a4aSRandall Stewart SCTP_INP_INFO_WLOCK(); 180542551e99SRandall Stewart TAILQ_REMOVE(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr); 1806f8829a4aSRandall Stewart /* stopping the callout is not needed, in theory */ 1807f8829a4aSRandall Stewart SCTP_INP_INFO_WUNLOCK(); 18086e55db54SRandall Stewart (void)SCTP_OS_TIMER_STOP(&it->tmr.timer); 1809f8829a4aSRandall Stewart if (it->function_atend != NULL) { 1810f8829a4aSRandall Stewart (*it->function_atend) (it->pointer, it->val); 1811f8829a4aSRandall Stewart } 1812207304d4SRandall Stewart SCTP_FREE(it, SCTP_M_ITER); 1813f8829a4aSRandall Stewart return; 1814f8829a4aSRandall Stewart } 1815f8829a4aSRandall Stewart select_a_new_ep: 1816f8829a4aSRandall Stewart SCTP_INP_WLOCK(it->inp); 1817f8829a4aSRandall Stewart while (((it->pcb_flags) && 1818f8829a4aSRandall Stewart ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || 1819f8829a4aSRandall Stewart ((it->pcb_features) && 1820f8829a4aSRandall Stewart ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) { 1821f8829a4aSRandall Stewart /* endpoint flags or features don't match, so keep looking */ 1822f8829a4aSRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 1823f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1824f8829a4aSRandall Stewart goto done_with_iterator; 1825f8829a4aSRandall Stewart } 1826f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1827f8829a4aSRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 1828f8829a4aSRandall Stewart if (it->inp == NULL) { 1829f8829a4aSRandall Stewart goto done_with_iterator; 1830f8829a4aSRandall Stewart } 1831f8829a4aSRandall Stewart SCTP_INP_WLOCK(it->inp); 1832f8829a4aSRandall Stewart } 1833f8829a4aSRandall Stewart if ((it->inp->inp_starting_point_for_iterator != NULL) && 1834f8829a4aSRandall Stewart (it->inp->inp_starting_point_for_iterator != it)) { 1835ad81507eSRandall Stewart SCTP_PRINTF("Iterator collision, waiting for one at %p\n", 1836e349e6b8SRuslan Ermilov it->inp); 1837f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1838f8829a4aSRandall Stewart goto start_timer_return; 1839f8829a4aSRandall Stewart } 1840f8829a4aSRandall Stewart /* mark the current iterator on the endpoint */ 1841f8829a4aSRandall Stewart it->inp->inp_starting_point_for_iterator = it; 1842f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1843f8829a4aSRandall Stewart SCTP_INP_RLOCK(it->inp); 1844f8829a4aSRandall Stewart /* now go through each assoc which is in the desired state */ 184542551e99SRandall Stewart if (it->done_current_ep == 0) { 184642551e99SRandall Stewart if (it->function_inp != NULL) 184742551e99SRandall Stewart inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val); 184842551e99SRandall Stewart it->done_current_ep = 1; 184942551e99SRandall Stewart } 1850f8829a4aSRandall Stewart if (it->stcb == NULL) { 1851f8829a4aSRandall Stewart /* run the per instance function */ 1852f8829a4aSRandall Stewart it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list); 1853f8829a4aSRandall Stewart } 1854f8829a4aSRandall Stewart SCTP_INP_RUNLOCK(it->inp); 185542551e99SRandall Stewart if ((inp_skip) || it->stcb == NULL) { 185642551e99SRandall Stewart if (it->function_inp_end != NULL) { 185742551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 185842551e99SRandall Stewart it->pointer, 185942551e99SRandall Stewart it->val); 186042551e99SRandall Stewart } 186142551e99SRandall Stewart goto no_stcb; 186242551e99SRandall Stewart } 1863f8829a4aSRandall Stewart if ((it->stcb) && 1864f8829a4aSRandall Stewart (it->stcb->asoc.stcb_starting_point_for_iterator == it)) { 1865f8829a4aSRandall Stewart it->stcb->asoc.stcb_starting_point_for_iterator = NULL; 1866f8829a4aSRandall Stewart } 1867f8829a4aSRandall Stewart while (it->stcb) { 1868f8829a4aSRandall Stewart SCTP_TCB_LOCK(it->stcb); 1869f8829a4aSRandall Stewart if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { 1870f8829a4aSRandall Stewart /* not in the right state... keep looking */ 1871f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1872f8829a4aSRandall Stewart goto next_assoc; 1873f8829a4aSRandall Stewart } 1874f8829a4aSRandall Stewart /* mark the current iterator on the assoc */ 1875f8829a4aSRandall Stewart it->stcb->asoc.stcb_starting_point_for_iterator = it; 1876f8829a4aSRandall Stewart /* see if we have limited out the iterator loop */ 1877f8829a4aSRandall Stewart iteration_count++; 1878f8829a4aSRandall Stewart if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) { 1879f8829a4aSRandall Stewart start_timer_return: 1880f8829a4aSRandall Stewart /* set a timer to continue this later */ 1881ea1fbec5SRandall Stewart if (it->stcb) 1882f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1883f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ITERATOR, 1884f8829a4aSRandall Stewart (struct sctp_inpcb *)it, NULL, NULL); 1885f8829a4aSRandall Stewart SCTP_ITERATOR_UNLOCK(); 1886f8829a4aSRandall Stewart return; 1887f8829a4aSRandall Stewart } 1888f8829a4aSRandall Stewart /* run function on this one */ 1889f8829a4aSRandall Stewart (*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val); 1890f8829a4aSRandall Stewart 1891f8829a4aSRandall Stewart /* 1892f8829a4aSRandall Stewart * we lie here, it really needs to have its own type but 1893f8829a4aSRandall Stewart * first I must verify that this won't effect things :-0 1894f8829a4aSRandall Stewart */ 1895f8829a4aSRandall Stewart if (it->no_chunk_output == 0) 1896ceaad40aSRandall Stewart sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1897f8829a4aSRandall Stewart 1898f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1899f8829a4aSRandall Stewart next_assoc: 1900f8829a4aSRandall Stewart it->stcb = LIST_NEXT(it->stcb, sctp_tcblist); 190142551e99SRandall Stewart if (it->stcb == NULL) { 190242551e99SRandall Stewart if (it->function_inp_end != NULL) { 190342551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 190442551e99SRandall Stewart it->pointer, 190542551e99SRandall Stewart it->val); 1906f8829a4aSRandall Stewart } 190742551e99SRandall Stewart } 190842551e99SRandall Stewart } 190942551e99SRandall Stewart no_stcb: 1910f8829a4aSRandall Stewart /* done with all assocs on this endpoint, move on to next endpoint */ 191142551e99SRandall Stewart it->done_current_ep = 0; 1912f8829a4aSRandall Stewart SCTP_INP_WLOCK(it->inp); 1913f8829a4aSRandall Stewart it->inp->inp_starting_point_for_iterator = NULL; 1914f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1915f8829a4aSRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 1916f8829a4aSRandall Stewart it->inp = NULL; 1917f8829a4aSRandall Stewart } else { 1918f8829a4aSRandall Stewart SCTP_INP_INFO_RLOCK(); 1919f8829a4aSRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 1920f8829a4aSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 1921f8829a4aSRandall Stewart } 1922f8829a4aSRandall Stewart if (it->inp == NULL) { 1923f8829a4aSRandall Stewart goto done_with_iterator; 1924f8829a4aSRandall Stewart } 1925f8829a4aSRandall Stewart goto select_a_new_ep; 1926f8829a4aSRandall Stewart } 1927