xref: /netbsd-src/sys/netinet/sctp_timer.c (revision 7f4592413ff580b0685f02f9694eeb3a1b0e9e7b)
18c2654abSrjs /*	$KAME: sctp_timer.c,v 1.30 2005/06/16 18:29:25 jinmei Exp $	*/
2*7f459241Sandvar /*	$NetBSD: sctp_timer.c,v 1.6 2022/02/16 22:00:56 andvar Exp $	*/
38c2654abSrjs 
48c2654abSrjs /*
58c2654abSrjs  * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
68c2654abSrjs  * All rights reserved.
78c2654abSrjs  *
88c2654abSrjs  * Redistribution and use in source and binary forms, with or without
98c2654abSrjs  * modification, are permitted provided that the following conditions
108c2654abSrjs  * are met:
118c2654abSrjs  * 1. Redistributions of source code must retain the above copyright
128c2654abSrjs  *    notice, this list of conditions and the following disclaimer.
138c2654abSrjs  * 2. Redistributions in binary form must reproduce the above copyright
148c2654abSrjs  *    notice, this list of conditions and the following disclaimer in the
158c2654abSrjs  *    documentation and/or other materials provided with the distribution.
168c2654abSrjs  * 3. Neither the name of the project nor the names of its contributors
178c2654abSrjs  *    may be used to endorse or promote products derived from this software
188c2654abSrjs  *    without specific prior written permission.
198c2654abSrjs  *
208c2654abSrjs  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
218c2654abSrjs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228c2654abSrjs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238c2654abSrjs  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
248c2654abSrjs  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
258c2654abSrjs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
268c2654abSrjs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
278c2654abSrjs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
288c2654abSrjs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
298c2654abSrjs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
308c2654abSrjs  * SUCH DAMAGE.
318c2654abSrjs  */
328c2654abSrjs #include <sys/cdefs.h>
33*7f459241Sandvar __KERNEL_RCSID(0, "$NetBSD: sctp_timer.c,v 1.6 2022/02/16 22:00:56 andvar Exp $");
348c2654abSrjs 
358c2654abSrjs #ifdef _KERNEL_OPT
368c2654abSrjs #include "opt_inet.h"
378c2654abSrjs #include "opt_sctp.h"
38a12c401aSrjs #include "opt_ipsec.h"
398c2654abSrjs #endif /* _KERNEL_OPT */
408c2654abSrjs 
418c2654abSrjs #include <sys/param.h>
428c2654abSrjs #include <sys/systm.h>
438c2654abSrjs #include <sys/malloc.h>
448c2654abSrjs #include <sys/mbuf.h>
458c2654abSrjs #include <sys/domain.h>
468c2654abSrjs #include <sys/protosw.h>
478c2654abSrjs #include <sys/socket.h>
488c2654abSrjs #include <sys/socketvar.h>
498c2654abSrjs #include <sys/proc.h>
508c2654abSrjs #include <sys/kernel.h>
518c2654abSrjs #include <sys/sysctl.h>
528c2654abSrjs #ifdef INET6
538c2654abSrjs #include <sys/domain.h>
548c2654abSrjs #endif
558c2654abSrjs 
568c2654abSrjs #include <machine/limits.h>
578c2654abSrjs 
588c2654abSrjs #include <net/if.h>
598c2654abSrjs #include <net/if_types.h>
608c2654abSrjs #include <net/route.h>
618c2654abSrjs #include <netinet/in.h>
628c2654abSrjs #include <netinet/in_systm.h>
638c2654abSrjs #define _IP_VHL
648c2654abSrjs #include <netinet/ip.h>
658c2654abSrjs #include <netinet/in_pcb.h>
668c2654abSrjs #include <netinet/in_var.h>
678c2654abSrjs #include <netinet/ip_var.h>
688c2654abSrjs 
698c2654abSrjs #ifdef INET6
708c2654abSrjs #include <netinet/ip6.h>
718c2654abSrjs #include <netinet6/ip6_var.h>
728c2654abSrjs #endif /* INET6 */
738c2654abSrjs 
748c2654abSrjs #include <netinet/sctp_pcb.h>
758c2654abSrjs 
768c2654abSrjs #ifdef IPSEC
77505ea976Srjs #include <netipsec/ipsec.h>
78505ea976Srjs #include <netipsec/key.h>
798c2654abSrjs #endif /* IPSEC */
808c2654abSrjs #ifdef INET6
818c2654abSrjs #include <netinet6/sctp6_var.h>
828c2654abSrjs #endif
838c2654abSrjs #include <netinet/sctp_var.h>
848c2654abSrjs #include <netinet/sctp_timer.h>
858c2654abSrjs #include <netinet/sctputil.h>
868c2654abSrjs #include <netinet/sctp_output.h>
878c2654abSrjs #include <netinet/sctp_hashdriver.h>
888c2654abSrjs #include <netinet/sctp_header.h>
898c2654abSrjs #include <netinet/sctp_indata.h>
908c2654abSrjs #include <netinet/sctp_asconf.h>
918c2654abSrjs 
928c2654abSrjs #include <netinet/sctp.h>
938c2654abSrjs #include <netinet/sctp_uio.h>
948c2654abSrjs 
958c2654abSrjs #ifdef SCTP_DEBUG
968c2654abSrjs extern u_int32_t sctp_debug_on;
978c2654abSrjs #endif /* SCTP_DEBUG */
988c2654abSrjs 
998c2654abSrjs void
sctp_audit_retranmission_queue(struct sctp_association * asoc)1008c2654abSrjs sctp_audit_retranmission_queue(struct sctp_association *asoc)
1018c2654abSrjs {
1028c2654abSrjs 	struct sctp_tmit_chunk *chk;
1038c2654abSrjs 
1048c2654abSrjs #ifdef SCTP_DEBUG
1058c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
1068c2654abSrjs 		printf("Audit invoked on send queue cnt:%d onqueue:%d\n",
1078c2654abSrjs 		    asoc->sent_queue_retran_cnt,
1088c2654abSrjs 		    asoc->sent_queue_cnt);
1098c2654abSrjs 	}
1108c2654abSrjs #endif /* SCTP_DEBUG */
1118c2654abSrjs 	asoc->sent_queue_retran_cnt = 0;
1128c2654abSrjs 	asoc->sent_queue_cnt = 0;
1138c2654abSrjs 	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
1148c2654abSrjs 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
1158c2654abSrjs 			asoc->sent_queue_retran_cnt++;
1168c2654abSrjs 		}
1178c2654abSrjs 		asoc->sent_queue_cnt++;
1188c2654abSrjs 	}
1198c2654abSrjs 	TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
1208c2654abSrjs 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
1218c2654abSrjs 			asoc->sent_queue_retran_cnt++;
1228c2654abSrjs 		}
1238c2654abSrjs 	}
1248c2654abSrjs #ifdef SCTP_DEBUG
1258c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
1268c2654abSrjs 		printf("Audit completes retran:%d onqueue:%d\n",
1278c2654abSrjs 		    asoc->sent_queue_retran_cnt,
1288c2654abSrjs 		    asoc->sent_queue_cnt);
1298c2654abSrjs 	}
1308c2654abSrjs #endif /* SCTP_DEBUG */
1318c2654abSrjs }
1328c2654abSrjs 
1338c2654abSrjs int
sctp_threshold_management(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net,uint16_t threshold)1348c2654abSrjs sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1358c2654abSrjs     struct sctp_nets *net, uint16_t threshold)
1368c2654abSrjs {
1378c2654abSrjs 	if (net) {
1388c2654abSrjs 		net->error_count++;
1398c2654abSrjs #ifdef SCTP_DEBUG
1408c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
1418c2654abSrjs 			printf("Error count for %p now %d thresh:%d\n",
1428c2654abSrjs 			    net, net->error_count,
1438c2654abSrjs 			    net->failure_threshold);
1448c2654abSrjs 		}
1458c2654abSrjs #endif /* SCTP_DEBUG */
1468c2654abSrjs 		if (net->error_count >= net->failure_threshold) {
1478c2654abSrjs 			/* We had a threshold failure */
1488c2654abSrjs 			if (net->dest_state & SCTP_ADDR_REACHABLE) {
1498c2654abSrjs 				net->dest_state &= ~SCTP_ADDR_REACHABLE;
1508c2654abSrjs 				net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
1518c2654abSrjs 				if (net == stcb->asoc.primary_destination) {
1528c2654abSrjs 					net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
1538c2654abSrjs 				}
1548c2654abSrjs 				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
1558c2654abSrjs 						stcb,
1568c2654abSrjs 						SCTP_FAILED_THRESHOLD,
1578c2654abSrjs 						(void *)net);
1588c2654abSrjs 			}
1598c2654abSrjs 		}
1608c2654abSrjs 		/*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE
1618c2654abSrjs 		 *********ROUTING CODE
1628c2654abSrjs 		 */
1638c2654abSrjs 		/*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE
1648c2654abSrjs 		 *********ROUTING CODE
1658c2654abSrjs 		 */
1668c2654abSrjs 	}
1678c2654abSrjs 	if (stcb == NULL)
1688c2654abSrjs 		return (0);
1698c2654abSrjs 
1708c2654abSrjs 	if (net) {
1718c2654abSrjs 		if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) {
1728c2654abSrjs 			stcb->asoc.overall_error_count++;
1738c2654abSrjs 		}
1748c2654abSrjs 	} else {
1758c2654abSrjs 		stcb->asoc.overall_error_count++;
1768c2654abSrjs 	}
1778c2654abSrjs #ifdef SCTP_DEBUG
1788c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
1798c2654abSrjs 		printf("Overall error count for %p now %d thresh:%u state:%x\n",
1808c2654abSrjs 		       &stcb->asoc,
1818c2654abSrjs 		       stcb->asoc.overall_error_count,
1828c2654abSrjs 		       (u_int)threshold,
1838c2654abSrjs 		       ((net == NULL) ? (u_int)0 : (u_int)net->dest_state));
1848c2654abSrjs 	}
1858c2654abSrjs #endif /* SCTP_DEBUG */
1868c2654abSrjs 	/* We specifically do not do >= to give the assoc one more
1878c2654abSrjs 	 * change before we fail it.
1888c2654abSrjs 	 */
1898c2654abSrjs 	if (stcb->asoc.overall_error_count > threshold) {
1908c2654abSrjs 		/* Abort notification sends a ULP notify */
1918c2654abSrjs 		struct mbuf *oper;
1928c2654abSrjs 		MGET(oper, M_DONTWAIT, MT_DATA);
1938c2654abSrjs 		if (oper) {
1948c2654abSrjs 			struct sctp_paramhdr *ph;
1958c2654abSrjs 			u_int32_t *ippp;
1968c2654abSrjs 
1978c2654abSrjs 			oper->m_len = sizeof(struct sctp_paramhdr) +
1988c2654abSrjs 			    sizeof(*ippp);
1998c2654abSrjs 			ph = mtod(oper, struct sctp_paramhdr *);
2008c2654abSrjs 			ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
2018c2654abSrjs 			ph->param_length = htons(oper->m_len);
2028c2654abSrjs 			ippp = (u_int32_t *)(ph + 1);
2038c2654abSrjs 			*ippp = htonl(0x40000001);
2048c2654abSrjs 		}
2058c2654abSrjs 		sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper);
2068c2654abSrjs 		return (1);
2078c2654abSrjs 	}
2088c2654abSrjs 	return (0);
2098c2654abSrjs }
2108c2654abSrjs 
2118c2654abSrjs struct sctp_nets *
sctp_find_alternate_net(struct sctp_tcb * stcb,struct sctp_nets * net)2128c2654abSrjs sctp_find_alternate_net(struct sctp_tcb *stcb,
2138c2654abSrjs 			struct sctp_nets *net)
2148c2654abSrjs {
2158c2654abSrjs 	/* Find and return an alternate network if possible */
2168c2654abSrjs 	struct sctp_nets *alt, *mnet;
2178c2654abSrjs 	struct rtentry *rt;
2188c2654abSrjs 	int once;
2198c2654abSrjs 
2208c2654abSrjs 	if (stcb->asoc.numnets == 1) {
2218c2654abSrjs 		/* No others but net */
2228c2654abSrjs 		return (TAILQ_FIRST(&stcb->asoc.nets));
2238c2654abSrjs 	}
2248c2654abSrjs 	mnet = net;
2258c2654abSrjs 	once = 0;
2268c2654abSrjs 
2278c2654abSrjs 	if (mnet == NULL) {
2288c2654abSrjs 		mnet = TAILQ_FIRST(&stcb->asoc.nets);
2298c2654abSrjs 	}
2308c2654abSrjs 	do {
2318c2654abSrjs 		alt = TAILQ_NEXT(mnet, sctp_next);
2328c2654abSrjs 		if (alt == NULL) {
2338c2654abSrjs 			once++;
2348c2654abSrjs 			if (once > 1) {
2358c2654abSrjs 				break;
2368c2654abSrjs 			}
2378c2654abSrjs 			alt = TAILQ_FIRST(&stcb->asoc.nets);
2388c2654abSrjs 		}
2398c2654abSrjs 		rt = rtcache_validate(&alt->ro);
2408c2654abSrjs 		if (rt == NULL) {
2418c2654abSrjs 			alt->src_addr_selected = 0;
2428c2654abSrjs 		}
2438c2654abSrjs 		if (
2448c2654abSrjs 			((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) &&
2458c2654abSrjs 			(rt != NULL) &&
2468c2654abSrjs 			(!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))
2478c2654abSrjs 			) {
2488c2654abSrjs 			/* Found a reachable address */
2494c25fb2fSozaki-r 			rtcache_unref(rt, &alt->ro);
2508c2654abSrjs 			break;
2518c2654abSrjs 		}
2524c25fb2fSozaki-r 		rtcache_unref(rt, &alt->ro);
2538c2654abSrjs 		mnet = alt;
2548c2654abSrjs 	} while (alt != NULL);
2558c2654abSrjs 
2568c2654abSrjs 	if (alt == NULL) {
2578c2654abSrjs 		/* Case where NO insv network exists (dormant state) */
2588c2654abSrjs 		/* we rotate destinations */
2598c2654abSrjs 		once = 0;
2608c2654abSrjs 		mnet = net;
2618c2654abSrjs 		do {
2628c2654abSrjs 			alt = TAILQ_NEXT(mnet, sctp_next);
2638c2654abSrjs 			if (alt == NULL) {
2648c2654abSrjs 				once++;
2658c2654abSrjs 				if (once > 1) {
2668c2654abSrjs 					break;
2678c2654abSrjs 				}
2688c2654abSrjs 				alt = TAILQ_FIRST(&stcb->asoc.nets);
2698c2654abSrjs 			}
2708c2654abSrjs 			if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) &&
2718c2654abSrjs 			    (alt != net)) {
2728c2654abSrjs 				/* Found an alternate address */
2738c2654abSrjs 				break;
2748c2654abSrjs 			}
2758c2654abSrjs 			mnet = alt;
2768c2654abSrjs 		} while (alt != NULL);
2778c2654abSrjs 	}
2788c2654abSrjs 	if (alt == NULL) {
2798c2654abSrjs 		return (net);
2808c2654abSrjs 	}
2818c2654abSrjs 	return (alt);
2828c2654abSrjs }
2838c2654abSrjs 
2848c2654abSrjs static void
sctp_backoff_on_timeout(struct sctp_tcb * stcb,struct sctp_nets * net,int win_probe,int num_marked)2858c2654abSrjs sctp_backoff_on_timeout(struct sctp_tcb *stcb,
2868c2654abSrjs 			struct sctp_nets *net,
2878c2654abSrjs 			int win_probe,
2888c2654abSrjs 			int num_marked)
2898c2654abSrjs {
2908c2654abSrjs #ifdef SCTP_DEBUG
2918c2654abSrjs 	int oldRTO;
2928c2654abSrjs 
2938c2654abSrjs 	oldRTO = net->RTO;
2948c2654abSrjs #endif /* SCTP_DEBUG */
2958c2654abSrjs 	net->RTO <<= 1;
2968c2654abSrjs #ifdef SCTP_DEBUG
2978c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
2988c2654abSrjs 		printf("Timer doubles from %d ms -to-> %d ms\n",
2998c2654abSrjs 		       oldRTO, net->RTO);
3008c2654abSrjs 	}
3018c2654abSrjs #endif /* SCTP_DEBUG */
3028c2654abSrjs 
3038c2654abSrjs 	if (net->RTO > stcb->asoc.maxrto) {
3048c2654abSrjs 		net->RTO = stcb->asoc.maxrto;
3058c2654abSrjs #ifdef SCTP_DEBUG
3068c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
3078c2654abSrjs 			printf("Growth capped by maxrto %d\n",
3088c2654abSrjs 			       net->RTO);
3098c2654abSrjs 		}
3108c2654abSrjs #endif /* SCTP_DEBUG */
3118c2654abSrjs 	}
3128c2654abSrjs 
3138c2654abSrjs 
3148c2654abSrjs 	if ((win_probe == 0) && num_marked) {
3158c2654abSrjs 		/* We don't apply penalty to window probe scenarios */
3168c2654abSrjs #ifdef SCTP_CWND_LOGGING
3178c2654abSrjs 		int old_cwnd=net->cwnd;
3188c2654abSrjs #endif
3198c2654abSrjs 		net->ssthresh = net->cwnd >> 1;
3208c2654abSrjs 		if (net->ssthresh < (net->mtu << 1)) {
3218c2654abSrjs 			net->ssthresh = (net->mtu << 1);
3228c2654abSrjs 		}
3238c2654abSrjs 		net->cwnd = net->mtu;
3248c2654abSrjs 		/* floor of 1 mtu */
3258c2654abSrjs 		if (net->cwnd < net->mtu)
3268c2654abSrjs 			net->cwnd = net->mtu;
3278c2654abSrjs #ifdef SCTP_CWND_LOGGING
3288c2654abSrjs 		sctp_log_cwnd(net, net->cwnd-old_cwnd, SCTP_CWND_LOG_FROM_RTX);
3298c2654abSrjs #endif
3308c2654abSrjs 
3318c2654abSrjs 		net->partial_bytes_acked = 0;
3328c2654abSrjs #ifdef SCTP_DEBUG
3338c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
3348c2654abSrjs 			printf("collapse cwnd to 1MTU ssthresh to %d\n",
3358c2654abSrjs 			       net->ssthresh);
3368c2654abSrjs 		}
3378c2654abSrjs #endif
3388c2654abSrjs 
3398c2654abSrjs 	}
3408c2654abSrjs }
3418c2654abSrjs 
3428c2654abSrjs 
3438c2654abSrjs static int
sctp_mark_all_for_resend(struct sctp_tcb * stcb,struct sctp_nets * net,struct sctp_nets * alt,int * num_marked)3448c2654abSrjs sctp_mark_all_for_resend(struct sctp_tcb *stcb,
3458c2654abSrjs 			 struct sctp_nets *net,
3468c2654abSrjs 			 struct sctp_nets *alt,
3478c2654abSrjs 			 int *num_marked)
3488c2654abSrjs {
3498c2654abSrjs 
3508c2654abSrjs 	/*
3518c2654abSrjs 	 * Mark all chunks (well not all) that were sent to *net for retransmission.
3528c2654abSrjs 	 * Move them to alt for there destination as well... We only
3538c2654abSrjs 	 * mark chunks that have been outstanding long enough to have
3548c2654abSrjs 	 * received feed-back.
3558c2654abSrjs 	 */
3568c2654abSrjs 	struct sctp_tmit_chunk *chk, *tp2;
3578c2654abSrjs 	struct sctp_nets *lnets;
3588c2654abSrjs 	struct timeval now, min_wait, tv;
3598c2654abSrjs 	int cur_rto;
3608c2654abSrjs 	int win_probes, non_win_probes, orig_rwnd, audit_tf, num_mk, fir;
3618c2654abSrjs 	unsigned int cnt_mk;
3628c2654abSrjs 	u_int32_t orig_flight;
3638c2654abSrjs #ifdef SCTP_FR_LOGGING
3648c2654abSrjs 	u_int32_t tsnfirst, tsnlast;
3658c2654abSrjs #endif
3668c2654abSrjs 
3678c2654abSrjs 	/* none in flight now */
3688c2654abSrjs 	audit_tf = 0;
3698c2654abSrjs 	fir=0;
3708c2654abSrjs 	/* figure out how long a data chunk must be pending
3718c2654abSrjs 	 * before we can mark it ..
3728c2654abSrjs 	 */
3738c2654abSrjs 	SCTP_GETTIME_TIMEVAL(&now);
3748c2654abSrjs 	/* get cur rto in micro-seconds */
3758c2654abSrjs 	cur_rto = (((net->lastsa >> 2) + net->lastsv) >> 1);
3768c2654abSrjs #ifdef SCTP_FR_LOGGING
3778c2654abSrjs 	sctp_log_fr(cur_rto, 0, 0, SCTP_FR_T3_MARK_TIME);
3788c2654abSrjs #endif
3798c2654abSrjs 	cur_rto *= 1000;
3808c2654abSrjs #ifdef SCTP_FR_LOGGING
3818c2654abSrjs 	sctp_log_fr(cur_rto, 0, 0, SCTP_FR_T3_MARK_TIME);
3828c2654abSrjs #endif
3838c2654abSrjs 	tv.tv_sec = cur_rto / 1000000;
3848c2654abSrjs 	tv.tv_usec = cur_rto % 1000000;
3858c2654abSrjs #ifndef __FreeBSD__
3868c2654abSrjs 	timersub(&now, &tv, &min_wait);
3878c2654abSrjs #else
3888c2654abSrjs 	min_wait = now;
3898c2654abSrjs 	timevalsub(&min_wait, &tv);
3908c2654abSrjs #endif
3918c2654abSrjs 	if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
3928c2654abSrjs 		/*
3938c2654abSrjs 		 * if we hit here, we don't
3948c2654abSrjs 		 * have enough seconds on the clock to account
3958c2654abSrjs 		 * for the RTO. We just let the lower seconds
3968c2654abSrjs 		 * be the bounds and don't worry about it. This
3978c2654abSrjs 		 * may mean we will mark a lot more than we should.
3988c2654abSrjs 		 */
3998c2654abSrjs 		min_wait.tv_sec = min_wait.tv_usec = 0;
4008c2654abSrjs 	}
4018c2654abSrjs #ifdef SCTP_FR_LOGGING
4028c2654abSrjs 	sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME);
4038c2654abSrjs 	sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME);
4048c2654abSrjs #endif
4058c2654abSrjs 	if (stcb->asoc.total_flight >= net->flight_size) {
4068c2654abSrjs 		stcb->asoc.total_flight -= net->flight_size;
4078c2654abSrjs 	} else {
4088c2654abSrjs 		audit_tf = 1;
4098c2654abSrjs 		stcb->asoc.total_flight = 0;
4108c2654abSrjs 	}
4118c2654abSrjs         /* Our rwnd will be incorrect here since we are not adding
4128c2654abSrjs 	 * back the cnt * mbuf but we will fix that down below.
4138c2654abSrjs 	 */
4148c2654abSrjs 	orig_rwnd = stcb->asoc.peers_rwnd;
4158c2654abSrjs 	orig_flight = net->flight_size;
4168c2654abSrjs 	stcb->asoc.peers_rwnd += net->flight_size;
4178c2654abSrjs 	net->flight_size = 0;
4188c2654abSrjs 	net->rto_pending = 0;
4198c2654abSrjs 	net->fast_retran_ip= 0;
4208c2654abSrjs 	win_probes = non_win_probes = 0;
4218c2654abSrjs #ifdef SCTP_DEBUG
4228c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
4238c2654abSrjs 		printf("Marking ALL un-acked for retransmission at t3-timeout\n");
4248c2654abSrjs 	}
4258c2654abSrjs #endif /* SCTP_DEBUG */
4268c2654abSrjs 	/* Now on to each chunk */
4278c2654abSrjs 	num_mk = cnt_mk = 0;
4288c2654abSrjs #ifdef SCTP_FR_LOGGING
4298c2654abSrjs 	tsnlast = tsnfirst = 0;
4308c2654abSrjs #endif
4318c2654abSrjs 	chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
4328c2654abSrjs 	for (;chk != NULL; chk = tp2) {
4338c2654abSrjs 		tp2 = TAILQ_NEXT(chk, sctp_next);
4348c2654abSrjs 		if ((compare_with_wrap(stcb->asoc.last_acked_seq,
4358c2654abSrjs 				       chk->rec.data.TSN_seq,
4368c2654abSrjs 				       MAX_TSN)) ||
4378c2654abSrjs 		    (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) {
4388c2654abSrjs 			/* Strange case our list got out of order? */
4398c2654abSrjs 			printf("Our list is out of order?\n");
4408c2654abSrjs 			TAILQ_REMOVE(&stcb->asoc.sent_queue, chk, sctp_next);
4418c2654abSrjs 			if (chk->data) {
4428c2654abSrjs 				sctp_release_pr_sctp_chunk(stcb, chk, 0xffff,
4438c2654abSrjs 				    &stcb->asoc.sent_queue);
4448c2654abSrjs 				if (chk->flags & SCTP_PR_SCTP_BUFFER) {
4458c2654abSrjs 					stcb->asoc.sent_queue_cnt_removeable--;
4468c2654abSrjs 				}
4478c2654abSrjs 			}
4488c2654abSrjs 			stcb->asoc.sent_queue_cnt--;
4498c2654abSrjs 			sctp_free_remote_addr(chk->whoTo);
4508c2654abSrjs 			sctppcbinfo.ipi_count_chunk--;
4518c2654abSrjs 			if ((int)sctppcbinfo.ipi_count_chunk < 0) {
4528c2654abSrjs 				panic("Chunk count is going negative");
4538c2654abSrjs 			}
4548c2654abSrjs 			SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
4558c2654abSrjs 			sctppcbinfo.ipi_gencnt_chunk++;
4568c2654abSrjs 			continue;
4578c2654abSrjs 		}
4588c2654abSrjs 		if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) {
4598c2654abSrjs 			/* found one to mark:
4608c2654abSrjs 			 * If it is less than DATAGRAM_ACKED it MUST
4618c2654abSrjs 			 * not be a skipped or marked TSN but instead
4628c2654abSrjs 			 * one that is either already set for retransmission OR
4638c2654abSrjs 			 * one that needs retransmission.
4648c2654abSrjs 			 */
4658c2654abSrjs 
4668c2654abSrjs 			/* validate its been outstanding long enough */
4678c2654abSrjs #ifdef SCTP_FR_LOGGING
4688c2654abSrjs 			sctp_log_fr(chk->rec.data.TSN_seq,
4698c2654abSrjs 				    chk->sent_rcv_time.tv_sec,
4708c2654abSrjs 				    chk->sent_rcv_time.tv_usec,
4718c2654abSrjs 				    SCTP_FR_T3_MARK_TIME);
4728c2654abSrjs #endif
4738c2654abSrjs 			if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) {
4748c2654abSrjs 				/* we have reached a chunk that was sent some
4758c2654abSrjs 				 * seconds past our min.. forget it we will
4768c2654abSrjs 				 * find no more to send.
4778c2654abSrjs 				 */
4788c2654abSrjs #ifdef SCTP_FR_LOGGING
4798c2654abSrjs 				sctp_log_fr(0,
4808c2654abSrjs 					    chk->sent_rcv_time.tv_sec,
4818c2654abSrjs 					    chk->sent_rcv_time.tv_usec,
4828c2654abSrjs 					    SCTP_FR_T3_STOPPED);
4838c2654abSrjs #endif
4848c2654abSrjs 				continue;
4858c2654abSrjs 			} else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) {
4868c2654abSrjs 				/* we must look at the micro seconds to know.
4878c2654abSrjs 				 */
4888c2654abSrjs 				if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
4898c2654abSrjs 					/* ok it was sent after our boundary time. */
4908c2654abSrjs #ifdef SCTP_FR_LOGGING
4918c2654abSrjs 					sctp_log_fr(0,
4928c2654abSrjs 						    chk->sent_rcv_time.tv_sec,
4938c2654abSrjs 						    chk->sent_rcv_time.tv_usec,
4948c2654abSrjs 						    SCTP_FR_T3_STOPPED);
4958c2654abSrjs #endif
4968c2654abSrjs 					continue;
4978c2654abSrjs 				}
4988c2654abSrjs 			}
4998c2654abSrjs 			if (stcb->asoc.total_flight_count > 0) {
5008c2654abSrjs 				stcb->asoc.total_flight_count--;
5018c2654abSrjs 			}
5028c2654abSrjs 			if ((chk->flags & (SCTP_PR_SCTP_ENABLED|SCTP_PR_SCTP_BUFFER)) == SCTP_PR_SCTP_ENABLED) {
5038c2654abSrjs 				/* Is it expired? */
5048c2654abSrjs 				if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) ||
5058c2654abSrjs 				    ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) &&
5068c2654abSrjs 				     (now.tv_usec > chk->rec.data.timetodrop.tv_usec))) {
5078c2654abSrjs 					/* Yes so drop it */
5088c2654abSrjs 					if (chk->data) {
5098c2654abSrjs 						sctp_release_pr_sctp_chunk(stcb,
5108c2654abSrjs 						    chk,
5118c2654abSrjs 						    (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT),
5128c2654abSrjs 						    &stcb->asoc.sent_queue);
5138c2654abSrjs 					}
5148c2654abSrjs 				}
5158c2654abSrjs 				continue;
5168c2654abSrjs 			}
5178c2654abSrjs 			if (chk->sent != SCTP_DATAGRAM_RESEND) {
5188c2654abSrjs  				stcb->asoc.sent_queue_retran_cnt++;
5198c2654abSrjs  				num_mk++;
5208c2654abSrjs 				if (fir == 0) {
5218c2654abSrjs 					fir = 1;
5228c2654abSrjs #ifdef SCTP_DEBUG
5238c2654abSrjs 					if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
5248c2654abSrjs 						printf("First TSN marked was %x\n",
5258c2654abSrjs 						       chk->rec.data.TSN_seq);
5268c2654abSrjs 					}
5278c2654abSrjs #endif
5288c2654abSrjs #ifdef SCTP_FR_LOGGING
5298c2654abSrjs 					tsnfirst = chk->rec.data.TSN_seq;
5308c2654abSrjs #endif
5318c2654abSrjs 				}
5328c2654abSrjs #ifdef SCTP_FR_LOGGING
5338c2654abSrjs 				tsnlast = chk->rec.data.TSN_seq;
5348c2654abSrjs 				sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
5358c2654abSrjs 					    0, SCTP_FR_T3_MARKED);
5368c2654abSrjs 
5378c2654abSrjs #endif
5388c2654abSrjs 			}
5398c2654abSrjs 			chk->sent = SCTP_DATAGRAM_RESEND;
5408c2654abSrjs 			/* reset the TSN for striking and other FR stuff */
5418c2654abSrjs 			chk->rec.data.doing_fast_retransmit = 0;
5428c2654abSrjs #ifdef SCTP_DEBUG
5438c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_TIMER3) {
5448c2654abSrjs 				printf("mark TSN:%x for retransmission\n", chk->rec.data.TSN_seq);
5458c2654abSrjs 			}
5468c2654abSrjs #endif /* SCTP_DEBUG */
5478c2654abSrjs 			/* Clear any time so NO RTT is being done */
5488c2654abSrjs 			chk->do_rtt = 0;
5498c2654abSrjs 			/* Bump up the count */
5508c2654abSrjs 			if (compare_with_wrap(chk->rec.data.TSN_seq,
5518c2654abSrjs 					      stcb->asoc.t3timeout_highest_marked,
5528c2654abSrjs 					      MAX_TSN)) {
5538c2654abSrjs 				/* TSN_seq > than t3timeout so update */
5548c2654abSrjs 				stcb->asoc.t3timeout_highest_marked = chk->rec.data.TSN_seq;
5558c2654abSrjs 			}
5568c2654abSrjs 			if (alt != net) {
5578c2654abSrjs 				sctp_free_remote_addr(chk->whoTo);
5588c2654abSrjs 				chk->whoTo = alt;
5598c2654abSrjs 				alt->ref_count++;
5608c2654abSrjs 			}
5618c2654abSrjs 			if ((chk->rec.data.state_flags & SCTP_WINDOW_PROBE) !=
5628c2654abSrjs 			    SCTP_WINDOW_PROBE) {
5638c2654abSrjs 				non_win_probes++;
5648c2654abSrjs 			} else {
5658c2654abSrjs 				chk->rec.data.state_flags &= ~SCTP_WINDOW_PROBE;
5668c2654abSrjs 				win_probes++;
5678c2654abSrjs 			}
5688c2654abSrjs 		}
5698c2654abSrjs 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
5708c2654abSrjs 			cnt_mk++;
5718c2654abSrjs 		}
5728c2654abSrjs 	}
5738c2654abSrjs 
5748c2654abSrjs #ifdef SCTP_FR_LOGGING
5758c2654abSrjs 	sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT);
5768c2654abSrjs #endif
5778c2654abSrjs 	/* compensate for the number we marked */
5788c2654abSrjs 	stcb->asoc.peers_rwnd += (num_mk /* * sizeof(struct mbuf)*/);
5798c2654abSrjs 
5808c2654abSrjs #ifdef SCTP_DEBUG
5818c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
5828c2654abSrjs 		if (num_mk) {
5838c2654abSrjs #ifdef SCTP_FR_LOGGING
5848c2654abSrjs 			printf("LAST TSN marked was %x\n", tsnlast);
5858c2654abSrjs #endif
5868c2654abSrjs 			printf("Num marked for retransmission was %d peer-rwd:%ld\n",
5878c2654abSrjs 			       num_mk, (u_long)stcb->asoc.peers_rwnd);
5888c2654abSrjs #ifdef SCTP_FR_LOGGING
5898c2654abSrjs 			printf("LAST TSN marked was %x\n", tsnlast);
5908c2654abSrjs #endif
5918c2654abSrjs 			printf("Num marked for retransmission was %d peer-rwd:%d\n",
5928c2654abSrjs 			       num_mk,
5938c2654abSrjs 			       (int)stcb->asoc.peers_rwnd
5948c2654abSrjs 				);
5958c2654abSrjs 		}
5968c2654abSrjs 	}
5978c2654abSrjs #endif
5988c2654abSrjs 	*num_marked = num_mk;
5998c2654abSrjs 	if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) {
6008c2654abSrjs 		printf("Local Audit says there are %d for retran asoc cnt:%d\n",
6018c2654abSrjs 		       cnt_mk, stcb->asoc.sent_queue_retran_cnt);
6028c2654abSrjs #ifndef SCTP_AUDITING_ENABLED
6038c2654abSrjs 		stcb->asoc.sent_queue_retran_cnt = cnt_mk;
6048c2654abSrjs #endif
6058c2654abSrjs 	}
6068c2654abSrjs #ifdef SCTP_DEBUG
6078c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_TIMER3) {
6088c2654abSrjs 		printf("**************************\n");
6098c2654abSrjs 	}
6108c2654abSrjs #endif /* SCTP_DEBUG */
6118c2654abSrjs 
6128c2654abSrjs 	/* Now check for a ECN Echo that may be stranded */
6138c2654abSrjs 	TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
6148c2654abSrjs 		if ((chk->whoTo == net) &&
6158c2654abSrjs 		    (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
6168c2654abSrjs 			sctp_free_remote_addr(chk->whoTo);
6178c2654abSrjs 			chk->whoTo = alt;
6188c2654abSrjs 			if (chk->sent != SCTP_DATAGRAM_RESEND) {
6198c2654abSrjs 				chk->sent = SCTP_DATAGRAM_RESEND;
6208c2654abSrjs 				stcb->asoc.sent_queue_retran_cnt++;
6218c2654abSrjs 			}
6228c2654abSrjs 			alt->ref_count++;
6238c2654abSrjs 		}
6248c2654abSrjs 	}
6258c2654abSrjs 	if ((orig_rwnd == 0) && (stcb->asoc.total_flight == 0) &&
6268c2654abSrjs 	    (orig_flight <= net->mtu)) {
6278c2654abSrjs 		/*
6288c2654abSrjs 		 * If the LAST packet sent was not acked and our rwnd is 0
6298c2654abSrjs 		 * then we are in a win-probe state.
6308c2654abSrjs 		 */
6318c2654abSrjs 		win_probes = 1;
6328c2654abSrjs 		non_win_probes = 0;
6338c2654abSrjs #ifdef SCTP_DEBUG
6348c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
6358c2654abSrjs 			printf("WIN_PROBE set via o_rwnd=0 tf=0 and all:%d fit in mtu:%d\n",
6368c2654abSrjs 			       orig_flight, net->mtu);
6378c2654abSrjs 		}
6388c2654abSrjs #endif
6398c2654abSrjs 	}
6408c2654abSrjs 
6418c2654abSrjs 	if (audit_tf) {
6428c2654abSrjs #ifdef SCTP_DEBUG
6438c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
6448c2654abSrjs 			printf("Audit total flight due to negative value net:%p\n",
6458c2654abSrjs 			    net);
6468c2654abSrjs 		}
6478c2654abSrjs #endif /* SCTP_DEBUG */
6488c2654abSrjs 		stcb->asoc.total_flight = 0;
6498c2654abSrjs 		stcb->asoc.total_flight_count = 0;
6508c2654abSrjs 		/* Clear all networks flight size */
6518c2654abSrjs 		TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) {
6528c2654abSrjs 			lnets->flight_size = 0;
6538c2654abSrjs #ifdef SCTP_DEBUG
6548c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
6558c2654abSrjs 				printf("Net:%p c-f cwnd:%d ssthresh:%d\n",
6568c2654abSrjs 				    lnets, lnets->cwnd, lnets->ssthresh);
6578c2654abSrjs 			}
6588c2654abSrjs #endif /* SCTP_DEBUG */
6598c2654abSrjs 		}
6608c2654abSrjs 		TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
6618c2654abSrjs 			if (chk->sent < SCTP_DATAGRAM_RESEND) {
6628c2654abSrjs 				stcb->asoc.total_flight += chk->book_size;
6638c2654abSrjs 				chk->whoTo->flight_size += chk->book_size;
6648c2654abSrjs 				stcb->asoc.total_flight_count++;
6658c2654abSrjs 			}
6668c2654abSrjs 		}
6678c2654abSrjs 	}
6688c2654abSrjs 	/* Setup the ecn nonce re-sync point. We
6698c2654abSrjs 	 * do this since retranmissions are NOT
6708c2654abSrjs 	 * setup for ECN. This means that do to
6718c2654abSrjs 	 * Karn's rule, we don't know the total
6728c2654abSrjs 	 * of the peers ecn bits.
6738c2654abSrjs 	 */
6748c2654abSrjs 	chk = TAILQ_FIRST(&stcb->asoc.send_queue);
6758c2654abSrjs 	if (chk == NULL) {
6768c2654abSrjs 		stcb->asoc.nonce_resync_tsn = stcb->asoc.sending_seq;
6778c2654abSrjs 	} else {
6788c2654abSrjs 		stcb->asoc.nonce_resync_tsn = chk->rec.data.TSN_seq;
6798c2654abSrjs 	}
6808c2654abSrjs 	stcb->asoc.nonce_wait_for_ecne = 0;
6818c2654abSrjs 	stcb->asoc.nonce_sum_check = 0;
6828c2654abSrjs 	/* We return 1 if we only have a window probe outstanding */
6838c2654abSrjs 	if (win_probes && (non_win_probes == 0)) {
6848c2654abSrjs 		return (1);
6858c2654abSrjs 	}
6868c2654abSrjs 	return (0);
6878c2654abSrjs }
6888c2654abSrjs 
6898c2654abSrjs static void
sctp_move_all_chunks_to_alt(struct sctp_tcb * stcb,struct sctp_nets * net,struct sctp_nets * alt)6908c2654abSrjs sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb,
6918c2654abSrjs 			    struct sctp_nets *net,
6928c2654abSrjs 			    struct sctp_nets *alt)
6938c2654abSrjs {
6948c2654abSrjs 	struct sctp_association *asoc;
6958c2654abSrjs 	struct sctp_stream_out *outs;
6968c2654abSrjs 	struct sctp_tmit_chunk *chk;
6978c2654abSrjs 
6988c2654abSrjs 	if (net == alt)
6998c2654abSrjs 		/* nothing to do */
7008c2654abSrjs 		return;
7018c2654abSrjs 
7028c2654abSrjs 	asoc = &stcb->asoc;
7038c2654abSrjs 
7048c2654abSrjs 	/*
7058c2654abSrjs 	 * now through all the streams checking for chunks sent to our
7068c2654abSrjs 	 * bad network.
7078c2654abSrjs 	 */
7088c2654abSrjs 	TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
7098c2654abSrjs 		/* now clean up any chunks here */
7108c2654abSrjs 		TAILQ_FOREACH(chk, &outs->outqueue, sctp_next) {
7118c2654abSrjs 			if (chk->whoTo == net) {
7128c2654abSrjs 				sctp_free_remote_addr(chk->whoTo);
7138c2654abSrjs 				chk->whoTo = alt;
7148c2654abSrjs 				alt->ref_count++;
7158c2654abSrjs 			}
7168c2654abSrjs 		}
7178c2654abSrjs 	}
7188c2654abSrjs 	/* Now check the pending queue */
7198c2654abSrjs 	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
7208c2654abSrjs 		if (chk->whoTo == net) {
7218c2654abSrjs 			sctp_free_remote_addr(chk->whoTo);
7228c2654abSrjs 			chk->whoTo = alt;
7238c2654abSrjs 			alt->ref_count++;
7248c2654abSrjs 		}
7258c2654abSrjs 	}
7268c2654abSrjs 
7278c2654abSrjs }
7288c2654abSrjs 
7298c2654abSrjs int
sctp_t3rxt_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)7308c2654abSrjs sctp_t3rxt_timer(struct sctp_inpcb *inp,
7318c2654abSrjs 		 struct sctp_tcb *stcb,
7328c2654abSrjs 		 struct sctp_nets *net)
7338c2654abSrjs {
7348c2654abSrjs 	struct sctp_nets *alt;
7358c2654abSrjs 	int win_probe, num_mk;
7368c2654abSrjs 
7378c2654abSrjs 
7388c2654abSrjs #ifdef SCTP_FR_LOGGING
7398c2654abSrjs 	sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT);
7408c2654abSrjs #endif
7418c2654abSrjs 	/* Find an alternate and mark those for retransmission */
7428c2654abSrjs 	alt = sctp_find_alternate_net(stcb, net);
7438c2654abSrjs 	win_probe = sctp_mark_all_for_resend(stcb, net, alt, &num_mk);
7448c2654abSrjs 
7458c2654abSrjs 	/* FR Loss recovery just ended with the T3. */
7468c2654abSrjs 	stcb->asoc.fast_retran_loss_recovery = 0;
7478c2654abSrjs 
7488c2654abSrjs 	/* setup the sat loss recovery that prevents
7498c2654abSrjs 	 * satellite cwnd advance.
7508c2654abSrjs 	 */
7518c2654abSrjs  	stcb->asoc.sat_t3_loss_recovery = 1;
7528c2654abSrjs 	stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq;
7538c2654abSrjs 
7548c2654abSrjs 	/* Backoff the timer and cwnd */
7558c2654abSrjs 	sctp_backoff_on_timeout(stcb, net, win_probe, num_mk);
7568c2654abSrjs 	if (win_probe == 0) {
7578c2654abSrjs 		/* We don't do normal threshold management on window probes */
7588c2654abSrjs 		if (sctp_threshold_management(inp, stcb, net,
7598c2654abSrjs 					      stcb->asoc.max_send_times)) {
7608c2654abSrjs 			/* Association was destroyed */
7618c2654abSrjs 			return (1);
7628c2654abSrjs 		} else {
7638c2654abSrjs 			if (net != stcb->asoc.primary_destination) {
7648c2654abSrjs 				/* send a immediate HB if our RTO is stale */
7658c2654abSrjs 				struct  timeval now;
7668c2654abSrjs 				unsigned int ms_goneby;
7678c2654abSrjs 				SCTP_GETTIME_TIMEVAL(&now);
7688c2654abSrjs 				if (net->last_sent_time.tv_sec) {
7698c2654abSrjs 					ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
7708c2654abSrjs 				} else {
7718c2654abSrjs 					ms_goneby = 0;
7728c2654abSrjs 				}
7738c2654abSrjs 				if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
7748c2654abSrjs 					/* no recent feed back in an RTO or more, request a RTT update */
7758c2654abSrjs 					sctp_send_hb(stcb, 1, net);
7768c2654abSrjs 				}
7778c2654abSrjs 			}
7788c2654abSrjs 		}
7798c2654abSrjs 	} else {
7808c2654abSrjs 		/*
7818c2654abSrjs 		 * For a window probe we don't penalize the net's but only
7828c2654abSrjs 		 * the association. This may fail it if SACKs are not coming
7838c2654abSrjs 		 * back. If sack's are coming with rwnd locked at 0, we will
7848c2654abSrjs 		 * continue to hold things waiting for rwnd to raise
7858c2654abSrjs 		 */
7868c2654abSrjs 		if (sctp_threshold_management(inp, stcb, NULL,
7878c2654abSrjs 					      stcb->asoc.max_send_times)) {
7888c2654abSrjs 			/* Association was destroyed */
7898c2654abSrjs 			return (1);
7908c2654abSrjs 		}
7918c2654abSrjs 	}
7928c2654abSrjs 	if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
7938c2654abSrjs 		/* Move all pending over too */
7948c2654abSrjs 		sctp_move_all_chunks_to_alt(stcb, net, alt);
7958c2654abSrjs 		/* Was it our primary? */
7968c2654abSrjs 		if ((stcb->asoc.primary_destination == net) && (alt != net)) {
7978c2654abSrjs 			/*
7988c2654abSrjs 			 * Yes, note it as such and find an alternate
7998c2654abSrjs 			 * note: this means HB code must use this to resent
8008c2654abSrjs 			 * the primary if it goes active AND if someone does
8018c2654abSrjs 			 * a change-primary then this flag must be cleared
8028c2654abSrjs 			 * from any net structures.
8038c2654abSrjs 			 */
8048c2654abSrjs 			if (sctp_set_primary_addr(stcb,
8058c2654abSrjs 						 (struct sockaddr *)NULL,
8068c2654abSrjs 						 alt) == 0) {
8078c2654abSrjs 				net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
8088c2654abSrjs 				net->src_addr_selected = 0;
8098c2654abSrjs 			}
8108c2654abSrjs 		}
8118c2654abSrjs 	}
8128c2654abSrjs 	/*
8138c2654abSrjs 	 * Special case for cookie-echo'ed case, we don't do output
8148c2654abSrjs 	 * but must await the COOKIE-ACK before retransmission
8158c2654abSrjs 	 */
8168c2654abSrjs 	if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
8178c2654abSrjs 		/*
8188c2654abSrjs 		 * Here we just reset the timer and start again since we
8198c2654abSrjs 		 * have not established the asoc
8208c2654abSrjs 		 */
8218c2654abSrjs #ifdef SCTP_DEBUG
8228c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
8238c2654abSrjs 			printf("Special cookie case return\n");
8248c2654abSrjs 		}
8258c2654abSrjs #endif /* SCTP_DEBUG */
8268c2654abSrjs 		sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
8278c2654abSrjs 		return (0);
8288c2654abSrjs 	}
8298c2654abSrjs 	if (stcb->asoc.peer_supports_prsctp) {
8308c2654abSrjs 		struct sctp_tmit_chunk *lchk;
8318c2654abSrjs 		lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc);
8328c2654abSrjs 		/* C3. See if we need to send a Fwd-TSN */
8338c2654abSrjs 		if (compare_with_wrap(stcb->asoc.advanced_peer_ack_point,
8348c2654abSrjs 				      stcb->asoc.last_acked_seq, MAX_TSN)) {
8358c2654abSrjs 			/*
8368c2654abSrjs 			 * ISSUE with ECN, see FWD-TSN processing for notes
8378c2654abSrjs 			 * on issues that will occur when the ECN NONCE stuff
8388c2654abSrjs 			 * is put into SCTP for cross checking.
8398c2654abSrjs 			 */
8408c2654abSrjs #ifdef SCTP_DEBUG
8418c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
8428c2654abSrjs 				printf("Forward TSN time\n");
8438c2654abSrjs 			}
8448c2654abSrjs #endif /* SCTP_DEBUG */
8458c2654abSrjs 			send_forward_tsn(stcb, &stcb->asoc);
8468c2654abSrjs 			if (lchk) {
8478c2654abSrjs 				/* Assure a timer is up */
8488c2654abSrjs 				sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo);
8498c2654abSrjs 			}
8508c2654abSrjs 		}
8518c2654abSrjs 	}
8528c2654abSrjs 	return (0);
8538c2654abSrjs }
8548c2654abSrjs 
8558c2654abSrjs int
sctp_t1init_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)8568c2654abSrjs sctp_t1init_timer(struct sctp_inpcb *inp,
8578c2654abSrjs 		  struct sctp_tcb *stcb,
8588c2654abSrjs 		  struct sctp_nets *net)
8598c2654abSrjs {
8608c2654abSrjs 	/* bump the thresholds */
8618c2654abSrjs 	if (stcb->asoc.delayed_connection) {
8628c2654abSrjs 		/* special hook for delayed connection. The
8638c2654abSrjs 		 * library did NOT complete the rest of its
8648c2654abSrjs 		 * sends.
8658c2654abSrjs 		 */
8668c2654abSrjs 		stcb->asoc.delayed_connection = 0;
8678c2654abSrjs 		sctp_send_initiate(inp, stcb);
8688c2654abSrjs 		return (0);
8698c2654abSrjs 	}
8708c2654abSrjs 	if (sctp_threshold_management(inp, stcb, net,
8718c2654abSrjs 				      stcb->asoc.max_init_times)) {
8728c2654abSrjs 		/* Association was destroyed */
8738c2654abSrjs 		return (1);
8748c2654abSrjs 	}
8758c2654abSrjs 	stcb->asoc.dropped_special_cnt = 0;
8768c2654abSrjs 	sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0);
8778c2654abSrjs 	if (stcb->asoc.initial_init_rto_max < net->RTO) {
8788c2654abSrjs 		net->RTO = stcb->asoc.initial_init_rto_max;
8798c2654abSrjs 	}
8808c2654abSrjs 	if (stcb->asoc.numnets > 1) {
8818c2654abSrjs 		/* If we have more than one addr use it */
8828c2654abSrjs 		struct sctp_nets *alt;
8838c2654abSrjs 		alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination);
8848c2654abSrjs 		if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) {
8858c2654abSrjs 			sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt);
8868c2654abSrjs 			stcb->asoc.primary_destination = alt;
8878c2654abSrjs 		}
8888c2654abSrjs 	}
8898c2654abSrjs 	/* Send out a new init */
8908c2654abSrjs 	sctp_send_initiate(inp, stcb);
8918c2654abSrjs 	return (0);
8928c2654abSrjs }
8938c2654abSrjs 
8948c2654abSrjs /*
8958c2654abSrjs  * For cookie and asconf we actually need to find and mark for resend,
8968c2654abSrjs  * then increment the resend counter (after all the threshold management
8978c2654abSrjs  * stuff of course).
8988c2654abSrjs  */
sctp_cookie_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)8998c2654abSrjs int  sctp_cookie_timer(struct sctp_inpcb *inp,
9008c2654abSrjs 		       struct sctp_tcb *stcb,
9018c2654abSrjs 		       struct sctp_nets *net)
9028c2654abSrjs {
9038c2654abSrjs 	struct sctp_nets *alt;
9048c2654abSrjs 	struct sctp_tmit_chunk *cookie;
9058c2654abSrjs 	/* first before all else we must find the cookie */
9068c2654abSrjs 	TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) {
9078c2654abSrjs 		if (cookie->rec.chunk_id == SCTP_COOKIE_ECHO) {
9088c2654abSrjs 			break;
9098c2654abSrjs 		}
9108c2654abSrjs 	}
9118c2654abSrjs 	if (cookie == NULL) {
9128c2654abSrjs 		if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
9138c2654abSrjs 			/* FOOBAR! */
9148c2654abSrjs 			struct mbuf *oper;
9158c2654abSrjs 			MGET(oper, M_DONTWAIT, MT_DATA);
9168c2654abSrjs 			if (oper) {
9178c2654abSrjs 				struct sctp_paramhdr *ph;
9188c2654abSrjs 				u_int32_t *ippp;
9198c2654abSrjs 
9208c2654abSrjs 				oper->m_len = sizeof(struct sctp_paramhdr) +
9218c2654abSrjs 				    sizeof(*ippp);
9228c2654abSrjs 				ph = mtod(oper, struct sctp_paramhdr *);
9238c2654abSrjs 				ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
9248c2654abSrjs 				ph->param_length = htons(oper->m_len);
9258c2654abSrjs 				ippp = (u_int32_t *)(ph + 1);
9268c2654abSrjs 				*ippp = htonl(0x40000002);
9278c2654abSrjs 			}
9288c2654abSrjs 			sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR,
9298c2654abSrjs 			    oper);
9308c2654abSrjs 		}
9318c2654abSrjs 		return (1);
9328c2654abSrjs 	}
9338c2654abSrjs 	/* Ok we found the cookie, threshold management next */
9348c2654abSrjs 	if (sctp_threshold_management(inp, stcb, cookie->whoTo,
9358c2654abSrjs 	    stcb->asoc.max_init_times)) {
9368c2654abSrjs 		/* Assoc is over */
9378c2654abSrjs 		return (1);
9388c2654abSrjs 	}
9398c2654abSrjs 	/*
9408c2654abSrjs 	 * cleared theshold management now lets backoff the address &
9418c2654abSrjs 	 * select an alternate
9428c2654abSrjs 	 */
9438c2654abSrjs 	stcb->asoc.dropped_special_cnt = 0;
9448c2654abSrjs 	sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0);
9458c2654abSrjs 	alt = sctp_find_alternate_net(stcb, cookie->whoTo);
9468c2654abSrjs 	if (alt != cookie->whoTo) {
9478c2654abSrjs 		sctp_free_remote_addr(cookie->whoTo);
9488c2654abSrjs 		cookie->whoTo = alt;
9498c2654abSrjs 		alt->ref_count++;
9508c2654abSrjs 	}
9518c2654abSrjs 	/* Now mark the retran info */
9528c2654abSrjs 	if (cookie->sent != SCTP_DATAGRAM_RESEND) {
9538c2654abSrjs 		stcb->asoc.sent_queue_retran_cnt++;
9548c2654abSrjs 	}
9558c2654abSrjs 	cookie->sent = SCTP_DATAGRAM_RESEND;
9568c2654abSrjs 	/*
9578c2654abSrjs 	 * Now call the output routine to kick out the cookie again, Note we
9588c2654abSrjs 	 * don't mark any chunks for retran so that FR will need to kick in
9598c2654abSrjs 	 * to move these (or a send timer).
9608c2654abSrjs 	 */
9618c2654abSrjs 	return (0);
9628c2654abSrjs }
9638c2654abSrjs 
sctp_strreset_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)9648c2654abSrjs int sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
9658c2654abSrjs     struct sctp_nets *net)
9668c2654abSrjs {
9678c2654abSrjs 	struct sctp_nets *alt;
9688c2654abSrjs 	struct sctp_tmit_chunk *strrst, *chk;
9698c2654abSrjs 	struct sctp_stream_reset_req *strreq;
9708c2654abSrjs 	/* find the existing STRRESET */
9718c2654abSrjs 	TAILQ_FOREACH(strrst, &stcb->asoc.control_send_queue,
9728c2654abSrjs 		      sctp_next) {
9738c2654abSrjs 		if (strrst->rec.chunk_id == SCTP_STREAM_RESET) {
9748c2654abSrjs 			/* is it what we want */
9758c2654abSrjs 			strreq = mtod(strrst->data, struct sctp_stream_reset_req *);
9768c2654abSrjs 			if (strreq->sr_req.ph.param_type == ntohs(SCTP_STR_RESET_REQUEST)) {
9778c2654abSrjs 				break;
9788c2654abSrjs 			}
9798c2654abSrjs 		}
9808c2654abSrjs 	}
9818c2654abSrjs 	if (strrst == NULL) {
9828c2654abSrjs #ifdef SCTP_DEBUG
9838c2654abSrjs 		if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
9848c2654abSrjs 			printf("Strange, strreset timer fires, but I can't find an str-reset?\n");
9858c2654abSrjs 		}
9868c2654abSrjs #endif /* SCTP_DEBUG */
9878c2654abSrjs 		return (0);
9888c2654abSrjs 	}
9898c2654abSrjs 	/* do threshold management */
9908c2654abSrjs 	if (sctp_threshold_management(inp, stcb, strrst->whoTo,
9918c2654abSrjs 				      stcb->asoc.max_send_times)) {
9928c2654abSrjs 		/* Assoc is over */
9938c2654abSrjs 		return (1);
9948c2654abSrjs 	}
9958c2654abSrjs 
9968c2654abSrjs 	/*
9978c2654abSrjs 	 * cleared theshold management
9988c2654abSrjs 	 * now lets backoff the address & select an alternate
9998c2654abSrjs 	 */
10008c2654abSrjs 	sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0);
10018c2654abSrjs 	alt = sctp_find_alternate_net(stcb, strrst->whoTo);
10028c2654abSrjs 	sctp_free_remote_addr(strrst->whoTo);
10038c2654abSrjs 	strrst->whoTo = alt;
10048c2654abSrjs 	alt->ref_count++;
10058c2654abSrjs 
10068c2654abSrjs 	/* See if a ECN Echo is also stranded */
10078c2654abSrjs 	TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
10088c2654abSrjs 		if ((chk->whoTo == net) &&
10098c2654abSrjs 		    (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
10108c2654abSrjs 			sctp_free_remote_addr(chk->whoTo);
10118c2654abSrjs 			if (chk->sent != SCTP_DATAGRAM_RESEND) {
10128c2654abSrjs 				chk->sent = SCTP_DATAGRAM_RESEND;
10138c2654abSrjs 				stcb->asoc.sent_queue_retran_cnt++;
10148c2654abSrjs 			}
10158c2654abSrjs 			chk->whoTo = alt;
10168c2654abSrjs 			alt->ref_count++;
10178c2654abSrjs 		}
10188c2654abSrjs 	}
10198c2654abSrjs 	if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
10208c2654abSrjs 		/*
10218c2654abSrjs 		 * If the address went un-reachable, we need to move
10228c2654abSrjs 		 * to alternates for ALL chk's in queue
10238c2654abSrjs 		 */
10248c2654abSrjs 		sctp_move_all_chunks_to_alt(stcb, net, alt);
10258c2654abSrjs 	}
10268c2654abSrjs 	/* mark the retran info */
10278c2654abSrjs 	if (strrst->sent != SCTP_DATAGRAM_RESEND)
10288c2654abSrjs 		stcb->asoc.sent_queue_retran_cnt++;
10298c2654abSrjs 	strrst->sent = SCTP_DATAGRAM_RESEND;
10308c2654abSrjs 
10318c2654abSrjs 	/* restart the timer */
10328c2654abSrjs 	sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo);
10338c2654abSrjs 	return (0);
10348c2654abSrjs }
10358c2654abSrjs 
sctp_asconf_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)10368c2654abSrjs int sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
10378c2654abSrjs     struct sctp_nets *net)
10388c2654abSrjs {
10398c2654abSrjs 	struct sctp_nets *alt;
10408c2654abSrjs 	struct sctp_tmit_chunk *asconf, *chk;
10418c2654abSrjs 
10428c2654abSrjs 	/* is this the first send, or a retransmission? */
10438c2654abSrjs 	if (stcb->asoc.asconf_sent == 0) {
10448c2654abSrjs 		/* compose a new ASCONF chunk and send it */
10458c2654abSrjs 		sctp_send_asconf(stcb, net);
10468c2654abSrjs 	} else {
10478c2654abSrjs 		/* Retransmission of the existing ASCONF needed... */
10488c2654abSrjs 
10498c2654abSrjs 		/* find the existing ASCONF */
10508c2654abSrjs 		TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue,
10518c2654abSrjs 		    sctp_next) {
10528c2654abSrjs 			if (asconf->rec.chunk_id == SCTP_ASCONF) {
10538c2654abSrjs 				break;
10548c2654abSrjs 			}
10558c2654abSrjs 		}
10568c2654abSrjs 		if (asconf == NULL) {
10578c2654abSrjs #ifdef SCTP_DEBUG
10588c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
10598c2654abSrjs 				printf("Strange, asconf timer fires, but I can't find an asconf?\n");
10608c2654abSrjs 			}
10618c2654abSrjs #endif /* SCTP_DEBUG */
10628c2654abSrjs 			return (0);
10638c2654abSrjs 		}
10648c2654abSrjs 		/* do threshold management */
10658c2654abSrjs 		if (sctp_threshold_management(inp, stcb, asconf->whoTo,
10668c2654abSrjs 		    stcb->asoc.max_send_times)) {
10678c2654abSrjs 			/* Assoc is over */
10688c2654abSrjs 			return (1);
10698c2654abSrjs 		}
10708c2654abSrjs 
10718c2654abSrjs 		/* PETER? FIX? How will the following code ever run? If
1072*7f459241Sandvar 		 * the max_send_times is hit, threshold management will
10738c2654abSrjs 		 * blow away the association?
10748c2654abSrjs 		 */
10758c2654abSrjs 		if (asconf->snd_count > stcb->asoc.max_send_times) {
10768c2654abSrjs 			/*
10778c2654abSrjs 			 * Something is rotten, peer is not responding to
10788c2654abSrjs 			 * ASCONFs but maybe is to data etc.  e.g. it is not
10798c2654abSrjs 			 * properly handling the chunk type upper bits
10808c2654abSrjs 			 * Mark this peer as ASCONF incapable and cleanup
10818c2654abSrjs 			 */
10828c2654abSrjs #ifdef SCTP_DEBUG
10838c2654abSrjs 			if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
10848c2654abSrjs 				printf("asconf_timer: Peer has not responded to our repeated ASCONFs\n");
10858c2654abSrjs 			}
10868c2654abSrjs #endif /* SCTP_DEBUG */
10878c2654abSrjs 			sctp_asconf_cleanup(stcb, net);
10888c2654abSrjs 			return (0);
10898c2654abSrjs 		}
10908c2654abSrjs 		/*
10918c2654abSrjs 		 * cleared theshold management
10928c2654abSrjs 		 * now lets backoff the address & select an alternate
10938c2654abSrjs 		 */
10948c2654abSrjs 		sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0);
10958c2654abSrjs 		alt = sctp_find_alternate_net(stcb, asconf->whoTo);
10968c2654abSrjs 		sctp_free_remote_addr(asconf->whoTo);
10978c2654abSrjs 		asconf->whoTo = alt;
10988c2654abSrjs 		alt->ref_count++;
10998c2654abSrjs 
11008c2654abSrjs 		/* See if a ECN Echo is also stranded */
11018c2654abSrjs 		TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
11028c2654abSrjs 			if ((chk->whoTo == net) &&
11038c2654abSrjs 			    (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
11048c2654abSrjs 				sctp_free_remote_addr(chk->whoTo);
11058c2654abSrjs 				chk->whoTo = alt;
11068c2654abSrjs 				if (chk->sent != SCTP_DATAGRAM_RESEND) {
11078c2654abSrjs 					chk->sent = SCTP_DATAGRAM_RESEND;
11088c2654abSrjs 					stcb->asoc.sent_queue_retran_cnt++;
11098c2654abSrjs 				}
11108c2654abSrjs 				alt->ref_count++;
11118c2654abSrjs 
11128c2654abSrjs 			}
11138c2654abSrjs 		}
11148c2654abSrjs 		if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
11158c2654abSrjs 			/*
11168c2654abSrjs 			 * If the address went un-reachable, we need to move
11178c2654abSrjs 			 * to alternates for ALL chk's in queue
11188c2654abSrjs 			 */
11198c2654abSrjs 			sctp_move_all_chunks_to_alt(stcb, net, alt);
11208c2654abSrjs 		}
11218c2654abSrjs 		/* mark the retran info */
11228c2654abSrjs 		if (asconf->sent != SCTP_DATAGRAM_RESEND)
11238c2654abSrjs 			stcb->asoc.sent_queue_retran_cnt++;
11248c2654abSrjs 		asconf->sent = SCTP_DATAGRAM_RESEND;
11258c2654abSrjs 	}
11268c2654abSrjs 	return (0);
11278c2654abSrjs }
11288c2654abSrjs 
11298c2654abSrjs /*
11308c2654abSrjs  * For the shutdown and shutdown-ack, we do not keep one around on the
11318c2654abSrjs  * control queue. This means we must generate a new one and call the general
11328c2654abSrjs  * chunk output routine, AFTER having done threshold
11338c2654abSrjs  * management.
11348c2654abSrjs  */
11358c2654abSrjs int
sctp_shutdown_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)11368c2654abSrjs sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
11378c2654abSrjs     struct sctp_nets *net)
11388c2654abSrjs {
11398c2654abSrjs 	struct sctp_nets *alt;
1140*7f459241Sandvar 	/* first threshold management */
11418c2654abSrjs 	if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
11428c2654abSrjs 		/* Assoc is over */
11438c2654abSrjs 		return (1);
11448c2654abSrjs 	}
11458c2654abSrjs 	/* second select an alternative */
11468c2654abSrjs 	alt = sctp_find_alternate_net(stcb, net);
11478c2654abSrjs 
11488c2654abSrjs 	/* third generate a shutdown into the queue for out net */
11498c2654abSrjs #ifdef SCTP_DEBUG
11508c2654abSrjs 	if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
11518c2654abSrjs 		printf("%s:%d sends a shutdown\n",
11528c2654abSrjs 		       __FILE__,
11538c2654abSrjs 		       __LINE__
11548c2654abSrjs 			);
11558c2654abSrjs 	}
11568c2654abSrjs #endif
11578c2654abSrjs 	if (alt) {
11588c2654abSrjs 		sctp_send_shutdown(stcb, alt);
11598c2654abSrjs 	} else {
11608c2654abSrjs 		/* if alt is NULL, there is no dest
11618c2654abSrjs 		 * to send to??
11628c2654abSrjs 		 */
11638c2654abSrjs 		return (0);
11648c2654abSrjs 	}
11658c2654abSrjs 	/* fourth restart timer */
11668c2654abSrjs 	sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt);
11678c2654abSrjs 	return (0);
11688c2654abSrjs }
11698c2654abSrjs 
sctp_shutdownack_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)11708c2654abSrjs int sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
11718c2654abSrjs     struct sctp_nets *net)
11728c2654abSrjs {
11738c2654abSrjs 	struct sctp_nets *alt;
1174*7f459241Sandvar 	/* first threshold management */
11758c2654abSrjs 	if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
11768c2654abSrjs 		/* Assoc is over */
11778c2654abSrjs 		return (1);
11788c2654abSrjs 	}
11798c2654abSrjs 	/* second select an alternative */
11808c2654abSrjs 	alt = sctp_find_alternate_net(stcb, net);
11818c2654abSrjs 
11828c2654abSrjs 	/* third generate a shutdown into the queue for out net */
11838c2654abSrjs 	sctp_send_shutdown_ack(stcb, alt);
11848c2654abSrjs 
11858c2654abSrjs 	/* fourth restart timer */
11868c2654abSrjs 	sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt);
11878c2654abSrjs 	return (0);
11888c2654abSrjs }
11898c2654abSrjs 
11908c2654abSrjs static void
sctp_audit_stream_queues_for_size(struct sctp_inpcb * inp,struct sctp_tcb * stcb)11918c2654abSrjs sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
11928c2654abSrjs 				  struct sctp_tcb *stcb)
11938c2654abSrjs {
11948c2654abSrjs 	struct sctp_stream_out *outs;
11958c2654abSrjs 	struct sctp_tmit_chunk *chk;
11968c2654abSrjs 	unsigned int chks_in_queue=0;
11978c2654abSrjs 
11988c2654abSrjs 	if ((stcb == NULL) || (inp == NULL))
11998c2654abSrjs 		return;
12008c2654abSrjs 	if (TAILQ_EMPTY(&stcb->asoc.out_wheel)) {
12018c2654abSrjs 		printf("Strange, out_wheel empty nothing on sent/send and  tot=%lu?\n",
12028c2654abSrjs 		    (u_long)stcb->asoc.total_output_queue_size);
12038c2654abSrjs 		stcb->asoc.total_output_queue_size = 0;
12048c2654abSrjs 		return;
12058c2654abSrjs 	}
12068c2654abSrjs 	if (stcb->asoc.sent_queue_retran_cnt) {
12078c2654abSrjs 		printf("Hmm, sent_queue_retran_cnt is non-zero %d\n",
12088c2654abSrjs 		    stcb->asoc.sent_queue_retran_cnt);
12098c2654abSrjs 		stcb->asoc.sent_queue_retran_cnt = 0;
12108c2654abSrjs 	}
12118c2654abSrjs 	/* Check to see if some data queued, if so report it */
12128c2654abSrjs 	TAILQ_FOREACH(outs, &stcb->asoc.out_wheel, next_spoke) {
12138c2654abSrjs 		if (!TAILQ_EMPTY(&outs->outqueue)) {
12148c2654abSrjs 			TAILQ_FOREACH(chk, &outs->outqueue, sctp_next) {
12158c2654abSrjs 				chks_in_queue++;
12168c2654abSrjs 			}
12178c2654abSrjs 		}
12188c2654abSrjs 	}
12198c2654abSrjs 	if (chks_in_queue != stcb->asoc.stream_queue_cnt) {
12208c2654abSrjs 		printf("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n",
12218c2654abSrjs 		       stcb->asoc.stream_queue_cnt, chks_in_queue);
12228c2654abSrjs 	}
12238c2654abSrjs 	if (chks_in_queue) {
12248c2654abSrjs 		/* call the output queue function */
12258c2654abSrjs 		sctp_chunk_output(inp, stcb, 1);
12268c2654abSrjs 		if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
12278c2654abSrjs 		    (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
12288c2654abSrjs 			/* Probably should go in and make it go back through and add fragments allowed */
12298c2654abSrjs 			printf("Still nothing moved %d chunks are stuck\n", chks_in_queue);
12308c2654abSrjs 		}
12318c2654abSrjs 	} else {
12328c2654abSrjs 		printf("Found no chunks on any queue tot:%lu\n",
12338c2654abSrjs 		    (u_long)stcb->asoc.total_output_queue_size);
12348c2654abSrjs 		stcb->asoc.total_output_queue_size = 0;
12358c2654abSrjs 	}
12368c2654abSrjs }
12378c2654abSrjs 
12388c2654abSrjs int
sctp_heartbeat_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)12398c2654abSrjs sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
12408c2654abSrjs     struct sctp_nets *net)
12418c2654abSrjs {
12428c2654abSrjs 	int cnt_of_unconf=0;
12438c2654abSrjs 
12448c2654abSrjs 	if (net) {
12458c2654abSrjs 		if (net->hb_responded == 0) {
12468c2654abSrjs 			sctp_backoff_on_timeout(stcb, net, 1, 0);
12478c2654abSrjs 		}
12488c2654abSrjs 		/* Zero PBA, if it needs it */
12498c2654abSrjs 		if (net->partial_bytes_acked) {
12508c2654abSrjs 			net->partial_bytes_acked = 0;
12518c2654abSrjs 		}
12528c2654abSrjs 	}
12538c2654abSrjs 	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
12548c2654abSrjs 		if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
12558c2654abSrjs 		    (net->dest_state & SCTP_ADDR_REACHABLE)) {
12568c2654abSrjs 			cnt_of_unconf++;
12578c2654abSrjs 		}
12588c2654abSrjs 	}
12598c2654abSrjs 	if ((stcb->asoc.total_output_queue_size > 0) &&
12608c2654abSrjs 	    (TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
12618c2654abSrjs 	    (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
12628c2654abSrjs 		sctp_audit_stream_queues_for_size(inp, stcb);
12638c2654abSrjs 	}
1264*7f459241Sandvar 	/* Send a new HB, this will do threshold management, pick a new dest */
12658c2654abSrjs 	if (sctp_send_hb(stcb, 0, NULL) < 0) {
12668c2654abSrjs 		return (1);
12678c2654abSrjs 	}
12688c2654abSrjs 	if (cnt_of_unconf > 1) {
12698c2654abSrjs 		/*
12708c2654abSrjs 		 * this will send out extra hb's up to maxburst if
12718c2654abSrjs 		 * there are any unconfirmed addresses.
12728c2654abSrjs 		 */
12738c2654abSrjs 		int cnt_sent = 1;
12748c2654abSrjs 		while ((cnt_sent < stcb->asoc.max_burst) && (cnt_of_unconf > 1)) {
12758c2654abSrjs 			if (sctp_send_hb(stcb, 0, NULL) == 0)
12768c2654abSrjs 				break;
12778c2654abSrjs 			cnt_of_unconf--;
12788c2654abSrjs 			cnt_sent++;
12798c2654abSrjs 		}
12808c2654abSrjs 	}
12818c2654abSrjs 	return (0);
12828c2654abSrjs }
12838c2654abSrjs 
12848c2654abSrjs #define SCTP_NUMBER_OF_MTU_SIZES 18
12858c2654abSrjs static u_int32_t mtu_sizes[]={
12868c2654abSrjs 	68,
12878c2654abSrjs 	296,
12888c2654abSrjs 	508,
12898c2654abSrjs 	512,
12908c2654abSrjs 	544,
12918c2654abSrjs 	576,
12928c2654abSrjs 	1006,
12938c2654abSrjs 	1492,
12948c2654abSrjs 	1500,
12958c2654abSrjs 	1536,
12968c2654abSrjs 	2002,
12978c2654abSrjs 	2048,
12988c2654abSrjs 	4352,
12998c2654abSrjs 	4464,
13008c2654abSrjs 	8166,
13018c2654abSrjs 	17914,
13028c2654abSrjs 	32000,
13038c2654abSrjs 	65535
13048c2654abSrjs };
13058c2654abSrjs 
13068c2654abSrjs 
13078c2654abSrjs static u_int32_t
sctp_getnext_mtu(struct sctp_inpcb * inp,u_int32_t cur_mtu)13088c2654abSrjs sctp_getnext_mtu(struct sctp_inpcb *inp, u_int32_t cur_mtu)
13098c2654abSrjs {
13108c2654abSrjs 	/* select another MTU that is just bigger than this one */
13118c2654abSrjs 	int i;
13128c2654abSrjs 
13138c2654abSrjs 	for (i = 0; i < SCTP_NUMBER_OF_MTU_SIZES; i++) {
13148c2654abSrjs 		if (cur_mtu < mtu_sizes[i]) {
13158c2654abSrjs 		    /* no max_mtu is bigger than this one */
13168c2654abSrjs 		    return (mtu_sizes[i]);
13178c2654abSrjs 		}
13188c2654abSrjs 	}
13198c2654abSrjs 	/* here return the highest allowable */
13208c2654abSrjs 	return (cur_mtu);
13218c2654abSrjs }
13228c2654abSrjs 
13238c2654abSrjs 
sctp_pathmtu_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)13248c2654abSrjs void sctp_pathmtu_timer(struct sctp_inpcb *inp,
13258c2654abSrjs 			struct sctp_tcb *stcb,
13268c2654abSrjs 			struct sctp_nets *net)
13278c2654abSrjs {
13288c2654abSrjs 	u_int32_t next_mtu;
13298c2654abSrjs 	struct rtentry *rt;
13308c2654abSrjs 
13318c2654abSrjs 	/* restart the timer in any case */
13328c2654abSrjs 	next_mtu = sctp_getnext_mtu(inp, net->mtu);
13338c2654abSrjs 	if (next_mtu <= net->mtu) {
13348c2654abSrjs 	    /* nothing to do */
13358c2654abSrjs 	    return;
13368c2654abSrjs 	}
13378c2654abSrjs 	rt = rtcache_validate(&net->ro);
13388c2654abSrjs 	if (rt != NULL) {
13398c2654abSrjs 		/* only if we have a route and interface do we
13408c2654abSrjs 		 * set anything. Note we always restart
13418c2654abSrjs 		 * the timer though just in case it is updated
13428c2654abSrjs 		 * (i.e. the ifp) or route/ifp is populated.
13438c2654abSrjs 		 */
13448c2654abSrjs 		if (rt->rt_ifp != NULL) {
13458c2654abSrjs 			if (rt->rt_ifp->if_mtu > next_mtu) {
13468c2654abSrjs 				/* ok it will fit out the door */
13478c2654abSrjs 				net->mtu = next_mtu;
13488c2654abSrjs 			}
13498c2654abSrjs 		}
13504c25fb2fSozaki-r 		rtcache_unref(rt, &net->ro);
13518c2654abSrjs 	}
13528c2654abSrjs 	/* restart the timer */
13538c2654abSrjs 	sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
13548c2654abSrjs }
13558c2654abSrjs 
sctp_autoclose_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)13568c2654abSrjs void sctp_autoclose_timer(struct sctp_inpcb *inp,
13578c2654abSrjs 			  struct sctp_tcb *stcb,
13588c2654abSrjs 			  struct sctp_nets *net)
13598c2654abSrjs {
13608c2654abSrjs 	struct timeval tn, *tim_touse;
13618c2654abSrjs 	struct sctp_association *asoc;
13628c2654abSrjs 	int ticks_gone_by;
13638c2654abSrjs 
13648c2654abSrjs 	SCTP_GETTIME_TIMEVAL(&tn);
13658c2654abSrjs 	if (stcb->asoc.sctp_autoclose_ticks &&
13668c2654abSrjs 	    (inp->sctp_flags & SCTP_PCB_FLAGS_AUTOCLOSE)) {
13678c2654abSrjs 		/* Auto close is on */
13688c2654abSrjs 		asoc = &stcb->asoc;
13698c2654abSrjs 		/* pick the time to use */
13708c2654abSrjs 		if (asoc->time_last_rcvd.tv_sec >
13718c2654abSrjs 		    asoc->time_last_sent.tv_sec) {
13728c2654abSrjs 			tim_touse = &asoc->time_last_rcvd;
13738c2654abSrjs 		} else {
13748c2654abSrjs 			tim_touse = &asoc->time_last_sent;
13758c2654abSrjs 		}
13768c2654abSrjs 		/* Now has long enough transpired to autoclose? */
13778c2654abSrjs 		ticks_gone_by = ((tn.tv_sec - tim_touse->tv_sec) * hz);
13788c2654abSrjs 		if ((ticks_gone_by > 0) &&
13798c2654abSrjs 		    (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) {
13808c2654abSrjs 			/*
13818c2654abSrjs 			 * autoclose time has hit, call the output routine,
13828c2654abSrjs 			 * which should do nothing just to be SURE we don't
13838c2654abSrjs 			 * have hanging data. We can then safely check the
13848c2654abSrjs 			 * queues and know that we are clear to send shutdown
13858c2654abSrjs 			 */
13868c2654abSrjs 			sctp_chunk_output(inp, stcb, 9);
13878c2654abSrjs 			/* Are we clean? */
13888c2654abSrjs 			if (TAILQ_EMPTY(&asoc->send_queue) &&
13898c2654abSrjs 			    TAILQ_EMPTY(&asoc->sent_queue)) {
13908c2654abSrjs 				/*
13918c2654abSrjs 				 * there is nothing queued to send,
13928c2654abSrjs 				 * so I'm done...
13938c2654abSrjs 				 */
13948c2654abSrjs 				if (SCTP_GET_STATE(asoc) !=
13958c2654abSrjs 				    SCTP_STATE_SHUTDOWN_SENT) {
13968c2654abSrjs 					/* only send SHUTDOWN 1st time thru */
13978c2654abSrjs #ifdef SCTP_DEBUG
13988c2654abSrjs 					if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
13998c2654abSrjs 						printf("%s:%d sends a shutdown\n",
14008c2654abSrjs 						       __FILE__,
14018c2654abSrjs 						       __LINE__
14028c2654abSrjs 							);
14038c2654abSrjs 					}
14048c2654abSrjs #endif
14058c2654abSrjs 					sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
14068c2654abSrjs 					asoc->state = SCTP_STATE_SHUTDOWN_SENT;
14078c2654abSrjs 					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
14088c2654abSrjs 					    stcb->sctp_ep, stcb,
14098c2654abSrjs 					    asoc->primary_destination);
14108c2654abSrjs 					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
14118c2654abSrjs 					    stcb->sctp_ep, stcb,
14128c2654abSrjs 					    asoc->primary_destination);
14138c2654abSrjs 				}
14148c2654abSrjs 			}
14158c2654abSrjs 		} else {
14168c2654abSrjs 			/*
14178c2654abSrjs 			 * No auto close at this time, reset t-o to
14188c2654abSrjs 			 * check later
14198c2654abSrjs 			 */
14208c2654abSrjs 			int tmp;
14218c2654abSrjs 			/* fool the timer startup to use the time left */
14228c2654abSrjs 			tmp = asoc->sctp_autoclose_ticks;
14238c2654abSrjs 			asoc->sctp_autoclose_ticks -= ticks_gone_by;
14248c2654abSrjs 			sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb,
14258c2654abSrjs 					 net);
14268c2654abSrjs 			/* restore the real tick value */
14278c2654abSrjs 			asoc->sctp_autoclose_ticks = tmp;
14288c2654abSrjs 		}
14298c2654abSrjs 	}
14308c2654abSrjs }
14318c2654abSrjs 
14328c2654abSrjs void
sctp_iterator_timer(struct sctp_iterator * it)14338c2654abSrjs sctp_iterator_timer(struct sctp_iterator *it)
14348c2654abSrjs {
14358c2654abSrjs 	int cnt= 0;
14368c2654abSrjs 	/* only one iterator can run at a
14378c2654abSrjs 	 * time. This is the only way we
14388c2654abSrjs 	 * can cleanly pull ep's from underneath
14398c2654abSrjs 	 * all the running interators when a
14408c2654abSrjs 	 * ep is freed.
14418c2654abSrjs 	 */
14428c2654abSrjs  	SCTP_ITERATOR_LOCK();
14438c2654abSrjs 	if (it->inp == NULL) {
14448c2654abSrjs 		/* iterator is complete */
14458c2654abSrjs 	done_with_iterator:
14468c2654abSrjs 		SCTP_ITERATOR_UNLOCK();
14478c2654abSrjs 		SCTP_INP_INFO_WLOCK();
14488c2654abSrjs 		LIST_REMOVE(it, sctp_nxt_itr);
14498c2654abSrjs 		/* stopping the callout is not needed, in theory,
14508c2654abSrjs 		 * but I am paranoid.
14518c2654abSrjs 		 */
14528c2654abSrjs 		SCTP_INP_INFO_WUNLOCK();
14538c2654abSrjs 		callout_stop(&it->tmr.timer);
14548c2654abSrjs 		if (it->function_atend != NULL) {
14558c2654abSrjs 			(*it->function_atend)(it->pointer, it->val);
14568c2654abSrjs 		}
14578c2654abSrjs 		callout_destroy(&it->tmr.timer);
14588c2654abSrjs 		free(it, M_PCB);
14598c2654abSrjs 		return;
14608c2654abSrjs 	}
14618c2654abSrjs  select_a_new_ep:
14628c2654abSrjs 	SCTP_INP_WLOCK(it->inp);
14638c2654abSrjs 	while ((it->pcb_flags) && ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) {
14648c2654abSrjs 		/* we do not like this ep */
14658c2654abSrjs 		if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
14668c2654abSrjs 			SCTP_INP_WUNLOCK(it->inp);
14678c2654abSrjs 			goto done_with_iterator;
14688c2654abSrjs 		}
14698c2654abSrjs 		SCTP_INP_WUNLOCK(it->inp);
14708c2654abSrjs 		it->inp = LIST_NEXT(it->inp, sctp_list);
14718c2654abSrjs 		if (it->inp == NULL) {
14728c2654abSrjs 			goto done_with_iterator;
14738c2654abSrjs 		}
14748c2654abSrjs 		SCTP_INP_WLOCK(it->inp);
14758c2654abSrjs 	}
14768c2654abSrjs 	if ((it->inp->inp_starting_point_for_iterator != NULL) &&
14778c2654abSrjs 	    (it->inp->inp_starting_point_for_iterator != it)) {
14788c2654abSrjs 		printf("Iterator collision, we must wait for other iterator at %p\n",
14798c2654abSrjs 		       it->inp);
14808c2654abSrjs 		SCTP_INP_WUNLOCK(it->inp);
14818c2654abSrjs 		goto start_timer_return;
14828c2654abSrjs 	}
14838c2654abSrjs 	/* now we do the actual write to this guy */
14848c2654abSrjs 	it->inp->inp_starting_point_for_iterator = it;
14858c2654abSrjs 	SCTP_INP_WUNLOCK(it->inp);
14868c2654abSrjs 	SCTP_INP_RLOCK(it->inp);
14878c2654abSrjs 	/* if we reach here we found a inp acceptable, now through each
14888c2654abSrjs 	 * one that has the association in the right state
14898c2654abSrjs 	 */
14908c2654abSrjs 	if (it->stcb == NULL) {
14918c2654abSrjs 		it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
14928c2654abSrjs 	}
14938c2654abSrjs 	if (it->stcb->asoc.stcb_starting_point_for_iterator == it) {
14948c2654abSrjs 		it->stcb->asoc.stcb_starting_point_for_iterator = NULL;
14958c2654abSrjs 	}
14968c2654abSrjs 	while (it->stcb) {
14978c2654abSrjs 		SCTP_TCB_LOCK(it->stcb);
14988c2654abSrjs 		if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
14998c2654abSrjs 			SCTP_TCB_UNLOCK(it->stcb);
15008c2654abSrjs 			it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
15018c2654abSrjs 			continue;
15028c2654abSrjs 		}
15038c2654abSrjs 		cnt++;
15048c2654abSrjs 		/* run function on this one */
15058c2654abSrjs 		SCTP_INP_RUNLOCK(it->inp);
15068c2654abSrjs 		(*it->function_toapply)(it->inp, it->stcb, it->pointer, it->val);
15078c2654abSrjs 		sctp_chunk_output(it->inp, it->stcb, 1);
15088c2654abSrjs 		SCTP_TCB_UNLOCK(it->stcb);
15098c2654abSrjs 		/* see if we have limited out */
15108c2654abSrjs 		if (cnt > SCTP_MAX_ITERATOR_AT_ONCE) {
15118c2654abSrjs 			it->stcb->asoc.stcb_starting_point_for_iterator = it;
15128c2654abSrjs 		start_timer_return:
15138c2654abSrjs 			SCTP_ITERATOR_UNLOCK();
15148c2654abSrjs 			sctp_timer_start(SCTP_TIMER_TYPE_ITERATOR, (struct sctp_inpcb *)it, NULL, NULL);
15158c2654abSrjs 			return;
15168c2654abSrjs 		}
15178c2654abSrjs 		SCTP_INP_RLOCK(it->inp);
15188c2654abSrjs 		it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
15198c2654abSrjs 	}
15208c2654abSrjs 	/* if we reach here, we ran out of stcb's in the inp we are looking at */
15218c2654abSrjs 	SCTP_INP_RUNLOCK(it->inp);
15228c2654abSrjs 	SCTP_INP_WLOCK(it->inp);
15238c2654abSrjs 	it->inp->inp_starting_point_for_iterator = NULL;
15248c2654abSrjs 	SCTP_INP_WUNLOCK(it->inp);
15258c2654abSrjs 	if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
15268c2654abSrjs 		it->inp = NULL;
15278c2654abSrjs 	} else {
15288c2654abSrjs 		SCTP_INP_INFO_RLOCK();
15298c2654abSrjs 		it->inp = LIST_NEXT(it->inp, sctp_list);
15308c2654abSrjs 		SCTP_INP_INFO_RUNLOCK();
15318c2654abSrjs 	}
15328c2654abSrjs 	if (it->inp == NULL) {
15338c2654abSrjs 		goto done_with_iterator;
15348c2654abSrjs 	}
15358c2654abSrjs 	goto select_a_new_ep;
15368c2654abSrjs }
1537