xref: /freebsd/sys/netinet/sctp_timer.c (revision b54d3a6c48b9608d35248ff39cba565f8bbbfb00)
1f8829a4aSRandall Stewart /*-
2b1006367SRandall Stewart  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3f8829a4aSRandall Stewart  *
4f8829a4aSRandall Stewart  * Redistribution and use in source and binary forms, with or without
5f8829a4aSRandall Stewart  * modification, are permitted provided that the following conditions are met:
6f8829a4aSRandall Stewart  *
7f8829a4aSRandall Stewart  * a) Redistributions of source code must retain the above copyright notice,
8f8829a4aSRandall Stewart  *   this list of conditions and the following disclaimer.
9f8829a4aSRandall Stewart  *
10f8829a4aSRandall Stewart  * b) Redistributions in binary form must reproduce the above copyright
11f8829a4aSRandall Stewart  *    notice, this list of conditions and the following disclaimer in
12f8829a4aSRandall Stewart  *   the documentation and/or other materials provided with the distribution.
13f8829a4aSRandall Stewart  *
14f8829a4aSRandall Stewart  * c) Neither the name of Cisco Systems, Inc. nor the names of its
15f8829a4aSRandall Stewart  *    contributors may be used to endorse or promote products derived
16f8829a4aSRandall Stewart  *    from this software without specific prior written permission.
17f8829a4aSRandall Stewart  *
18f8829a4aSRandall Stewart  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19f8829a4aSRandall Stewart  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20f8829a4aSRandall Stewart  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21f8829a4aSRandall Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22f8829a4aSRandall Stewart  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23f8829a4aSRandall Stewart  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24f8829a4aSRandall Stewart  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25f8829a4aSRandall Stewart  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26f8829a4aSRandall Stewart  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27f8829a4aSRandall Stewart  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28f8829a4aSRandall Stewart  * THE POSSIBILITY OF SUCH DAMAGE.
29f8829a4aSRandall Stewart  */
30f8829a4aSRandall Stewart 
31f8829a4aSRandall Stewart /* $KAME: sctp_timer.c,v 1.29 2005/03/06 16:04:18 itojun Exp $	 */
32f8829a4aSRandall Stewart 
33f8829a4aSRandall Stewart #include <sys/cdefs.h>
34f8829a4aSRandall Stewart __FBSDID("$FreeBSD$");
35f8829a4aSRandall Stewart 
36f8829a4aSRandall Stewart #define _IP_VHL
3793164cf9SRandall Stewart #include <netinet/sctp_os.h>
38f8829a4aSRandall Stewart #include <netinet/sctp_pcb.h>
39f8829a4aSRandall Stewart #ifdef INET6
40f8829a4aSRandall Stewart #include <netinet6/sctp6_var.h>
41f8829a4aSRandall Stewart #endif
42f8829a4aSRandall Stewart #include <netinet/sctp_var.h>
4342551e99SRandall Stewart #include <netinet/sctp_sysctl.h>
44f8829a4aSRandall Stewart #include <netinet/sctp_timer.h>
45f8829a4aSRandall Stewart #include <netinet/sctputil.h>
46f8829a4aSRandall Stewart #include <netinet/sctp_output.h>
47f8829a4aSRandall Stewart #include <netinet/sctp_header.h>
48f8829a4aSRandall Stewart #include <netinet/sctp_indata.h>
49f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h>
50f8829a4aSRandall Stewart #include <netinet/sctp_input.h>
51f8829a4aSRandall Stewart #include <netinet/sctp.h>
52f8829a4aSRandall Stewart #include <netinet/sctp_uio.h>
53f8829a4aSRandall Stewart 
54f8829a4aSRandall Stewart 
55f8829a4aSRandall Stewart 
56f8829a4aSRandall Stewart void
57f8829a4aSRandall Stewart sctp_early_fr_timer(struct sctp_inpcb *inp,
58f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
59f8829a4aSRandall Stewart     struct sctp_nets *net)
60f8829a4aSRandall Stewart {
61f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk, *tp2;
62f8829a4aSRandall Stewart 	struct timeval now, min_wait, tv;
63f8829a4aSRandall Stewart 	unsigned int cur_rtt, cnt = 0, cnt_resend = 0;
64f8829a4aSRandall Stewart 
65f8829a4aSRandall Stewart 	/* an early FR is occuring. */
666e55db54SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&now);
67f8829a4aSRandall Stewart 	/* get cur rto in micro-seconds */
68f8829a4aSRandall Stewart 	if (net->lastsa == 0) {
69f8829a4aSRandall Stewart 		/* Hmm no rtt estimate yet? */
70f8829a4aSRandall Stewart 		cur_rtt = stcb->asoc.initial_rto >> 2;
71f8829a4aSRandall Stewart 	} else {
72f8829a4aSRandall Stewart 
73f8829a4aSRandall Stewart 		cur_rtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
74f8829a4aSRandall Stewart 	}
75f8829a4aSRandall Stewart 	if (cur_rtt < sctp_early_fr_msec) {
76f8829a4aSRandall Stewart 		cur_rtt = sctp_early_fr_msec;
77f8829a4aSRandall Stewart 	}
78f8829a4aSRandall Stewart 	cur_rtt *= 1000;
79f8829a4aSRandall Stewart 	tv.tv_sec = cur_rtt / 1000000;
80f8829a4aSRandall Stewart 	tv.tv_usec = cur_rtt % 1000000;
81f8829a4aSRandall Stewart 	min_wait = now;
82f8829a4aSRandall Stewart 	timevalsub(&min_wait, &tv);
83f8829a4aSRandall Stewart 	if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
84f8829a4aSRandall Stewart 		/*
85f8829a4aSRandall Stewart 		 * if we hit here, we don't have enough seconds on the clock
86f8829a4aSRandall Stewart 		 * to account for the RTO. We just let the lower seconds be
87f8829a4aSRandall Stewart 		 * the bounds and don't worry about it. This may mean we
88f8829a4aSRandall Stewart 		 * will mark a lot more than we should.
89f8829a4aSRandall Stewart 		 */
90f8829a4aSRandall Stewart 		min_wait.tv_sec = min_wait.tv_usec = 0;
91f8829a4aSRandall Stewart 	}
92f8829a4aSRandall Stewart 	chk = TAILQ_LAST(&stcb->asoc.sent_queue, sctpchunk_listhead);
93f8829a4aSRandall Stewart 	for (; chk != NULL; chk = tp2) {
94f8829a4aSRandall Stewart 		tp2 = TAILQ_PREV(chk, sctpchunk_listhead, sctp_next);
95f8829a4aSRandall Stewart 		if (chk->whoTo != net) {
96f8829a4aSRandall Stewart 			continue;
97f8829a4aSRandall Stewart 		}
98f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND)
99f8829a4aSRandall Stewart 			cnt_resend++;
100f8829a4aSRandall Stewart 		else if ((chk->sent > SCTP_DATAGRAM_UNSENT) &&
101f8829a4aSRandall Stewart 		    (chk->sent < SCTP_DATAGRAM_RESEND)) {
102f8829a4aSRandall Stewart 			/* pending, may need retran */
103f8829a4aSRandall Stewart 			if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) {
104f8829a4aSRandall Stewart 				/*
105f8829a4aSRandall Stewart 				 * we have reached a chunk that was sent
106f8829a4aSRandall Stewart 				 * some seconds past our min.. forget it we
107f8829a4aSRandall Stewart 				 * will find no more to send.
108f8829a4aSRandall Stewart 				 */
109f8829a4aSRandall Stewart 				continue;
110f8829a4aSRandall Stewart 			} else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) {
111f8829a4aSRandall Stewart 				/*
112f8829a4aSRandall Stewart 				 * we must look at the micro seconds to
113f8829a4aSRandall Stewart 				 * know.
114f8829a4aSRandall Stewart 				 */
115f8829a4aSRandall Stewart 				if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
116f8829a4aSRandall Stewart 					/*
117f8829a4aSRandall Stewart 					 * ok it was sent after our boundary
118f8829a4aSRandall Stewart 					 * time.
119f8829a4aSRandall Stewart 					 */
120f8829a4aSRandall Stewart 					continue;
121f8829a4aSRandall Stewart 				}
122f8829a4aSRandall Stewart 			}
12380fefe0aSRandall Stewart 			if (sctp_logging_level & SCTP_EARLYFR_LOGGING_ENABLE) {
124f8829a4aSRandall Stewart 				sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
125f8829a4aSRandall Stewart 				    4, SCTP_FR_MARKED_EARLY);
12680fefe0aSRandall Stewart 			}
127f8829a4aSRandall Stewart 			SCTP_STAT_INCR(sctps_earlyfrmrkretrans);
128f8829a4aSRandall Stewart 			chk->sent = SCTP_DATAGRAM_RESEND;
129f8829a4aSRandall Stewart 			sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
130f8829a4aSRandall Stewart 			/* double book size since we are doing an early FR */
131f8829a4aSRandall Stewart 			chk->book_size_scale++;
132f8829a4aSRandall Stewart 			cnt += chk->send_size;
133f8829a4aSRandall Stewart 			if ((cnt + net->flight_size) > net->cwnd) {
134f8829a4aSRandall Stewart 				/* Mark all we could possibly resend */
135f8829a4aSRandall Stewart 				break;
136f8829a4aSRandall Stewart 			}
137f8829a4aSRandall Stewart 		}
138f8829a4aSRandall Stewart 	}
139f8829a4aSRandall Stewart 	if (cnt) {
140f8829a4aSRandall Stewart 		/*
141b54d3a6cSRandall Stewart 		 * JRS - Use the congestion control given in the congestion
142b54d3a6cSRandall Stewart 		 * control module
143f8829a4aSRandall Stewart 		 */
144b54d3a6cSRandall Stewart 		stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer(inp, stcb, net);
145f8829a4aSRandall Stewart 	} else if (cnt_resend) {
146f8829a4aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR);
147f8829a4aSRandall Stewart 	}
148f8829a4aSRandall Stewart 	/* Restart it? */
149f8829a4aSRandall Stewart 	if (net->flight_size < net->cwnd) {
150f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_earlyfrstrtmr);
151f8829a4aSRandall Stewart 		sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
152f8829a4aSRandall Stewart 	}
153f8829a4aSRandall Stewart }
154f8829a4aSRandall Stewart 
155f8829a4aSRandall Stewart void
156f8829a4aSRandall Stewart sctp_audit_retranmission_queue(struct sctp_association *asoc)
157f8829a4aSRandall Stewart {
158f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk;
159f8829a4aSRandall Stewart 
160ad81507eSRandall Stewart 	SCTPDBG(SCTP_DEBUG_TIMER4, "Audit invoked on send queue cnt:%d onqueue:%d\n",
161f8829a4aSRandall Stewart 	    asoc->sent_queue_retran_cnt,
162f8829a4aSRandall Stewart 	    asoc->sent_queue_cnt);
163f8829a4aSRandall Stewart 	asoc->sent_queue_retran_cnt = 0;
164f8829a4aSRandall Stewart 	asoc->sent_queue_cnt = 0;
165f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
166f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
167f8829a4aSRandall Stewart 			sctp_ucount_incr(asoc->sent_queue_retran_cnt);
168f8829a4aSRandall Stewart 		}
169f8829a4aSRandall Stewart 		asoc->sent_queue_cnt++;
170f8829a4aSRandall Stewart 	}
171f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
172f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
173f8829a4aSRandall Stewart 			sctp_ucount_incr(asoc->sent_queue_retran_cnt);
174f8829a4aSRandall Stewart 		}
175f8829a4aSRandall Stewart 	}
176ad81507eSRandall Stewart 	SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n",
177f8829a4aSRandall Stewart 	    asoc->sent_queue_retran_cnt,
178f8829a4aSRandall Stewart 	    asoc->sent_queue_cnt);
179f8829a4aSRandall Stewart }
180f8829a4aSRandall Stewart 
181f8829a4aSRandall Stewart int
182f8829a4aSRandall Stewart sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
183f8829a4aSRandall Stewart     struct sctp_nets *net, uint16_t threshold)
184f8829a4aSRandall Stewart {
185f8829a4aSRandall Stewart 	if (net) {
186f8829a4aSRandall Stewart 		net->error_count++;
187ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n",
188f8829a4aSRandall Stewart 		    net, net->error_count,
189f8829a4aSRandall Stewart 		    net->failure_threshold);
190f8829a4aSRandall Stewart 		if (net->error_count > net->failure_threshold) {
191f8829a4aSRandall Stewart 			/* We had a threshold failure */
192f8829a4aSRandall Stewart 			if (net->dest_state & SCTP_ADDR_REACHABLE) {
193f8829a4aSRandall Stewart 				net->dest_state &= ~SCTP_ADDR_REACHABLE;
194f8829a4aSRandall Stewart 				net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
19542551e99SRandall Stewart 				net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY;
196f8829a4aSRandall Stewart 				if (net == stcb->asoc.primary_destination) {
197f8829a4aSRandall Stewart 					net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
198f8829a4aSRandall Stewart 				}
199b54d3a6cSRandall Stewart 				/*
200b54d3a6cSRandall Stewart 				 * JRS 5/14/07 - If a destination is
201b54d3a6cSRandall Stewart 				 * unreachable, the PF bit is turned off.
202b54d3a6cSRandall Stewart 				 * This allows an unambiguous use of the PF
203b54d3a6cSRandall Stewart 				 * bit for destinations that are reachable
204b54d3a6cSRandall Stewart 				 * but potentially failed. If the
205b54d3a6cSRandall Stewart 				 * destination is set to the unreachable
206b54d3a6cSRandall Stewart 				 * state, also set the destination to the PF
207b54d3a6cSRandall Stewart 				 * state.
208b54d3a6cSRandall Stewart 				 */
209b54d3a6cSRandall Stewart 				/*
210b54d3a6cSRandall Stewart 				 * Add debug message here if destination is
211b54d3a6cSRandall Stewart 				 * not in PF state.
212b54d3a6cSRandall Stewart 				 */
213b54d3a6cSRandall Stewart 				/* Stop any running T3 timers here? */
214b54d3a6cSRandall Stewart 				if (sctp_cmt_pf) {
215b54d3a6cSRandall Stewart 					net->dest_state &= ~SCTP_ADDR_PF;
216b54d3a6cSRandall Stewart 					SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
217b54d3a6cSRandall Stewart 					    net);
218b54d3a6cSRandall Stewart 				}
219f8829a4aSRandall Stewart 				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
220f8829a4aSRandall Stewart 				    stcb,
221f8829a4aSRandall Stewart 				    SCTP_FAILED_THRESHOLD,
222f8829a4aSRandall Stewart 				    (void *)net);
223f8829a4aSRandall Stewart 			}
224f8829a4aSRandall Stewart 		}
225f8829a4aSRandall Stewart 		/*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE
226f8829a4aSRandall Stewart 		 *********ROUTING CODE
227f8829a4aSRandall Stewart 		 */
228f8829a4aSRandall Stewart 		/*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE
229f8829a4aSRandall Stewart 		 *********ROUTING CODE
230f8829a4aSRandall Stewart 		 */
231f8829a4aSRandall Stewart 	}
232f8829a4aSRandall Stewart 	if (stcb == NULL)
233f8829a4aSRandall Stewart 		return (0);
234f8829a4aSRandall Stewart 
235f8829a4aSRandall Stewart 	if (net) {
236f8829a4aSRandall Stewart 		if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) {
237f8829a4aSRandall Stewart 			stcb->asoc.overall_error_count++;
238f8829a4aSRandall Stewart 		}
239f8829a4aSRandall Stewart 	} else {
240f8829a4aSRandall Stewart 		stcb->asoc.overall_error_count++;
241f8829a4aSRandall Stewart 	}
242ad81507eSRandall Stewart 	SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n",
243ad81507eSRandall Stewart 	    &stcb->asoc, stcb->asoc.overall_error_count,
244f8829a4aSRandall Stewart 	    (uint32_t) threshold,
245f8829a4aSRandall Stewart 	    ((net == NULL) ? (uint32_t) 0 : (uint32_t) net->dest_state));
246f8829a4aSRandall Stewart 	/*
247f8829a4aSRandall Stewart 	 * We specifically do not do >= to give the assoc one more change
248f8829a4aSRandall Stewart 	 * before we fail it.
249f8829a4aSRandall Stewart 	 */
250f8829a4aSRandall Stewart 	if (stcb->asoc.overall_error_count > threshold) {
251f8829a4aSRandall Stewart 		/* Abort notification sends a ULP notify */
252f8829a4aSRandall Stewart 		struct mbuf *oper;
253f8829a4aSRandall Stewart 
254f8829a4aSRandall Stewart 		oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
255f8829a4aSRandall Stewart 		    0, M_DONTWAIT, 1, MT_DATA);
256f8829a4aSRandall Stewart 		if (oper) {
257f8829a4aSRandall Stewart 			struct sctp_paramhdr *ph;
258f8829a4aSRandall Stewart 			uint32_t *ippp;
259f8829a4aSRandall Stewart 
260139bc87fSRandall Stewart 			SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) +
261f8829a4aSRandall Stewart 			    sizeof(uint32_t);
262f8829a4aSRandall Stewart 			ph = mtod(oper, struct sctp_paramhdr *);
263f8829a4aSRandall Stewart 			ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
264139bc87fSRandall Stewart 			ph->param_length = htons(SCTP_BUF_LEN(oper));
265f8829a4aSRandall Stewart 			ippp = (uint32_t *) (ph + 1);
266a5d547adSRandall Stewart 			*ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_1);
267f8829a4aSRandall Stewart 		}
268a5d547adSRandall Stewart 		inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1;
269f8829a4aSRandall Stewart 		sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper);
270f8829a4aSRandall Stewart 		return (1);
271f8829a4aSRandall Stewart 	}
272f8829a4aSRandall Stewart 	return (0);
273f8829a4aSRandall Stewart }
274f8829a4aSRandall Stewart 
275f8829a4aSRandall Stewart struct sctp_nets *
276f8829a4aSRandall Stewart sctp_find_alternate_net(struct sctp_tcb *stcb,
277f8829a4aSRandall Stewart     struct sctp_nets *net,
278b54d3a6cSRandall Stewart     int mode)
279f8829a4aSRandall Stewart {
280f8829a4aSRandall Stewart 	/* Find and return an alternate network if possible */
281b54d3a6cSRandall Stewart 	struct sctp_nets *alt, *mnet, *min_errors_net = NULL, *max_cwnd_net = NULL;
282f8829a4aSRandall Stewart 	int once;
283b54d3a6cSRandall Stewart 
284b54d3a6cSRandall Stewart 	/* JRS 5/14/07 - Initialize min_errors to an impossible value. */
285b54d3a6cSRandall Stewart 	int min_errors = -1;
286b54d3a6cSRandall Stewart 	uint32_t max_cwnd = 0;
287f8829a4aSRandall Stewart 
288f8829a4aSRandall Stewart 	if (stcb->asoc.numnets == 1) {
289f8829a4aSRandall Stewart 		/* No others but net */
290f8829a4aSRandall Stewart 		return (TAILQ_FIRST(&stcb->asoc.nets));
291f8829a4aSRandall Stewart 	}
292b54d3a6cSRandall Stewart 	/*
293b54d3a6cSRandall Stewart 	 * JRS 5/14/07 - If mode is set to 2, use the CMT PF find alternate
294b54d3a6cSRandall Stewart 	 * net algorithm. This algorithm chooses the active destination (not
295b54d3a6cSRandall Stewart 	 * in PF state) with the largest cwnd value. If all destinations are
296b54d3a6cSRandall Stewart 	 * in PF state, unreachable, or unconfirmed, choose the desination
297b54d3a6cSRandall Stewart 	 * that is in PF state with the lowest error count. In case of a
298b54d3a6cSRandall Stewart 	 * tie, choose the destination that was most recently active.
299b54d3a6cSRandall Stewart 	 */
300b54d3a6cSRandall Stewart 	if (mode == 2) {
301b54d3a6cSRandall Stewart 		TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) {
302b54d3a6cSRandall Stewart 			/*
303b54d3a6cSRandall Stewart 			 * JRS 5/14/07 - If the destination is unreachable
304b54d3a6cSRandall Stewart 			 * or unconfirmed, skip it.
305b54d3a6cSRandall Stewart 			 */
306b54d3a6cSRandall Stewart 			if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) ||
307b54d3a6cSRandall Stewart 			    (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) {
308b54d3a6cSRandall Stewart 				continue;
309b54d3a6cSRandall Stewart 			}
310b54d3a6cSRandall Stewart 			/*
311b54d3a6cSRandall Stewart 			 * JRS 5/14/07 -  If the destination is reachable
312b54d3a6cSRandall Stewart 			 * but in PF state, compare the error count of the
313b54d3a6cSRandall Stewart 			 * destination to the minimum error count seen thus
314b54d3a6cSRandall Stewart 			 * far. Store the destination with the lower error
315b54d3a6cSRandall Stewart 			 * count.  If the error counts are equal, store the
316b54d3a6cSRandall Stewart 			 * destination that was most recently active.
317b54d3a6cSRandall Stewart 			 */
318b54d3a6cSRandall Stewart 			if (mnet->dest_state & SCTP_ADDR_PF) {
319b54d3a6cSRandall Stewart 				/*
320b54d3a6cSRandall Stewart 				 * JRS 5/14/07 - If the destination under
321b54d3a6cSRandall Stewart 				 * consideration is the current destination,
322b54d3a6cSRandall Stewart 				 * work as if the error count is one higher.
323b54d3a6cSRandall Stewart 				 * The actual error count will not be
324b54d3a6cSRandall Stewart 				 * incremented until later in the t3
325b54d3a6cSRandall Stewart 				 * handler.
326b54d3a6cSRandall Stewart 				 */
327b54d3a6cSRandall Stewart 				if (mnet == net) {
328b54d3a6cSRandall Stewart 					if (min_errors == -1) {
329b54d3a6cSRandall Stewart 						min_errors = mnet->error_count + 1;
330b54d3a6cSRandall Stewart 						min_errors_net = mnet;
331b54d3a6cSRandall Stewart 					} else if (mnet->error_count + 1 < min_errors) {
332b54d3a6cSRandall Stewart 						min_errors = mnet->error_count + 1;
333b54d3a6cSRandall Stewart 						min_errors_net = mnet;
334b54d3a6cSRandall Stewart 					} else if (mnet->error_count + 1 == min_errors
335b54d3a6cSRandall Stewart 					    && mnet->last_active > min_errors_net->last_active) {
336b54d3a6cSRandall Stewart 						min_errors_net = mnet;
337b54d3a6cSRandall Stewart 						min_errors = mnet->error_count + 1;
338b54d3a6cSRandall Stewart 					}
339b54d3a6cSRandall Stewart 					continue;
340b54d3a6cSRandall Stewart 				} else {
341b54d3a6cSRandall Stewart 					if (min_errors == -1) {
342b54d3a6cSRandall Stewart 						min_errors = mnet->error_count;
343b54d3a6cSRandall Stewart 						min_errors_net = mnet;
344b54d3a6cSRandall Stewart 					} else if (mnet->error_count < min_errors) {
345b54d3a6cSRandall Stewart 						min_errors = mnet->error_count;
346b54d3a6cSRandall Stewart 						min_errors_net = mnet;
347b54d3a6cSRandall Stewart 					} else if (mnet->error_count == min_errors
348b54d3a6cSRandall Stewart 					    && mnet->last_active > min_errors_net->last_active) {
349b54d3a6cSRandall Stewart 						min_errors_net = mnet;
350b54d3a6cSRandall Stewart 						min_errors = mnet->error_count;
351b54d3a6cSRandall Stewart 					}
352b54d3a6cSRandall Stewart 					continue;
353b54d3a6cSRandall Stewart 				}
354b54d3a6cSRandall Stewart 			}
355b54d3a6cSRandall Stewart 			/*
356b54d3a6cSRandall Stewart 			 * JRS 5/14/07 - If the destination is reachable and
357b54d3a6cSRandall Stewart 			 * not in PF state, compare the cwnd of the
358b54d3a6cSRandall Stewart 			 * destination to the highest cwnd seen thus far.
359b54d3a6cSRandall Stewart 			 * Store the destination with the higher cwnd value.
360b54d3a6cSRandall Stewart 			 * If the cwnd values are equal, randomly choose one
361b54d3a6cSRandall Stewart 			 * of the two destinations.
362b54d3a6cSRandall Stewart 			 */
363b54d3a6cSRandall Stewart 			if (max_cwnd < mnet->cwnd) {
364b54d3a6cSRandall Stewart 				max_cwnd_net = mnet;
365b54d3a6cSRandall Stewart 				max_cwnd = mnet->cwnd;
366b54d3a6cSRandall Stewart 			} else if (max_cwnd == mnet->cwnd) {
367b54d3a6cSRandall Stewart 				uint32_t rndval;
368b54d3a6cSRandall Stewart 				uint8_t this_random;
369b54d3a6cSRandall Stewart 
370b54d3a6cSRandall Stewart 				if (stcb->asoc.hb_random_idx > 3) {
371b54d3a6cSRandall Stewart 					rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep);
372b54d3a6cSRandall Stewart 					memcpy(stcb->asoc.hb_random_values, &rndval, sizeof(stcb->asoc.hb_random_values));
373b54d3a6cSRandall Stewart 					this_random = stcb->asoc.hb_random_values[0];
374b54d3a6cSRandall Stewart 					stcb->asoc.hb_random_idx++;
375b54d3a6cSRandall Stewart 					stcb->asoc.hb_ect_randombit = 0;
376b54d3a6cSRandall Stewart 				} else {
377b54d3a6cSRandall Stewart 					this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
378b54d3a6cSRandall Stewart 					stcb->asoc.hb_random_idx++;
379b54d3a6cSRandall Stewart 					stcb->asoc.hb_ect_randombit = 0;
380b54d3a6cSRandall Stewart 				}
381b54d3a6cSRandall Stewart 				if (this_random % 2 == 1) {
382b54d3a6cSRandall Stewart 					max_cwnd_net = mnet;
383b54d3a6cSRandall Stewart 					max_cwnd = mnet->cwnd;
384b54d3a6cSRandall Stewart 					//Useless ?
385b54d3a6cSRandall Stewart 				}
386b54d3a6cSRandall Stewart 			}
387b54d3a6cSRandall Stewart 		}
388b54d3a6cSRandall Stewart 		/*
389b54d3a6cSRandall Stewart 		 * JRS 5/14/07 - After all destination have been considered
390b54d3a6cSRandall Stewart 		 * as alternates, check to see if there was some active
391b54d3a6cSRandall Stewart 		 * destination (not in PF state).  If not, check to see if
392b54d3a6cSRandall Stewart 		 * there was some PF destination with the minimum number of
393b54d3a6cSRandall Stewart 		 * errors.  If not, return the original destination.  If
394b54d3a6cSRandall Stewart 		 * there is a min_errors_net, remove the PF flag from that
395b54d3a6cSRandall Stewart 		 * destination, set the cwnd to one or two MTUs, and return
396b54d3a6cSRandall Stewart 		 * the destination as an alt. If there was some active
397b54d3a6cSRandall Stewart 		 * destination with a highest cwnd, return the destination
398b54d3a6cSRandall Stewart 		 * as an alt.
399b54d3a6cSRandall Stewart 		 */
400b54d3a6cSRandall Stewart 		if (max_cwnd_net == NULL) {
401b54d3a6cSRandall Stewart 			if (min_errors_net == NULL) {
402b54d3a6cSRandall Stewart 				return (net);
403b54d3a6cSRandall Stewart 			}
404b54d3a6cSRandall Stewart 			min_errors_net->dest_state &= ~SCTP_ADDR_PF;
405b54d3a6cSRandall Stewart 			min_errors_net->cwnd = min_errors_net->mtu * sctp_cmt_pf;
406b54d3a6cSRandall Stewart 			if (SCTP_OS_TIMER_PENDING(&min_errors_net->rxt_timer.timer)) {
407b54d3a6cSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
408b54d3a6cSRandall Stewart 				    stcb, min_errors_net,
409b54d3a6cSRandall Stewart 				    SCTP_FROM_SCTP_TIMER + SCTP_LOC_2);
410b54d3a6cSRandall Stewart 			}
411b54d3a6cSRandall Stewart 			SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to active with %d errors.\n",
412b54d3a6cSRandall Stewart 			    min_errors_net, min_errors_net->error_count);
413b54d3a6cSRandall Stewart 			return (min_errors_net);
414b54d3a6cSRandall Stewart 		} else {
415b54d3a6cSRandall Stewart 			return (max_cwnd_net);
416b54d3a6cSRandall Stewart 		}
417b54d3a6cSRandall Stewart 	}
418b54d3a6cSRandall Stewart 	/*
419b54d3a6cSRandall Stewart 	 * JRS 5/14/07 - If mode is set to 1, use the CMT policy for
420b54d3a6cSRandall Stewart 	 * choosing an alternate net.
421b54d3a6cSRandall Stewart 	 */
422b54d3a6cSRandall Stewart 	else if (mode == 1) {
423f8829a4aSRandall Stewart 		TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) {
424f8829a4aSRandall Stewart 			if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) ||
425f8829a4aSRandall Stewart 			    (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)
426f8829a4aSRandall Stewart 			    ) {
427f8829a4aSRandall Stewart 				/*
428f8829a4aSRandall Stewart 				 * will skip ones that are not-reachable or
429f8829a4aSRandall Stewart 				 * unconfirmed
430f8829a4aSRandall Stewart 				 */
431f8829a4aSRandall Stewart 				continue;
432f8829a4aSRandall Stewart 			}
433b54d3a6cSRandall Stewart 			if (max_cwnd < mnet->cwnd) {
434b54d3a6cSRandall Stewart 				max_cwnd_net = mnet;
435b54d3a6cSRandall Stewart 				max_cwnd = mnet->cwnd;
436b54d3a6cSRandall Stewart 			} else if (max_cwnd == mnet->cwnd) {
437f8829a4aSRandall Stewart 				uint32_t rndval;
438f8829a4aSRandall Stewart 				uint8_t this_random;
439f8829a4aSRandall Stewart 
440f8829a4aSRandall Stewart 				if (stcb->asoc.hb_random_idx > 3) {
441f8829a4aSRandall Stewart 					rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep);
442f8829a4aSRandall Stewart 					memcpy(stcb->asoc.hb_random_values, &rndval,
443f8829a4aSRandall Stewart 					    sizeof(stcb->asoc.hb_random_values));
444f8829a4aSRandall Stewart 					this_random = stcb->asoc.hb_random_values[0];
445f8829a4aSRandall Stewart 					stcb->asoc.hb_random_idx = 0;
446f8829a4aSRandall Stewart 					stcb->asoc.hb_ect_randombit = 0;
447f8829a4aSRandall Stewart 				} else {
448f8829a4aSRandall Stewart 					this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
449f8829a4aSRandall Stewart 					stcb->asoc.hb_random_idx++;
450f8829a4aSRandall Stewart 					stcb->asoc.hb_ect_randombit = 0;
451f8829a4aSRandall Stewart 				}
452f8829a4aSRandall Stewart 				if (this_random % 2) {
453b54d3a6cSRandall Stewart 					max_cwnd_net = mnet;
454b54d3a6cSRandall Stewart 					max_cwnd = mnet->cwnd;
455f8829a4aSRandall Stewart 				}
456f8829a4aSRandall Stewart 			}
457f8829a4aSRandall Stewart 		}
458b54d3a6cSRandall Stewart 		if (max_cwnd_net) {
459b54d3a6cSRandall Stewart 			return (max_cwnd_net);
460f8829a4aSRandall Stewart 		}
461f8829a4aSRandall Stewart 	}
462f8829a4aSRandall Stewart 	mnet = net;
463f8829a4aSRandall Stewart 	once = 0;
464f8829a4aSRandall Stewart 
465f8829a4aSRandall Stewart 	if (mnet == NULL) {
466f8829a4aSRandall Stewart 		mnet = TAILQ_FIRST(&stcb->asoc.nets);
467f8829a4aSRandall Stewart 	}
468f8829a4aSRandall Stewart 	do {
469f8829a4aSRandall Stewart 		alt = TAILQ_NEXT(mnet, sctp_next);
470f8829a4aSRandall Stewart 		if (alt == NULL) {
471f8829a4aSRandall Stewart 			once++;
472f8829a4aSRandall Stewart 			if (once > 1) {
473f8829a4aSRandall Stewart 				break;
474f8829a4aSRandall Stewart 			}
475f8829a4aSRandall Stewart 			alt = TAILQ_FIRST(&stcb->asoc.nets);
476f8829a4aSRandall Stewart 		}
477f8829a4aSRandall Stewart 		if (alt->ro.ro_rt == NULL) {
47842551e99SRandall Stewart 			if (alt->ro._s_addr) {
47942551e99SRandall Stewart 				sctp_free_ifa(alt->ro._s_addr);
48042551e99SRandall Stewart 				alt->ro._s_addr = NULL;
48117205eccSRandall Stewart 
48242551e99SRandall Stewart 			}
483f8829a4aSRandall Stewart 			alt->src_addr_selected = 0;
484f8829a4aSRandall Stewart 		}
485f8829a4aSRandall Stewart 		if (
486f8829a4aSRandall Stewart 		    ((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) &&
487f8829a4aSRandall Stewart 		    (alt->ro.ro_rt != NULL) &&
4883c503c28SRandall Stewart 		/* sa_ignore NO_NULL_CHK */
489f8829a4aSRandall Stewart 		    (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))
490f8829a4aSRandall Stewart 		    ) {
491f8829a4aSRandall Stewart 			/* Found a reachable address */
492f8829a4aSRandall Stewart 			break;
493f8829a4aSRandall Stewart 		}
494f8829a4aSRandall Stewart 		mnet = alt;
495f8829a4aSRandall Stewart 	} while (alt != NULL);
496f8829a4aSRandall Stewart 
497f8829a4aSRandall Stewart 	if (alt == NULL) {
498f8829a4aSRandall Stewart 		/* Case where NO insv network exists (dormant state) */
499f8829a4aSRandall Stewart 		/* we rotate destinations */
500f8829a4aSRandall Stewart 		once = 0;
501f8829a4aSRandall Stewart 		mnet = net;
502f8829a4aSRandall Stewart 		do {
503f8829a4aSRandall Stewart 			alt = TAILQ_NEXT(mnet, sctp_next);
504f8829a4aSRandall Stewart 			if (alt == NULL) {
505f8829a4aSRandall Stewart 				once++;
506f8829a4aSRandall Stewart 				if (once > 1) {
507f8829a4aSRandall Stewart 					break;
508f8829a4aSRandall Stewart 				}
509f8829a4aSRandall Stewart 				alt = TAILQ_FIRST(&stcb->asoc.nets);
510f8829a4aSRandall Stewart 			}
5113c503c28SRandall Stewart 			/* sa_ignore NO_NULL_CHK */
512f8829a4aSRandall Stewart 			if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) &&
513f8829a4aSRandall Stewart 			    (alt != net)) {
514f8829a4aSRandall Stewart 				/* Found an alternate address */
515f8829a4aSRandall Stewart 				break;
516f8829a4aSRandall Stewart 			}
517f8829a4aSRandall Stewart 			mnet = alt;
518f8829a4aSRandall Stewart 		} while (alt != NULL);
519f8829a4aSRandall Stewart 	}
520f8829a4aSRandall Stewart 	if (alt == NULL) {
521f8829a4aSRandall Stewart 		return (net);
522f8829a4aSRandall Stewart 	}
523f8829a4aSRandall Stewart 	return (alt);
524f8829a4aSRandall Stewart }
525f8829a4aSRandall Stewart 
526b54d3a6cSRandall Stewart 
527b54d3a6cSRandall Stewart 
528f8829a4aSRandall Stewart static void
529f8829a4aSRandall Stewart sctp_backoff_on_timeout(struct sctp_tcb *stcb,
530f8829a4aSRandall Stewart     struct sctp_nets *net,
531f8829a4aSRandall Stewart     int win_probe,
532f8829a4aSRandall Stewart     int num_marked)
533f8829a4aSRandall Stewart {
5349a972525SRandall Stewart 	if (net->RTO == 0) {
5359a972525SRandall Stewart 		net->RTO = stcb->asoc.minrto;
5369a972525SRandall Stewart 	}
537f8829a4aSRandall Stewart 	net->RTO <<= 1;
538f8829a4aSRandall Stewart 	if (net->RTO > stcb->asoc.maxrto) {
539f8829a4aSRandall Stewart 		net->RTO = stcb->asoc.maxrto;
540f8829a4aSRandall Stewart 	}
541f8829a4aSRandall Stewart 	if ((win_probe == 0) && num_marked) {
542f8829a4aSRandall Stewart 		/* We don't apply penalty to window probe scenarios */
543b54d3a6cSRandall Stewart 		/* JRS - Use the congestion control given in the CC module */
544b54d3a6cSRandall Stewart 		stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net);
545f8829a4aSRandall Stewart 	}
546f8829a4aSRandall Stewart }
547f8829a4aSRandall Stewart 
548f8829a4aSRandall Stewart static int
549f8829a4aSRandall Stewart sctp_mark_all_for_resend(struct sctp_tcb *stcb,
550f8829a4aSRandall Stewart     struct sctp_nets *net,
551f8829a4aSRandall Stewart     struct sctp_nets *alt,
552f8829a4aSRandall Stewart     int window_probe,
553f8829a4aSRandall Stewart     int *num_marked)
554f8829a4aSRandall Stewart {
555f8829a4aSRandall Stewart 
556f8829a4aSRandall Stewart 	/*
557f8829a4aSRandall Stewart 	 * Mark all chunks (well not all) that were sent to *net for
558f8829a4aSRandall Stewart 	 * retransmission. Move them to alt for there destination as well...
559f8829a4aSRandall Stewart 	 * We only mark chunks that have been outstanding long enough to
560f8829a4aSRandall Stewart 	 * have received feed-back.
561f8829a4aSRandall Stewart 	 */
562f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk, *tp2, *could_be_sent = NULL;
563f8829a4aSRandall Stewart 	struct sctp_nets *lnets;
564f8829a4aSRandall Stewart 	struct timeval now, min_wait, tv;
565f8829a4aSRandall Stewart 	int cur_rtt;
566c105859eSRandall Stewart 	int audit_tf, num_mk, fir;
567f8829a4aSRandall Stewart 	unsigned int cnt_mk;
568c105859eSRandall Stewart 	uint32_t orig_flight, orig_tf;
569f8829a4aSRandall Stewart 	uint32_t tsnlast, tsnfirst;
570f8829a4aSRandall Stewart 
571b54d3a6cSRandall Stewart 
572f8829a4aSRandall Stewart 	/* none in flight now */
573f8829a4aSRandall Stewart 	audit_tf = 0;
574f8829a4aSRandall Stewart 	fir = 0;
575f8829a4aSRandall Stewart 	/*
576f8829a4aSRandall Stewart 	 * figure out how long a data chunk must be pending before we can
577f8829a4aSRandall Stewart 	 * mark it ..
578f8829a4aSRandall Stewart 	 */
5796e55db54SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&now);
580f8829a4aSRandall Stewart 	/* get cur rto in micro-seconds */
581f8829a4aSRandall Stewart 	cur_rtt = (((net->lastsa >> 2) + net->lastsv) >> 1);
582f8829a4aSRandall Stewart 	cur_rtt *= 1000;
58380fefe0aSRandall Stewart 	if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
584f8829a4aSRandall Stewart 		sctp_log_fr(cur_rtt,
585f8829a4aSRandall Stewart 		    stcb->asoc.peers_rwnd,
586f8829a4aSRandall Stewart 		    window_probe,
587f8829a4aSRandall Stewart 		    SCTP_FR_T3_MARK_TIME);
588f8829a4aSRandall Stewart 		sctp_log_fr(net->flight_size,
589139bc87fSRandall Stewart 		    SCTP_OS_TIMER_PENDING(&net->fr_timer.timer),
590139bc87fSRandall Stewart 		    SCTP_OS_TIMER_ACTIVE(&net->fr_timer.timer),
591f8829a4aSRandall Stewart 		    SCTP_FR_CWND_REPORT);
592f8829a4aSRandall Stewart 		sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT);
59380fefe0aSRandall Stewart 	}
594f8829a4aSRandall Stewart 	tv.tv_sec = cur_rtt / 1000000;
595f8829a4aSRandall Stewart 	tv.tv_usec = cur_rtt % 1000000;
596f8829a4aSRandall Stewart 	min_wait = now;
597f8829a4aSRandall Stewart 	timevalsub(&min_wait, &tv);
598f8829a4aSRandall Stewart 	if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
599f8829a4aSRandall Stewart 		/*
600f8829a4aSRandall Stewart 		 * if we hit here, we don't have enough seconds on the clock
601f8829a4aSRandall Stewart 		 * to account for the RTO. We just let the lower seconds be
602f8829a4aSRandall Stewart 		 * the bounds and don't worry about it. This may mean we
603f8829a4aSRandall Stewart 		 * will mark a lot more than we should.
604f8829a4aSRandall Stewart 		 */
605f8829a4aSRandall Stewart 		min_wait.tv_sec = min_wait.tv_usec = 0;
606f8829a4aSRandall Stewart 	}
60780fefe0aSRandall Stewart 	if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
608f8829a4aSRandall Stewart 		sctp_log_fr(cur_rtt, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME);
609f8829a4aSRandall Stewart 		sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME);
61080fefe0aSRandall Stewart 	}
611f8829a4aSRandall Stewart 	/*
612f8829a4aSRandall Stewart 	 * Our rwnd will be incorrect here since we are not adding back the
613f8829a4aSRandall Stewart 	 * cnt * mbuf but we will fix that down below.
614f8829a4aSRandall Stewart 	 */
615f8829a4aSRandall Stewart 	orig_flight = net->flight_size;
616c105859eSRandall Stewart 	orig_tf = stcb->asoc.total_flight;
617c105859eSRandall Stewart 
618f8829a4aSRandall Stewart 	net->fast_retran_ip = 0;
619f8829a4aSRandall Stewart 	/* Now on to each chunk */
620f8829a4aSRandall Stewart 	num_mk = cnt_mk = 0;
621f8829a4aSRandall Stewart 	tsnfirst = tsnlast = 0;
622f8829a4aSRandall Stewart 	chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
623f8829a4aSRandall Stewart 	for (; chk != NULL; chk = tp2) {
624f8829a4aSRandall Stewart 		tp2 = TAILQ_NEXT(chk, sctp_next);
625f8829a4aSRandall Stewart 		if ((compare_with_wrap(stcb->asoc.last_acked_seq,
626f8829a4aSRandall Stewart 		    chk->rec.data.TSN_seq,
627f8829a4aSRandall Stewart 		    MAX_TSN)) ||
628f8829a4aSRandall Stewart 		    (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) {
629f8829a4aSRandall Stewart 			/* Strange case our list got out of order? */
630ad81507eSRandall Stewart 			SCTP_PRINTF("Our list is out of order?\n");
631f8829a4aSRandall Stewart 			panic("Out of order list");
632f8829a4aSRandall Stewart 		}
633f8829a4aSRandall Stewart 		if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) {
634f8829a4aSRandall Stewart 			/*
635f8829a4aSRandall Stewart 			 * found one to mark: If it is less than
636f8829a4aSRandall Stewart 			 * DATAGRAM_ACKED it MUST not be a skipped or marked
637f8829a4aSRandall Stewart 			 * TSN but instead one that is either already set
638f8829a4aSRandall Stewart 			 * for retransmission OR one that needs
639f8829a4aSRandall Stewart 			 * retransmission.
640f8829a4aSRandall Stewart 			 */
641f8829a4aSRandall Stewart 
642f8829a4aSRandall Stewart 			/* validate its been outstanding long enough */
64380fefe0aSRandall Stewart 			if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
644f8829a4aSRandall Stewart 				sctp_log_fr(chk->rec.data.TSN_seq,
645f8829a4aSRandall Stewart 				    chk->sent_rcv_time.tv_sec,
646f8829a4aSRandall Stewart 				    chk->sent_rcv_time.tv_usec,
647f8829a4aSRandall Stewart 				    SCTP_FR_T3_MARK_TIME);
64880fefe0aSRandall Stewart 			}
649f8829a4aSRandall Stewart 			if ((chk->sent_rcv_time.tv_sec > min_wait.tv_sec) && (window_probe == 0)) {
650f8829a4aSRandall Stewart 				/*
651f8829a4aSRandall Stewart 				 * we have reached a chunk that was sent
652f8829a4aSRandall Stewart 				 * some seconds past our min.. forget it we
653f8829a4aSRandall Stewart 				 * will find no more to send.
654f8829a4aSRandall Stewart 				 */
65580fefe0aSRandall Stewart 				if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
656f8829a4aSRandall Stewart 					sctp_log_fr(0,
657f8829a4aSRandall Stewart 					    chk->sent_rcv_time.tv_sec,
658f8829a4aSRandall Stewart 					    chk->sent_rcv_time.tv_usec,
659f8829a4aSRandall Stewart 					    SCTP_FR_T3_STOPPED);
66080fefe0aSRandall Stewart 				}
661f8829a4aSRandall Stewart 				continue;
662f8829a4aSRandall Stewart 			} else if ((chk->sent_rcv_time.tv_sec == min_wait.tv_sec) &&
663f8829a4aSRandall Stewart 			    (window_probe == 0)) {
664f8829a4aSRandall Stewart 				/*
665f8829a4aSRandall Stewart 				 * we must look at the micro seconds to
666f8829a4aSRandall Stewart 				 * know.
667f8829a4aSRandall Stewart 				 */
668f8829a4aSRandall Stewart 				if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
669f8829a4aSRandall Stewart 					/*
670f8829a4aSRandall Stewart 					 * ok it was sent after our boundary
671f8829a4aSRandall Stewart 					 * time.
672f8829a4aSRandall Stewart 					 */
67380fefe0aSRandall Stewart 					if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
674f8829a4aSRandall Stewart 						sctp_log_fr(0,
675f8829a4aSRandall Stewart 						    chk->sent_rcv_time.tv_sec,
676f8829a4aSRandall Stewart 						    chk->sent_rcv_time.tv_usec,
677f8829a4aSRandall Stewart 						    SCTP_FR_T3_STOPPED);
67880fefe0aSRandall Stewart 					}
679f8829a4aSRandall Stewart 					continue;
680f8829a4aSRandall Stewart 				}
681f8829a4aSRandall Stewart 			}
682f8829a4aSRandall Stewart 			if (PR_SCTP_TTL_ENABLED(chk->flags)) {
683f8829a4aSRandall Stewart 				/* Is it expired? */
684f8829a4aSRandall Stewart 				if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) ||
685f8829a4aSRandall Stewart 				    ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) &&
686f8829a4aSRandall Stewart 				    (now.tv_usec > chk->rec.data.timetodrop.tv_usec))) {
687f8829a4aSRandall Stewart 					/* Yes so drop it */
688f8829a4aSRandall Stewart 					if (chk->data) {
689ad81507eSRandall Stewart 						(void)sctp_release_pr_sctp_chunk(stcb,
690f8829a4aSRandall Stewart 						    chk,
691f8829a4aSRandall Stewart 						    (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
692f8829a4aSRandall Stewart 						    &stcb->asoc.sent_queue);
693f8829a4aSRandall Stewart 					}
694f8829a4aSRandall Stewart 				}
695f8829a4aSRandall Stewart 				continue;
696f8829a4aSRandall Stewart 			}
697f8829a4aSRandall Stewart 			if (PR_SCTP_RTX_ENABLED(chk->flags)) {
698f8829a4aSRandall Stewart 				/* Has it been retransmitted tv_sec times? */
699f8829a4aSRandall Stewart 				if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) {
700f8829a4aSRandall Stewart 					if (chk->data) {
701ad81507eSRandall Stewart 						(void)sctp_release_pr_sctp_chunk(stcb,
702f8829a4aSRandall Stewart 						    chk,
703f8829a4aSRandall Stewart 						    (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
704f8829a4aSRandall Stewart 						    &stcb->asoc.sent_queue);
705f8829a4aSRandall Stewart 					}
706f8829a4aSRandall Stewart 				}
707f8829a4aSRandall Stewart 				continue;
708f8829a4aSRandall Stewart 			}
709c105859eSRandall Stewart 			if (chk->sent < SCTP_DATAGRAM_RESEND) {
710f8829a4aSRandall Stewart 				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
711f8829a4aSRandall Stewart 				num_mk++;
712f8829a4aSRandall Stewart 				if (fir == 0) {
713f8829a4aSRandall Stewart 					fir = 1;
714f8829a4aSRandall Stewart 					tsnfirst = chk->rec.data.TSN_seq;
715f8829a4aSRandall Stewart 				}
716f8829a4aSRandall Stewart 				tsnlast = chk->rec.data.TSN_seq;
71780fefe0aSRandall Stewart 				if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
718f8829a4aSRandall Stewart 					sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
719f8829a4aSRandall Stewart 					    0, SCTP_FR_T3_MARKED);
72080fefe0aSRandall Stewart 				}
72142551e99SRandall Stewart 				if (chk->rec.data.chunk_was_revoked) {
72242551e99SRandall Stewart 					/* deflate the cwnd */
72342551e99SRandall Stewart 					chk->whoTo->cwnd -= chk->book_size;
72442551e99SRandall Stewart 					chk->rec.data.chunk_was_revoked = 0;
72542551e99SRandall Stewart 				}
726f42a358aSRandall Stewart 				net->marked_retrans++;
727f42a358aSRandall Stewart 				stcb->asoc.marked_retrans++;
72880fefe0aSRandall Stewart 				if (sctp_logging_level & SCTP_FLIGHT_LOGGING_ENABLE) {
729c105859eSRandall Stewart 					sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO,
730a5d547adSRandall Stewart 					    chk->whoTo->flight_size,
731a5d547adSRandall Stewart 					    chk->book_size,
732c105859eSRandall Stewart 					    (uintptr_t) chk->whoTo,
733a5d547adSRandall Stewart 					    chk->rec.data.TSN_seq);
73480fefe0aSRandall Stewart 				}
735c105859eSRandall Stewart 				sctp_flight_size_decrease(chk);
736c105859eSRandall Stewart 				sctp_total_flight_decrease(stcb, chk);
737f8829a4aSRandall Stewart 				stcb->asoc.peers_rwnd += chk->send_size;
738f8829a4aSRandall Stewart 				stcb->asoc.peers_rwnd += sctp_peer_chunk_oh;
739c105859eSRandall Stewart 			}
740c105859eSRandall Stewart 			chk->sent = SCTP_DATAGRAM_RESEND;
741c105859eSRandall Stewart 			SCTP_STAT_INCR(sctps_markedretrans);
742f8829a4aSRandall Stewart 
743f8829a4aSRandall Stewart 			/* reset the TSN for striking and other FR stuff */
744b54d3a6cSRandall Stewart 			chk->window_probe = 0;
745f8829a4aSRandall Stewart 			chk->rec.data.doing_fast_retransmit = 0;
746f8829a4aSRandall Stewart 			/* Clear any time so NO RTT is being done */
747f8829a4aSRandall Stewart 			chk->do_rtt = 0;
748f8829a4aSRandall Stewart 			if (alt != net) {
749f8829a4aSRandall Stewart 				sctp_free_remote_addr(chk->whoTo);
750f8829a4aSRandall Stewart 				chk->no_fr_allowed = 1;
751f8829a4aSRandall Stewart 				chk->whoTo = alt;
752f8829a4aSRandall Stewart 				atomic_add_int(&alt->ref_count, 1);
753f8829a4aSRandall Stewart 			} else {
754f8829a4aSRandall Stewart 				chk->no_fr_allowed = 0;
755f8829a4aSRandall Stewart 				if (TAILQ_EMPTY(&stcb->asoc.send_queue)) {
756f8829a4aSRandall Stewart 					chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq;
757f8829a4aSRandall Stewart 				} else {
758f8829a4aSRandall Stewart 					chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq;
759f8829a4aSRandall Stewart 				}
760f8829a4aSRandall Stewart 			}
761ad21a364SRandall Stewart 			/*
762ad21a364SRandall Stewart 			 * CMT: Do not allow FRs on retransmitted TSNs.
763ad21a364SRandall Stewart 			 */
764f8829a4aSRandall Stewart 			if (sctp_cmt_on_off == 1) {
765f8829a4aSRandall Stewart 				chk->no_fr_allowed = 1;
766f8829a4aSRandall Stewart 			}
767f8829a4aSRandall Stewart 		} else if (chk->sent == SCTP_DATAGRAM_ACKED) {
768f8829a4aSRandall Stewart 			/* remember highest acked one */
769f8829a4aSRandall Stewart 			could_be_sent = chk;
770f8829a4aSRandall Stewart 		}
771f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
772f8829a4aSRandall Stewart 			cnt_mk++;
773f8829a4aSRandall Stewart 		}
774f8829a4aSRandall Stewart 	}
775c105859eSRandall Stewart 	if ((orig_flight - net->flight_size) != (orig_tf - stcb->asoc.total_flight)) {
776c105859eSRandall Stewart 		/* we did not subtract the same things? */
777c105859eSRandall Stewart 		audit_tf = 1;
778c105859eSRandall Stewart 	}
77980fefe0aSRandall Stewart 	if (sctp_logging_level & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
780f8829a4aSRandall Stewart 		sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT);
78180fefe0aSRandall Stewart 	}
782f8829a4aSRandall Stewart #ifdef SCTP_DEBUG
783f8829a4aSRandall Stewart 	if (num_mk) {
784ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n",
785ad81507eSRandall Stewart 		    tsnlast);
786ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%ld\n",
787f8829a4aSRandall Stewart 		    num_mk, (u_long)stcb->asoc.peers_rwnd);
788ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n",
789ad81507eSRandall Stewart 		    tsnlast);
790ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%d\n",
791f8829a4aSRandall Stewart 		    num_mk,
792ad81507eSRandall Stewart 		    (int)stcb->asoc.peers_rwnd);
793f8829a4aSRandall Stewart 	}
794f8829a4aSRandall Stewart #endif
795f8829a4aSRandall Stewart 	*num_marked = num_mk;
796f8829a4aSRandall Stewart 	if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) {
797f8829a4aSRandall Stewart 		/* fix it so we retransmit the highest acked anyway */
798f8829a4aSRandall Stewart 		sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
799f8829a4aSRandall Stewart 		cnt_mk++;
800f8829a4aSRandall Stewart 		could_be_sent->sent = SCTP_DATAGRAM_RESEND;
801f8829a4aSRandall Stewart 	}
802f8829a4aSRandall Stewart 	if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) {
803a5d547adSRandall Stewart #ifdef INVARIANTS
804ad81507eSRandall Stewart 		SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d\n",
805f8829a4aSRandall Stewart 		    cnt_mk, stcb->asoc.sent_queue_retran_cnt);
806f8829a4aSRandall Stewart #endif
807f8829a4aSRandall Stewart #ifndef SCTP_AUDITING_ENABLED
808f8829a4aSRandall Stewart 		stcb->asoc.sent_queue_retran_cnt = cnt_mk;
809f8829a4aSRandall Stewart #endif
810f8829a4aSRandall Stewart 	}
811f8829a4aSRandall Stewart 	/* Now check for a ECN Echo that may be stranded */
812f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
813f8829a4aSRandall Stewart 		if ((chk->whoTo == net) &&
814f8829a4aSRandall Stewart 		    (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) {
815f8829a4aSRandall Stewart 			sctp_free_remote_addr(chk->whoTo);
816f8829a4aSRandall Stewart 			chk->whoTo = alt;
817f8829a4aSRandall Stewart 			if (chk->sent != SCTP_DATAGRAM_RESEND) {
818f8829a4aSRandall Stewart 				chk->sent = SCTP_DATAGRAM_RESEND;
819f8829a4aSRandall Stewart 				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
820f8829a4aSRandall Stewart 			}
821f8829a4aSRandall Stewart 			atomic_add_int(&alt->ref_count, 1);
822f8829a4aSRandall Stewart 		}
823f8829a4aSRandall Stewart 	}
824f8829a4aSRandall Stewart 	if (audit_tf) {
825ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER4,
826ad81507eSRandall Stewart 		    "Audit total flight due to negative value net:%p\n",
827f8829a4aSRandall Stewart 		    net);
828f8829a4aSRandall Stewart 		stcb->asoc.total_flight = 0;
829f8829a4aSRandall Stewart 		stcb->asoc.total_flight_count = 0;
830f8829a4aSRandall Stewart 		/* Clear all networks flight size */
831f8829a4aSRandall Stewart 		TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) {
832f8829a4aSRandall Stewart 			lnets->flight_size = 0;
833ad81507eSRandall Stewart 			SCTPDBG(SCTP_DEBUG_TIMER4,
834ad81507eSRandall Stewart 			    "Net:%p c-f cwnd:%d ssthresh:%d\n",
835f8829a4aSRandall Stewart 			    lnets, lnets->cwnd, lnets->ssthresh);
836f8829a4aSRandall Stewart 		}
837f8829a4aSRandall Stewart 		TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
838f8829a4aSRandall Stewart 			if (chk->sent < SCTP_DATAGRAM_RESEND) {
83980fefe0aSRandall Stewart 				if (sctp_logging_level & SCTP_FLIGHT_LOGGING_ENABLE) {
840a5d547adSRandall Stewart 					sctp_misc_ints(SCTP_FLIGHT_LOG_UP,
841a5d547adSRandall Stewart 					    chk->whoTo->flight_size,
842a5d547adSRandall Stewart 					    chk->book_size,
843c105859eSRandall Stewart 					    (uintptr_t) chk->whoTo,
844a5d547adSRandall Stewart 					    chk->rec.data.TSN_seq);
84580fefe0aSRandall Stewart 				}
846c105859eSRandall Stewart 				sctp_flight_size_increase(chk);
847c105859eSRandall Stewart 				sctp_total_flight_increase(stcb, chk);
848f8829a4aSRandall Stewart 			}
849f8829a4aSRandall Stewart 		}
850f8829a4aSRandall Stewart 	}
851f8829a4aSRandall Stewart 	/*
852f8829a4aSRandall Stewart 	 * Setup the ecn nonce re-sync point. We do this since
853f8829a4aSRandall Stewart 	 * retranmissions are NOT setup for ECN. This means that do to
854f8829a4aSRandall Stewart 	 * Karn's rule, we don't know the total of the peers ecn bits.
855f8829a4aSRandall Stewart 	 */
856f8829a4aSRandall Stewart 	chk = TAILQ_FIRST(&stcb->asoc.send_queue);
857f8829a4aSRandall Stewart 	if (chk == NULL) {
858f8829a4aSRandall Stewart 		stcb->asoc.nonce_resync_tsn = stcb->asoc.sending_seq;
859f8829a4aSRandall Stewart 	} else {
860f8829a4aSRandall Stewart 		stcb->asoc.nonce_resync_tsn = chk->rec.data.TSN_seq;
861f8829a4aSRandall Stewart 	}
862f8829a4aSRandall Stewart 	stcb->asoc.nonce_wait_for_ecne = 0;
863f8829a4aSRandall Stewart 	stcb->asoc.nonce_sum_check = 0;
864f8829a4aSRandall Stewart 	/* We return 1 if we only have a window probe outstanding */
865f8829a4aSRandall Stewart 	return (0);
866f8829a4aSRandall Stewart }
867f8829a4aSRandall Stewart 
868f8829a4aSRandall Stewart static void
869f8829a4aSRandall Stewart sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb,
870f8829a4aSRandall Stewart     struct sctp_nets *net,
871f8829a4aSRandall Stewart     struct sctp_nets *alt)
872f8829a4aSRandall Stewart {
873f8829a4aSRandall Stewart 	struct sctp_association *asoc;
874f8829a4aSRandall Stewart 	struct sctp_stream_out *outs;
875f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk;
876f8829a4aSRandall Stewart 	struct sctp_stream_queue_pending *sp;
877f8829a4aSRandall Stewart 
878f8829a4aSRandall Stewart 	if (net == alt)
879f8829a4aSRandall Stewart 		/* nothing to do */
880f8829a4aSRandall Stewart 		return;
881f8829a4aSRandall Stewart 
882f8829a4aSRandall Stewart 	asoc = &stcb->asoc;
883f8829a4aSRandall Stewart 
884f8829a4aSRandall Stewart 	/*
885f8829a4aSRandall Stewart 	 * now through all the streams checking for chunks sent to our bad
886f8829a4aSRandall Stewart 	 * network.
887f8829a4aSRandall Stewart 	 */
888f8829a4aSRandall Stewart 	TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
889f8829a4aSRandall Stewart 		/* now clean up any chunks here */
890f8829a4aSRandall Stewart 		TAILQ_FOREACH(sp, &outs->outqueue, next) {
891f8829a4aSRandall Stewart 			if (sp->net == net) {
892f8829a4aSRandall Stewart 				sctp_free_remote_addr(sp->net);
893f8829a4aSRandall Stewart 				sp->net = alt;
894f8829a4aSRandall Stewart 				atomic_add_int(&alt->ref_count, 1);
895f8829a4aSRandall Stewart 			}
896f8829a4aSRandall Stewart 		}
897f8829a4aSRandall Stewart 	}
898f8829a4aSRandall Stewart 	/* Now check the pending queue */
899f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
900f8829a4aSRandall Stewart 		if (chk->whoTo == net) {
901f8829a4aSRandall Stewart 			sctp_free_remote_addr(chk->whoTo);
902f8829a4aSRandall Stewart 			chk->whoTo = alt;
903f8829a4aSRandall Stewart 			atomic_add_int(&alt->ref_count, 1);
904f8829a4aSRandall Stewart 		}
905f8829a4aSRandall Stewart 	}
906f8829a4aSRandall Stewart 
907f8829a4aSRandall Stewart }
908f8829a4aSRandall Stewart 
909f8829a4aSRandall Stewart int
910f8829a4aSRandall Stewart sctp_t3rxt_timer(struct sctp_inpcb *inp,
911f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
912f8829a4aSRandall Stewart     struct sctp_nets *net)
913f8829a4aSRandall Stewart {
914f8829a4aSRandall Stewart 	struct sctp_nets *alt;
915f8829a4aSRandall Stewart 	int win_probe, num_mk;
916f8829a4aSRandall Stewart 
91780fefe0aSRandall Stewart 	if (sctp_logging_level & SCTP_FR_LOGGING_ENABLE) {
918562a89b5SRandall Stewart 		sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT);
91980fefe0aSRandall Stewart 	}
92080fefe0aSRandall Stewart 	if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
921f8829a4aSRandall Stewart 		struct sctp_nets *lnet;
922f8829a4aSRandall Stewart 
923f8829a4aSRandall Stewart 		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
924f8829a4aSRandall Stewart 			if (net == lnet) {
925f8829a4aSRandall Stewart 				sctp_log_cwnd(stcb, lnet, 1, SCTP_CWND_LOG_FROM_T3);
926f8829a4aSRandall Stewart 			} else {
927f8829a4aSRandall Stewart 				sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_LOG_FROM_T3);
928f8829a4aSRandall Stewart 			}
929f8829a4aSRandall Stewart 		}
930f8829a4aSRandall Stewart 	}
931f8829a4aSRandall Stewart 	/* Find an alternate and mark those for retransmission */
932f8829a4aSRandall Stewart 	if ((stcb->asoc.peers_rwnd == 0) &&
933f8829a4aSRandall Stewart 	    (stcb->asoc.total_flight < net->mtu)) {
934f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timowindowprobe);
935f8829a4aSRandall Stewart 		win_probe = 1;
936f8829a4aSRandall Stewart 	} else {
937f8829a4aSRandall Stewart 		win_probe = 0;
938f8829a4aSRandall Stewart 	}
939c105859eSRandall Stewart 
940b54d3a6cSRandall Stewart 	/*
941b54d3a6cSRandall Stewart 	 * JRS 5/14/07 - If CMT PF is on and the destination if not already
942b54d3a6cSRandall Stewart 	 * in PF state, set the destination to PF state and store the
943b54d3a6cSRandall Stewart 	 * current time as the time that the destination was last active. In
944b54d3a6cSRandall Stewart 	 * addition, find an alternate destination with PF-based
945b54d3a6cSRandall Stewart 	 * find_alt_net().
946b54d3a6cSRandall Stewart 	 */
947b54d3a6cSRandall Stewart 	if (sctp_cmt_pf) {
948b54d3a6cSRandall Stewart 		if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) {
949b54d3a6cSRandall Stewart 			net->dest_state |= SCTP_ADDR_PF;
950b54d3a6cSRandall Stewart 			net->last_active = ticks;
951b54d3a6cSRandall Stewart 			SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from active to PF.\n",
952b54d3a6cSRandall Stewart 			    net);
953b54d3a6cSRandall Stewart 		}
954b54d3a6cSRandall Stewart 		alt = sctp_find_alternate_net(stcb, net, 2);
955b54d3a6cSRandall Stewart 	} else if (sctp_cmt_on_off) {
956c105859eSRandall Stewart 		/*
957c105859eSRandall Stewart 		 * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being
958c105859eSRandall Stewart 		 * used, then pick dest with largest ssthresh for any
959c105859eSRandall Stewart 		 * retransmission.
960c105859eSRandall Stewart 		 */
961c105859eSRandall Stewart 		alt = net;
962c105859eSRandall Stewart 		alt = sctp_find_alternate_net(stcb, alt, 1);
963c105859eSRandall Stewart 		/*
964c105859eSRandall Stewart 		 * CUCv2: If a different dest is picked for the
965c105859eSRandall Stewart 		 * retransmission, then new (rtx-)pseudo_cumack needs to be
966c105859eSRandall Stewart 		 * tracked for orig dest. Let CUCv2 track new (rtx-)
967c105859eSRandall Stewart 		 * pseudo-cumack always.
968c105859eSRandall Stewart 		 */
969c105859eSRandall Stewart 		net->find_pseudo_cumack = 1;
970c105859eSRandall Stewart 		net->find_rtx_pseudo_cumack = 1;
971c105859eSRandall Stewart 
972c105859eSRandall Stewart 	} else {		/* CMT is OFF */
973f8829a4aSRandall Stewart 		alt = sctp_find_alternate_net(stcb, net, 0);
974c105859eSRandall Stewart 	}
975c105859eSRandall Stewart 
976ad81507eSRandall Stewart 	(void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, &num_mk);
977f8829a4aSRandall Stewart 	/* FR Loss recovery just ended with the T3. */
978f8829a4aSRandall Stewart 	stcb->asoc.fast_retran_loss_recovery = 0;
979f8829a4aSRandall Stewart 
980f8829a4aSRandall Stewart 	/* CMT FR loss recovery ended with the T3 */
981f8829a4aSRandall Stewart 	net->fast_retran_loss_recovery = 0;
982f8829a4aSRandall Stewart 
983f8829a4aSRandall Stewart 	/*
984f8829a4aSRandall Stewart 	 * setup the sat loss recovery that prevents satellite cwnd advance.
985f8829a4aSRandall Stewart 	 */
986f8829a4aSRandall Stewart 	stcb->asoc.sat_t3_loss_recovery = 1;
987f8829a4aSRandall Stewart 	stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq;
988f8829a4aSRandall Stewart 
989f8829a4aSRandall Stewart 	/* Backoff the timer and cwnd */
990f8829a4aSRandall Stewart 	sctp_backoff_on_timeout(stcb, net, win_probe, num_mk);
991f8829a4aSRandall Stewart 	if (win_probe == 0) {
992f8829a4aSRandall Stewart 		/* We don't do normal threshold management on window probes */
993f8829a4aSRandall Stewart 		if (sctp_threshold_management(inp, stcb, net,
994f8829a4aSRandall Stewart 		    stcb->asoc.max_send_times)) {
995f8829a4aSRandall Stewart 			/* Association was destroyed */
996f8829a4aSRandall Stewart 			return (1);
997f8829a4aSRandall Stewart 		} else {
998f8829a4aSRandall Stewart 			if (net != stcb->asoc.primary_destination) {
999f8829a4aSRandall Stewart 				/* send a immediate HB if our RTO is stale */
1000f8829a4aSRandall Stewart 				struct timeval now;
1001f8829a4aSRandall Stewart 				unsigned int ms_goneby;
1002f8829a4aSRandall Stewart 
10036e55db54SRandall Stewart 				(void)SCTP_GETTIME_TIMEVAL(&now);
1004f8829a4aSRandall Stewart 				if (net->last_sent_time.tv_sec) {
1005f8829a4aSRandall Stewart 					ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
1006f8829a4aSRandall Stewart 				} else {
1007f8829a4aSRandall Stewart 					ms_goneby = 0;
1008f8829a4aSRandall Stewart 				}
1009f8829a4aSRandall Stewart 				if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
1010f8829a4aSRandall Stewart 					/*
1011f8829a4aSRandall Stewart 					 * no recent feed back in an RTO or
1012f8829a4aSRandall Stewart 					 * more, request a RTT update
1013f8829a4aSRandall Stewart 					 */
1014b54d3a6cSRandall Stewart 					if (sctp_send_hb(stcb, 1, net) < 0)
1015b54d3a6cSRandall Stewart 						return 1;
1016f8829a4aSRandall Stewart 				}
1017f8829a4aSRandall Stewart 			}
1018f8829a4aSRandall Stewart 		}
1019f8829a4aSRandall Stewart 	} else {
1020f8829a4aSRandall Stewart 		/*
1021f8829a4aSRandall Stewart 		 * For a window probe we don't penalize the net's but only
1022f8829a4aSRandall Stewart 		 * the association. This may fail it if SACKs are not coming
1023f8829a4aSRandall Stewart 		 * back. If sack's are coming with rwnd locked at 0, we will
1024f8829a4aSRandall Stewart 		 * continue to hold things waiting for rwnd to raise
1025f8829a4aSRandall Stewart 		 */
1026f8829a4aSRandall Stewart 		if (sctp_threshold_management(inp, stcb, NULL,
1027f8829a4aSRandall Stewart 		    stcb->asoc.max_send_times)) {
1028f8829a4aSRandall Stewart 			/* Association was destroyed */
1029f8829a4aSRandall Stewart 			return (1);
1030f8829a4aSRandall Stewart 		}
1031f8829a4aSRandall Stewart 	}
1032f8829a4aSRandall Stewart 	if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
1033f8829a4aSRandall Stewart 		/* Move all pending over too */
1034f8829a4aSRandall Stewart 		sctp_move_all_chunks_to_alt(stcb, net, alt);
103517205eccSRandall Stewart 
103617205eccSRandall Stewart 		/*
103717205eccSRandall Stewart 		 * Get the address that failed, to force a new src address
103817205eccSRandall Stewart 		 * selecton and a route allocation.
103917205eccSRandall Stewart 		 */
104017205eccSRandall Stewart 		if (net->ro._s_addr) {
104117205eccSRandall Stewart 			sctp_free_ifa(net->ro._s_addr);
104217205eccSRandall Stewart 			net->ro._s_addr = NULL;
104317205eccSRandall Stewart 		}
104417205eccSRandall Stewart 		net->src_addr_selected = 0;
104517205eccSRandall Stewart 
104617205eccSRandall Stewart 		/* Force a route allocation too */
104717205eccSRandall Stewart 		if (net->ro.ro_rt) {
104817205eccSRandall Stewart 			RTFREE(net->ro.ro_rt);
104917205eccSRandall Stewart 			net->ro.ro_rt = NULL;
105017205eccSRandall Stewart 		}
1051f8829a4aSRandall Stewart 		/* Was it our primary? */
1052f8829a4aSRandall Stewart 		if ((stcb->asoc.primary_destination == net) && (alt != net)) {
1053f8829a4aSRandall Stewart 			/*
1054f8829a4aSRandall Stewart 			 * Yes, note it as such and find an alternate note:
1055f8829a4aSRandall Stewart 			 * this means HB code must use this to resent the
1056f8829a4aSRandall Stewart 			 * primary if it goes active AND if someone does a
1057f8829a4aSRandall Stewart 			 * change-primary then this flag must be cleared
1058f8829a4aSRandall Stewart 			 * from any net structures.
1059f8829a4aSRandall Stewart 			 */
1060f8829a4aSRandall Stewart 			if (sctp_set_primary_addr(stcb,
1061f8829a4aSRandall Stewart 			    (struct sockaddr *)NULL,
1062f8829a4aSRandall Stewart 			    alt) == 0) {
1063f8829a4aSRandall Stewart 				net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
1064f8829a4aSRandall Stewart 			}
1065f8829a4aSRandall Stewart 		}
1066b54d3a6cSRandall Stewart 	} else if (sctp_cmt_pf && (net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) {
1067b54d3a6cSRandall Stewart 		/*
1068b54d3a6cSRandall Stewart 		 * JRS 5/14/07 - If the destination hasn't failed completely
1069b54d3a6cSRandall Stewart 		 * but is in PF state, a PF-heartbeat needs to be sent
1070b54d3a6cSRandall Stewart 		 * manually.
1071b54d3a6cSRandall Stewart 		 */
1072b54d3a6cSRandall Stewart 		if (sctp_send_hb(stcb, 1, net) < 0)
1073b54d3a6cSRandall Stewart 			return 1;
1074f8829a4aSRandall Stewart 	}
1075f8829a4aSRandall Stewart 	/*
1076f8829a4aSRandall Stewart 	 * Special case for cookie-echo'ed case, we don't do output but must
1077f8829a4aSRandall Stewart 	 * await the COOKIE-ACK before retransmission
1078f8829a4aSRandall Stewart 	 */
1079f8829a4aSRandall Stewart 	if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
1080f8829a4aSRandall Stewart 		/*
1081f8829a4aSRandall Stewart 		 * Here we just reset the timer and start again since we
1082f8829a4aSRandall Stewart 		 * have not established the asoc
1083f8829a4aSRandall Stewart 		 */
1084f8829a4aSRandall Stewart 		sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
1085f8829a4aSRandall Stewart 		return (0);
1086f8829a4aSRandall Stewart 	}
1087f8829a4aSRandall Stewart 	if (stcb->asoc.peer_supports_prsctp) {
1088f8829a4aSRandall Stewart 		struct sctp_tmit_chunk *lchk;
1089f8829a4aSRandall Stewart 
1090f8829a4aSRandall Stewart 		lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc);
1091f8829a4aSRandall Stewart 		/* C3. See if we need to send a Fwd-TSN */
1092f8829a4aSRandall Stewart 		if (compare_with_wrap(stcb->asoc.advanced_peer_ack_point,
1093f8829a4aSRandall Stewart 		    stcb->asoc.last_acked_seq, MAX_TSN)) {
1094f8829a4aSRandall Stewart 			/*
1095f8829a4aSRandall Stewart 			 * ISSUE with ECN, see FWD-TSN processing for notes
1096f8829a4aSRandall Stewart 			 * on issues that will occur when the ECN NONCE
1097f8829a4aSRandall Stewart 			 * stuff is put into SCTP for cross checking.
1098f8829a4aSRandall Stewart 			 */
1099f8829a4aSRandall Stewart 			send_forward_tsn(stcb, &stcb->asoc);
1100f8829a4aSRandall Stewart 			if (lchk) {
1101f8829a4aSRandall Stewart 				/* Assure a timer is up */
1102f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo);
1103f8829a4aSRandall Stewart 			}
1104f8829a4aSRandall Stewart 		}
1105f8829a4aSRandall Stewart 	}
110680fefe0aSRandall Stewart 	if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
1107f8829a4aSRandall Stewart 		sctp_log_cwnd(stcb, net, net->cwnd, SCTP_CWND_LOG_FROM_RTX);
110880fefe0aSRandall Stewart 	}
1109f8829a4aSRandall Stewart 	return (0);
1110f8829a4aSRandall Stewart }
1111f8829a4aSRandall Stewart 
1112f8829a4aSRandall Stewart int
1113f8829a4aSRandall Stewart sctp_t1init_timer(struct sctp_inpcb *inp,
1114f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
1115f8829a4aSRandall Stewart     struct sctp_nets *net)
1116f8829a4aSRandall Stewart {
1117f8829a4aSRandall Stewart 	/* bump the thresholds */
1118f8829a4aSRandall Stewart 	if (stcb->asoc.delayed_connection) {
1119f8829a4aSRandall Stewart 		/*
1120f8829a4aSRandall Stewart 		 * special hook for delayed connection. The library did NOT
1121f8829a4aSRandall Stewart 		 * complete the rest of its sends.
1122f8829a4aSRandall Stewart 		 */
1123f8829a4aSRandall Stewart 		stcb->asoc.delayed_connection = 0;
1124f8829a4aSRandall Stewart 		sctp_send_initiate(inp, stcb);
1125f8829a4aSRandall Stewart 		return (0);
1126f8829a4aSRandall Stewart 	}
1127f8829a4aSRandall Stewart 	if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) {
1128f8829a4aSRandall Stewart 		return (0);
1129f8829a4aSRandall Stewart 	}
1130f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, net,
1131f8829a4aSRandall Stewart 	    stcb->asoc.max_init_times)) {
1132f8829a4aSRandall Stewart 		/* Association was destroyed */
1133f8829a4aSRandall Stewart 		return (1);
1134f8829a4aSRandall Stewart 	}
1135f8829a4aSRandall Stewart 	stcb->asoc.dropped_special_cnt = 0;
1136f8829a4aSRandall Stewart 	sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0);
1137f8829a4aSRandall Stewart 	if (stcb->asoc.initial_init_rto_max < net->RTO) {
1138f8829a4aSRandall Stewart 		net->RTO = stcb->asoc.initial_init_rto_max;
1139f8829a4aSRandall Stewart 	}
1140f8829a4aSRandall Stewart 	if (stcb->asoc.numnets > 1) {
1141f8829a4aSRandall Stewart 		/* If we have more than one addr use it */
1142f8829a4aSRandall Stewart 		struct sctp_nets *alt;
1143f8829a4aSRandall Stewart 
1144f8829a4aSRandall Stewart 		alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0);
1145f8829a4aSRandall Stewart 		if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) {
1146f8829a4aSRandall Stewart 			sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt);
1147f8829a4aSRandall Stewart 			stcb->asoc.primary_destination = alt;
1148f8829a4aSRandall Stewart 		}
1149f8829a4aSRandall Stewart 	}
1150f8829a4aSRandall Stewart 	/* Send out a new init */
1151f8829a4aSRandall Stewart 	sctp_send_initiate(inp, stcb);
1152f8829a4aSRandall Stewart 	return (0);
1153f8829a4aSRandall Stewart }
1154f8829a4aSRandall Stewart 
1155f8829a4aSRandall Stewart /*
1156f8829a4aSRandall Stewart  * For cookie and asconf we actually need to find and mark for resend, then
1157f8829a4aSRandall Stewart  * increment the resend counter (after all the threshold management stuff of
1158f8829a4aSRandall Stewart  * course).
1159f8829a4aSRandall Stewart  */
1160f8829a4aSRandall Stewart int
1161f8829a4aSRandall Stewart sctp_cookie_timer(struct sctp_inpcb *inp,
1162f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
1163f8829a4aSRandall Stewart     struct sctp_nets *net)
1164f8829a4aSRandall Stewart {
1165f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1166f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *cookie;
1167f8829a4aSRandall Stewart 
1168f8829a4aSRandall Stewart 	/* first before all else we must find the cookie */
1169f8829a4aSRandall Stewart 	TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) {
1170f8829a4aSRandall Stewart 		if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) {
1171f8829a4aSRandall Stewart 			break;
1172f8829a4aSRandall Stewart 		}
1173f8829a4aSRandall Stewart 	}
1174f8829a4aSRandall Stewart 	if (cookie == NULL) {
1175f8829a4aSRandall Stewart 		if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
1176f8829a4aSRandall Stewart 			/* FOOBAR! */
1177f8829a4aSRandall Stewart 			struct mbuf *oper;
1178f8829a4aSRandall Stewart 
1179f8829a4aSRandall Stewart 			oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
1180f8829a4aSRandall Stewart 			    0, M_DONTWAIT, 1, MT_DATA);
1181f8829a4aSRandall Stewart 			if (oper) {
1182f8829a4aSRandall Stewart 				struct sctp_paramhdr *ph;
1183f8829a4aSRandall Stewart 				uint32_t *ippp;
1184f8829a4aSRandall Stewart 
1185139bc87fSRandall Stewart 				SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) +
1186f8829a4aSRandall Stewart 				    sizeof(uint32_t);
1187f8829a4aSRandall Stewart 				ph = mtod(oper, struct sctp_paramhdr *);
1188f8829a4aSRandall Stewart 				ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
1189139bc87fSRandall Stewart 				ph->param_length = htons(SCTP_BUF_LEN(oper));
1190f8829a4aSRandall Stewart 				ippp = (uint32_t *) (ph + 1);
1191b54d3a6cSRandall Stewart 				*ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
1192f8829a4aSRandall Stewart 			}
1193b54d3a6cSRandall Stewart 			inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_4;
1194f8829a4aSRandall Stewart 			sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR,
1195f8829a4aSRandall Stewart 			    oper);
1196f8829a4aSRandall Stewart 		} else {
1197a5d547adSRandall Stewart #ifdef INVARIANTS
1198f8829a4aSRandall Stewart 			panic("Cookie timer expires in wrong state?");
1199f8829a4aSRandall Stewart #else
1200ad81507eSRandall Stewart 			SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc));
1201f8829a4aSRandall Stewart 			return (0);
1202f8829a4aSRandall Stewart #endif
1203f8829a4aSRandall Stewart 		}
1204f8829a4aSRandall Stewart 		return (0);
1205f8829a4aSRandall Stewart 	}
1206f8829a4aSRandall Stewart 	/* Ok we found the cookie, threshold management next */
1207f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, cookie->whoTo,
1208f8829a4aSRandall Stewart 	    stcb->asoc.max_init_times)) {
1209f8829a4aSRandall Stewart 		/* Assoc is over */
1210f8829a4aSRandall Stewart 		return (1);
1211f8829a4aSRandall Stewart 	}
1212f8829a4aSRandall Stewart 	/*
1213f8829a4aSRandall Stewart 	 * cleared theshold management now lets backoff the address & select
1214f8829a4aSRandall Stewart 	 * an alternate
1215f8829a4aSRandall Stewart 	 */
1216f8829a4aSRandall Stewart 	stcb->asoc.dropped_special_cnt = 0;
1217f8829a4aSRandall Stewart 	sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0);
1218f8829a4aSRandall Stewart 	alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0);
1219f8829a4aSRandall Stewart 	if (alt != cookie->whoTo) {
1220f8829a4aSRandall Stewart 		sctp_free_remote_addr(cookie->whoTo);
1221f8829a4aSRandall Stewart 		cookie->whoTo = alt;
1222f8829a4aSRandall Stewart 		atomic_add_int(&alt->ref_count, 1);
1223f8829a4aSRandall Stewart 	}
1224f8829a4aSRandall Stewart 	/* Now mark the retran info */
1225f8829a4aSRandall Stewart 	if (cookie->sent != SCTP_DATAGRAM_RESEND) {
1226f8829a4aSRandall Stewart 		sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1227f8829a4aSRandall Stewart 	}
1228f8829a4aSRandall Stewart 	cookie->sent = SCTP_DATAGRAM_RESEND;
1229f8829a4aSRandall Stewart 	/*
1230f8829a4aSRandall Stewart 	 * Now call the output routine to kick out the cookie again, Note we
1231f8829a4aSRandall Stewart 	 * don't mark any chunks for retran so that FR will need to kick in
1232f8829a4aSRandall Stewart 	 * to move these (or a send timer).
1233f8829a4aSRandall Stewart 	 */
1234f8829a4aSRandall Stewart 	return (0);
1235f8829a4aSRandall Stewart }
1236f8829a4aSRandall Stewart 
1237f8829a4aSRandall Stewart int
1238f8829a4aSRandall Stewart sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1239f8829a4aSRandall Stewart     struct sctp_nets *net)
1240f8829a4aSRandall Stewart {
1241f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1242f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *strrst = NULL, *chk = NULL;
1243f8829a4aSRandall Stewart 
1244f8829a4aSRandall Stewart 	if (stcb->asoc.stream_reset_outstanding == 0) {
1245f8829a4aSRandall Stewart 		return (0);
1246f8829a4aSRandall Stewart 	}
1247f8829a4aSRandall Stewart 	/* find the existing STRRESET, we use the seq number we sent out on */
1248ad81507eSRandall Stewart 	(void)sctp_find_stream_reset(stcb, stcb->asoc.str_reset_seq_out, &strrst);
1249f8829a4aSRandall Stewart 	if (strrst == NULL) {
1250f8829a4aSRandall Stewart 		return (0);
1251f8829a4aSRandall Stewart 	}
1252f8829a4aSRandall Stewart 	/* do threshold management */
1253f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, strrst->whoTo,
1254f8829a4aSRandall Stewart 	    stcb->asoc.max_send_times)) {
1255f8829a4aSRandall Stewart 		/* Assoc is over */
1256f8829a4aSRandall Stewart 		return (1);
1257f8829a4aSRandall Stewart 	}
1258f8829a4aSRandall Stewart 	/*
1259f8829a4aSRandall Stewart 	 * cleared theshold management now lets backoff the address & select
1260f8829a4aSRandall Stewart 	 * an alternate
1261f8829a4aSRandall Stewart 	 */
1262f8829a4aSRandall Stewart 	sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0);
1263f8829a4aSRandall Stewart 	alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0);
1264f8829a4aSRandall Stewart 	sctp_free_remote_addr(strrst->whoTo);
1265f8829a4aSRandall Stewart 	strrst->whoTo = alt;
1266f8829a4aSRandall Stewart 	atomic_add_int(&alt->ref_count, 1);
1267f8829a4aSRandall Stewart 
1268f8829a4aSRandall Stewart 	/* See if a ECN Echo is also stranded */
1269f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
1270f8829a4aSRandall Stewart 		if ((chk->whoTo == net) &&
1271f8829a4aSRandall Stewart 		    (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) {
1272f8829a4aSRandall Stewart 			sctp_free_remote_addr(chk->whoTo);
1273f8829a4aSRandall Stewart 			if (chk->sent != SCTP_DATAGRAM_RESEND) {
1274f8829a4aSRandall Stewart 				chk->sent = SCTP_DATAGRAM_RESEND;
1275f8829a4aSRandall Stewart 				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1276f8829a4aSRandall Stewart 			}
1277f8829a4aSRandall Stewart 			chk->whoTo = alt;
1278f8829a4aSRandall Stewart 			atomic_add_int(&alt->ref_count, 1);
1279f8829a4aSRandall Stewart 		}
1280f8829a4aSRandall Stewart 	}
1281f8829a4aSRandall Stewart 	if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
1282f8829a4aSRandall Stewart 		/*
1283f8829a4aSRandall Stewart 		 * If the address went un-reachable, we need to move to
1284f8829a4aSRandall Stewart 		 * alternates for ALL chk's in queue
1285f8829a4aSRandall Stewart 		 */
1286f8829a4aSRandall Stewart 		sctp_move_all_chunks_to_alt(stcb, net, alt);
1287f8829a4aSRandall Stewart 	}
1288f8829a4aSRandall Stewart 	/* mark the retran info */
1289f8829a4aSRandall Stewart 	if (strrst->sent != SCTP_DATAGRAM_RESEND)
1290f8829a4aSRandall Stewart 		sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1291f8829a4aSRandall Stewart 	strrst->sent = SCTP_DATAGRAM_RESEND;
1292f8829a4aSRandall Stewart 
1293f8829a4aSRandall Stewart 	/* restart the timer */
1294f8829a4aSRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo);
1295f8829a4aSRandall Stewart 	return (0);
1296f8829a4aSRandall Stewart }
1297f8829a4aSRandall Stewart 
1298f8829a4aSRandall Stewart int
1299f8829a4aSRandall Stewart sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1300f8829a4aSRandall Stewart     struct sctp_nets *net)
1301f8829a4aSRandall Stewart {
1302f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1303f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *asconf, *chk;
1304f8829a4aSRandall Stewart 
1305f8829a4aSRandall Stewart 	/* is this the first send, or a retransmission? */
1306f8829a4aSRandall Stewart 	if (stcb->asoc.asconf_sent == 0) {
1307f8829a4aSRandall Stewart 		/* compose a new ASCONF chunk and send it */
1308f8829a4aSRandall Stewart 		sctp_send_asconf(stcb, net);
1309f8829a4aSRandall Stewart 	} else {
1310f8829a4aSRandall Stewart 		/* Retransmission of the existing ASCONF needed... */
1311f8829a4aSRandall Stewart 
1312f8829a4aSRandall Stewart 		/* find the existing ASCONF */
1313f8829a4aSRandall Stewart 		TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue,
1314f8829a4aSRandall Stewart 		    sctp_next) {
1315f8829a4aSRandall Stewart 			if (asconf->rec.chunk_id.id == SCTP_ASCONF) {
1316f8829a4aSRandall Stewart 				break;
1317f8829a4aSRandall Stewart 			}
1318f8829a4aSRandall Stewart 		}
1319f8829a4aSRandall Stewart 		if (asconf == NULL) {
1320f8829a4aSRandall Stewart 			return (0);
1321f8829a4aSRandall Stewart 		}
1322f8829a4aSRandall Stewart 		/* do threshold management */
1323f8829a4aSRandall Stewart 		if (sctp_threshold_management(inp, stcb, asconf->whoTo,
1324f8829a4aSRandall Stewart 		    stcb->asoc.max_send_times)) {
1325f8829a4aSRandall Stewart 			/* Assoc is over */
1326f8829a4aSRandall Stewart 			return (1);
1327f8829a4aSRandall Stewart 		}
1328f8829a4aSRandall Stewart 		/*
1329f8829a4aSRandall Stewart 		 * PETER? FIX? How will the following code ever run? If the
1330f8829a4aSRandall Stewart 		 * max_send_times is hit, threshold managment will blow away
1331f8829a4aSRandall Stewart 		 * the association?
1332f8829a4aSRandall Stewart 		 */
1333f8829a4aSRandall Stewart 		if (asconf->snd_count > stcb->asoc.max_send_times) {
1334f8829a4aSRandall Stewart 			/*
1335f8829a4aSRandall Stewart 			 * Something is rotten, peer is not responding to
1336f8829a4aSRandall Stewart 			 * ASCONFs but maybe is to data etc.  e.g. it is not
1337f8829a4aSRandall Stewart 			 * properly handling the chunk type upper bits Mark
1338f8829a4aSRandall Stewart 			 * this peer as ASCONF incapable and cleanup
1339f8829a4aSRandall Stewart 			 */
1340ad81507eSRandall Stewart 			SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n");
1341f8829a4aSRandall Stewart 			sctp_asconf_cleanup(stcb, net);
1342f8829a4aSRandall Stewart 			return (0);
1343f8829a4aSRandall Stewart 		}
1344f8829a4aSRandall Stewart 		/*
1345f8829a4aSRandall Stewart 		 * cleared theshold management now lets backoff the address
1346f8829a4aSRandall Stewart 		 * & select an alternate
1347f8829a4aSRandall Stewart 		 */
1348f8829a4aSRandall Stewart 		sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0);
1349f8829a4aSRandall Stewart 		alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0);
1350f8829a4aSRandall Stewart 		sctp_free_remote_addr(asconf->whoTo);
1351f8829a4aSRandall Stewart 		asconf->whoTo = alt;
1352f8829a4aSRandall Stewart 		atomic_add_int(&alt->ref_count, 1);
1353f8829a4aSRandall Stewart 
1354f8829a4aSRandall Stewart 		/* See if a ECN Echo is also stranded */
1355f8829a4aSRandall Stewart 		TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
1356f8829a4aSRandall Stewart 			if ((chk->whoTo == net) &&
1357f8829a4aSRandall Stewart 			    (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) {
1358f8829a4aSRandall Stewart 				sctp_free_remote_addr(chk->whoTo);
1359f8829a4aSRandall Stewart 				chk->whoTo = alt;
1360f8829a4aSRandall Stewart 				if (chk->sent != SCTP_DATAGRAM_RESEND) {
1361f8829a4aSRandall Stewart 					chk->sent = SCTP_DATAGRAM_RESEND;
1362f8829a4aSRandall Stewart 					sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1363f8829a4aSRandall Stewart 				}
1364f8829a4aSRandall Stewart 				atomic_add_int(&alt->ref_count, 1);
1365f8829a4aSRandall Stewart 			}
1366f8829a4aSRandall Stewart 		}
1367f8829a4aSRandall Stewart 		if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
1368f8829a4aSRandall Stewart 			/*
1369f8829a4aSRandall Stewart 			 * If the address went un-reachable, we need to move
1370f8829a4aSRandall Stewart 			 * to alternates for ALL chk's in queue
1371f8829a4aSRandall Stewart 			 */
1372f8829a4aSRandall Stewart 			sctp_move_all_chunks_to_alt(stcb, net, alt);
1373f8829a4aSRandall Stewart 		}
1374f8829a4aSRandall Stewart 		/* mark the retran info */
1375f8829a4aSRandall Stewart 		if (asconf->sent != SCTP_DATAGRAM_RESEND)
1376f8829a4aSRandall Stewart 			sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1377f8829a4aSRandall Stewart 		asconf->sent = SCTP_DATAGRAM_RESEND;
1378f8829a4aSRandall Stewart 	}
1379f8829a4aSRandall Stewart 	return (0);
1380f8829a4aSRandall Stewart }
1381f8829a4aSRandall Stewart 
1382f8829a4aSRandall Stewart /*
1383f8829a4aSRandall Stewart  * For the shutdown and shutdown-ack, we do not keep one around on the
1384f8829a4aSRandall Stewart  * control queue. This means we must generate a new one and call the general
1385f8829a4aSRandall Stewart  * chunk output routine, AFTER having done threshold management.
1386f8829a4aSRandall Stewart  */
1387f8829a4aSRandall Stewart int
1388f8829a4aSRandall Stewart sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1389f8829a4aSRandall Stewart     struct sctp_nets *net)
1390f8829a4aSRandall Stewart {
1391f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1392f8829a4aSRandall Stewart 
1393f8829a4aSRandall Stewart 	/* first threshold managment */
1394f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
1395f8829a4aSRandall Stewart 		/* Assoc is over */
1396f8829a4aSRandall Stewart 		return (1);
1397f8829a4aSRandall Stewart 	}
1398f8829a4aSRandall Stewart 	/* second select an alternative */
1399f8829a4aSRandall Stewart 	alt = sctp_find_alternate_net(stcb, net, 0);
1400f8829a4aSRandall Stewart 
1401f8829a4aSRandall Stewart 	/* third generate a shutdown into the queue for out net */
1402f8829a4aSRandall Stewart 	if (alt) {
1403f8829a4aSRandall Stewart 		sctp_send_shutdown(stcb, alt);
1404f8829a4aSRandall Stewart 	} else {
1405f8829a4aSRandall Stewart 		/*
1406f8829a4aSRandall Stewart 		 * if alt is NULL, there is no dest to send to??
1407f8829a4aSRandall Stewart 		 */
1408f8829a4aSRandall Stewart 		return (0);
1409f8829a4aSRandall Stewart 	}
1410f8829a4aSRandall Stewart 	/* fourth restart timer */
1411f8829a4aSRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt);
1412f8829a4aSRandall Stewart 	return (0);
1413f8829a4aSRandall Stewart }
1414f8829a4aSRandall Stewart 
1415f8829a4aSRandall Stewart int
1416f8829a4aSRandall Stewart sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1417f8829a4aSRandall Stewart     struct sctp_nets *net)
1418f8829a4aSRandall Stewart {
1419f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1420f8829a4aSRandall Stewart 
1421f8829a4aSRandall Stewart 	/* first threshold managment */
1422f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
1423f8829a4aSRandall Stewart 		/* Assoc is over */
1424f8829a4aSRandall Stewart 		return (1);
1425f8829a4aSRandall Stewart 	}
1426f8829a4aSRandall Stewart 	/* second select an alternative */
1427f8829a4aSRandall Stewart 	alt = sctp_find_alternate_net(stcb, net, 0);
1428f8829a4aSRandall Stewart 
1429f8829a4aSRandall Stewart 	/* third generate a shutdown into the queue for out net */
1430f8829a4aSRandall Stewart 	sctp_send_shutdown_ack(stcb, alt);
1431f8829a4aSRandall Stewart 
1432f8829a4aSRandall Stewart 	/* fourth restart timer */
1433f8829a4aSRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt);
1434f8829a4aSRandall Stewart 	return (0);
1435f8829a4aSRandall Stewart }
1436f8829a4aSRandall Stewart 
1437f8829a4aSRandall Stewart static void
1438f8829a4aSRandall Stewart sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
1439f8829a4aSRandall Stewart     struct sctp_tcb *stcb)
1440f8829a4aSRandall Stewart {
1441f8829a4aSRandall Stewart 	struct sctp_stream_out *outs;
1442f8829a4aSRandall Stewart 	struct sctp_stream_queue_pending *sp;
1443f8829a4aSRandall Stewart 	unsigned int chks_in_queue = 0;
1444f8829a4aSRandall Stewart 	int being_filled = 0;
1445f8829a4aSRandall Stewart 
1446f8829a4aSRandall Stewart 	/*
1447f8829a4aSRandall Stewart 	 * This function is ONLY called when the send/sent queues are empty.
1448f8829a4aSRandall Stewart 	 */
1449f8829a4aSRandall Stewart 	if ((stcb == NULL) || (inp == NULL))
1450f8829a4aSRandall Stewart 		return;
1451f8829a4aSRandall Stewart 
1452f8829a4aSRandall Stewart 	if (stcb->asoc.sent_queue_retran_cnt) {
1453ad81507eSRandall Stewart 		SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n",
1454f8829a4aSRandall Stewart 		    stcb->asoc.sent_queue_retran_cnt);
1455f8829a4aSRandall Stewart 		stcb->asoc.sent_queue_retran_cnt = 0;
1456f8829a4aSRandall Stewart 	}
1457f8829a4aSRandall Stewart 	SCTP_TCB_SEND_LOCK(stcb);
1458f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&stcb->asoc.out_wheel)) {
1459f8829a4aSRandall Stewart 		int i, cnt = 0;
1460f8829a4aSRandall Stewart 
1461f8829a4aSRandall Stewart 		/* Check to see if a spoke fell off the wheel */
1462f8829a4aSRandall Stewart 		for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
1463f8829a4aSRandall Stewart 			if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
1464f8829a4aSRandall Stewart 				sctp_insert_on_wheel(stcb, &stcb->asoc, &stcb->asoc.strmout[i], 1);
1465f8829a4aSRandall Stewart 				cnt++;
1466f8829a4aSRandall Stewart 			}
1467f8829a4aSRandall Stewart 		}
1468f8829a4aSRandall Stewart 		if (cnt) {
1469f8829a4aSRandall Stewart 			/* yep, we lost a spoke or two */
1470ad81507eSRandall Stewart 			SCTP_PRINTF("Found an additional %d streams NOT on outwheel, corrected\n", cnt);
1471f8829a4aSRandall Stewart 		} else {
1472f8829a4aSRandall Stewart 			/* no spokes lost, */
1473f8829a4aSRandall Stewart 			stcb->asoc.total_output_queue_size = 0;
1474f8829a4aSRandall Stewart 		}
1475f8829a4aSRandall Stewart 		SCTP_TCB_SEND_UNLOCK(stcb);
1476f8829a4aSRandall Stewart 		return;
1477f8829a4aSRandall Stewart 	}
1478f8829a4aSRandall Stewart 	SCTP_TCB_SEND_UNLOCK(stcb);
1479f8829a4aSRandall Stewart 	/* Check to see if some data queued, if so report it */
1480f8829a4aSRandall Stewart 	TAILQ_FOREACH(outs, &stcb->asoc.out_wheel, next_spoke) {
1481f8829a4aSRandall Stewart 		if (!TAILQ_EMPTY(&outs->outqueue)) {
1482f8829a4aSRandall Stewart 			TAILQ_FOREACH(sp, &outs->outqueue, next) {
1483f8829a4aSRandall Stewart 				if (sp->msg_is_complete)
1484f8829a4aSRandall Stewart 					being_filled++;
1485f8829a4aSRandall Stewart 				chks_in_queue++;
1486f8829a4aSRandall Stewart 			}
1487f8829a4aSRandall Stewart 		}
1488f8829a4aSRandall Stewart 	}
1489f8829a4aSRandall Stewart 	if (chks_in_queue != stcb->asoc.stream_queue_cnt) {
1490ad81507eSRandall Stewart 		SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n",
1491f8829a4aSRandall Stewart 		    stcb->asoc.stream_queue_cnt, chks_in_queue);
1492f8829a4aSRandall Stewart 	}
1493f8829a4aSRandall Stewart 	if (chks_in_queue) {
1494f8829a4aSRandall Stewart 		/* call the output queue function */
1495f8829a4aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3);
1496f8829a4aSRandall Stewart 		if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
1497f8829a4aSRandall Stewart 		    (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
1498f8829a4aSRandall Stewart 			/*
1499f8829a4aSRandall Stewart 			 * Probably should go in and make it go back through
1500f8829a4aSRandall Stewart 			 * and add fragments allowed
1501f8829a4aSRandall Stewart 			 */
1502f8829a4aSRandall Stewart 			if (being_filled == 0) {
1503ad81507eSRandall Stewart 				SCTP_PRINTF("Still nothing moved %d chunks are stuck\n",
1504f8829a4aSRandall Stewart 				    chks_in_queue);
1505f8829a4aSRandall Stewart 			}
1506f8829a4aSRandall Stewart 		}
1507f8829a4aSRandall Stewart 	} else {
1508ad81507eSRandall Stewart 		SCTP_PRINTF("Found no chunks on any queue tot:%lu\n",
1509f8829a4aSRandall Stewart 		    (u_long)stcb->asoc.total_output_queue_size);
1510f8829a4aSRandall Stewart 		stcb->asoc.total_output_queue_size = 0;
1511f8829a4aSRandall Stewart 	}
1512f8829a4aSRandall Stewart }
1513f8829a4aSRandall Stewart 
1514f8829a4aSRandall Stewart int
1515f8829a4aSRandall Stewart sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1516f8829a4aSRandall Stewart     struct sctp_nets *net, int cnt_of_unconf)
1517f8829a4aSRandall Stewart {
1518b54d3a6cSRandall Stewart 	int ret;
1519b54d3a6cSRandall Stewart 
1520f8829a4aSRandall Stewart 	if (net) {
1521f8829a4aSRandall Stewart 		if (net->hb_responded == 0) {
152242551e99SRandall Stewart 			if (net->ro._s_addr) {
152342551e99SRandall Stewart 				/*
152442551e99SRandall Stewart 				 * Invalidate the src address if we did not
152542551e99SRandall Stewart 				 * get a response last time.
152642551e99SRandall Stewart 				 */
152742551e99SRandall Stewart 				sctp_free_ifa(net->ro._s_addr);
152842551e99SRandall Stewart 				net->ro._s_addr = NULL;
152942551e99SRandall Stewart 				net->src_addr_selected = 0;
153042551e99SRandall Stewart 			}
1531f8829a4aSRandall Stewart 			sctp_backoff_on_timeout(stcb, net, 1, 0);
1532f8829a4aSRandall Stewart 		}
1533f8829a4aSRandall Stewart 		/* Zero PBA, if it needs it */
1534f8829a4aSRandall Stewart 		if (net->partial_bytes_acked) {
1535f8829a4aSRandall Stewart 			net->partial_bytes_acked = 0;
1536f8829a4aSRandall Stewart 		}
1537f8829a4aSRandall Stewart 	}
1538f8829a4aSRandall Stewart 	if ((stcb->asoc.total_output_queue_size > 0) &&
1539f8829a4aSRandall Stewart 	    (TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
1540f8829a4aSRandall Stewart 	    (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
1541f8829a4aSRandall Stewart 		sctp_audit_stream_queues_for_size(inp, stcb);
1542f8829a4aSRandall Stewart 	}
1543f8829a4aSRandall Stewart 	/* Send a new HB, this will do threshold managment, pick a new dest */
1544f8829a4aSRandall Stewart 	if (cnt_of_unconf == 0) {
1545f8829a4aSRandall Stewart 		if (sctp_send_hb(stcb, 0, NULL) < 0) {
1546f8829a4aSRandall Stewart 			return (1);
1547f8829a4aSRandall Stewart 		}
1548f8829a4aSRandall Stewart 	} else {
1549f8829a4aSRandall Stewart 		/*
1550f8829a4aSRandall Stewart 		 * this will send out extra hb's up to maxburst if there are
1551f8829a4aSRandall Stewart 		 * any unconfirmed addresses.
1552f8829a4aSRandall Stewart 		 */
1553d61a0ae0SRandall Stewart 		uint32_t cnt_sent = 0;
1554f8829a4aSRandall Stewart 
1555f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1556f8829a4aSRandall Stewart 			if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
1557f8829a4aSRandall Stewart 			    (net->dest_state & SCTP_ADDR_REACHABLE)) {
1558f8829a4aSRandall Stewart 				cnt_sent++;
155942551e99SRandall Stewart 				if (net->hb_responded == 0) {
156042551e99SRandall Stewart 					/* Did we respond last time? */
156142551e99SRandall Stewart 					if (net->ro._s_addr) {
156242551e99SRandall Stewart 						sctp_free_ifa(net->ro._s_addr);
156342551e99SRandall Stewart 						net->ro._s_addr = NULL;
156442551e99SRandall Stewart 						net->src_addr_selected = 0;
156542551e99SRandall Stewart 					}
156642551e99SRandall Stewart 				}
1567b54d3a6cSRandall Stewart 				ret = sctp_send_hb(stcb, 1, net);
1568b54d3a6cSRandall Stewart 				if (ret < 0)
1569b54d3a6cSRandall Stewart 					return 1;
1570b54d3a6cSRandall Stewart 				else if (ret == 0) {
1571f8829a4aSRandall Stewart 					break;
1572f8829a4aSRandall Stewart 				}
157342551e99SRandall Stewart 				if (cnt_sent >= sctp_hb_maxburst)
1574f8829a4aSRandall Stewart 					break;
1575f8829a4aSRandall Stewart 			}
1576f8829a4aSRandall Stewart 		}
1577f8829a4aSRandall Stewart 	}
1578f8829a4aSRandall Stewart 	return (0);
1579f8829a4aSRandall Stewart }
1580f8829a4aSRandall Stewart 
1581f8829a4aSRandall Stewart int
1582f8829a4aSRandall Stewart sctp_is_hb_timer_running(struct sctp_tcb *stcb)
1583f8829a4aSRandall Stewart {
1584139bc87fSRandall Stewart 	if (SCTP_OS_TIMER_PENDING(&stcb->asoc.hb_timer.timer)) {
1585f8829a4aSRandall Stewart 		/* its running */
1586f8829a4aSRandall Stewart 		return (1);
1587f8829a4aSRandall Stewart 	} else {
1588f8829a4aSRandall Stewart 		/* nope */
1589f8829a4aSRandall Stewart 		return (0);
1590f8829a4aSRandall Stewart 	}
1591f8829a4aSRandall Stewart }
1592f8829a4aSRandall Stewart 
1593f8829a4aSRandall Stewart int
1594f8829a4aSRandall Stewart sctp_is_sack_timer_running(struct sctp_tcb *stcb)
1595f8829a4aSRandall Stewart {
1596139bc87fSRandall Stewart 	if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
1597f8829a4aSRandall Stewart 		/* its running */
1598f8829a4aSRandall Stewart 		return (1);
1599f8829a4aSRandall Stewart 	} else {
1600f8829a4aSRandall Stewart 		/* nope */
1601f8829a4aSRandall Stewart 		return (0);
1602f8829a4aSRandall Stewart 	}
1603f8829a4aSRandall Stewart }
1604f8829a4aSRandall Stewart 
1605f8829a4aSRandall Stewart #define SCTP_NUMBER_OF_MTU_SIZES 18
1606f8829a4aSRandall Stewart static uint32_t mtu_sizes[] = {
1607f8829a4aSRandall Stewart 	68,
1608f8829a4aSRandall Stewart 	296,
1609f8829a4aSRandall Stewart 	508,
1610f8829a4aSRandall Stewart 	512,
1611f8829a4aSRandall Stewart 	544,
1612f8829a4aSRandall Stewart 	576,
1613f8829a4aSRandall Stewart 	1006,
1614f8829a4aSRandall Stewart 	1492,
1615f8829a4aSRandall Stewart 	1500,
1616f8829a4aSRandall Stewart 	1536,
1617f8829a4aSRandall Stewart 	2002,
1618f8829a4aSRandall Stewart 	2048,
1619f8829a4aSRandall Stewart 	4352,
1620f8829a4aSRandall Stewart 	4464,
1621f8829a4aSRandall Stewart 	8166,
1622f8829a4aSRandall Stewart 	17914,
1623f8829a4aSRandall Stewart 	32000,
1624f8829a4aSRandall Stewart 	65535
1625f8829a4aSRandall Stewart };
1626f8829a4aSRandall Stewart 
1627f8829a4aSRandall Stewart 
1628f8829a4aSRandall Stewart static uint32_t
1629f8829a4aSRandall Stewart sctp_getnext_mtu(struct sctp_inpcb *inp, uint32_t cur_mtu)
1630f8829a4aSRandall Stewart {
1631f8829a4aSRandall Stewart 	/* select another MTU that is just bigger than this one */
1632f8829a4aSRandall Stewart 	int i;
1633f8829a4aSRandall Stewart 
1634f8829a4aSRandall Stewart 	for (i = 0; i < SCTP_NUMBER_OF_MTU_SIZES; i++) {
1635f8829a4aSRandall Stewart 		if (cur_mtu < mtu_sizes[i]) {
1636f8829a4aSRandall Stewart 			/* no max_mtu is bigger than this one */
1637f8829a4aSRandall Stewart 			return (mtu_sizes[i]);
1638f8829a4aSRandall Stewart 		}
1639f8829a4aSRandall Stewart 	}
1640f8829a4aSRandall Stewart 	/* here return the highest allowable */
1641f8829a4aSRandall Stewart 	return (cur_mtu);
1642f8829a4aSRandall Stewart }
1643f8829a4aSRandall Stewart 
1644f8829a4aSRandall Stewart 
1645f8829a4aSRandall Stewart void
1646f8829a4aSRandall Stewart sctp_pathmtu_timer(struct sctp_inpcb *inp,
1647f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
1648f8829a4aSRandall Stewart     struct sctp_nets *net)
1649f8829a4aSRandall Stewart {
1650f8829a4aSRandall Stewart 	uint32_t next_mtu;
1651f8829a4aSRandall Stewart 
1652f8829a4aSRandall Stewart 	/* restart the timer in any case */
1653f8829a4aSRandall Stewart 	next_mtu = sctp_getnext_mtu(inp, net->mtu);
1654f8829a4aSRandall Stewart 	if (next_mtu <= net->mtu) {
1655f8829a4aSRandall Stewart 		/* nothing to do */
1656f8829a4aSRandall Stewart 		return;
165717205eccSRandall Stewart 	} {
165817205eccSRandall Stewart 		uint32_t mtu;
165917205eccSRandall Stewart 
166017205eccSRandall Stewart 		if ((net->src_addr_selected == 0) ||
166117205eccSRandall Stewart 		    (net->ro._s_addr == NULL) ||
166217205eccSRandall Stewart 		    (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
1663ad81507eSRandall Stewart 			if ((net->ro._s_addr != NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
166417205eccSRandall Stewart 				sctp_free_ifa(net->ro._s_addr);
166517205eccSRandall Stewart 				net->ro._s_addr = NULL;
166617205eccSRandall Stewart 				net->src_addr_selected = 0;
1667ad81507eSRandall Stewart 			} else if (net->ro._s_addr == NULL) {
166817205eccSRandall Stewart 				net->ro._s_addr = sctp_source_address_selection(inp,
166917205eccSRandall Stewart 				    stcb,
167017205eccSRandall Stewart 				    (sctp_route_t *) & net->ro,
167117205eccSRandall Stewart 				    net, 0, stcb->asoc.vrf_id);
1672ad81507eSRandall Stewart 			}
167317205eccSRandall Stewart 			if (net->ro._s_addr)
167417205eccSRandall Stewart 				net->src_addr_selected = 1;
167517205eccSRandall Stewart 		}
167617205eccSRandall Stewart 		if (net->ro._s_addr) {
167717205eccSRandall Stewart 			mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt);
167817205eccSRandall Stewart 			if (mtu > next_mtu) {
1679f8829a4aSRandall Stewart 				net->mtu = next_mtu;
1680f8829a4aSRandall Stewart 			}
1681f8829a4aSRandall Stewart 		}
1682f8829a4aSRandall Stewart 	}
1683f8829a4aSRandall Stewart 	/* restart the timer */
1684f8829a4aSRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
1685f8829a4aSRandall Stewart }
1686f8829a4aSRandall Stewart 
1687f8829a4aSRandall Stewart void
1688f8829a4aSRandall Stewart sctp_autoclose_timer(struct sctp_inpcb *inp,
1689f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
1690f8829a4aSRandall Stewart     struct sctp_nets *net)
1691f8829a4aSRandall Stewart {
1692f8829a4aSRandall Stewart 	struct timeval tn, *tim_touse;
1693f8829a4aSRandall Stewart 	struct sctp_association *asoc;
1694f8829a4aSRandall Stewart 	int ticks_gone_by;
1695f8829a4aSRandall Stewart 
16966e55db54SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&tn);
1697f8829a4aSRandall Stewart 	if (stcb->asoc.sctp_autoclose_ticks &&
1698f8829a4aSRandall Stewart 	    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
1699f8829a4aSRandall Stewart 		/* Auto close is on */
1700f8829a4aSRandall Stewart 		asoc = &stcb->asoc;
1701f8829a4aSRandall Stewart 		/* pick the time to use */
1702f8829a4aSRandall Stewart 		if (asoc->time_last_rcvd.tv_sec >
1703f8829a4aSRandall Stewart 		    asoc->time_last_sent.tv_sec) {
1704f8829a4aSRandall Stewart 			tim_touse = &asoc->time_last_rcvd;
1705f8829a4aSRandall Stewart 		} else {
1706f8829a4aSRandall Stewart 			tim_touse = &asoc->time_last_sent;
1707f8829a4aSRandall Stewart 		}
1708f8829a4aSRandall Stewart 		/* Now has long enough transpired to autoclose? */
1709f8829a4aSRandall Stewart 		ticks_gone_by = SEC_TO_TICKS(tn.tv_sec - tim_touse->tv_sec);
1710f8829a4aSRandall Stewart 		if ((ticks_gone_by > 0) &&
1711f8829a4aSRandall Stewart 		    (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) {
1712f8829a4aSRandall Stewart 			/*
1713f8829a4aSRandall Stewart 			 * autoclose time has hit, call the output routine,
1714f8829a4aSRandall Stewart 			 * which should do nothing just to be SURE we don't
1715f8829a4aSRandall Stewart 			 * have hanging data. We can then safely check the
1716f8829a4aSRandall Stewart 			 * queues and know that we are clear to send
1717f8829a4aSRandall Stewart 			 * shutdown
1718f8829a4aSRandall Stewart 			 */
1719f8829a4aSRandall Stewart 			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR);
1720f8829a4aSRandall Stewart 			/* Are we clean? */
1721f8829a4aSRandall Stewart 			if (TAILQ_EMPTY(&asoc->send_queue) &&
1722f8829a4aSRandall Stewart 			    TAILQ_EMPTY(&asoc->sent_queue)) {
1723f8829a4aSRandall Stewart 				/*
1724f8829a4aSRandall Stewart 				 * there is nothing queued to send, so I'm
1725f8829a4aSRandall Stewart 				 * done...
1726f8829a4aSRandall Stewart 				 */
1727f42a358aSRandall Stewart 				if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
1728f8829a4aSRandall Stewart 					/* only send SHUTDOWN 1st time thru */
1729f8829a4aSRandall Stewart 					sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
1730f42a358aSRandall Stewart 					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
1731f42a358aSRandall Stewart 					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1732f8829a4aSRandall Stewart 						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1733f42a358aSRandall Stewart 					}
1734f42a358aSRandall Stewart 					asoc->state = SCTP_STATE_SHUTDOWN_SENT;
1735f8829a4aSRandall Stewart 					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1736f8829a4aSRandall Stewart 					    stcb->sctp_ep, stcb,
1737f8829a4aSRandall Stewart 					    asoc->primary_destination);
1738f8829a4aSRandall Stewart 					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1739f8829a4aSRandall Stewart 					    stcb->sctp_ep, stcb,
1740f8829a4aSRandall Stewart 					    asoc->primary_destination);
1741f8829a4aSRandall Stewart 				}
1742f8829a4aSRandall Stewart 			}
1743f8829a4aSRandall Stewart 		} else {
1744f8829a4aSRandall Stewart 			/*
1745f8829a4aSRandall Stewart 			 * No auto close at this time, reset t-o to check
1746f8829a4aSRandall Stewart 			 * later
1747f8829a4aSRandall Stewart 			 */
1748f8829a4aSRandall Stewart 			int tmp;
1749f8829a4aSRandall Stewart 
1750f8829a4aSRandall Stewart 			/* fool the timer startup to use the time left */
1751f8829a4aSRandall Stewart 			tmp = asoc->sctp_autoclose_ticks;
1752f8829a4aSRandall Stewart 			asoc->sctp_autoclose_ticks -= ticks_gone_by;
1753f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb,
1754f8829a4aSRandall Stewart 			    net);
1755f8829a4aSRandall Stewart 			/* restore the real tick value */
1756f8829a4aSRandall Stewart 			asoc->sctp_autoclose_ticks = tmp;
1757f8829a4aSRandall Stewart 		}
1758f8829a4aSRandall Stewart 	}
1759f8829a4aSRandall Stewart }
1760f8829a4aSRandall Stewart 
1761f8829a4aSRandall Stewart void
1762f8829a4aSRandall Stewart sctp_iterator_timer(struct sctp_iterator *it)
1763f8829a4aSRandall Stewart {
1764f8829a4aSRandall Stewart 	int iteration_count = 0;
176542551e99SRandall Stewart 	int inp_skip = 0;
1766f8829a4aSRandall Stewart 
1767f8829a4aSRandall Stewart 	/*
1768f8829a4aSRandall Stewart 	 * only one iterator can run at a time. This is the only way we can
1769f8829a4aSRandall Stewart 	 * cleanly pull ep's from underneath all the running interators when
1770f8829a4aSRandall Stewart 	 * a ep is freed.
1771f8829a4aSRandall Stewart 	 */
1772f8829a4aSRandall Stewart 	SCTP_ITERATOR_LOCK();
1773f8829a4aSRandall Stewart 	if (it->inp == NULL) {
1774f8829a4aSRandall Stewart 		/* iterator is complete */
1775f8829a4aSRandall Stewart done_with_iterator:
1776f8829a4aSRandall Stewart 		SCTP_ITERATOR_UNLOCK();
1777f8829a4aSRandall Stewart 		SCTP_INP_INFO_WLOCK();
177842551e99SRandall Stewart 		TAILQ_REMOVE(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr);
1779f8829a4aSRandall Stewart 		/* stopping the callout is not needed, in theory */
1780f8829a4aSRandall Stewart 		SCTP_INP_INFO_WUNLOCK();
17816e55db54SRandall Stewart 		(void)SCTP_OS_TIMER_STOP(&it->tmr.timer);
1782f8829a4aSRandall Stewart 		if (it->function_atend != NULL) {
1783f8829a4aSRandall Stewart 			(*it->function_atend) (it->pointer, it->val);
1784f8829a4aSRandall Stewart 		}
1785207304d4SRandall Stewart 		SCTP_FREE(it, SCTP_M_ITER);
1786f8829a4aSRandall Stewart 		return;
1787f8829a4aSRandall Stewart 	}
1788f8829a4aSRandall Stewart select_a_new_ep:
1789f8829a4aSRandall Stewart 	SCTP_INP_WLOCK(it->inp);
1790f8829a4aSRandall Stewart 	while (((it->pcb_flags) &&
1791f8829a4aSRandall Stewart 	    ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) ||
1792f8829a4aSRandall Stewart 	    ((it->pcb_features) &&
1793f8829a4aSRandall Stewart 	    ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) {
1794f8829a4aSRandall Stewart 		/* endpoint flags or features don't match, so keep looking */
1795f8829a4aSRandall Stewart 		if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
1796f8829a4aSRandall Stewart 			SCTP_INP_WUNLOCK(it->inp);
1797f8829a4aSRandall Stewart 			goto done_with_iterator;
1798f8829a4aSRandall Stewart 		}
1799f8829a4aSRandall Stewart 		SCTP_INP_WUNLOCK(it->inp);
1800f8829a4aSRandall Stewart 		it->inp = LIST_NEXT(it->inp, sctp_list);
1801f8829a4aSRandall Stewart 		if (it->inp == NULL) {
1802f8829a4aSRandall Stewart 			goto done_with_iterator;
1803f8829a4aSRandall Stewart 		}
1804f8829a4aSRandall Stewart 		SCTP_INP_WLOCK(it->inp);
1805f8829a4aSRandall Stewart 	}
1806f8829a4aSRandall Stewart 	if ((it->inp->inp_starting_point_for_iterator != NULL) &&
1807f8829a4aSRandall Stewart 	    (it->inp->inp_starting_point_for_iterator != it)) {
1808ad81507eSRandall Stewart 		SCTP_PRINTF("Iterator collision, waiting for one at %p\n",
1809e349e6b8SRuslan Ermilov 		    it->inp);
1810f8829a4aSRandall Stewart 		SCTP_INP_WUNLOCK(it->inp);
1811f8829a4aSRandall Stewart 		goto start_timer_return;
1812f8829a4aSRandall Stewart 	}
1813f8829a4aSRandall Stewart 	/* mark the current iterator on the endpoint */
1814f8829a4aSRandall Stewart 	it->inp->inp_starting_point_for_iterator = it;
1815f8829a4aSRandall Stewart 	SCTP_INP_WUNLOCK(it->inp);
1816f8829a4aSRandall Stewart 	SCTP_INP_RLOCK(it->inp);
1817f8829a4aSRandall Stewart 	/* now go through each assoc which is in the desired state */
181842551e99SRandall Stewart 	if (it->done_current_ep == 0) {
181942551e99SRandall Stewart 		if (it->function_inp != NULL)
182042551e99SRandall Stewart 			inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val);
182142551e99SRandall Stewart 		it->done_current_ep = 1;
182242551e99SRandall Stewart 	}
1823f8829a4aSRandall Stewart 	if (it->stcb == NULL) {
1824f8829a4aSRandall Stewart 		/* run the per instance function */
1825f8829a4aSRandall Stewart 		it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
1826f8829a4aSRandall Stewart 	}
1827f8829a4aSRandall Stewart 	SCTP_INP_RUNLOCK(it->inp);
182842551e99SRandall Stewart 	if ((inp_skip) || it->stcb == NULL) {
182942551e99SRandall Stewart 		if (it->function_inp_end != NULL) {
183042551e99SRandall Stewart 			inp_skip = (*it->function_inp_end) (it->inp,
183142551e99SRandall Stewart 			    it->pointer,
183242551e99SRandall Stewart 			    it->val);
183342551e99SRandall Stewart 		}
183442551e99SRandall Stewart 		goto no_stcb;
183542551e99SRandall Stewart 	}
1836f8829a4aSRandall Stewart 	if ((it->stcb) &&
1837f8829a4aSRandall Stewart 	    (it->stcb->asoc.stcb_starting_point_for_iterator == it)) {
1838f8829a4aSRandall Stewart 		it->stcb->asoc.stcb_starting_point_for_iterator = NULL;
1839f8829a4aSRandall Stewart 	}
1840f8829a4aSRandall Stewart 	while (it->stcb) {
1841f8829a4aSRandall Stewart 		SCTP_TCB_LOCK(it->stcb);
1842f8829a4aSRandall Stewart 		if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
1843f8829a4aSRandall Stewart 			/* not in the right state... keep looking */
1844f8829a4aSRandall Stewart 			SCTP_TCB_UNLOCK(it->stcb);
1845f8829a4aSRandall Stewart 			goto next_assoc;
1846f8829a4aSRandall Stewart 		}
1847f8829a4aSRandall Stewart 		/* mark the current iterator on the assoc */
1848f8829a4aSRandall Stewart 		it->stcb->asoc.stcb_starting_point_for_iterator = it;
1849f8829a4aSRandall Stewart 		/* see if we have limited out the iterator loop */
1850f8829a4aSRandall Stewart 		iteration_count++;
1851f8829a4aSRandall Stewart 		if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) {
1852f8829a4aSRandall Stewart 	start_timer_return:
1853f8829a4aSRandall Stewart 			/* set a timer to continue this later */
1854ea1fbec5SRandall Stewart 			if (it->stcb)
1855f8829a4aSRandall Stewart 				SCTP_TCB_UNLOCK(it->stcb);
1856f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_ITERATOR,
1857f8829a4aSRandall Stewart 			    (struct sctp_inpcb *)it, NULL, NULL);
1858f8829a4aSRandall Stewart 			SCTP_ITERATOR_UNLOCK();
1859f8829a4aSRandall Stewart 			return;
1860f8829a4aSRandall Stewart 		}
1861f8829a4aSRandall Stewart 		/* run function on this one */
1862f8829a4aSRandall Stewart 		(*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val);
1863f8829a4aSRandall Stewart 
1864f8829a4aSRandall Stewart 		/*
1865f8829a4aSRandall Stewart 		 * we lie here, it really needs to have its own type but
1866f8829a4aSRandall Stewart 		 * first I must verify that this won't effect things :-0
1867f8829a4aSRandall Stewart 		 */
1868f8829a4aSRandall Stewart 		if (it->no_chunk_output == 0)
1869f8829a4aSRandall Stewart 			sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3);
1870f8829a4aSRandall Stewart 
1871f8829a4aSRandall Stewart 		SCTP_TCB_UNLOCK(it->stcb);
1872f8829a4aSRandall Stewart next_assoc:
1873f8829a4aSRandall Stewart 		it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
187442551e99SRandall Stewart 		if (it->stcb == NULL) {
187542551e99SRandall Stewart 			if (it->function_inp_end != NULL) {
187642551e99SRandall Stewart 				inp_skip = (*it->function_inp_end) (it->inp,
187742551e99SRandall Stewart 				    it->pointer,
187842551e99SRandall Stewart 				    it->val);
1879f8829a4aSRandall Stewart 			}
188042551e99SRandall Stewart 		}
188142551e99SRandall Stewart 	}
188242551e99SRandall Stewart no_stcb:
1883f8829a4aSRandall Stewart 	/* done with all assocs on this endpoint, move on to next endpoint */
188442551e99SRandall Stewart 	it->done_current_ep = 0;
1885f8829a4aSRandall Stewart 	SCTP_INP_WLOCK(it->inp);
1886f8829a4aSRandall Stewart 	it->inp->inp_starting_point_for_iterator = NULL;
1887f8829a4aSRandall Stewart 	SCTP_INP_WUNLOCK(it->inp);
1888f8829a4aSRandall Stewart 	if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
1889f8829a4aSRandall Stewart 		it->inp = NULL;
1890f8829a4aSRandall Stewart 	} else {
1891f8829a4aSRandall Stewart 		SCTP_INP_INFO_RLOCK();
1892f8829a4aSRandall Stewart 		it->inp = LIST_NEXT(it->inp, sctp_list);
1893f8829a4aSRandall Stewart 		SCTP_INP_INFO_RUNLOCK();
1894f8829a4aSRandall Stewart 	}
1895f8829a4aSRandall Stewart 	if (it->inp == NULL) {
1896f8829a4aSRandall Stewart 		goto done_with_iterator;
1897f8829a4aSRandall Stewart 	}
1898f8829a4aSRandall Stewart 	goto select_a_new_ep;
1899f8829a4aSRandall Stewart }
1900