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