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