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 } 123f8829a4aSRandall Stewart #ifdef SCTP_EARLYFR_LOGGING 124f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, 125f8829a4aSRandall Stewart 4, SCTP_FR_MARKED_EARLY); 126f8829a4aSRandall Stewart #endif 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 #ifdef SCTP_CWND_MONITOR 141f8829a4aSRandall Stewart int old_cwnd; 142f8829a4aSRandall Stewart 143f8829a4aSRandall Stewart old_cwnd = net->cwnd; 144f8829a4aSRandall Stewart #endif 145f8829a4aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR); 146f8829a4aSRandall Stewart /* 147f8829a4aSRandall Stewart * make a small adjustment to cwnd and force to CA. 148f8829a4aSRandall Stewart */ 149f8829a4aSRandall Stewart 150f8829a4aSRandall Stewart if (net->cwnd > net->mtu) 151f8829a4aSRandall Stewart /* drop down one MTU after sending */ 152f8829a4aSRandall Stewart net->cwnd -= net->mtu; 153f8829a4aSRandall Stewart if (net->cwnd < net->ssthresh) 154f8829a4aSRandall Stewart /* still in SS move to CA */ 155f8829a4aSRandall Stewart net->ssthresh = net->cwnd - 1; 156f8829a4aSRandall Stewart #ifdef SCTP_CWND_MONITOR 157f8829a4aSRandall Stewart sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR); 158f8829a4aSRandall Stewart #endif 159f8829a4aSRandall Stewart } else if (cnt_resend) { 160f8829a4aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR); 161f8829a4aSRandall Stewart } 162f8829a4aSRandall Stewart /* Restart it? */ 163f8829a4aSRandall Stewart if (net->flight_size < net->cwnd) { 164f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_earlyfrstrtmr); 165f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net); 166f8829a4aSRandall Stewart } 167f8829a4aSRandall Stewart } 168f8829a4aSRandall Stewart 169f8829a4aSRandall Stewart void 170f8829a4aSRandall Stewart sctp_audit_retranmission_queue(struct sctp_association *asoc) 171f8829a4aSRandall Stewart { 172f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 173f8829a4aSRandall Stewart 174ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Audit invoked on send queue cnt:%d onqueue:%d\n", 175f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt, 176f8829a4aSRandall Stewart asoc->sent_queue_cnt); 177f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0; 178f8829a4aSRandall Stewart asoc->sent_queue_cnt = 0; 179f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 180f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 181f8829a4aSRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 182f8829a4aSRandall Stewart } 183f8829a4aSRandall Stewart asoc->sent_queue_cnt++; 184f8829a4aSRandall Stewart } 185f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { 186f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 187f8829a4aSRandall Stewart sctp_ucount_incr(asoc->sent_queue_retran_cnt); 188f8829a4aSRandall Stewart } 189f8829a4aSRandall Stewart } 190ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n", 191f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt, 192f8829a4aSRandall Stewart asoc->sent_queue_cnt); 193f8829a4aSRandall Stewart } 194f8829a4aSRandall Stewart 195f8829a4aSRandall Stewart int 196f8829a4aSRandall Stewart sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 197f8829a4aSRandall Stewart struct sctp_nets *net, uint16_t threshold) 198f8829a4aSRandall Stewart { 199f8829a4aSRandall Stewart if (net) { 200f8829a4aSRandall Stewart net->error_count++; 201ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n", 202f8829a4aSRandall Stewart net, net->error_count, 203f8829a4aSRandall Stewart net->failure_threshold); 204f8829a4aSRandall Stewart if (net->error_count > net->failure_threshold) { 205f8829a4aSRandall Stewart /* We had a threshold failure */ 206f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_REACHABLE) { 207f8829a4aSRandall Stewart net->dest_state &= ~SCTP_ADDR_REACHABLE; 208f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 20942551e99SRandall Stewart net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; 210f8829a4aSRandall Stewart if (net == stcb->asoc.primary_destination) { 211f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_WAS_PRIMARY; 212f8829a4aSRandall Stewart } 213f8829a4aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 214f8829a4aSRandall Stewart stcb, 215f8829a4aSRandall Stewart SCTP_FAILED_THRESHOLD, 216f8829a4aSRandall Stewart (void *)net); 217f8829a4aSRandall Stewart } 218f8829a4aSRandall Stewart } 219f8829a4aSRandall Stewart /*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE 220f8829a4aSRandall Stewart *********ROUTING CODE 221f8829a4aSRandall Stewart */ 222f8829a4aSRandall Stewart /*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE 223f8829a4aSRandall Stewart *********ROUTING CODE 224f8829a4aSRandall Stewart */ 225f8829a4aSRandall Stewart } 226f8829a4aSRandall Stewart if (stcb == NULL) 227f8829a4aSRandall Stewart return (0); 228f8829a4aSRandall Stewart 229f8829a4aSRandall Stewart if (net) { 230f8829a4aSRandall Stewart if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { 231f8829a4aSRandall Stewart stcb->asoc.overall_error_count++; 232f8829a4aSRandall Stewart } 233f8829a4aSRandall Stewart } else { 234f8829a4aSRandall Stewart stcb->asoc.overall_error_count++; 235f8829a4aSRandall Stewart } 236ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n", 237ad81507eSRandall Stewart &stcb->asoc, stcb->asoc.overall_error_count, 238f8829a4aSRandall Stewart (uint32_t) threshold, 239f8829a4aSRandall Stewart ((net == NULL) ? (uint32_t) 0 : (uint32_t) net->dest_state)); 240f8829a4aSRandall Stewart /* 241f8829a4aSRandall Stewart * We specifically do not do >= to give the assoc one more change 242f8829a4aSRandall Stewart * before we fail it. 243f8829a4aSRandall Stewart */ 244f8829a4aSRandall Stewart if (stcb->asoc.overall_error_count > threshold) { 245f8829a4aSRandall Stewart /* Abort notification sends a ULP notify */ 246f8829a4aSRandall Stewart struct mbuf *oper; 247f8829a4aSRandall Stewart 248f8829a4aSRandall Stewart oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 249f8829a4aSRandall Stewart 0, M_DONTWAIT, 1, MT_DATA); 250f8829a4aSRandall Stewart if (oper) { 251f8829a4aSRandall Stewart struct sctp_paramhdr *ph; 252f8829a4aSRandall Stewart uint32_t *ippp; 253f8829a4aSRandall Stewart 254139bc87fSRandall Stewart SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) + 255f8829a4aSRandall Stewart sizeof(uint32_t); 256f8829a4aSRandall Stewart ph = mtod(oper, struct sctp_paramhdr *); 257f8829a4aSRandall Stewart ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 258139bc87fSRandall Stewart ph->param_length = htons(SCTP_BUF_LEN(oper)); 259f8829a4aSRandall Stewart ippp = (uint32_t *) (ph + 1); 260a5d547adSRandall Stewart *ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); 261f8829a4aSRandall Stewart } 262a5d547adSRandall Stewart inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1; 263f8829a4aSRandall Stewart sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper); 264f8829a4aSRandall Stewart return (1); 265f8829a4aSRandall Stewart } 266f8829a4aSRandall Stewart return (0); 267f8829a4aSRandall Stewart } 268f8829a4aSRandall Stewart 269f8829a4aSRandall Stewart struct sctp_nets * 270f8829a4aSRandall Stewart sctp_find_alternate_net(struct sctp_tcb *stcb, 271f8829a4aSRandall Stewart struct sctp_nets *net, 272f8829a4aSRandall Stewart int highest_ssthresh) 273f8829a4aSRandall Stewart { 274f8829a4aSRandall Stewart /* Find and return an alternate network if possible */ 275f8829a4aSRandall Stewart struct sctp_nets *alt, *mnet, *hthresh = NULL; 276f8829a4aSRandall Stewart int once; 277f8829a4aSRandall Stewart uint32_t val = 0; 278f8829a4aSRandall Stewart 279f8829a4aSRandall Stewart if (stcb->asoc.numnets == 1) { 280f8829a4aSRandall Stewart /* No others but net */ 281f8829a4aSRandall Stewart return (TAILQ_FIRST(&stcb->asoc.nets)); 282f8829a4aSRandall Stewart } 283f8829a4aSRandall Stewart if (highest_ssthresh) { 284f8829a4aSRandall Stewart TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { 285f8829a4aSRandall Stewart if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || 286f8829a4aSRandall Stewart (mnet->dest_state & SCTP_ADDR_UNCONFIRMED) 287f8829a4aSRandall Stewart ) { 288f8829a4aSRandall Stewart /* 289f8829a4aSRandall Stewart * will skip ones that are not-reachable or 290f8829a4aSRandall Stewart * unconfirmed 291f8829a4aSRandall Stewart */ 292f8829a4aSRandall Stewart continue; 293f8829a4aSRandall Stewart } 294f8829a4aSRandall Stewart if (val > mnet->ssthresh) { 295f8829a4aSRandall Stewart hthresh = mnet; 296f8829a4aSRandall Stewart val = mnet->ssthresh; 297f8829a4aSRandall Stewart } else if (val == mnet->ssthresh) { 298f8829a4aSRandall Stewart uint32_t rndval; 299f8829a4aSRandall Stewart uint8_t this_random; 300f8829a4aSRandall Stewart 301f8829a4aSRandall Stewart if (stcb->asoc.hb_random_idx > 3) { 302f8829a4aSRandall Stewart rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); 303f8829a4aSRandall Stewart memcpy(stcb->asoc.hb_random_values, &rndval, 304f8829a4aSRandall Stewart sizeof(stcb->asoc.hb_random_values)); 305f8829a4aSRandall Stewart this_random = stcb->asoc.hb_random_values[0]; 306f8829a4aSRandall Stewart stcb->asoc.hb_random_idx = 0; 307f8829a4aSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 308f8829a4aSRandall Stewart } else { 309f8829a4aSRandall Stewart this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; 310f8829a4aSRandall Stewart stcb->asoc.hb_random_idx++; 311f8829a4aSRandall Stewart stcb->asoc.hb_ect_randombit = 0; 312f8829a4aSRandall Stewart } 313f8829a4aSRandall Stewart if (this_random % 2) { 314f8829a4aSRandall Stewart hthresh = mnet; 315f8829a4aSRandall Stewart val = mnet->ssthresh; 316f8829a4aSRandall Stewart } 317f8829a4aSRandall Stewart } 318f8829a4aSRandall Stewart } 319f8829a4aSRandall Stewart if (hthresh) { 320f8829a4aSRandall Stewart return (hthresh); 321f8829a4aSRandall Stewart } 322f8829a4aSRandall Stewart } 323f8829a4aSRandall Stewart mnet = net; 324f8829a4aSRandall Stewart once = 0; 325f8829a4aSRandall Stewart 326f8829a4aSRandall Stewart if (mnet == NULL) { 327f8829a4aSRandall Stewart mnet = TAILQ_FIRST(&stcb->asoc.nets); 328f8829a4aSRandall Stewart } 329f8829a4aSRandall Stewart do { 330f8829a4aSRandall Stewart alt = TAILQ_NEXT(mnet, sctp_next); 331f8829a4aSRandall Stewart if (alt == NULL) { 332f8829a4aSRandall Stewart once++; 333f8829a4aSRandall Stewart if (once > 1) { 334f8829a4aSRandall Stewart break; 335f8829a4aSRandall Stewart } 336f8829a4aSRandall Stewart alt = TAILQ_FIRST(&stcb->asoc.nets); 337f8829a4aSRandall Stewart } 338f8829a4aSRandall Stewart if (alt->ro.ro_rt == NULL) { 33942551e99SRandall Stewart if (alt->ro._s_addr) { 34042551e99SRandall Stewart sctp_free_ifa(alt->ro._s_addr); 34142551e99SRandall Stewart alt->ro._s_addr = NULL; 34217205eccSRandall Stewart 34342551e99SRandall Stewart } 344f8829a4aSRandall Stewart alt->src_addr_selected = 0; 345f8829a4aSRandall Stewart } 346f8829a4aSRandall Stewart if ( 347f8829a4aSRandall Stewart ((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) && 348f8829a4aSRandall Stewart (alt->ro.ro_rt != NULL) && 349f8829a4aSRandall Stewart (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) 350f8829a4aSRandall Stewart ) { 351f8829a4aSRandall Stewart /* Found a reachable address */ 352f8829a4aSRandall Stewart break; 353f8829a4aSRandall Stewart } 354f8829a4aSRandall Stewart mnet = alt; 355f8829a4aSRandall Stewart } while (alt != NULL); 356f8829a4aSRandall Stewart 357f8829a4aSRandall Stewart if (alt == NULL) { 358f8829a4aSRandall Stewart /* Case where NO insv network exists (dormant state) */ 359f8829a4aSRandall Stewart /* we rotate destinations */ 360f8829a4aSRandall Stewart once = 0; 361f8829a4aSRandall Stewart mnet = net; 362f8829a4aSRandall Stewart do { 363f8829a4aSRandall Stewart alt = TAILQ_NEXT(mnet, sctp_next); 364f8829a4aSRandall Stewart if (alt == NULL) { 365f8829a4aSRandall Stewart once++; 366f8829a4aSRandall Stewart if (once > 1) { 367f8829a4aSRandall Stewart break; 368f8829a4aSRandall Stewart } 369f8829a4aSRandall Stewart alt = TAILQ_FIRST(&stcb->asoc.nets); 370f8829a4aSRandall Stewart } 371f8829a4aSRandall Stewart if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) && 372f8829a4aSRandall Stewart (alt != net)) { 373f8829a4aSRandall Stewart /* Found an alternate address */ 374f8829a4aSRandall Stewart break; 375f8829a4aSRandall Stewart } 376f8829a4aSRandall Stewart mnet = alt; 377f8829a4aSRandall Stewart } while (alt != NULL); 378f8829a4aSRandall Stewart } 379f8829a4aSRandall Stewart if (alt == NULL) { 380f8829a4aSRandall Stewart return (net); 381f8829a4aSRandall Stewart } 382f8829a4aSRandall Stewart return (alt); 383f8829a4aSRandall Stewart } 384f8829a4aSRandall Stewart 385f8829a4aSRandall Stewart static void 386f8829a4aSRandall Stewart sctp_backoff_on_timeout(struct sctp_tcb *stcb, 387f8829a4aSRandall Stewart struct sctp_nets *net, 388f8829a4aSRandall Stewart int win_probe, 389f8829a4aSRandall Stewart int num_marked) 390f8829a4aSRandall Stewart { 391f8829a4aSRandall Stewart net->RTO <<= 1; 392f8829a4aSRandall Stewart if (net->RTO > stcb->asoc.maxrto) { 393f8829a4aSRandall Stewart net->RTO = stcb->asoc.maxrto; 394f8829a4aSRandall Stewart } 395f8829a4aSRandall Stewart if ((win_probe == 0) && num_marked) { 396f8829a4aSRandall Stewart /* We don't apply penalty to window probe scenarios */ 397f8829a4aSRandall Stewart #ifdef SCTP_CWND_MONITOR 398f8829a4aSRandall Stewart int old_cwnd = net->cwnd; 399f8829a4aSRandall Stewart 400f8829a4aSRandall Stewart #endif 401f8829a4aSRandall Stewart net->ssthresh = net->cwnd >> 1; 402f8829a4aSRandall Stewart if (net->ssthresh < (net->mtu << 1)) { 403f8829a4aSRandall Stewart net->ssthresh = (net->mtu << 1); 404f8829a4aSRandall Stewart } 405f8829a4aSRandall Stewart net->cwnd = net->mtu; 406f8829a4aSRandall Stewart /* floor of 1 mtu */ 407f8829a4aSRandall Stewart if (net->cwnd < net->mtu) 408f8829a4aSRandall Stewart net->cwnd = net->mtu; 409f8829a4aSRandall Stewart #ifdef SCTP_CWND_MONITOR 410f8829a4aSRandall Stewart sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX); 411f8829a4aSRandall Stewart #endif 412f8829a4aSRandall Stewart 413f8829a4aSRandall Stewart net->partial_bytes_acked = 0; 414f8829a4aSRandall Stewart } 415f8829a4aSRandall Stewart } 416f8829a4aSRandall Stewart 417f8829a4aSRandall Stewart static int 418f8829a4aSRandall Stewart sctp_mark_all_for_resend(struct sctp_tcb *stcb, 419f8829a4aSRandall Stewart struct sctp_nets *net, 420f8829a4aSRandall Stewart struct sctp_nets *alt, 421f8829a4aSRandall Stewart int window_probe, 422f8829a4aSRandall Stewart int *num_marked) 423f8829a4aSRandall Stewart { 424f8829a4aSRandall Stewart 425f8829a4aSRandall Stewart /* 426f8829a4aSRandall Stewart * Mark all chunks (well not all) that were sent to *net for 427f8829a4aSRandall Stewart * retransmission. Move them to alt for there destination as well... 428f8829a4aSRandall Stewart * We only mark chunks that have been outstanding long enough to 429f8829a4aSRandall Stewart * have received feed-back. 430f8829a4aSRandall Stewart */ 431f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk, *tp2, *could_be_sent = NULL; 432f8829a4aSRandall Stewart struct sctp_nets *lnets; 433f8829a4aSRandall Stewart struct timeval now, min_wait, tv; 434f8829a4aSRandall Stewart int cur_rtt; 435c105859eSRandall Stewart int audit_tf, num_mk, fir; 436f8829a4aSRandall Stewart unsigned int cnt_mk; 437c105859eSRandall Stewart uint32_t orig_flight, orig_tf; 438f8829a4aSRandall Stewart uint32_t tsnlast, tsnfirst; 439f8829a4aSRandall Stewart 440f8829a4aSRandall Stewart /* 441f8829a4aSRandall Stewart * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being used, 442f8829a4aSRandall Stewart * then pick dest with largest ssthresh for any retransmission. 443f8829a4aSRandall Stewart * (iyengar@cis.udel.edu, 2005/08/12) 444f8829a4aSRandall Stewart */ 445f8829a4aSRandall Stewart if (sctp_cmt_on_off) { 446f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 1); 447f8829a4aSRandall Stewart /* 448f8829a4aSRandall Stewart * CUCv2: If a different dest is picked for the 449f8829a4aSRandall Stewart * retransmission, then new (rtx-)pseudo_cumack needs to be 450f8829a4aSRandall Stewart * tracked for orig dest. Let CUCv2 track new (rtx-) 451f8829a4aSRandall Stewart * pseudo-cumack always. 452f8829a4aSRandall Stewart */ 453f8829a4aSRandall Stewart net->find_pseudo_cumack = 1; 454f8829a4aSRandall Stewart net->find_rtx_pseudo_cumack = 1; 455f8829a4aSRandall Stewart } 456f8829a4aSRandall Stewart /* none in flight now */ 457f8829a4aSRandall Stewart audit_tf = 0; 458f8829a4aSRandall Stewart fir = 0; 459f8829a4aSRandall Stewart /* 460f8829a4aSRandall Stewart * figure out how long a data chunk must be pending before we can 461f8829a4aSRandall Stewart * mark it .. 462f8829a4aSRandall Stewart */ 4636e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 464f8829a4aSRandall Stewart /* get cur rto in micro-seconds */ 465f8829a4aSRandall Stewart cur_rtt = (((net->lastsa >> 2) + net->lastsv) >> 1); 466f8829a4aSRandall Stewart cur_rtt *= 1000; 467f8829a4aSRandall Stewart #if defined(SCTP_FR_LOGGING) || defined(SCTP_EARLYFR_LOGGING) 468f8829a4aSRandall Stewart sctp_log_fr(cur_rtt, 469f8829a4aSRandall Stewart stcb->asoc.peers_rwnd, 470f8829a4aSRandall Stewart window_probe, 471f8829a4aSRandall Stewart SCTP_FR_T3_MARK_TIME); 472f8829a4aSRandall Stewart sctp_log_fr(net->flight_size, 473139bc87fSRandall Stewart SCTP_OS_TIMER_PENDING(&net->fr_timer.timer), 474139bc87fSRandall Stewart SCTP_OS_TIMER_ACTIVE(&net->fr_timer.timer), 475f8829a4aSRandall Stewart SCTP_FR_CWND_REPORT); 476f8829a4aSRandall Stewart sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT); 477f8829a4aSRandall Stewart #endif 478f8829a4aSRandall Stewart tv.tv_sec = cur_rtt / 1000000; 479f8829a4aSRandall Stewart tv.tv_usec = cur_rtt % 1000000; 480f8829a4aSRandall Stewart min_wait = now; 481f8829a4aSRandall Stewart timevalsub(&min_wait, &tv); 482f8829a4aSRandall Stewart if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { 483f8829a4aSRandall Stewart /* 484f8829a4aSRandall Stewart * if we hit here, we don't have enough seconds on the clock 485f8829a4aSRandall Stewart * to account for the RTO. We just let the lower seconds be 486f8829a4aSRandall Stewart * the bounds and don't worry about it. This may mean we 487f8829a4aSRandall Stewart * will mark a lot more than we should. 488f8829a4aSRandall Stewart */ 489f8829a4aSRandall Stewart min_wait.tv_sec = min_wait.tv_usec = 0; 490f8829a4aSRandall Stewart } 491f8829a4aSRandall Stewart #if defined(SCTP_FR_LOGGING) || defined(SCTP_EARLYFR_LOGGING) 492f8829a4aSRandall Stewart sctp_log_fr(cur_rtt, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); 493f8829a4aSRandall Stewart sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); 494f8829a4aSRandall Stewart #endif 495f8829a4aSRandall Stewart /* 496f8829a4aSRandall Stewart * Our rwnd will be incorrect here since we are not adding back the 497f8829a4aSRandall Stewart * cnt * mbuf but we will fix that down below. 498f8829a4aSRandall Stewart */ 499f8829a4aSRandall Stewart orig_flight = net->flight_size; 500c105859eSRandall Stewart orig_tf = stcb->asoc.total_flight; 501c105859eSRandall Stewart 502f8829a4aSRandall Stewart net->fast_retran_ip = 0; 503f8829a4aSRandall Stewart /* Now on to each chunk */ 504f8829a4aSRandall Stewart num_mk = cnt_mk = 0; 505f8829a4aSRandall Stewart tsnfirst = tsnlast = 0; 506f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 507f8829a4aSRandall Stewart for (; chk != NULL; chk = tp2) { 508f8829a4aSRandall Stewart tp2 = TAILQ_NEXT(chk, sctp_next); 509f8829a4aSRandall Stewart if ((compare_with_wrap(stcb->asoc.last_acked_seq, 510f8829a4aSRandall Stewart chk->rec.data.TSN_seq, 511f8829a4aSRandall Stewart MAX_TSN)) || 512f8829a4aSRandall Stewart (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) { 513f8829a4aSRandall Stewart /* Strange case our list got out of order? */ 514ad81507eSRandall Stewart SCTP_PRINTF("Our list is out of order?\n"); 515f8829a4aSRandall Stewart panic("Out of order list"); 516f8829a4aSRandall Stewart } 517f8829a4aSRandall Stewart if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) { 518f8829a4aSRandall Stewart /* 519f8829a4aSRandall Stewart * found one to mark: If it is less than 520f8829a4aSRandall Stewart * DATAGRAM_ACKED it MUST not be a skipped or marked 521f8829a4aSRandall Stewart * TSN but instead one that is either already set 522f8829a4aSRandall Stewart * for retransmission OR one that needs 523f8829a4aSRandall Stewart * retransmission. 524f8829a4aSRandall Stewart */ 525f8829a4aSRandall Stewart 526f8829a4aSRandall Stewart /* validate its been outstanding long enough */ 527f8829a4aSRandall Stewart #if defined(SCTP_FR_LOGGING) || defined(SCTP_EARLYFR_LOGGING) 528f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, 529f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 530f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 531f8829a4aSRandall Stewart SCTP_FR_T3_MARK_TIME); 532f8829a4aSRandall Stewart #endif 533f8829a4aSRandall Stewart if ((chk->sent_rcv_time.tv_sec > min_wait.tv_sec) && (window_probe == 0)) { 534f8829a4aSRandall Stewart /* 535f8829a4aSRandall Stewart * we have reached a chunk that was sent 536f8829a4aSRandall Stewart * some seconds past our min.. forget it we 537f8829a4aSRandall Stewart * will find no more to send. 538f8829a4aSRandall Stewart */ 539f8829a4aSRandall Stewart #if defined(SCTP_FR_LOGGING) || defined(SCTP_EARLYFR_LOGGING) 540f8829a4aSRandall Stewart sctp_log_fr(0, 541f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 542f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 543f8829a4aSRandall Stewart SCTP_FR_T3_STOPPED); 544f8829a4aSRandall Stewart #endif 545f8829a4aSRandall Stewart continue; 546f8829a4aSRandall Stewart } else if ((chk->sent_rcv_time.tv_sec == min_wait.tv_sec) && 547f8829a4aSRandall Stewart (window_probe == 0)) { 548f8829a4aSRandall Stewart /* 549f8829a4aSRandall Stewart * we must look at the micro seconds to 550f8829a4aSRandall Stewart * know. 551f8829a4aSRandall Stewart */ 552f8829a4aSRandall Stewart if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { 553f8829a4aSRandall Stewart /* 554f8829a4aSRandall Stewart * ok it was sent after our boundary 555f8829a4aSRandall Stewart * time. 556f8829a4aSRandall Stewart */ 557f8829a4aSRandall Stewart #if defined(SCTP_FR_LOGGING) || defined(SCTP_EARLYFR_LOGGING) 558f8829a4aSRandall Stewart sctp_log_fr(0, 559f8829a4aSRandall Stewart chk->sent_rcv_time.tv_sec, 560f8829a4aSRandall Stewart chk->sent_rcv_time.tv_usec, 561f8829a4aSRandall Stewart SCTP_FR_T3_STOPPED); 562f8829a4aSRandall Stewart #endif 563f8829a4aSRandall Stewart continue; 564f8829a4aSRandall Stewart } 565f8829a4aSRandall Stewart } 566f8829a4aSRandall Stewart if (PR_SCTP_TTL_ENABLED(chk->flags)) { 567f8829a4aSRandall Stewart /* Is it expired? */ 568f8829a4aSRandall Stewart if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) || 569f8829a4aSRandall Stewart ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) && 570f8829a4aSRandall Stewart (now.tv_usec > chk->rec.data.timetodrop.tv_usec))) { 571f8829a4aSRandall Stewart /* Yes so drop it */ 572f8829a4aSRandall Stewart if (chk->data) { 573ad81507eSRandall Stewart (void)sctp_release_pr_sctp_chunk(stcb, 574f8829a4aSRandall Stewart chk, 575f8829a4aSRandall Stewart (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), 576f8829a4aSRandall Stewart &stcb->asoc.sent_queue); 577f8829a4aSRandall Stewart } 578f8829a4aSRandall Stewart } 579f8829a4aSRandall Stewart continue; 580f8829a4aSRandall Stewart } 581f8829a4aSRandall Stewart if (PR_SCTP_RTX_ENABLED(chk->flags)) { 582f8829a4aSRandall Stewart /* Has it been retransmitted tv_sec times? */ 583f8829a4aSRandall Stewart if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) { 584f8829a4aSRandall Stewart if (chk->data) { 585ad81507eSRandall Stewart (void)sctp_release_pr_sctp_chunk(stcb, 586f8829a4aSRandall Stewart chk, 587f8829a4aSRandall Stewart (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT), 588f8829a4aSRandall Stewart &stcb->asoc.sent_queue); 589f8829a4aSRandall Stewart } 590f8829a4aSRandall Stewart } 591f8829a4aSRandall Stewart continue; 592f8829a4aSRandall Stewart } 593c105859eSRandall Stewart if (chk->sent < SCTP_DATAGRAM_RESEND) { 594f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 595f8829a4aSRandall Stewart num_mk++; 596f8829a4aSRandall Stewart if (fir == 0) { 597f8829a4aSRandall Stewart fir = 1; 598f8829a4aSRandall Stewart tsnfirst = chk->rec.data.TSN_seq; 599f8829a4aSRandall Stewart } 600f8829a4aSRandall Stewart tsnlast = chk->rec.data.TSN_seq; 601f8829a4aSRandall Stewart #if defined(SCTP_FR_LOGGING) || defined(SCTP_EARLYFR_LOGGING) 602f8829a4aSRandall Stewart sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count, 603f8829a4aSRandall Stewart 0, SCTP_FR_T3_MARKED); 604f8829a4aSRandall Stewart 605f8829a4aSRandall Stewart #endif 60642551e99SRandall Stewart if (chk->rec.data.chunk_was_revoked) { 60742551e99SRandall Stewart /* deflate the cwnd */ 60842551e99SRandall Stewart chk->whoTo->cwnd -= chk->book_size; 60942551e99SRandall Stewart chk->rec.data.chunk_was_revoked = 0; 61042551e99SRandall Stewart } 611f42a358aSRandall Stewart net->marked_retrans++; 612f42a358aSRandall Stewart stcb->asoc.marked_retrans++; 613a5d547adSRandall Stewart #ifdef SCTP_FLIGHT_LOGGING 614c105859eSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO, 615a5d547adSRandall Stewart chk->whoTo->flight_size, 616a5d547adSRandall Stewart chk->book_size, 617c105859eSRandall Stewart (uintptr_t) chk->whoTo, 618a5d547adSRandall Stewart chk->rec.data.TSN_seq); 619a5d547adSRandall Stewart #endif 620c105859eSRandall Stewart sctp_flight_size_decrease(chk); 621c105859eSRandall Stewart sctp_total_flight_decrease(stcb, chk); 622f8829a4aSRandall Stewart stcb->asoc.peers_rwnd += chk->send_size; 623f8829a4aSRandall Stewart stcb->asoc.peers_rwnd += sctp_peer_chunk_oh; 624c105859eSRandall Stewart } 625c105859eSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 626c105859eSRandall Stewart SCTP_STAT_INCR(sctps_markedretrans); 627f8829a4aSRandall Stewart 628f8829a4aSRandall Stewart /* reset the TSN for striking and other FR stuff */ 629f8829a4aSRandall Stewart chk->rec.data.doing_fast_retransmit = 0; 630f8829a4aSRandall Stewart /* Clear any time so NO RTT is being done */ 631f8829a4aSRandall Stewart chk->do_rtt = 0; 632f8829a4aSRandall Stewart if (alt != net) { 633f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 634f8829a4aSRandall Stewart chk->no_fr_allowed = 1; 635f8829a4aSRandall Stewart chk->whoTo = alt; 636f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 637f8829a4aSRandall Stewart } else { 638f8829a4aSRandall Stewart chk->no_fr_allowed = 0; 639f8829a4aSRandall Stewart if (TAILQ_EMPTY(&stcb->asoc.send_queue)) { 640f8829a4aSRandall Stewart chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq; 641f8829a4aSRandall Stewart } else { 642f8829a4aSRandall Stewart chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq; 643f8829a4aSRandall Stewart } 644f8829a4aSRandall Stewart } 645f8829a4aSRandall Stewart if (sctp_cmt_on_off == 1) { 646f8829a4aSRandall Stewart chk->no_fr_allowed = 1; 647f8829a4aSRandall Stewart } 648f8829a4aSRandall Stewart } else if (chk->sent == SCTP_DATAGRAM_ACKED) { 649f8829a4aSRandall Stewart /* remember highest acked one */ 650f8829a4aSRandall Stewart could_be_sent = chk; 651f8829a4aSRandall Stewart } 652f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 653f8829a4aSRandall Stewart cnt_mk++; 654f8829a4aSRandall Stewart } 655f8829a4aSRandall Stewart } 656c105859eSRandall Stewart if ((orig_flight - net->flight_size) != (orig_tf - stcb->asoc.total_flight)) { 657c105859eSRandall Stewart /* we did not subtract the same things? */ 658c105859eSRandall Stewart audit_tf = 1; 659c105859eSRandall Stewart } 660f8829a4aSRandall Stewart #if defined(SCTP_FR_LOGGING) || defined(SCTP_EARLYFR_LOGGING) 661f8829a4aSRandall Stewart sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT); 662f8829a4aSRandall Stewart #endif 663f8829a4aSRandall Stewart #ifdef SCTP_DEBUG 664f8829a4aSRandall Stewart if (num_mk) { 665ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", 666ad81507eSRandall Stewart tsnlast); 667ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%ld\n", 668f8829a4aSRandall Stewart num_mk, (u_long)stcb->asoc.peers_rwnd); 669ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", 670ad81507eSRandall Stewart tsnlast); 671ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%d\n", 672f8829a4aSRandall Stewart num_mk, 673ad81507eSRandall Stewart (int)stcb->asoc.peers_rwnd); 674f8829a4aSRandall Stewart } 675f8829a4aSRandall Stewart #endif 676f8829a4aSRandall Stewart *num_marked = num_mk; 677f8829a4aSRandall Stewart if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) { 678f8829a4aSRandall Stewart /* fix it so we retransmit the highest acked anyway */ 679f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 680f8829a4aSRandall Stewart cnt_mk++; 681f8829a4aSRandall Stewart could_be_sent->sent = SCTP_DATAGRAM_RESEND; 682f8829a4aSRandall Stewart } 683f8829a4aSRandall Stewart if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { 684a5d547adSRandall Stewart #ifdef INVARIANTS 685ad81507eSRandall Stewart SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d\n", 686f8829a4aSRandall Stewart cnt_mk, stcb->asoc.sent_queue_retran_cnt); 687f8829a4aSRandall Stewart #endif 688f8829a4aSRandall Stewart #ifndef SCTP_AUDITING_ENABLED 689f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = cnt_mk; 690f8829a4aSRandall Stewart #endif 691f8829a4aSRandall Stewart } 692f8829a4aSRandall Stewart /* Now check for a ECN Echo that may be stranded */ 693f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 694f8829a4aSRandall Stewart if ((chk->whoTo == net) && 695f8829a4aSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 696f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 697f8829a4aSRandall Stewart chk->whoTo = alt; 698f8829a4aSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 699f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 700f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 701f8829a4aSRandall Stewart } 702f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 703f8829a4aSRandall Stewart } 704f8829a4aSRandall Stewart } 705f8829a4aSRandall Stewart if (audit_tf) { 706ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, 707ad81507eSRandall Stewart "Audit total flight due to negative value net:%p\n", 708f8829a4aSRandall Stewart net); 709f8829a4aSRandall Stewart stcb->asoc.total_flight = 0; 710f8829a4aSRandall Stewart stcb->asoc.total_flight_count = 0; 711f8829a4aSRandall Stewart /* Clear all networks flight size */ 712f8829a4aSRandall Stewart TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) { 713f8829a4aSRandall Stewart lnets->flight_size = 0; 714ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER4, 715ad81507eSRandall Stewart "Net:%p c-f cwnd:%d ssthresh:%d\n", 716f8829a4aSRandall Stewart lnets, lnets->cwnd, lnets->ssthresh); 717f8829a4aSRandall Stewart } 718f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 719f8829a4aSRandall Stewart if (chk->sent < SCTP_DATAGRAM_RESEND) { 720a5d547adSRandall Stewart #ifdef SCTP_FLIGHT_LOGGING 721a5d547adSRandall Stewart sctp_misc_ints(SCTP_FLIGHT_LOG_UP, 722a5d547adSRandall Stewart chk->whoTo->flight_size, 723a5d547adSRandall Stewart chk->book_size, 724c105859eSRandall Stewart (uintptr_t) chk->whoTo, 725a5d547adSRandall Stewart chk->rec.data.TSN_seq); 726a5d547adSRandall Stewart #endif 727c105859eSRandall Stewart 728c105859eSRandall Stewart sctp_flight_size_increase(chk); 729c105859eSRandall Stewart sctp_total_flight_increase(stcb, chk); 730f8829a4aSRandall Stewart } 731f8829a4aSRandall Stewart } 732f8829a4aSRandall Stewart } 733f8829a4aSRandall Stewart /* 734f8829a4aSRandall Stewart * Setup the ecn nonce re-sync point. We do this since 735f8829a4aSRandall Stewart * retranmissions are NOT setup for ECN. This means that do to 736f8829a4aSRandall Stewart * Karn's rule, we don't know the total of the peers ecn bits. 737f8829a4aSRandall Stewart */ 738f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.send_queue); 739f8829a4aSRandall Stewart if (chk == NULL) { 740f8829a4aSRandall Stewart stcb->asoc.nonce_resync_tsn = stcb->asoc.sending_seq; 741f8829a4aSRandall Stewart } else { 742f8829a4aSRandall Stewart stcb->asoc.nonce_resync_tsn = chk->rec.data.TSN_seq; 743f8829a4aSRandall Stewart } 744f8829a4aSRandall Stewart stcb->asoc.nonce_wait_for_ecne = 0; 745f8829a4aSRandall Stewart stcb->asoc.nonce_sum_check = 0; 746f8829a4aSRandall Stewart /* We return 1 if we only have a window probe outstanding */ 747f8829a4aSRandall Stewart return (0); 748f8829a4aSRandall Stewart } 749f8829a4aSRandall Stewart 750f8829a4aSRandall Stewart static void 751f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb, 752f8829a4aSRandall Stewart struct sctp_nets *net, 753f8829a4aSRandall Stewart struct sctp_nets *alt) 754f8829a4aSRandall Stewart { 755f8829a4aSRandall Stewart struct sctp_association *asoc; 756f8829a4aSRandall Stewart struct sctp_stream_out *outs; 757f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 758f8829a4aSRandall Stewart struct sctp_stream_queue_pending *sp; 759f8829a4aSRandall Stewart 760f8829a4aSRandall Stewart if (net == alt) 761f8829a4aSRandall Stewart /* nothing to do */ 762f8829a4aSRandall Stewart return; 763f8829a4aSRandall Stewart 764f8829a4aSRandall Stewart asoc = &stcb->asoc; 765f8829a4aSRandall Stewart 766f8829a4aSRandall Stewart /* 767f8829a4aSRandall Stewart * now through all the streams checking for chunks sent to our bad 768f8829a4aSRandall Stewart * network. 769f8829a4aSRandall Stewart */ 770f8829a4aSRandall Stewart TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { 771f8829a4aSRandall Stewart /* now clean up any chunks here */ 772f8829a4aSRandall Stewart TAILQ_FOREACH(sp, &outs->outqueue, next) { 773f8829a4aSRandall Stewart if (sp->net == net) { 774f8829a4aSRandall Stewart sctp_free_remote_addr(sp->net); 775f8829a4aSRandall Stewart sp->net = alt; 776f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 777f8829a4aSRandall Stewart } 778f8829a4aSRandall Stewart } 779f8829a4aSRandall Stewart } 780f8829a4aSRandall Stewart /* Now check the pending queue */ 781f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { 782f8829a4aSRandall Stewart if (chk->whoTo == net) { 783f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 784f8829a4aSRandall Stewart chk->whoTo = alt; 785f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 786f8829a4aSRandall Stewart } 787f8829a4aSRandall Stewart } 788f8829a4aSRandall Stewart 789f8829a4aSRandall Stewart } 790f8829a4aSRandall Stewart 791f8829a4aSRandall Stewart int 792f8829a4aSRandall Stewart sctp_t3rxt_timer(struct sctp_inpcb *inp, 793f8829a4aSRandall Stewart struct sctp_tcb *stcb, 794f8829a4aSRandall Stewart struct sctp_nets *net) 795f8829a4aSRandall Stewart { 796f8829a4aSRandall Stewart struct sctp_nets *alt; 797f8829a4aSRandall Stewart int win_probe, num_mk; 798f8829a4aSRandall Stewart 799f8829a4aSRandall Stewart #ifdef SCTP_FR_LOGGING 800562a89b5SRandall Stewart sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT); 801f8829a4aSRandall Stewart #ifdef SCTP_CWND_LOGGING 802f8829a4aSRandall Stewart { 803f8829a4aSRandall Stewart struct sctp_nets *lnet; 804f8829a4aSRandall Stewart 805f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 806f8829a4aSRandall Stewart if (net == lnet) { 807f8829a4aSRandall Stewart sctp_log_cwnd(stcb, lnet, 1, SCTP_CWND_LOG_FROM_T3); 808f8829a4aSRandall Stewart } else { 809f8829a4aSRandall Stewart sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_LOG_FROM_T3); 810f8829a4aSRandall Stewart } 811f8829a4aSRandall Stewart } 812f8829a4aSRandall Stewart } 813f8829a4aSRandall Stewart #endif 814f8829a4aSRandall Stewart #endif 815f8829a4aSRandall Stewart /* Find an alternate and mark those for retransmission */ 816f8829a4aSRandall Stewart if ((stcb->asoc.peers_rwnd == 0) && 817f8829a4aSRandall Stewart (stcb->asoc.total_flight < net->mtu)) { 818f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timowindowprobe); 819f8829a4aSRandall Stewart win_probe = 1; 820f8829a4aSRandall Stewart } else { 821f8829a4aSRandall Stewart win_probe = 0; 822f8829a4aSRandall Stewart } 823c105859eSRandall Stewart 824c105859eSRandall Stewart if (sctp_cmt_on_off) { 825c105859eSRandall Stewart /* 826c105859eSRandall Stewart * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being 827c105859eSRandall Stewart * used, then pick dest with largest ssthresh for any 828c105859eSRandall Stewart * retransmission. 829c105859eSRandall Stewart */ 830c105859eSRandall Stewart alt = net; 831c105859eSRandall Stewart alt = sctp_find_alternate_net(stcb, alt, 1); 832c105859eSRandall Stewart /* 833c105859eSRandall Stewart * CUCv2: If a different dest is picked for the 834c105859eSRandall Stewart * retransmission, then new (rtx-)pseudo_cumack needs to be 835c105859eSRandall Stewart * tracked for orig dest. Let CUCv2 track new (rtx-) 836c105859eSRandall Stewart * pseudo-cumack always. 837c105859eSRandall Stewart */ 838c105859eSRandall Stewart net->find_pseudo_cumack = 1; 839c105859eSRandall Stewart net->find_rtx_pseudo_cumack = 1; 840c105859eSRandall Stewart 841c105859eSRandall Stewart } else { /* CMT is OFF */ 842c105859eSRandall Stewart 843f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 844c105859eSRandall Stewart } 845c105859eSRandall Stewart 846ad81507eSRandall Stewart (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, &num_mk); 847f8829a4aSRandall Stewart /* FR Loss recovery just ended with the T3. */ 848f8829a4aSRandall Stewart stcb->asoc.fast_retran_loss_recovery = 0; 849f8829a4aSRandall Stewart 850f8829a4aSRandall Stewart /* CMT FR loss recovery ended with the T3 */ 851f8829a4aSRandall Stewart net->fast_retran_loss_recovery = 0; 852f8829a4aSRandall Stewart 853f8829a4aSRandall Stewart /* 854f8829a4aSRandall Stewart * setup the sat loss recovery that prevents satellite cwnd advance. 855f8829a4aSRandall Stewart */ 856f8829a4aSRandall Stewart stcb->asoc.sat_t3_loss_recovery = 1; 857f8829a4aSRandall Stewart stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; 858f8829a4aSRandall Stewart 859f8829a4aSRandall Stewart /* Backoff the timer and cwnd */ 860f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, net, win_probe, num_mk); 861f8829a4aSRandall Stewart if (win_probe == 0) { 862f8829a4aSRandall Stewart /* We don't do normal threshold management on window probes */ 863f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, 864f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 865f8829a4aSRandall Stewart /* Association was destroyed */ 866f8829a4aSRandall Stewart return (1); 867f8829a4aSRandall Stewart } else { 868f8829a4aSRandall Stewart if (net != stcb->asoc.primary_destination) { 869f8829a4aSRandall Stewart /* send a immediate HB if our RTO is stale */ 870f8829a4aSRandall Stewart struct timeval now; 871f8829a4aSRandall Stewart unsigned int ms_goneby; 872f8829a4aSRandall Stewart 8736e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 874f8829a4aSRandall Stewart if (net->last_sent_time.tv_sec) { 875f8829a4aSRandall Stewart ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000; 876f8829a4aSRandall Stewart } else { 877f8829a4aSRandall Stewart ms_goneby = 0; 878f8829a4aSRandall Stewart } 879f8829a4aSRandall Stewart if ((ms_goneby > net->RTO) || (net->RTO == 0)) { 880f8829a4aSRandall Stewart /* 881f8829a4aSRandall Stewart * no recent feed back in an RTO or 882f8829a4aSRandall Stewart * more, request a RTT update 883f8829a4aSRandall Stewart */ 8846e55db54SRandall Stewart (void)sctp_send_hb(stcb, 1, net); 885f8829a4aSRandall Stewart } 886f8829a4aSRandall Stewart } 887f8829a4aSRandall Stewart } 888f8829a4aSRandall Stewart } else { 889f8829a4aSRandall Stewart /* 890f8829a4aSRandall Stewart * For a window probe we don't penalize the net's but only 891f8829a4aSRandall Stewart * the association. This may fail it if SACKs are not coming 892f8829a4aSRandall Stewart * back. If sack's are coming with rwnd locked at 0, we will 893f8829a4aSRandall Stewart * continue to hold things waiting for rwnd to raise 894f8829a4aSRandall Stewart */ 895f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, NULL, 896f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 897f8829a4aSRandall Stewart /* Association was destroyed */ 898f8829a4aSRandall Stewart return (1); 899f8829a4aSRandall Stewart } 900f8829a4aSRandall Stewart } 901f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 902f8829a4aSRandall Stewart /* Move all pending over too */ 903f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 90417205eccSRandall Stewart 90517205eccSRandall Stewart /* 90617205eccSRandall Stewart * Get the address that failed, to force a new src address 90717205eccSRandall Stewart * selecton and a route allocation. 90817205eccSRandall Stewart */ 90917205eccSRandall Stewart if (net->ro._s_addr) { 91017205eccSRandall Stewart sctp_free_ifa(net->ro._s_addr); 91117205eccSRandall Stewart net->ro._s_addr = NULL; 91217205eccSRandall Stewart } 91317205eccSRandall Stewart net->src_addr_selected = 0; 91417205eccSRandall Stewart 91517205eccSRandall Stewart /* Force a route allocation too */ 91617205eccSRandall Stewart if (net->ro.ro_rt) { 91717205eccSRandall Stewart RTFREE(net->ro.ro_rt); 91817205eccSRandall Stewart net->ro.ro_rt = NULL; 91917205eccSRandall Stewart } 920f8829a4aSRandall Stewart /* Was it our primary? */ 921f8829a4aSRandall Stewart if ((stcb->asoc.primary_destination == net) && (alt != net)) { 922f8829a4aSRandall Stewart /* 923f8829a4aSRandall Stewart * Yes, note it as such and find an alternate note: 924f8829a4aSRandall Stewart * this means HB code must use this to resent the 925f8829a4aSRandall Stewart * primary if it goes active AND if someone does a 926f8829a4aSRandall Stewart * change-primary then this flag must be cleared 927f8829a4aSRandall Stewart * from any net structures. 928f8829a4aSRandall Stewart */ 929f8829a4aSRandall Stewart if (sctp_set_primary_addr(stcb, 930f8829a4aSRandall Stewart (struct sockaddr *)NULL, 931f8829a4aSRandall Stewart alt) == 0) { 932f8829a4aSRandall Stewart net->dest_state |= SCTP_ADDR_WAS_PRIMARY; 933f8829a4aSRandall Stewart } 934f8829a4aSRandall Stewart } 935f8829a4aSRandall Stewart } 936f8829a4aSRandall Stewart /* 937f8829a4aSRandall Stewart * Special case for cookie-echo'ed case, we don't do output but must 938f8829a4aSRandall Stewart * await the COOKIE-ACK before retransmission 939f8829a4aSRandall Stewart */ 940f8829a4aSRandall Stewart if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { 941f8829a4aSRandall Stewart /* 942f8829a4aSRandall Stewart * Here we just reset the timer and start again since we 943f8829a4aSRandall Stewart * have not established the asoc 944f8829a4aSRandall Stewart */ 945f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); 946f8829a4aSRandall Stewart return (0); 947f8829a4aSRandall Stewart } 948f8829a4aSRandall Stewart if (stcb->asoc.peer_supports_prsctp) { 949f8829a4aSRandall Stewart struct sctp_tmit_chunk *lchk; 950f8829a4aSRandall Stewart 951f8829a4aSRandall Stewart lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc); 952f8829a4aSRandall Stewart /* C3. See if we need to send a Fwd-TSN */ 953f8829a4aSRandall Stewart if (compare_with_wrap(stcb->asoc.advanced_peer_ack_point, 954f8829a4aSRandall Stewart stcb->asoc.last_acked_seq, MAX_TSN)) { 955f8829a4aSRandall Stewart /* 956f8829a4aSRandall Stewart * ISSUE with ECN, see FWD-TSN processing for notes 957f8829a4aSRandall Stewart * on issues that will occur when the ECN NONCE 958f8829a4aSRandall Stewart * stuff is put into SCTP for cross checking. 959f8829a4aSRandall Stewart */ 960f8829a4aSRandall Stewart send_forward_tsn(stcb, &stcb->asoc); 961f8829a4aSRandall Stewart if (lchk) { 962f8829a4aSRandall Stewart /* Assure a timer is up */ 963f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo); 964f8829a4aSRandall Stewart } 965f8829a4aSRandall Stewart } 966f8829a4aSRandall Stewart } 967f8829a4aSRandall Stewart #ifdef SCTP_CWND_MONITOR 968f8829a4aSRandall Stewart sctp_log_cwnd(stcb, net, net->cwnd, SCTP_CWND_LOG_FROM_RTX); 969f8829a4aSRandall Stewart #endif 970f8829a4aSRandall Stewart return (0); 971f8829a4aSRandall Stewart } 972f8829a4aSRandall Stewart 973f8829a4aSRandall Stewart int 974f8829a4aSRandall Stewart sctp_t1init_timer(struct sctp_inpcb *inp, 975f8829a4aSRandall Stewart struct sctp_tcb *stcb, 976f8829a4aSRandall Stewart struct sctp_nets *net) 977f8829a4aSRandall Stewart { 978f8829a4aSRandall Stewart /* bump the thresholds */ 979f8829a4aSRandall Stewart if (stcb->asoc.delayed_connection) { 980f8829a4aSRandall Stewart /* 981f8829a4aSRandall Stewart * special hook for delayed connection. The library did NOT 982f8829a4aSRandall Stewart * complete the rest of its sends. 983f8829a4aSRandall Stewart */ 984f8829a4aSRandall Stewart stcb->asoc.delayed_connection = 0; 985f8829a4aSRandall Stewart sctp_send_initiate(inp, stcb); 986f8829a4aSRandall Stewart return (0); 987f8829a4aSRandall Stewart } 988f8829a4aSRandall Stewart if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) { 989f8829a4aSRandall Stewart return (0); 990f8829a4aSRandall Stewart } 991f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, 992f8829a4aSRandall Stewart stcb->asoc.max_init_times)) { 993f8829a4aSRandall Stewart /* Association was destroyed */ 994f8829a4aSRandall Stewart return (1); 995f8829a4aSRandall Stewart } 996f8829a4aSRandall Stewart stcb->asoc.dropped_special_cnt = 0; 997f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0); 998f8829a4aSRandall Stewart if (stcb->asoc.initial_init_rto_max < net->RTO) { 999f8829a4aSRandall Stewart net->RTO = stcb->asoc.initial_init_rto_max; 1000f8829a4aSRandall Stewart } 1001f8829a4aSRandall Stewart if (stcb->asoc.numnets > 1) { 1002f8829a4aSRandall Stewart /* If we have more than one addr use it */ 1003f8829a4aSRandall Stewart struct sctp_nets *alt; 1004f8829a4aSRandall Stewart 1005f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0); 1006f8829a4aSRandall Stewart if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) { 1007f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt); 1008f8829a4aSRandall Stewart stcb->asoc.primary_destination = alt; 1009f8829a4aSRandall Stewart } 1010f8829a4aSRandall Stewart } 1011f8829a4aSRandall Stewart /* Send out a new init */ 1012f8829a4aSRandall Stewart sctp_send_initiate(inp, stcb); 1013f8829a4aSRandall Stewart return (0); 1014f8829a4aSRandall Stewart } 1015f8829a4aSRandall Stewart 1016f8829a4aSRandall Stewart /* 1017f8829a4aSRandall Stewart * For cookie and asconf we actually need to find and mark for resend, then 1018f8829a4aSRandall Stewart * increment the resend counter (after all the threshold management stuff of 1019f8829a4aSRandall Stewart * course). 1020f8829a4aSRandall Stewart */ 1021f8829a4aSRandall Stewart int 1022f8829a4aSRandall Stewart sctp_cookie_timer(struct sctp_inpcb *inp, 1023f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1024f8829a4aSRandall Stewart struct sctp_nets *net) 1025f8829a4aSRandall Stewart { 1026f8829a4aSRandall Stewart struct sctp_nets *alt; 1027f8829a4aSRandall Stewart struct sctp_tmit_chunk *cookie; 1028f8829a4aSRandall Stewart 1029f8829a4aSRandall Stewart /* first before all else we must find the cookie */ 1030f8829a4aSRandall Stewart TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) { 1031f8829a4aSRandall Stewart if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) { 1032f8829a4aSRandall Stewart break; 1033f8829a4aSRandall Stewart } 1034f8829a4aSRandall Stewart } 1035f8829a4aSRandall Stewart if (cookie == NULL) { 1036f8829a4aSRandall Stewart if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { 1037f8829a4aSRandall Stewart /* FOOBAR! */ 1038f8829a4aSRandall Stewart struct mbuf *oper; 1039f8829a4aSRandall Stewart 1040f8829a4aSRandall Stewart oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 1041f8829a4aSRandall Stewart 0, M_DONTWAIT, 1, MT_DATA); 1042f8829a4aSRandall Stewart if (oper) { 1043f8829a4aSRandall Stewart struct sctp_paramhdr *ph; 1044f8829a4aSRandall Stewart uint32_t *ippp; 1045f8829a4aSRandall Stewart 1046139bc87fSRandall Stewart SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) + 1047f8829a4aSRandall Stewart sizeof(uint32_t); 1048f8829a4aSRandall Stewart ph = mtod(oper, struct sctp_paramhdr *); 1049f8829a4aSRandall Stewart ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); 1050139bc87fSRandall Stewart ph->param_length = htons(SCTP_BUF_LEN(oper)); 1051f8829a4aSRandall Stewart ippp = (uint32_t *) (ph + 1); 1052a5d547adSRandall Stewart *ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_2); 1053f8829a4aSRandall Stewart } 1054a5d547adSRandall Stewart inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_3; 1055f8829a4aSRandall Stewart sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR, 1056f8829a4aSRandall Stewart oper); 1057f8829a4aSRandall Stewart } else { 1058a5d547adSRandall Stewart #ifdef INVARIANTS 1059f8829a4aSRandall Stewart panic("Cookie timer expires in wrong state?"); 1060f8829a4aSRandall Stewart #else 1061ad81507eSRandall Stewart SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc)); 1062f8829a4aSRandall Stewart return (0); 1063f8829a4aSRandall Stewart #endif 1064f8829a4aSRandall Stewart } 1065f8829a4aSRandall Stewart return (0); 1066f8829a4aSRandall Stewart } 1067f8829a4aSRandall Stewart /* Ok we found the cookie, threshold management next */ 1068f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, cookie->whoTo, 1069f8829a4aSRandall Stewart stcb->asoc.max_init_times)) { 1070f8829a4aSRandall Stewart /* Assoc is over */ 1071f8829a4aSRandall Stewart return (1); 1072f8829a4aSRandall Stewart } 1073f8829a4aSRandall Stewart /* 1074f8829a4aSRandall Stewart * cleared theshold management now lets backoff the address & select 1075f8829a4aSRandall Stewart * an alternate 1076f8829a4aSRandall Stewart */ 1077f8829a4aSRandall Stewart stcb->asoc.dropped_special_cnt = 0; 1078f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0); 1079f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0); 1080f8829a4aSRandall Stewart if (alt != cookie->whoTo) { 1081f8829a4aSRandall Stewart sctp_free_remote_addr(cookie->whoTo); 1082f8829a4aSRandall Stewart cookie->whoTo = alt; 1083f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1084f8829a4aSRandall Stewart } 1085f8829a4aSRandall Stewart /* Now mark the retran info */ 1086f8829a4aSRandall Stewart if (cookie->sent != SCTP_DATAGRAM_RESEND) { 1087f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1088f8829a4aSRandall Stewart } 1089f8829a4aSRandall Stewart cookie->sent = SCTP_DATAGRAM_RESEND; 1090f8829a4aSRandall Stewart /* 1091f8829a4aSRandall Stewart * Now call the output routine to kick out the cookie again, Note we 1092f8829a4aSRandall Stewart * don't mark any chunks for retran so that FR will need to kick in 1093f8829a4aSRandall Stewart * to move these (or a send timer). 1094f8829a4aSRandall Stewart */ 1095f8829a4aSRandall Stewart return (0); 1096f8829a4aSRandall Stewart } 1097f8829a4aSRandall Stewart 1098f8829a4aSRandall Stewart int 1099f8829a4aSRandall Stewart sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1100f8829a4aSRandall Stewart struct sctp_nets *net) 1101f8829a4aSRandall Stewart { 1102f8829a4aSRandall Stewart struct sctp_nets *alt; 1103f8829a4aSRandall Stewart struct sctp_tmit_chunk *strrst = NULL, *chk = NULL; 1104f8829a4aSRandall Stewart 1105f8829a4aSRandall Stewart if (stcb->asoc.stream_reset_outstanding == 0) { 1106f8829a4aSRandall Stewart return (0); 1107f8829a4aSRandall Stewart } 1108f8829a4aSRandall Stewart /* find the existing STRRESET, we use the seq number we sent out on */ 1109ad81507eSRandall Stewart (void)sctp_find_stream_reset(stcb, stcb->asoc.str_reset_seq_out, &strrst); 1110f8829a4aSRandall Stewart if (strrst == NULL) { 1111f8829a4aSRandall Stewart return (0); 1112f8829a4aSRandall Stewart } 1113f8829a4aSRandall Stewart /* do threshold management */ 1114f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, strrst->whoTo, 1115f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1116f8829a4aSRandall Stewart /* Assoc is over */ 1117f8829a4aSRandall Stewart return (1); 1118f8829a4aSRandall Stewart } 1119f8829a4aSRandall Stewart /* 1120f8829a4aSRandall Stewart * cleared theshold management now lets backoff the address & select 1121f8829a4aSRandall Stewart * an alternate 1122f8829a4aSRandall Stewart */ 1123f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0); 1124f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0); 1125f8829a4aSRandall Stewart sctp_free_remote_addr(strrst->whoTo); 1126f8829a4aSRandall Stewart strrst->whoTo = alt; 1127f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1128f8829a4aSRandall Stewart 1129f8829a4aSRandall Stewart /* See if a ECN Echo is also stranded */ 1130f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 1131f8829a4aSRandall Stewart if ((chk->whoTo == net) && 1132f8829a4aSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 1133f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 1134f8829a4aSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 1135f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 1136f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1137f8829a4aSRandall Stewart } 1138f8829a4aSRandall Stewart chk->whoTo = alt; 1139f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1140f8829a4aSRandall Stewart } 1141f8829a4aSRandall Stewart } 1142f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 1143f8829a4aSRandall Stewart /* 1144f8829a4aSRandall Stewart * If the address went un-reachable, we need to move to 1145f8829a4aSRandall Stewart * alternates for ALL chk's in queue 1146f8829a4aSRandall Stewart */ 1147f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 1148f8829a4aSRandall Stewart } 1149f8829a4aSRandall Stewart /* mark the retran info */ 1150f8829a4aSRandall Stewart if (strrst->sent != SCTP_DATAGRAM_RESEND) 1151f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1152f8829a4aSRandall Stewart strrst->sent = SCTP_DATAGRAM_RESEND; 1153f8829a4aSRandall Stewart 1154f8829a4aSRandall Stewart /* restart the timer */ 1155f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo); 1156f8829a4aSRandall Stewart return (0); 1157f8829a4aSRandall Stewart } 1158f8829a4aSRandall Stewart 1159f8829a4aSRandall Stewart int 1160f8829a4aSRandall Stewart sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1161f8829a4aSRandall Stewart struct sctp_nets *net) 1162f8829a4aSRandall Stewart { 1163f8829a4aSRandall Stewart struct sctp_nets *alt; 1164f8829a4aSRandall Stewart struct sctp_tmit_chunk *asconf, *chk; 1165f8829a4aSRandall Stewart 1166f8829a4aSRandall Stewart /* is this the first send, or a retransmission? */ 1167f8829a4aSRandall Stewart if (stcb->asoc.asconf_sent == 0) { 1168f8829a4aSRandall Stewart /* compose a new ASCONF chunk and send it */ 1169f8829a4aSRandall Stewart sctp_send_asconf(stcb, net); 1170f8829a4aSRandall Stewart } else { 1171f8829a4aSRandall Stewart /* Retransmission of the existing ASCONF needed... */ 1172f8829a4aSRandall Stewart 1173f8829a4aSRandall Stewart /* find the existing ASCONF */ 1174f8829a4aSRandall Stewart TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue, 1175f8829a4aSRandall Stewart sctp_next) { 1176f8829a4aSRandall Stewart if (asconf->rec.chunk_id.id == SCTP_ASCONF) { 1177f8829a4aSRandall Stewart break; 1178f8829a4aSRandall Stewart } 1179f8829a4aSRandall Stewart } 1180f8829a4aSRandall Stewart if (asconf == NULL) { 1181f8829a4aSRandall Stewart return (0); 1182f8829a4aSRandall Stewart } 1183f8829a4aSRandall Stewart /* do threshold management */ 1184f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, asconf->whoTo, 1185f8829a4aSRandall Stewart stcb->asoc.max_send_times)) { 1186f8829a4aSRandall Stewart /* Assoc is over */ 1187f8829a4aSRandall Stewart return (1); 1188f8829a4aSRandall Stewart } 1189f8829a4aSRandall Stewart /* 1190f8829a4aSRandall Stewart * PETER? FIX? How will the following code ever run? If the 1191f8829a4aSRandall Stewart * max_send_times is hit, threshold managment will blow away 1192f8829a4aSRandall Stewart * the association? 1193f8829a4aSRandall Stewart */ 1194f8829a4aSRandall Stewart if (asconf->snd_count > stcb->asoc.max_send_times) { 1195f8829a4aSRandall Stewart /* 1196f8829a4aSRandall Stewart * Something is rotten, peer is not responding to 1197f8829a4aSRandall Stewart * ASCONFs but maybe is to data etc. e.g. it is not 1198f8829a4aSRandall Stewart * properly handling the chunk type upper bits Mark 1199f8829a4aSRandall Stewart * this peer as ASCONF incapable and cleanup 1200f8829a4aSRandall Stewart */ 1201ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n"); 1202f8829a4aSRandall Stewart sctp_asconf_cleanup(stcb, net); 1203f8829a4aSRandall Stewart return (0); 1204f8829a4aSRandall Stewart } 1205f8829a4aSRandall Stewart /* 1206f8829a4aSRandall Stewart * cleared theshold management now lets backoff the address 1207f8829a4aSRandall Stewart * & select an alternate 1208f8829a4aSRandall Stewart */ 1209f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0); 1210f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0); 1211f8829a4aSRandall Stewart sctp_free_remote_addr(asconf->whoTo); 1212f8829a4aSRandall Stewart asconf->whoTo = alt; 1213f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1214f8829a4aSRandall Stewart 1215f8829a4aSRandall Stewart /* See if a ECN Echo is also stranded */ 1216f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { 1217f8829a4aSRandall Stewart if ((chk->whoTo == net) && 1218f8829a4aSRandall Stewart (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { 1219f8829a4aSRandall Stewart sctp_free_remote_addr(chk->whoTo); 1220f8829a4aSRandall Stewart chk->whoTo = alt; 1221f8829a4aSRandall Stewart if (chk->sent != SCTP_DATAGRAM_RESEND) { 1222f8829a4aSRandall Stewart chk->sent = SCTP_DATAGRAM_RESEND; 1223f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1224f8829a4aSRandall Stewart } 1225f8829a4aSRandall Stewart atomic_add_int(&alt->ref_count, 1); 1226f8829a4aSRandall Stewart } 1227f8829a4aSRandall Stewart } 1228f8829a4aSRandall Stewart if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { 1229f8829a4aSRandall Stewart /* 1230f8829a4aSRandall Stewart * If the address went un-reachable, we need to move 1231f8829a4aSRandall Stewart * to alternates for ALL chk's in queue 1232f8829a4aSRandall Stewart */ 1233f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(stcb, net, alt); 1234f8829a4aSRandall Stewart } 1235f8829a4aSRandall Stewart /* mark the retran info */ 1236f8829a4aSRandall Stewart if (asconf->sent != SCTP_DATAGRAM_RESEND) 1237f8829a4aSRandall Stewart sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 1238f8829a4aSRandall Stewart asconf->sent = SCTP_DATAGRAM_RESEND; 1239f8829a4aSRandall Stewart } 1240f8829a4aSRandall Stewart return (0); 1241f8829a4aSRandall Stewart } 1242f8829a4aSRandall Stewart 1243f8829a4aSRandall Stewart /* 1244f8829a4aSRandall Stewart * For the shutdown and shutdown-ack, we do not keep one around on the 1245f8829a4aSRandall Stewart * control queue. This means we must generate a new one and call the general 1246f8829a4aSRandall Stewart * chunk output routine, AFTER having done threshold management. 1247f8829a4aSRandall Stewart */ 1248f8829a4aSRandall Stewart int 1249f8829a4aSRandall Stewart sctp_shutdown_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 1254f8829a4aSRandall Stewart /* first threshold managment */ 1255f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { 1256f8829a4aSRandall Stewart /* Assoc is over */ 1257f8829a4aSRandall Stewart return (1); 1258f8829a4aSRandall Stewart } 1259f8829a4aSRandall Stewart /* second select an alternative */ 1260f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 1261f8829a4aSRandall Stewart 1262f8829a4aSRandall Stewart /* third generate a shutdown into the queue for out net */ 1263f8829a4aSRandall Stewart if (alt) { 1264f8829a4aSRandall Stewart sctp_send_shutdown(stcb, alt); 1265f8829a4aSRandall Stewart } else { 1266f8829a4aSRandall Stewart /* 1267f8829a4aSRandall Stewart * if alt is NULL, there is no dest to send to?? 1268f8829a4aSRandall Stewart */ 1269f8829a4aSRandall Stewart return (0); 1270f8829a4aSRandall Stewart } 1271f8829a4aSRandall Stewart /* fourth restart timer */ 1272f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt); 1273f8829a4aSRandall Stewart return (0); 1274f8829a4aSRandall Stewart } 1275f8829a4aSRandall Stewart 1276f8829a4aSRandall Stewart int 1277f8829a4aSRandall Stewart sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1278f8829a4aSRandall Stewart struct sctp_nets *net) 1279f8829a4aSRandall Stewart { 1280f8829a4aSRandall Stewart struct sctp_nets *alt; 1281f8829a4aSRandall Stewart 1282f8829a4aSRandall Stewart /* first threshold managment */ 1283f8829a4aSRandall Stewart if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { 1284f8829a4aSRandall Stewart /* Assoc is over */ 1285f8829a4aSRandall Stewart return (1); 1286f8829a4aSRandall Stewart } 1287f8829a4aSRandall Stewart /* second select an alternative */ 1288f8829a4aSRandall Stewart alt = sctp_find_alternate_net(stcb, net, 0); 1289f8829a4aSRandall Stewart 1290f8829a4aSRandall Stewart /* third generate a shutdown into the queue for out net */ 1291f8829a4aSRandall Stewart sctp_send_shutdown_ack(stcb, alt); 1292f8829a4aSRandall Stewart 1293f8829a4aSRandall Stewart /* fourth restart timer */ 1294f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt); 1295f8829a4aSRandall Stewart return (0); 1296f8829a4aSRandall Stewart } 1297f8829a4aSRandall Stewart 1298f8829a4aSRandall Stewart static void 1299f8829a4aSRandall Stewart sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, 1300f8829a4aSRandall Stewart struct sctp_tcb *stcb) 1301f8829a4aSRandall Stewart { 1302f8829a4aSRandall Stewart struct sctp_stream_out *outs; 1303f8829a4aSRandall Stewart struct sctp_stream_queue_pending *sp; 1304f8829a4aSRandall Stewart unsigned int chks_in_queue = 0; 1305f8829a4aSRandall Stewart int being_filled = 0; 1306f8829a4aSRandall Stewart 1307f8829a4aSRandall Stewart /* 1308f8829a4aSRandall Stewart * This function is ONLY called when the send/sent queues are empty. 1309f8829a4aSRandall Stewart */ 1310f8829a4aSRandall Stewart if ((stcb == NULL) || (inp == NULL)) 1311f8829a4aSRandall Stewart return; 1312f8829a4aSRandall Stewart 1313f8829a4aSRandall Stewart if (stcb->asoc.sent_queue_retran_cnt) { 1314ad81507eSRandall Stewart SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n", 1315f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt); 1316f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = 0; 1317f8829a4aSRandall Stewart } 1318f8829a4aSRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 1319f8829a4aSRandall Stewart if (TAILQ_EMPTY(&stcb->asoc.out_wheel)) { 1320f8829a4aSRandall Stewart int i, cnt = 0; 1321f8829a4aSRandall Stewart 1322f8829a4aSRandall Stewart /* Check to see if a spoke fell off the wheel */ 1323f8829a4aSRandall Stewart for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 1324f8829a4aSRandall Stewart if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 1325f8829a4aSRandall Stewart sctp_insert_on_wheel(stcb, &stcb->asoc, &stcb->asoc.strmout[i], 1); 1326f8829a4aSRandall Stewart cnt++; 1327f8829a4aSRandall Stewart } 1328f8829a4aSRandall Stewart } 1329f8829a4aSRandall Stewart if (cnt) { 1330f8829a4aSRandall Stewart /* yep, we lost a spoke or two */ 1331ad81507eSRandall Stewart SCTP_PRINTF("Found an additional %d streams NOT on outwheel, corrected\n", cnt); 1332f8829a4aSRandall Stewart } else { 1333f8829a4aSRandall Stewart /* no spokes lost, */ 1334f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size = 0; 1335f8829a4aSRandall Stewart } 1336f8829a4aSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 1337f8829a4aSRandall Stewart return; 1338f8829a4aSRandall Stewart } 1339f8829a4aSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 1340f8829a4aSRandall Stewart /* Check to see if some data queued, if so report it */ 1341f8829a4aSRandall Stewart TAILQ_FOREACH(outs, &stcb->asoc.out_wheel, next_spoke) { 1342f8829a4aSRandall Stewart if (!TAILQ_EMPTY(&outs->outqueue)) { 1343f8829a4aSRandall Stewart TAILQ_FOREACH(sp, &outs->outqueue, next) { 1344f8829a4aSRandall Stewart if (sp->msg_is_complete) 1345f8829a4aSRandall Stewart being_filled++; 1346f8829a4aSRandall Stewart chks_in_queue++; 1347f8829a4aSRandall Stewart } 1348f8829a4aSRandall Stewart } 1349f8829a4aSRandall Stewart } 1350f8829a4aSRandall Stewart if (chks_in_queue != stcb->asoc.stream_queue_cnt) { 1351ad81507eSRandall Stewart SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n", 1352f8829a4aSRandall Stewart stcb->asoc.stream_queue_cnt, chks_in_queue); 1353f8829a4aSRandall Stewart } 1354f8829a4aSRandall Stewart if (chks_in_queue) { 1355f8829a4aSRandall Stewart /* call the output queue function */ 1356f8829a4aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3); 1357f8829a4aSRandall Stewart if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) && 1358f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { 1359f8829a4aSRandall Stewart /* 1360f8829a4aSRandall Stewart * Probably should go in and make it go back through 1361f8829a4aSRandall Stewart * and add fragments allowed 1362f8829a4aSRandall Stewart */ 1363f8829a4aSRandall Stewart if (being_filled == 0) { 1364ad81507eSRandall Stewart SCTP_PRINTF("Still nothing moved %d chunks are stuck\n", 1365f8829a4aSRandall Stewart chks_in_queue); 1366f8829a4aSRandall Stewart } 1367f8829a4aSRandall Stewart } 1368f8829a4aSRandall Stewart } else { 1369ad81507eSRandall Stewart SCTP_PRINTF("Found no chunks on any queue tot:%lu\n", 1370f8829a4aSRandall Stewart (u_long)stcb->asoc.total_output_queue_size); 1371f8829a4aSRandall Stewart stcb->asoc.total_output_queue_size = 0; 1372f8829a4aSRandall Stewart } 1373f8829a4aSRandall Stewart } 1374f8829a4aSRandall Stewart 1375f8829a4aSRandall Stewart int 1376f8829a4aSRandall Stewart sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1377f8829a4aSRandall Stewart struct sctp_nets *net, int cnt_of_unconf) 1378f8829a4aSRandall Stewart { 1379f8829a4aSRandall Stewart if (net) { 1380f8829a4aSRandall Stewart if (net->hb_responded == 0) { 138142551e99SRandall Stewart if (net->ro._s_addr) { 138242551e99SRandall Stewart /* 138342551e99SRandall Stewart * Invalidate the src address if we did not 138442551e99SRandall Stewart * get a response last time. 138542551e99SRandall Stewart */ 138642551e99SRandall Stewart sctp_free_ifa(net->ro._s_addr); 138742551e99SRandall Stewart net->ro._s_addr = NULL; 138842551e99SRandall Stewart net->src_addr_selected = 0; 138942551e99SRandall Stewart } 1390f8829a4aSRandall Stewart sctp_backoff_on_timeout(stcb, net, 1, 0); 1391f8829a4aSRandall Stewart } 1392f8829a4aSRandall Stewart /* Zero PBA, if it needs it */ 1393f8829a4aSRandall Stewart if (net->partial_bytes_acked) { 1394f8829a4aSRandall Stewart net->partial_bytes_acked = 0; 1395f8829a4aSRandall Stewart } 1396f8829a4aSRandall Stewart } 1397f8829a4aSRandall Stewart if ((stcb->asoc.total_output_queue_size > 0) && 1398f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.send_queue)) && 1399f8829a4aSRandall Stewart (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { 1400f8829a4aSRandall Stewart sctp_audit_stream_queues_for_size(inp, stcb); 1401f8829a4aSRandall Stewart } 1402f8829a4aSRandall Stewart /* Send a new HB, this will do threshold managment, pick a new dest */ 1403f8829a4aSRandall Stewart if (cnt_of_unconf == 0) { 1404f8829a4aSRandall Stewart if (sctp_send_hb(stcb, 0, NULL) < 0) { 1405f8829a4aSRandall Stewart return (1); 1406f8829a4aSRandall Stewart } 1407f8829a4aSRandall Stewart } else { 1408f8829a4aSRandall Stewart /* 1409f8829a4aSRandall Stewart * this will send out extra hb's up to maxburst if there are 1410f8829a4aSRandall Stewart * any unconfirmed addresses. 1411f8829a4aSRandall Stewart */ 1412f8829a4aSRandall Stewart int cnt_sent = 0; 1413f8829a4aSRandall Stewart 1414f8829a4aSRandall Stewart TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1415f8829a4aSRandall Stewart if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) && 1416f8829a4aSRandall Stewart (net->dest_state & SCTP_ADDR_REACHABLE)) { 1417f8829a4aSRandall Stewart cnt_sent++; 141842551e99SRandall Stewart if (net->hb_responded == 0) { 141942551e99SRandall Stewart /* Did we respond last time? */ 142042551e99SRandall Stewart if (net->ro._s_addr) { 142142551e99SRandall Stewart sctp_free_ifa(net->ro._s_addr); 142242551e99SRandall Stewart net->ro._s_addr = NULL; 142342551e99SRandall Stewart net->src_addr_selected = 0; 142442551e99SRandall Stewart } 142542551e99SRandall Stewart } 1426f8829a4aSRandall Stewart if (sctp_send_hb(stcb, 1, net) == 0) { 1427f8829a4aSRandall Stewart break; 1428f8829a4aSRandall Stewart } 142942551e99SRandall Stewart if (cnt_sent >= sctp_hb_maxburst) 1430f8829a4aSRandall Stewart break; 1431f8829a4aSRandall Stewart } 1432f8829a4aSRandall Stewart } 1433f8829a4aSRandall Stewart } 1434f8829a4aSRandall Stewart return (0); 1435f8829a4aSRandall Stewart } 1436f8829a4aSRandall Stewart 1437f8829a4aSRandall Stewart int 1438f8829a4aSRandall Stewart sctp_is_hb_timer_running(struct sctp_tcb *stcb) 1439f8829a4aSRandall Stewart { 1440139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&stcb->asoc.hb_timer.timer)) { 1441f8829a4aSRandall Stewart /* its running */ 1442f8829a4aSRandall Stewart return (1); 1443f8829a4aSRandall Stewart } else { 1444f8829a4aSRandall Stewart /* nope */ 1445f8829a4aSRandall Stewart return (0); 1446f8829a4aSRandall Stewart } 1447f8829a4aSRandall Stewart } 1448f8829a4aSRandall Stewart 1449f8829a4aSRandall Stewart int 1450f8829a4aSRandall Stewart sctp_is_sack_timer_running(struct sctp_tcb *stcb) 1451f8829a4aSRandall Stewart { 1452139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { 1453f8829a4aSRandall Stewart /* its running */ 1454f8829a4aSRandall Stewart return (1); 1455f8829a4aSRandall Stewart } else { 1456f8829a4aSRandall Stewart /* nope */ 1457f8829a4aSRandall Stewart return (0); 1458f8829a4aSRandall Stewart } 1459f8829a4aSRandall Stewart } 1460f8829a4aSRandall Stewart 1461f8829a4aSRandall Stewart #define SCTP_NUMBER_OF_MTU_SIZES 18 1462f8829a4aSRandall Stewart static uint32_t mtu_sizes[] = { 1463f8829a4aSRandall Stewart 68, 1464f8829a4aSRandall Stewart 296, 1465f8829a4aSRandall Stewart 508, 1466f8829a4aSRandall Stewart 512, 1467f8829a4aSRandall Stewart 544, 1468f8829a4aSRandall Stewart 576, 1469f8829a4aSRandall Stewart 1006, 1470f8829a4aSRandall Stewart 1492, 1471f8829a4aSRandall Stewart 1500, 1472f8829a4aSRandall Stewart 1536, 1473f8829a4aSRandall Stewart 2002, 1474f8829a4aSRandall Stewart 2048, 1475f8829a4aSRandall Stewart 4352, 1476f8829a4aSRandall Stewart 4464, 1477f8829a4aSRandall Stewart 8166, 1478f8829a4aSRandall Stewart 17914, 1479f8829a4aSRandall Stewart 32000, 1480f8829a4aSRandall Stewart 65535 1481f8829a4aSRandall Stewart }; 1482f8829a4aSRandall Stewart 1483f8829a4aSRandall Stewart 1484f8829a4aSRandall Stewart static uint32_t 1485f8829a4aSRandall Stewart sctp_getnext_mtu(struct sctp_inpcb *inp, uint32_t cur_mtu) 1486f8829a4aSRandall Stewart { 1487f8829a4aSRandall Stewart /* select another MTU that is just bigger than this one */ 1488f8829a4aSRandall Stewart int i; 1489f8829a4aSRandall Stewart 1490f8829a4aSRandall Stewart for (i = 0; i < SCTP_NUMBER_OF_MTU_SIZES; i++) { 1491f8829a4aSRandall Stewart if (cur_mtu < mtu_sizes[i]) { 1492f8829a4aSRandall Stewart /* no max_mtu is bigger than this one */ 1493f8829a4aSRandall Stewart return (mtu_sizes[i]); 1494f8829a4aSRandall Stewart } 1495f8829a4aSRandall Stewart } 1496f8829a4aSRandall Stewart /* here return the highest allowable */ 1497f8829a4aSRandall Stewart return (cur_mtu); 1498f8829a4aSRandall Stewart } 1499f8829a4aSRandall Stewart 1500f8829a4aSRandall Stewart 1501f8829a4aSRandall Stewart void 1502f8829a4aSRandall Stewart sctp_pathmtu_timer(struct sctp_inpcb *inp, 1503f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1504f8829a4aSRandall Stewart struct sctp_nets *net) 1505f8829a4aSRandall Stewart { 1506f8829a4aSRandall Stewart uint32_t next_mtu; 1507f8829a4aSRandall Stewart 1508f8829a4aSRandall Stewart /* restart the timer in any case */ 1509f8829a4aSRandall Stewart next_mtu = sctp_getnext_mtu(inp, net->mtu); 1510f8829a4aSRandall Stewart if (next_mtu <= net->mtu) { 1511f8829a4aSRandall Stewart /* nothing to do */ 1512f8829a4aSRandall Stewart return; 151317205eccSRandall Stewart } { 151417205eccSRandall Stewart uint32_t mtu; 151517205eccSRandall Stewart 151617205eccSRandall Stewart if ((net->src_addr_selected == 0) || 151717205eccSRandall Stewart (net->ro._s_addr == NULL) || 151817205eccSRandall Stewart (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { 1519ad81507eSRandall Stewart if ((net->ro._s_addr != NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { 152017205eccSRandall Stewart sctp_free_ifa(net->ro._s_addr); 152117205eccSRandall Stewart net->ro._s_addr = NULL; 152217205eccSRandall Stewart net->src_addr_selected = 0; 1523ad81507eSRandall Stewart } else if (net->ro._s_addr == NULL) { 152417205eccSRandall Stewart net->ro._s_addr = sctp_source_address_selection(inp, 152517205eccSRandall Stewart stcb, 152617205eccSRandall Stewart (sctp_route_t *) & net->ro, 152717205eccSRandall Stewart net, 0, stcb->asoc.vrf_id); 1528ad81507eSRandall Stewart } 152917205eccSRandall Stewart if (net->ro._s_addr) 153017205eccSRandall Stewart net->src_addr_selected = 1; 153117205eccSRandall Stewart } 153217205eccSRandall Stewart if (net->ro._s_addr) { 153317205eccSRandall Stewart mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt); 153417205eccSRandall Stewart if (mtu > next_mtu) { 1535f8829a4aSRandall Stewart net->mtu = next_mtu; 1536f8829a4aSRandall Stewart } 1537f8829a4aSRandall Stewart } 1538f8829a4aSRandall Stewart } 1539f8829a4aSRandall Stewart /* restart the timer */ 1540f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 1541f8829a4aSRandall Stewart } 1542f8829a4aSRandall Stewart 1543f8829a4aSRandall Stewart void 1544f8829a4aSRandall Stewart sctp_autoclose_timer(struct sctp_inpcb *inp, 1545f8829a4aSRandall Stewart struct sctp_tcb *stcb, 1546f8829a4aSRandall Stewart struct sctp_nets *net) 1547f8829a4aSRandall Stewart { 1548f8829a4aSRandall Stewart struct timeval tn, *tim_touse; 1549f8829a4aSRandall Stewart struct sctp_association *asoc; 1550f8829a4aSRandall Stewart int ticks_gone_by; 1551f8829a4aSRandall Stewart 15526e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&tn); 1553f8829a4aSRandall Stewart if (stcb->asoc.sctp_autoclose_ticks && 1554f8829a4aSRandall Stewart sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { 1555f8829a4aSRandall Stewart /* Auto close is on */ 1556f8829a4aSRandall Stewart asoc = &stcb->asoc; 1557f8829a4aSRandall Stewart /* pick the time to use */ 1558f8829a4aSRandall Stewart if (asoc->time_last_rcvd.tv_sec > 1559f8829a4aSRandall Stewart asoc->time_last_sent.tv_sec) { 1560f8829a4aSRandall Stewart tim_touse = &asoc->time_last_rcvd; 1561f8829a4aSRandall Stewart } else { 1562f8829a4aSRandall Stewart tim_touse = &asoc->time_last_sent; 1563f8829a4aSRandall Stewart } 1564f8829a4aSRandall Stewart /* Now has long enough transpired to autoclose? */ 1565f8829a4aSRandall Stewart ticks_gone_by = SEC_TO_TICKS(tn.tv_sec - tim_touse->tv_sec); 1566f8829a4aSRandall Stewart if ((ticks_gone_by > 0) && 1567f8829a4aSRandall Stewart (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) { 1568f8829a4aSRandall Stewart /* 1569f8829a4aSRandall Stewart * autoclose time has hit, call the output routine, 1570f8829a4aSRandall Stewart * which should do nothing just to be SURE we don't 1571f8829a4aSRandall Stewart * have hanging data. We can then safely check the 1572f8829a4aSRandall Stewart * queues and know that we are clear to send 1573f8829a4aSRandall Stewart * shutdown 1574f8829a4aSRandall Stewart */ 1575f8829a4aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR); 1576f8829a4aSRandall Stewart /* Are we clean? */ 1577f8829a4aSRandall Stewart if (TAILQ_EMPTY(&asoc->send_queue) && 1578f8829a4aSRandall Stewart TAILQ_EMPTY(&asoc->sent_queue)) { 1579f8829a4aSRandall Stewart /* 1580f8829a4aSRandall Stewart * there is nothing queued to send, so I'm 1581f8829a4aSRandall Stewart * done... 1582f8829a4aSRandall Stewart */ 1583f42a358aSRandall Stewart if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 1584f8829a4aSRandall Stewart /* only send SHUTDOWN 1st time thru */ 1585f8829a4aSRandall Stewart sctp_send_shutdown(stcb, stcb->asoc.primary_destination); 1586f42a358aSRandall Stewart if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 1587f42a358aSRandall Stewart (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 1588f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 1589f42a358aSRandall Stewart } 1590f42a358aSRandall Stewart asoc->state = SCTP_STATE_SHUTDOWN_SENT; 1591f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 1592f8829a4aSRandall Stewart stcb->sctp_ep, stcb, 1593f8829a4aSRandall Stewart asoc->primary_destination); 1594f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 1595f8829a4aSRandall Stewart stcb->sctp_ep, stcb, 1596f8829a4aSRandall Stewart asoc->primary_destination); 1597f8829a4aSRandall Stewart } 1598f8829a4aSRandall Stewart } 1599f8829a4aSRandall Stewart } else { 1600f8829a4aSRandall Stewart /* 1601f8829a4aSRandall Stewart * No auto close at this time, reset t-o to check 1602f8829a4aSRandall Stewart * later 1603f8829a4aSRandall Stewart */ 1604f8829a4aSRandall Stewart int tmp; 1605f8829a4aSRandall Stewart 1606f8829a4aSRandall Stewart /* fool the timer startup to use the time left */ 1607f8829a4aSRandall Stewart tmp = asoc->sctp_autoclose_ticks; 1608f8829a4aSRandall Stewart asoc->sctp_autoclose_ticks -= ticks_gone_by; 1609f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, 1610f8829a4aSRandall Stewart net); 1611f8829a4aSRandall Stewart /* restore the real tick value */ 1612f8829a4aSRandall Stewart asoc->sctp_autoclose_ticks = tmp; 1613f8829a4aSRandall Stewart } 1614f8829a4aSRandall Stewart } 1615f8829a4aSRandall Stewart } 1616f8829a4aSRandall Stewart 1617f8829a4aSRandall Stewart void 1618f8829a4aSRandall Stewart sctp_iterator_timer(struct sctp_iterator *it) 1619f8829a4aSRandall Stewart { 1620f8829a4aSRandall Stewart int iteration_count = 0; 162142551e99SRandall Stewart int inp_skip = 0; 1622f8829a4aSRandall Stewart 1623f8829a4aSRandall Stewart /* 1624f8829a4aSRandall Stewart * only one iterator can run at a time. This is the only way we can 1625f8829a4aSRandall Stewart * cleanly pull ep's from underneath all the running interators when 1626f8829a4aSRandall Stewart * a ep is freed. 1627f8829a4aSRandall Stewart */ 1628f8829a4aSRandall Stewart SCTP_ITERATOR_LOCK(); 1629f8829a4aSRandall Stewart if (it->inp == NULL) { 1630f8829a4aSRandall Stewart /* iterator is complete */ 1631f8829a4aSRandall Stewart done_with_iterator: 1632f8829a4aSRandall Stewart SCTP_ITERATOR_UNLOCK(); 1633f8829a4aSRandall Stewart SCTP_INP_INFO_WLOCK(); 163442551e99SRandall Stewart TAILQ_REMOVE(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr); 1635f8829a4aSRandall Stewart /* stopping the callout is not needed, in theory */ 1636f8829a4aSRandall Stewart SCTP_INP_INFO_WUNLOCK(); 16376e55db54SRandall Stewart (void)SCTP_OS_TIMER_STOP(&it->tmr.timer); 1638f8829a4aSRandall Stewart if (it->function_atend != NULL) { 1639f8829a4aSRandall Stewart (*it->function_atend) (it->pointer, it->val); 1640f8829a4aSRandall Stewart } 1641f8829a4aSRandall Stewart SCTP_FREE(it); 1642f8829a4aSRandall Stewart return; 1643f8829a4aSRandall Stewart } 1644f8829a4aSRandall Stewart select_a_new_ep: 1645f8829a4aSRandall Stewart SCTP_INP_WLOCK(it->inp); 1646f8829a4aSRandall Stewart while (((it->pcb_flags) && 1647f8829a4aSRandall Stewart ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || 1648f8829a4aSRandall Stewart ((it->pcb_features) && 1649f8829a4aSRandall Stewart ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) { 1650f8829a4aSRandall Stewart /* endpoint flags or features don't match, so keep looking */ 1651f8829a4aSRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 1652f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1653f8829a4aSRandall Stewart goto done_with_iterator; 1654f8829a4aSRandall Stewart } 1655f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1656f8829a4aSRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 1657f8829a4aSRandall Stewart if (it->inp == NULL) { 1658f8829a4aSRandall Stewart goto done_with_iterator; 1659f8829a4aSRandall Stewart } 1660f8829a4aSRandall Stewart SCTP_INP_WLOCK(it->inp); 1661f8829a4aSRandall Stewart } 1662f8829a4aSRandall Stewart if ((it->inp->inp_starting_point_for_iterator != NULL) && 1663f8829a4aSRandall Stewart (it->inp->inp_starting_point_for_iterator != it)) { 1664ad81507eSRandall Stewart SCTP_PRINTF("Iterator collision, waiting for one at %p\n", 1665e349e6b8SRuslan Ermilov it->inp); 1666f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1667f8829a4aSRandall Stewart goto start_timer_return; 1668f8829a4aSRandall Stewart } 1669f8829a4aSRandall Stewart /* mark the current iterator on the endpoint */ 1670f8829a4aSRandall Stewart it->inp->inp_starting_point_for_iterator = it; 1671f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1672f8829a4aSRandall Stewart SCTP_INP_RLOCK(it->inp); 1673f8829a4aSRandall Stewart /* now go through each assoc which is in the desired state */ 167442551e99SRandall Stewart if (it->done_current_ep == 0) { 167542551e99SRandall Stewart if (it->function_inp != NULL) 167642551e99SRandall Stewart inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val); 167742551e99SRandall Stewart it->done_current_ep = 1; 167842551e99SRandall Stewart } 1679f8829a4aSRandall Stewart if (it->stcb == NULL) { 1680f8829a4aSRandall Stewart /* run the per instance function */ 1681f8829a4aSRandall Stewart it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list); 1682f8829a4aSRandall Stewart } 1683f8829a4aSRandall Stewart SCTP_INP_RUNLOCK(it->inp); 168442551e99SRandall Stewart if ((inp_skip) || it->stcb == NULL) { 168542551e99SRandall Stewart if (it->function_inp_end != NULL) { 168642551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 168742551e99SRandall Stewart it->pointer, 168842551e99SRandall Stewart it->val); 168942551e99SRandall Stewart } 169042551e99SRandall Stewart goto no_stcb; 169142551e99SRandall Stewart } 1692f8829a4aSRandall Stewart if ((it->stcb) && 1693f8829a4aSRandall Stewart (it->stcb->asoc.stcb_starting_point_for_iterator == it)) { 1694f8829a4aSRandall Stewart it->stcb->asoc.stcb_starting_point_for_iterator = NULL; 1695f8829a4aSRandall Stewart } 1696f8829a4aSRandall Stewart while (it->stcb) { 1697f8829a4aSRandall Stewart SCTP_TCB_LOCK(it->stcb); 1698f8829a4aSRandall Stewart if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { 1699f8829a4aSRandall Stewart /* not in the right state... keep looking */ 1700f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1701f8829a4aSRandall Stewart goto next_assoc; 1702f8829a4aSRandall Stewart } 1703f8829a4aSRandall Stewart /* mark the current iterator on the assoc */ 1704f8829a4aSRandall Stewart it->stcb->asoc.stcb_starting_point_for_iterator = it; 1705f8829a4aSRandall Stewart /* see if we have limited out the iterator loop */ 1706f8829a4aSRandall Stewart iteration_count++; 1707f8829a4aSRandall Stewart if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) { 1708f8829a4aSRandall Stewart start_timer_return: 1709f8829a4aSRandall Stewart /* set a timer to continue this later */ 1710f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1711f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ITERATOR, 1712f8829a4aSRandall Stewart (struct sctp_inpcb *)it, NULL, NULL); 1713f8829a4aSRandall Stewart SCTP_ITERATOR_UNLOCK(); 1714f8829a4aSRandall Stewart return; 1715f8829a4aSRandall Stewart } 1716f8829a4aSRandall Stewart /* run function on this one */ 1717f8829a4aSRandall Stewart (*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val); 1718f8829a4aSRandall Stewart 1719f8829a4aSRandall Stewart /* 1720f8829a4aSRandall Stewart * we lie here, it really needs to have its own type but 1721f8829a4aSRandall Stewart * first I must verify that this won't effect things :-0 1722f8829a4aSRandall Stewart */ 1723f8829a4aSRandall Stewart if (it->no_chunk_output == 0) 1724f8829a4aSRandall Stewart sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3); 1725f8829a4aSRandall Stewart 1726f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1727f8829a4aSRandall Stewart next_assoc: 1728f8829a4aSRandall Stewart it->stcb = LIST_NEXT(it->stcb, sctp_tcblist); 172942551e99SRandall Stewart if (it->stcb == NULL) { 173042551e99SRandall Stewart if (it->function_inp_end != NULL) { 173142551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 173242551e99SRandall Stewart it->pointer, 173342551e99SRandall Stewart it->val); 1734f8829a4aSRandall Stewart } 173542551e99SRandall Stewart } 173642551e99SRandall Stewart } 173742551e99SRandall Stewart no_stcb: 1738f8829a4aSRandall Stewart /* done with all assocs on this endpoint, move on to next endpoint */ 173942551e99SRandall Stewart it->done_current_ep = 0; 1740f8829a4aSRandall Stewart SCTP_INP_WLOCK(it->inp); 1741f8829a4aSRandall Stewart it->inp->inp_starting_point_for_iterator = NULL; 1742f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(it->inp); 1743f8829a4aSRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 1744f8829a4aSRandall Stewart it->inp = NULL; 1745f8829a4aSRandall Stewart } else { 1746f8829a4aSRandall Stewart SCTP_INP_INFO_RLOCK(); 1747f8829a4aSRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 1748f8829a4aSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 1749f8829a4aSRandall Stewart } 1750f8829a4aSRandall Stewart if (it->inp == NULL) { 1751f8829a4aSRandall Stewart goto done_with_iterator; 1752f8829a4aSRandall Stewart } 1753f8829a4aSRandall Stewart goto select_a_new_ep; 1754f8829a4aSRandall Stewart } 1755