xref: /freebsd/sys/netinet/sctp_timer.c (revision 99ddc825f38fb1809ff7381eec529e2584a181c6)
1f8829a4aSRandall Stewart /*-
2b1006367SRandall Stewart  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3f8829a4aSRandall Stewart  *
4f8829a4aSRandall Stewart  * Redistribution and use in source and binary forms, with or without
5f8829a4aSRandall Stewart  * modification, are permitted provided that the following conditions are met:
6f8829a4aSRandall Stewart  *
7f8829a4aSRandall Stewart  * a) Redistributions of source code must retain the above copyright notice,
8f8829a4aSRandall Stewart  *   this list of conditions and the following disclaimer.
9f8829a4aSRandall Stewart  *
10f8829a4aSRandall Stewart  * b) Redistributions in binary form must reproduce the above copyright
11f8829a4aSRandall Stewart  *    notice, this list of conditions and the following disclaimer in
12f8829a4aSRandall Stewart  *   the documentation and/or other materials provided with the distribution.
13f8829a4aSRandall Stewart  *
14f8829a4aSRandall Stewart  * c) Neither the name of Cisco Systems, Inc. nor the names of its
15f8829a4aSRandall Stewart  *    contributors may be used to endorse or promote products derived
16f8829a4aSRandall Stewart  *    from this software without specific prior written permission.
17f8829a4aSRandall Stewart  *
18f8829a4aSRandall Stewart  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19f8829a4aSRandall Stewart  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20f8829a4aSRandall Stewart  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21f8829a4aSRandall Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22f8829a4aSRandall Stewart  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23f8829a4aSRandall Stewart  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24f8829a4aSRandall Stewart  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25f8829a4aSRandall Stewart  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26f8829a4aSRandall Stewart  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27f8829a4aSRandall Stewart  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28f8829a4aSRandall Stewart  * THE POSSIBILITY OF SUCH DAMAGE.
29f8829a4aSRandall Stewart  */
30f8829a4aSRandall Stewart 
31f8829a4aSRandall Stewart /* $KAME: sctp_timer.c,v 1.29 2005/03/06 16:04:18 itojun Exp $	 */
32f8829a4aSRandall Stewart 
33f8829a4aSRandall Stewart #include <sys/cdefs.h>
34f8829a4aSRandall Stewart __FBSDID("$FreeBSD$");
35f8829a4aSRandall Stewart 
36f8829a4aSRandall Stewart #define _IP_VHL
3793164cf9SRandall Stewart #include <netinet/sctp_os.h>
38f8829a4aSRandall Stewart #include <netinet/sctp_pcb.h>
39f8829a4aSRandall Stewart #ifdef INET6
40f8829a4aSRandall Stewart #endif
41f8829a4aSRandall Stewart #include <netinet/sctp_var.h>
4242551e99SRandall Stewart #include <netinet/sctp_sysctl.h>
43f8829a4aSRandall Stewart #include <netinet/sctp_timer.h>
44f8829a4aSRandall Stewart #include <netinet/sctputil.h>
45f8829a4aSRandall Stewart #include <netinet/sctp_output.h>
46f8829a4aSRandall Stewart #include <netinet/sctp_header.h>
47f8829a4aSRandall Stewart #include <netinet/sctp_indata.h>
48f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h>
49f8829a4aSRandall Stewart #include <netinet/sctp_input.h>
50f8829a4aSRandall Stewart #include <netinet/sctp.h>
51f8829a4aSRandall Stewart #include <netinet/sctp_uio.h>
52830d754dSRandall Stewart #include <netinet/udp.h>
53f8829a4aSRandall Stewart 
54f8829a4aSRandall Stewart 
55f8829a4aSRandall Stewart void
56f8829a4aSRandall Stewart sctp_early_fr_timer(struct sctp_inpcb *inp,
57f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
58f8829a4aSRandall Stewart     struct sctp_nets *net)
59f8829a4aSRandall Stewart {
60f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk, *tp2;
61f8829a4aSRandall Stewart 	struct timeval now, min_wait, tv;
62f8829a4aSRandall Stewart 	unsigned int cur_rtt, cnt = 0, cnt_resend = 0;
63f8829a4aSRandall Stewart 
64f8829a4aSRandall Stewart 	/* an early FR is occuring. */
656e55db54SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&now);
66f8829a4aSRandall Stewart 	/* get cur rto in micro-seconds */
67f8829a4aSRandall Stewart 	if (net->lastsa == 0) {
68f8829a4aSRandall Stewart 		/* Hmm no rtt estimate yet? */
69f8829a4aSRandall Stewart 		cur_rtt = stcb->asoc.initial_rto >> 2;
70f8829a4aSRandall Stewart 	} else {
71f8829a4aSRandall Stewart 
72f8829a4aSRandall Stewart 		cur_rtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
73f8829a4aSRandall Stewart 	}
74b3f1ea41SRandall Stewart 	if (cur_rtt < SCTP_BASE_SYSCTL(sctp_early_fr_msec)) {
75b3f1ea41SRandall Stewart 		cur_rtt = SCTP_BASE_SYSCTL(sctp_early_fr_msec);
76f8829a4aSRandall Stewart 	}
77f8829a4aSRandall Stewart 	cur_rtt *= 1000;
78f8829a4aSRandall Stewart 	tv.tv_sec = cur_rtt / 1000000;
79f8829a4aSRandall Stewart 	tv.tv_usec = cur_rtt % 1000000;
80f8829a4aSRandall Stewart 	min_wait = now;
81f8829a4aSRandall Stewart 	timevalsub(&min_wait, &tv);
82f8829a4aSRandall Stewart 	if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
83f8829a4aSRandall Stewart 		/*
84f8829a4aSRandall Stewart 		 * if we hit here, we don't have enough seconds on the clock
85f8829a4aSRandall Stewart 		 * to account for the RTO. We just let the lower seconds be
86f8829a4aSRandall Stewart 		 * the bounds and don't worry about it. This may mean we
87f8829a4aSRandall Stewart 		 * will mark a lot more than we should.
88f8829a4aSRandall Stewart 		 */
89f8829a4aSRandall Stewart 		min_wait.tv_sec = min_wait.tv_usec = 0;
90f8829a4aSRandall Stewart 	}
91f8829a4aSRandall Stewart 	chk = TAILQ_LAST(&stcb->asoc.sent_queue, sctpchunk_listhead);
92f8829a4aSRandall Stewart 	for (; chk != NULL; chk = tp2) {
93f8829a4aSRandall Stewart 		tp2 = TAILQ_PREV(chk, sctpchunk_listhead, sctp_next);
94f8829a4aSRandall Stewart 		if (chk->whoTo != net) {
95f8829a4aSRandall Stewart 			continue;
96f8829a4aSRandall Stewart 		}
97f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND)
98f8829a4aSRandall Stewart 			cnt_resend++;
99f8829a4aSRandall Stewart 		else if ((chk->sent > SCTP_DATAGRAM_UNSENT) &&
100f8829a4aSRandall Stewart 		    (chk->sent < SCTP_DATAGRAM_RESEND)) {
101f8829a4aSRandall Stewart 			/* pending, may need retran */
102f8829a4aSRandall Stewart 			if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) {
103f8829a4aSRandall Stewart 				/*
104f8829a4aSRandall Stewart 				 * we have reached a chunk that was sent
105f8829a4aSRandall Stewart 				 * some seconds past our min.. forget it we
106f8829a4aSRandall Stewart 				 * will find no more to send.
107f8829a4aSRandall Stewart 				 */
108f8829a4aSRandall Stewart 				continue;
109f8829a4aSRandall Stewart 			} else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) {
110f8829a4aSRandall Stewart 				/*
111f8829a4aSRandall Stewart 				 * we must look at the micro seconds to
112f8829a4aSRandall Stewart 				 * know.
113f8829a4aSRandall Stewart 				 */
114f8829a4aSRandall Stewart 				if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
115f8829a4aSRandall Stewart 					/*
116f8829a4aSRandall Stewart 					 * ok it was sent after our boundary
117f8829a4aSRandall Stewart 					 * time.
118f8829a4aSRandall Stewart 					 */
119f8829a4aSRandall Stewart 					continue;
120f8829a4aSRandall Stewart 				}
121f8829a4aSRandall Stewart 			}
122b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_EARLYFR_LOGGING_ENABLE) {
123f8829a4aSRandall Stewart 				sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
124f8829a4aSRandall Stewart 				    4, SCTP_FR_MARKED_EARLY);
12580fefe0aSRandall Stewart 			}
126f8829a4aSRandall Stewart 			SCTP_STAT_INCR(sctps_earlyfrmrkretrans);
127f8829a4aSRandall Stewart 			chk->sent = SCTP_DATAGRAM_RESEND;
128f8829a4aSRandall Stewart 			sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
129f8829a4aSRandall Stewart 			/* double book size since we are doing an early FR */
130f8829a4aSRandall Stewart 			chk->book_size_scale++;
131f8829a4aSRandall Stewart 			cnt += chk->send_size;
132f8829a4aSRandall Stewart 			if ((cnt + net->flight_size) > net->cwnd) {
133f8829a4aSRandall Stewart 				/* Mark all we could possibly resend */
134f8829a4aSRandall Stewart 				break;
135f8829a4aSRandall Stewart 			}
136f8829a4aSRandall Stewart 		}
137f8829a4aSRandall Stewart 	}
138f8829a4aSRandall Stewart 	if (cnt) {
139f8829a4aSRandall Stewart 		/*
140b54d3a6cSRandall Stewart 		 * JRS - Use the congestion control given in the congestion
141b54d3a6cSRandall Stewart 		 * control module
142f8829a4aSRandall Stewart 		 */
143b54d3a6cSRandall Stewart 		stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer(inp, stcb, net);
144f8829a4aSRandall Stewart 	} else if (cnt_resend) {
145ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
146f8829a4aSRandall Stewart 	}
147f8829a4aSRandall Stewart 	/* Restart it? */
148f8829a4aSRandall Stewart 	if (net->flight_size < net->cwnd) {
149f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_earlyfrstrtmr);
150f8829a4aSRandall Stewart 		sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
151f8829a4aSRandall Stewart 	}
152f8829a4aSRandall Stewart }
153f8829a4aSRandall Stewart 
154f8829a4aSRandall Stewart void
155f8829a4aSRandall Stewart sctp_audit_retranmission_queue(struct sctp_association *asoc)
156f8829a4aSRandall Stewart {
157f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *chk;
158f8829a4aSRandall Stewart 
159ad81507eSRandall Stewart 	SCTPDBG(SCTP_DEBUG_TIMER4, "Audit invoked on send queue cnt:%d onqueue:%d\n",
160f8829a4aSRandall Stewart 	    asoc->sent_queue_retran_cnt,
161f8829a4aSRandall Stewart 	    asoc->sent_queue_cnt);
162f8829a4aSRandall Stewart 	asoc->sent_queue_retran_cnt = 0;
163f8829a4aSRandall Stewart 	asoc->sent_queue_cnt = 0;
164f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
165f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
166f8829a4aSRandall Stewart 			sctp_ucount_incr(asoc->sent_queue_retran_cnt);
167f8829a4aSRandall Stewart 		}
168f8829a4aSRandall Stewart 		asoc->sent_queue_cnt++;
169f8829a4aSRandall Stewart 	}
170f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
171f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
172f8829a4aSRandall Stewart 			sctp_ucount_incr(asoc->sent_queue_retran_cnt);
173f8829a4aSRandall Stewart 		}
174f8829a4aSRandall Stewart 	}
175c54a18d2SRandall Stewart 	TAILQ_FOREACH(chk, &asoc->asconf_send_queue, sctp_next) {
176c54a18d2SRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
177c54a18d2SRandall Stewart 			sctp_ucount_incr(asoc->sent_queue_retran_cnt);
178c54a18d2SRandall Stewart 		}
179c54a18d2SRandall Stewart 	}
180ad81507eSRandall Stewart 	SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n",
181f8829a4aSRandall Stewart 	    asoc->sent_queue_retran_cnt,
182f8829a4aSRandall Stewart 	    asoc->sent_queue_cnt);
183f8829a4aSRandall Stewart }
184f8829a4aSRandall Stewart 
185f8829a4aSRandall Stewart int
186f8829a4aSRandall Stewart sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
187f8829a4aSRandall Stewart     struct sctp_nets *net, uint16_t threshold)
188f8829a4aSRandall Stewart {
189f8829a4aSRandall Stewart 	if (net) {
190f8829a4aSRandall Stewart 		net->error_count++;
191ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n",
192f8829a4aSRandall Stewart 		    net, net->error_count,
193f8829a4aSRandall Stewart 		    net->failure_threshold);
194f8829a4aSRandall Stewart 		if (net->error_count > net->failure_threshold) {
195f8829a4aSRandall Stewart 			/* We had a threshold failure */
196f8829a4aSRandall Stewart 			if (net->dest_state & SCTP_ADDR_REACHABLE) {
197f8829a4aSRandall Stewart 				net->dest_state &= ~SCTP_ADDR_REACHABLE;
198f8829a4aSRandall Stewart 				net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
19942551e99SRandall Stewart 				net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY;
200f8829a4aSRandall Stewart 				if (net == stcb->asoc.primary_destination) {
201f8829a4aSRandall Stewart 					net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
202f8829a4aSRandall Stewart 				}
203b54d3a6cSRandall Stewart 				/*
204b54d3a6cSRandall Stewart 				 * JRS 5/14/07 - If a destination is
205b54d3a6cSRandall Stewart 				 * unreachable, the PF bit is turned off.
206b54d3a6cSRandall Stewart 				 * This allows an unambiguous use of the PF
207b54d3a6cSRandall Stewart 				 * bit for destinations that are reachable
208b54d3a6cSRandall Stewart 				 * but potentially failed. If the
209b54d3a6cSRandall Stewart 				 * destination is set to the unreachable
210b54d3a6cSRandall Stewart 				 * state, also set the destination to the PF
211b54d3a6cSRandall Stewart 				 * state.
212b54d3a6cSRandall Stewart 				 */
213b54d3a6cSRandall Stewart 				/*
214b54d3a6cSRandall Stewart 				 * Add debug message here if destination is
215b54d3a6cSRandall Stewart 				 * not in PF state.
216b54d3a6cSRandall Stewart 				 */
217b54d3a6cSRandall Stewart 				/* Stop any running T3 timers here? */
21820083c2eSMichael Tuexen 				if ((stcb->asoc.sctp_cmt_on_off == 1) &&
21920083c2eSMichael Tuexen 				    (stcb->asoc.sctp_cmt_pf > 0)) {
220b54d3a6cSRandall Stewart 					net->dest_state &= ~SCTP_ADDR_PF;
221b54d3a6cSRandall Stewart 					SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
222b54d3a6cSRandall Stewart 					    net);
223b54d3a6cSRandall Stewart 				}
224f8829a4aSRandall Stewart 				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
225f8829a4aSRandall Stewart 				    stcb,
226f8829a4aSRandall Stewart 				    SCTP_FAILED_THRESHOLD,
227ceaad40aSRandall Stewart 				    (void *)net, SCTP_SO_NOT_LOCKED);
228f8829a4aSRandall Stewart 			}
229f8829a4aSRandall Stewart 		}
230f8829a4aSRandall Stewart 		/*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE
231f8829a4aSRandall Stewart 		 *********ROUTING CODE
232f8829a4aSRandall Stewart 		 */
233f8829a4aSRandall Stewart 		/*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE
234f8829a4aSRandall Stewart 		 *********ROUTING CODE
235f8829a4aSRandall Stewart 		 */
236f8829a4aSRandall Stewart 	}
237f8829a4aSRandall Stewart 	if (stcb == NULL)
238f8829a4aSRandall Stewart 		return (0);
239f8829a4aSRandall Stewart 
240f8829a4aSRandall Stewart 	if (net) {
241f8829a4aSRandall Stewart 		if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) {
242b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
243c4739e2fSRandall Stewart 				sctp_misc_ints(SCTP_THRESHOLD_INCR,
244c4739e2fSRandall Stewart 				    stcb->asoc.overall_error_count,
245c4739e2fSRandall Stewart 				    (stcb->asoc.overall_error_count + 1),
246c4739e2fSRandall Stewart 				    SCTP_FROM_SCTP_TIMER,
247c4739e2fSRandall Stewart 				    __LINE__);
248c4739e2fSRandall Stewart 			}
249f8829a4aSRandall Stewart 			stcb->asoc.overall_error_count++;
250f8829a4aSRandall Stewart 		}
251f8829a4aSRandall Stewart 	} else {
252b3f1ea41SRandall Stewart 		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
253c4739e2fSRandall Stewart 			sctp_misc_ints(SCTP_THRESHOLD_INCR,
254c4739e2fSRandall Stewart 			    stcb->asoc.overall_error_count,
255c4739e2fSRandall Stewart 			    (stcb->asoc.overall_error_count + 1),
256c4739e2fSRandall Stewart 			    SCTP_FROM_SCTP_TIMER,
257c4739e2fSRandall Stewart 			    __LINE__);
258c4739e2fSRandall Stewart 		}
259f8829a4aSRandall Stewart 		stcb->asoc.overall_error_count++;
260f8829a4aSRandall Stewart 	}
261ad81507eSRandall Stewart 	SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n",
262ad81507eSRandall Stewart 	    &stcb->asoc, stcb->asoc.overall_error_count,
263f8829a4aSRandall Stewart 	    (uint32_t) threshold,
264f8829a4aSRandall Stewart 	    ((net == NULL) ? (uint32_t) 0 : (uint32_t) net->dest_state));
265f8829a4aSRandall Stewart 	/*
266f8829a4aSRandall Stewart 	 * We specifically do not do >= to give the assoc one more change
267f8829a4aSRandall Stewart 	 * before we fail it.
268f8829a4aSRandall Stewart 	 */
269f8829a4aSRandall Stewart 	if (stcb->asoc.overall_error_count > threshold) {
270f8829a4aSRandall Stewart 		/* Abort notification sends a ULP notify */
271f8829a4aSRandall Stewart 		struct mbuf *oper;
272f8829a4aSRandall Stewart 
273f8829a4aSRandall Stewart 		oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
274f8829a4aSRandall Stewart 		    0, M_DONTWAIT, 1, MT_DATA);
275f8829a4aSRandall Stewart 		if (oper) {
276f8829a4aSRandall Stewart 			struct sctp_paramhdr *ph;
277f8829a4aSRandall Stewart 			uint32_t *ippp;
278f8829a4aSRandall Stewart 
279139bc87fSRandall Stewart 			SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) +
280f8829a4aSRandall Stewart 			    sizeof(uint32_t);
281f8829a4aSRandall Stewart 			ph = mtod(oper, struct sctp_paramhdr *);
282f8829a4aSRandall Stewart 			ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
283139bc87fSRandall Stewart 			ph->param_length = htons(SCTP_BUF_LEN(oper));
284f8829a4aSRandall Stewart 			ippp = (uint32_t *) (ph + 1);
285a5d547adSRandall Stewart 			*ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_1);
286f8829a4aSRandall Stewart 		}
287a5d547adSRandall Stewart 		inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1;
288ceaad40aSRandall Stewart 		sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper, SCTP_SO_NOT_LOCKED);
289f8829a4aSRandall Stewart 		return (1);
290f8829a4aSRandall Stewart 	}
291f8829a4aSRandall Stewart 	return (0);
292f8829a4aSRandall Stewart }
293f8829a4aSRandall Stewart 
294f8829a4aSRandall Stewart struct sctp_nets *
295f8829a4aSRandall Stewart sctp_find_alternate_net(struct sctp_tcb *stcb,
296f8829a4aSRandall Stewart     struct sctp_nets *net,
297b54d3a6cSRandall Stewart     int mode)
298f8829a4aSRandall Stewart {
299f8829a4aSRandall Stewart 	/* Find and return an alternate network if possible */
300b54d3a6cSRandall Stewart 	struct sctp_nets *alt, *mnet, *min_errors_net = NULL, *max_cwnd_net = NULL;
301f8829a4aSRandall Stewart 	int once;
302b54d3a6cSRandall Stewart 
303b54d3a6cSRandall Stewart 	/* JRS 5/14/07 - Initialize min_errors to an impossible value. */
304b54d3a6cSRandall Stewart 	int min_errors = -1;
305b54d3a6cSRandall Stewart 	uint32_t max_cwnd = 0;
306f8829a4aSRandall Stewart 
307f8829a4aSRandall Stewart 	if (stcb->asoc.numnets == 1) {
308f8829a4aSRandall Stewart 		/* No others but net */
309f8829a4aSRandall Stewart 		return (TAILQ_FIRST(&stcb->asoc.nets));
310f8829a4aSRandall Stewart 	}
311b54d3a6cSRandall Stewart 	/*
312b54d3a6cSRandall Stewart 	 * JRS 5/14/07 - If mode is set to 2, use the CMT PF find alternate
313b54d3a6cSRandall Stewart 	 * net algorithm. This algorithm chooses the active destination (not
314b54d3a6cSRandall Stewart 	 * in PF state) with the largest cwnd value. If all destinations are
315b54d3a6cSRandall Stewart 	 * in PF state, unreachable, or unconfirmed, choose the desination
316b54d3a6cSRandall Stewart 	 * that is in PF state with the lowest error count. In case of a
317b54d3a6cSRandall Stewart 	 * tie, choose the destination that was most recently active.
318b54d3a6cSRandall Stewart 	 */
319b54d3a6cSRandall Stewart 	if (mode == 2) {
320b54d3a6cSRandall Stewart 		TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) {
321b54d3a6cSRandall Stewart 			/*
322b54d3a6cSRandall Stewart 			 * JRS 5/14/07 - If the destination is unreachable
323b54d3a6cSRandall Stewart 			 * or unconfirmed, skip it.
324b54d3a6cSRandall Stewart 			 */
325b54d3a6cSRandall Stewart 			if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) ||
326b54d3a6cSRandall Stewart 			    (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) {
327b54d3a6cSRandall Stewart 				continue;
328b54d3a6cSRandall Stewart 			}
329b54d3a6cSRandall Stewart 			/*
330b54d3a6cSRandall Stewart 			 * JRS 5/14/07 -  If the destination is reachable
331b54d3a6cSRandall Stewart 			 * but in PF state, compare the error count of the
332b54d3a6cSRandall Stewart 			 * destination to the minimum error count seen thus
333b54d3a6cSRandall Stewart 			 * far. Store the destination with the lower error
334b54d3a6cSRandall Stewart 			 * count.  If the error counts are equal, store the
335b54d3a6cSRandall Stewart 			 * destination that was most recently active.
336b54d3a6cSRandall Stewart 			 */
337b54d3a6cSRandall Stewart 			if (mnet->dest_state & SCTP_ADDR_PF) {
338b54d3a6cSRandall Stewart 				/*
339b54d3a6cSRandall Stewart 				 * JRS 5/14/07 - If the destination under
340b54d3a6cSRandall Stewart 				 * consideration is the current destination,
341b54d3a6cSRandall Stewart 				 * work as if the error count is one higher.
342b54d3a6cSRandall Stewart 				 * The actual error count will not be
343b54d3a6cSRandall Stewart 				 * incremented until later in the t3
344b54d3a6cSRandall Stewart 				 * handler.
345b54d3a6cSRandall Stewart 				 */
346b54d3a6cSRandall Stewart 				if (mnet == net) {
347b54d3a6cSRandall Stewart 					if (min_errors == -1) {
348b54d3a6cSRandall Stewart 						min_errors = mnet->error_count + 1;
349b54d3a6cSRandall Stewart 						min_errors_net = mnet;
350b54d3a6cSRandall Stewart 					} else if (mnet->error_count + 1 < min_errors) {
351b54d3a6cSRandall Stewart 						min_errors = mnet->error_count + 1;
352b54d3a6cSRandall Stewart 						min_errors_net = mnet;
353b54d3a6cSRandall Stewart 					} else if (mnet->error_count + 1 == min_errors
354b54d3a6cSRandall Stewart 					    && mnet->last_active > min_errors_net->last_active) {
355b54d3a6cSRandall Stewart 						min_errors_net = mnet;
356b54d3a6cSRandall Stewart 						min_errors = mnet->error_count + 1;
357b54d3a6cSRandall Stewart 					}
358b54d3a6cSRandall Stewart 					continue;
359b54d3a6cSRandall Stewart 				} else {
360b54d3a6cSRandall Stewart 					if (min_errors == -1) {
361b54d3a6cSRandall Stewart 						min_errors = mnet->error_count;
362b54d3a6cSRandall Stewart 						min_errors_net = mnet;
363b54d3a6cSRandall Stewart 					} else if (mnet->error_count < min_errors) {
364b54d3a6cSRandall Stewart 						min_errors = mnet->error_count;
365b54d3a6cSRandall Stewart 						min_errors_net = mnet;
366b54d3a6cSRandall Stewart 					} else if (mnet->error_count == min_errors
367b54d3a6cSRandall Stewart 					    && mnet->last_active > min_errors_net->last_active) {
368b54d3a6cSRandall Stewart 						min_errors_net = mnet;
369b54d3a6cSRandall Stewart 						min_errors = mnet->error_count;
370b54d3a6cSRandall Stewart 					}
371b54d3a6cSRandall Stewart 					continue;
372b54d3a6cSRandall Stewart 				}
373b54d3a6cSRandall Stewart 			}
374b54d3a6cSRandall Stewart 			/*
375b54d3a6cSRandall Stewart 			 * JRS 5/14/07 - If the destination is reachable and
376b54d3a6cSRandall Stewart 			 * not in PF state, compare the cwnd of the
377b54d3a6cSRandall Stewart 			 * destination to the highest cwnd seen thus far.
378b54d3a6cSRandall Stewart 			 * Store the destination with the higher cwnd value.
379b54d3a6cSRandall Stewart 			 * If the cwnd values are equal, randomly choose one
380b54d3a6cSRandall Stewart 			 * of the two destinations.
381b54d3a6cSRandall Stewart 			 */
382b54d3a6cSRandall Stewart 			if (max_cwnd < mnet->cwnd) {
383b54d3a6cSRandall Stewart 				max_cwnd_net = mnet;
384b54d3a6cSRandall Stewart 				max_cwnd = mnet->cwnd;
385b54d3a6cSRandall Stewart 			} else if (max_cwnd == mnet->cwnd) {
386b54d3a6cSRandall Stewart 				uint32_t rndval;
387b54d3a6cSRandall Stewart 				uint8_t this_random;
388b54d3a6cSRandall Stewart 
389b54d3a6cSRandall Stewart 				if (stcb->asoc.hb_random_idx > 3) {
390b54d3a6cSRandall Stewart 					rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep);
391b54d3a6cSRandall Stewart 					memcpy(stcb->asoc.hb_random_values, &rndval, sizeof(stcb->asoc.hb_random_values));
392b54d3a6cSRandall Stewart 					this_random = stcb->asoc.hb_random_values[0];
393b54d3a6cSRandall Stewart 					stcb->asoc.hb_random_idx++;
394b54d3a6cSRandall Stewart 					stcb->asoc.hb_ect_randombit = 0;
395b54d3a6cSRandall Stewart 				} else {
396b54d3a6cSRandall Stewart 					this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
397b54d3a6cSRandall Stewart 					stcb->asoc.hb_random_idx++;
398b54d3a6cSRandall Stewart 					stcb->asoc.hb_ect_randombit = 0;
399b54d3a6cSRandall Stewart 				}
400b54d3a6cSRandall Stewart 				if (this_random % 2 == 1) {
401b54d3a6cSRandall Stewart 					max_cwnd_net = mnet;
402fc14de76SRandall Stewart 					max_cwnd = mnet->cwnd;	/* Useless? */
403b54d3a6cSRandall Stewart 				}
404b54d3a6cSRandall Stewart 			}
405b54d3a6cSRandall Stewart 		}
406b54d3a6cSRandall Stewart 		/*
407b54d3a6cSRandall Stewart 		 * JRS 5/14/07 - After all destination have been considered
408b54d3a6cSRandall Stewart 		 * as alternates, check to see if there was some active
409b54d3a6cSRandall Stewart 		 * destination (not in PF state).  If not, check to see if
410b54d3a6cSRandall Stewart 		 * there was some PF destination with the minimum number of
411b54d3a6cSRandall Stewart 		 * errors.  If not, return the original destination.  If
412b54d3a6cSRandall Stewart 		 * there is a min_errors_net, remove the PF flag from that
413b54d3a6cSRandall Stewart 		 * destination, set the cwnd to one or two MTUs, and return
414b54d3a6cSRandall Stewart 		 * the destination as an alt. If there was some active
415b54d3a6cSRandall Stewart 		 * destination with a highest cwnd, return the destination
416b54d3a6cSRandall Stewart 		 * as an alt.
417b54d3a6cSRandall Stewart 		 */
418b54d3a6cSRandall Stewart 		if (max_cwnd_net == NULL) {
419b54d3a6cSRandall Stewart 			if (min_errors_net == NULL) {
420b54d3a6cSRandall Stewart 				return (net);
421b54d3a6cSRandall Stewart 			}
422b54d3a6cSRandall Stewart 			min_errors_net->dest_state &= ~SCTP_ADDR_PF;
42320083c2eSMichael Tuexen 			min_errors_net->cwnd = min_errors_net->mtu * stcb->asoc.sctp_cmt_pf;
424b54d3a6cSRandall Stewart 			if (SCTP_OS_TIMER_PENDING(&min_errors_net->rxt_timer.timer)) {
425b54d3a6cSRandall Stewart 				sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
426b54d3a6cSRandall Stewart 				    stcb, min_errors_net,
427b54d3a6cSRandall Stewart 				    SCTP_FROM_SCTP_TIMER + SCTP_LOC_2);
428b54d3a6cSRandall Stewart 			}
429b54d3a6cSRandall Stewart 			SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to active with %d errors.\n",
430b54d3a6cSRandall Stewart 			    min_errors_net, min_errors_net->error_count);
431b54d3a6cSRandall Stewart 			return (min_errors_net);
432b54d3a6cSRandall Stewart 		} else {
433b54d3a6cSRandall Stewart 			return (max_cwnd_net);
434b54d3a6cSRandall Stewart 		}
435b54d3a6cSRandall Stewart 	}
436b54d3a6cSRandall Stewart 	/*
437b54d3a6cSRandall Stewart 	 * JRS 5/14/07 - If mode is set to 1, use the CMT policy for
438b54d3a6cSRandall Stewart 	 * choosing an alternate net.
439b54d3a6cSRandall Stewart 	 */
440b54d3a6cSRandall Stewart 	else if (mode == 1) {
441f8829a4aSRandall Stewart 		TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) {
442f8829a4aSRandall Stewart 			if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) ||
443f8829a4aSRandall Stewart 			    (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)
444f8829a4aSRandall Stewart 			    ) {
445f8829a4aSRandall Stewart 				/*
446f8829a4aSRandall Stewart 				 * will skip ones that are not-reachable or
447f8829a4aSRandall Stewart 				 * unconfirmed
448f8829a4aSRandall Stewart 				 */
449f8829a4aSRandall Stewart 				continue;
450f8829a4aSRandall Stewart 			}
451b54d3a6cSRandall Stewart 			if (max_cwnd < mnet->cwnd) {
452b54d3a6cSRandall Stewart 				max_cwnd_net = mnet;
453b54d3a6cSRandall Stewart 				max_cwnd = mnet->cwnd;
454b54d3a6cSRandall Stewart 			} else if (max_cwnd == mnet->cwnd) {
455f8829a4aSRandall Stewart 				uint32_t rndval;
456f8829a4aSRandall Stewart 				uint8_t this_random;
457f8829a4aSRandall Stewart 
458f8829a4aSRandall Stewart 				if (stcb->asoc.hb_random_idx > 3) {
459f8829a4aSRandall Stewart 					rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep);
460f8829a4aSRandall Stewart 					memcpy(stcb->asoc.hb_random_values, &rndval,
461f8829a4aSRandall Stewart 					    sizeof(stcb->asoc.hb_random_values));
462f8829a4aSRandall Stewart 					this_random = stcb->asoc.hb_random_values[0];
463f8829a4aSRandall Stewart 					stcb->asoc.hb_random_idx = 0;
464f8829a4aSRandall Stewart 					stcb->asoc.hb_ect_randombit = 0;
465f8829a4aSRandall Stewart 				} else {
466f8829a4aSRandall Stewart 					this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
467f8829a4aSRandall Stewart 					stcb->asoc.hb_random_idx++;
468f8829a4aSRandall Stewart 					stcb->asoc.hb_ect_randombit = 0;
469f8829a4aSRandall Stewart 				}
470f8829a4aSRandall Stewart 				if (this_random % 2) {
471b54d3a6cSRandall Stewart 					max_cwnd_net = mnet;
472b54d3a6cSRandall Stewart 					max_cwnd = mnet->cwnd;
473f8829a4aSRandall Stewart 				}
474f8829a4aSRandall Stewart 			}
475f8829a4aSRandall Stewart 		}
476b54d3a6cSRandall Stewart 		if (max_cwnd_net) {
477b54d3a6cSRandall Stewart 			return (max_cwnd_net);
478f8829a4aSRandall Stewart 		}
479f8829a4aSRandall Stewart 	}
480f8829a4aSRandall Stewart 	mnet = net;
481f8829a4aSRandall Stewart 	once = 0;
482f8829a4aSRandall Stewart 
483f8829a4aSRandall Stewart 	if (mnet == NULL) {
484f8829a4aSRandall Stewart 		mnet = TAILQ_FIRST(&stcb->asoc.nets);
48552129fcdSRandall Stewart 		if (mnet == NULL) {
48652129fcdSRandall Stewart 			return (NULL);
48752129fcdSRandall Stewart 		}
488f8829a4aSRandall Stewart 	}
489f8829a4aSRandall Stewart 	do {
490f8829a4aSRandall Stewart 		alt = TAILQ_NEXT(mnet, sctp_next);
491f8829a4aSRandall Stewart 		if (alt == NULL) {
492f8829a4aSRandall Stewart 			once++;
493f8829a4aSRandall Stewart 			if (once > 1) {
494f8829a4aSRandall Stewart 				break;
495f8829a4aSRandall Stewart 			}
496f8829a4aSRandall Stewart 			alt = TAILQ_FIRST(&stcb->asoc.nets);
49752129fcdSRandall Stewart 			if (alt == NULL) {
49852129fcdSRandall Stewart 				return (NULL);
49952129fcdSRandall Stewart 			}
500f8829a4aSRandall Stewart 		}
501f8829a4aSRandall Stewart 		if (alt->ro.ro_rt == NULL) {
50242551e99SRandall Stewart 			if (alt->ro._s_addr) {
50342551e99SRandall Stewart 				sctp_free_ifa(alt->ro._s_addr);
50442551e99SRandall Stewart 				alt->ro._s_addr = NULL;
50542551e99SRandall Stewart 			}
506f8829a4aSRandall Stewart 			alt->src_addr_selected = 0;
507f8829a4aSRandall Stewart 		}
508f8829a4aSRandall Stewart 		if (
509f8829a4aSRandall Stewart 		    ((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) &&
510f8829a4aSRandall Stewart 		    (alt->ro.ro_rt != NULL) &&
5113c503c28SRandall Stewart 		/* sa_ignore NO_NULL_CHK */
512f8829a4aSRandall Stewart 		    (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))
513f8829a4aSRandall Stewart 		    ) {
514f8829a4aSRandall Stewart 			/* Found a reachable address */
515f8829a4aSRandall Stewart 			break;
516f8829a4aSRandall Stewart 		}
517f8829a4aSRandall Stewart 		mnet = alt;
518f8829a4aSRandall Stewart 	} while (alt != NULL);
519f8829a4aSRandall Stewart 
520f8829a4aSRandall Stewart 	if (alt == NULL) {
521f8829a4aSRandall Stewart 		/* Case where NO insv network exists (dormant state) */
522f8829a4aSRandall Stewart 		/* we rotate destinations */
523f8829a4aSRandall Stewart 		once = 0;
524f8829a4aSRandall Stewart 		mnet = net;
525f8829a4aSRandall Stewart 		do {
52652129fcdSRandall Stewart 			if (mnet == NULL) {
52752129fcdSRandall Stewart 				return (TAILQ_FIRST(&stcb->asoc.nets));
52852129fcdSRandall Stewart 			}
529f8829a4aSRandall Stewart 			alt = TAILQ_NEXT(mnet, sctp_next);
530f8829a4aSRandall Stewart 			if (alt == NULL) {
531f8829a4aSRandall Stewart 				once++;
532f8829a4aSRandall Stewart 				if (once > 1) {
533f8829a4aSRandall Stewart 					break;
534f8829a4aSRandall Stewart 				}
535f8829a4aSRandall Stewart 				alt = TAILQ_FIRST(&stcb->asoc.nets);
536f8829a4aSRandall Stewart 			}
5373c503c28SRandall Stewart 			/* sa_ignore NO_NULL_CHK */
538f8829a4aSRandall Stewart 			if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) &&
539f8829a4aSRandall Stewart 			    (alt != net)) {
540f8829a4aSRandall Stewart 				/* Found an alternate address */
541f8829a4aSRandall Stewart 				break;
542f8829a4aSRandall Stewart 			}
543f8829a4aSRandall Stewart 			mnet = alt;
544f8829a4aSRandall Stewart 		} while (alt != NULL);
545f8829a4aSRandall Stewart 	}
546f8829a4aSRandall Stewart 	if (alt == NULL) {
547f8829a4aSRandall Stewart 		return (net);
548f8829a4aSRandall Stewart 	}
549f8829a4aSRandall Stewart 	return (alt);
550f8829a4aSRandall Stewart }
551f8829a4aSRandall Stewart 
552b54d3a6cSRandall Stewart 
553b54d3a6cSRandall Stewart 
554f8829a4aSRandall Stewart static void
555f8829a4aSRandall Stewart sctp_backoff_on_timeout(struct sctp_tcb *stcb,
556f8829a4aSRandall Stewart     struct sctp_nets *net,
557f8829a4aSRandall Stewart     int win_probe,
55844fbe462SRandall Stewart     int num_marked, int num_abandoned)
559f8829a4aSRandall Stewart {
5609a972525SRandall Stewart 	if (net->RTO == 0) {
5619a972525SRandall Stewart 		net->RTO = stcb->asoc.minrto;
5629a972525SRandall Stewart 	}
563f8829a4aSRandall Stewart 	net->RTO <<= 1;
564f8829a4aSRandall Stewart 	if (net->RTO > stcb->asoc.maxrto) {
565f8829a4aSRandall Stewart 		net->RTO = stcb->asoc.maxrto;
566f8829a4aSRandall Stewart 	}
56744fbe462SRandall Stewart 	if ((win_probe == 0) && (num_marked || num_abandoned)) {
568f8829a4aSRandall Stewart 		/* We don't apply penalty to window probe scenarios */
569b54d3a6cSRandall Stewart 		/* JRS - Use the congestion control given in the CC module */
570b54d3a6cSRandall Stewart 		stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net);
571f8829a4aSRandall Stewart 	}
572f8829a4aSRandall Stewart }
573f8829a4aSRandall Stewart 
57483416c88SRandall Stewart #ifndef INVARIANTS
57583416c88SRandall Stewart static void
576df6e0cc3SRandall Stewart sctp_recover_sent_list(struct sctp_tcb *stcb)
577df6e0cc3SRandall Stewart {
578df6e0cc3SRandall Stewart 	struct sctp_tmit_chunk *chk, *tp2;
579df6e0cc3SRandall Stewart 	struct sctp_association *asoc;
580df6e0cc3SRandall Stewart 
581df6e0cc3SRandall Stewart 	asoc = &stcb->asoc;
582df6e0cc3SRandall Stewart 	chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
583df6e0cc3SRandall Stewart 	for (; chk != NULL; chk = tp2) {
584df6e0cc3SRandall Stewart 		tp2 = TAILQ_NEXT(chk, sctp_next);
585df6e0cc3SRandall Stewart 		if ((compare_with_wrap(stcb->asoc.last_acked_seq,
586df6e0cc3SRandall Stewart 		    chk->rec.data.TSN_seq,
587df6e0cc3SRandall Stewart 		    MAX_TSN)) ||
588df6e0cc3SRandall Stewart 		    (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) {
589df6e0cc3SRandall Stewart 
590df6e0cc3SRandall Stewart 			SCTP_PRINTF("Found chk:%p tsn:%x <= last_acked_seq:%x\n",
591df6e0cc3SRandall Stewart 			    chk, chk->rec.data.TSN_seq, stcb->asoc.last_acked_seq);
592df6e0cc3SRandall Stewart 			TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
593df6e0cc3SRandall Stewart 			if (chk->pr_sctp_on) {
594df6e0cc3SRandall Stewart 				if (asoc->pr_sctp_cnt != 0)
595df6e0cc3SRandall Stewart 					asoc->pr_sctp_cnt--;
596df6e0cc3SRandall Stewart 			}
597df6e0cc3SRandall Stewart 			if (chk->data) {
598df6e0cc3SRandall Stewart 				/* sa_ignore NO_NULL_CHK */
599df6e0cc3SRandall Stewart 				sctp_free_bufspace(stcb, asoc, chk, 1);
600df6e0cc3SRandall Stewart 				sctp_m_freem(chk->data);
601810ec536SMichael Tuexen 				if (asoc->peer_supports_prsctp && PR_SCTP_BUF_ENABLED(chk->flags)) {
602df6e0cc3SRandall Stewart 					asoc->sent_queue_cnt_removeable--;
603df6e0cc3SRandall Stewart 				}
604df6e0cc3SRandall Stewart 			}
605df6e0cc3SRandall Stewart 			chk->data = NULL;
606df6e0cc3SRandall Stewart 			asoc->sent_queue_cnt--;
607df6e0cc3SRandall Stewart 			sctp_free_a_chunk(stcb, chk);
608df6e0cc3SRandall Stewart 		}
609df6e0cc3SRandall Stewart 	}
610df6e0cc3SRandall Stewart 	SCTP_PRINTF("after recover order is as follows\n");
611df6e0cc3SRandall Stewart 	chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
612df6e0cc3SRandall Stewart 	for (; chk != NULL; chk = tp2) {
613df6e0cc3SRandall Stewart 		tp2 = TAILQ_NEXT(chk, sctp_next);
614df6e0cc3SRandall Stewart 		SCTP_PRINTF("chk:%p TSN:%x\n", chk, chk->rec.data.TSN_seq);
615df6e0cc3SRandall Stewart 	}
616df6e0cc3SRandall Stewart }
617df6e0cc3SRandall Stewart 
61883416c88SRandall Stewart #endif
61983416c88SRandall Stewart 
620f8829a4aSRandall Stewart static int
621f8829a4aSRandall Stewart sctp_mark_all_for_resend(struct sctp_tcb *stcb,
622f8829a4aSRandall Stewart     struct sctp_nets *net,
623f8829a4aSRandall Stewart     struct sctp_nets *alt,
624f8829a4aSRandall Stewart     int window_probe,
62544fbe462SRandall Stewart     int *num_marked,
62644fbe462SRandall Stewart     int *num_abandoned)
627f8829a4aSRandall Stewart {
628f8829a4aSRandall Stewart 
629f8829a4aSRandall Stewart 	/*
630f8829a4aSRandall Stewart 	 * Mark all chunks (well not all) that were sent to *net for
631f8829a4aSRandall Stewart 	 * retransmission. Move them to alt for there destination as well...
632f8829a4aSRandall Stewart 	 * We only mark chunks that have been outstanding long enough to
633f8829a4aSRandall Stewart 	 * have received feed-back.
634f8829a4aSRandall Stewart 	 */
63544fbe462SRandall Stewart 	struct sctp_tmit_chunk *chk, *tp2;
636f8829a4aSRandall Stewart 	struct sctp_nets *lnets;
637f8829a4aSRandall Stewart 	struct timeval now, min_wait, tv;
638f8829a4aSRandall Stewart 	int cur_rtt;
63944fbe462SRandall Stewart 	int cnt_abandoned;
640c105859eSRandall Stewart 	int audit_tf, num_mk, fir;
641f8829a4aSRandall Stewart 	unsigned int cnt_mk;
642c105859eSRandall Stewart 	uint32_t orig_flight, orig_tf;
643f8829a4aSRandall Stewart 	uint32_t tsnlast, tsnfirst;
644df6e0cc3SRandall Stewart 	int recovery_cnt = 0;
645f8829a4aSRandall Stewart 
646b54d3a6cSRandall Stewart 
647f8829a4aSRandall Stewart 	/* none in flight now */
648f8829a4aSRandall Stewart 	audit_tf = 0;
649f8829a4aSRandall Stewart 	fir = 0;
650f8829a4aSRandall Stewart 	/*
651f8829a4aSRandall Stewart 	 * figure out how long a data chunk must be pending before we can
652f8829a4aSRandall Stewart 	 * mark it ..
653f8829a4aSRandall Stewart 	 */
6546e55db54SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&now);
655f8829a4aSRandall Stewart 	/* get cur rto in micro-seconds */
656f8829a4aSRandall Stewart 	cur_rtt = (((net->lastsa >> 2) + net->lastsv) >> 1);
657f8829a4aSRandall Stewart 	cur_rtt *= 1000;
658b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
659f8829a4aSRandall Stewart 		sctp_log_fr(cur_rtt,
660f8829a4aSRandall Stewart 		    stcb->asoc.peers_rwnd,
661f8829a4aSRandall Stewart 		    window_probe,
662f8829a4aSRandall Stewart 		    SCTP_FR_T3_MARK_TIME);
663f8829a4aSRandall Stewart 		sctp_log_fr(net->flight_size,
664139bc87fSRandall Stewart 		    SCTP_OS_TIMER_PENDING(&net->fr_timer.timer),
665139bc87fSRandall Stewart 		    SCTP_OS_TIMER_ACTIVE(&net->fr_timer.timer),
666f8829a4aSRandall Stewart 		    SCTP_FR_CWND_REPORT);
667f8829a4aSRandall Stewart 		sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT);
66880fefe0aSRandall Stewart 	}
669f8829a4aSRandall Stewart 	tv.tv_sec = cur_rtt / 1000000;
670f8829a4aSRandall Stewart 	tv.tv_usec = cur_rtt % 1000000;
671f8829a4aSRandall Stewart 	min_wait = now;
672f8829a4aSRandall Stewart 	timevalsub(&min_wait, &tv);
673f8829a4aSRandall Stewart 	if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
674f8829a4aSRandall Stewart 		/*
675f8829a4aSRandall Stewart 		 * if we hit here, we don't have enough seconds on the clock
676f8829a4aSRandall Stewart 		 * to account for the RTO. We just let the lower seconds be
677f8829a4aSRandall Stewart 		 * the bounds and don't worry about it. This may mean we
678f8829a4aSRandall Stewart 		 * will mark a lot more than we should.
679f8829a4aSRandall Stewart 		 */
680f8829a4aSRandall Stewart 		min_wait.tv_sec = min_wait.tv_usec = 0;
681f8829a4aSRandall Stewart 	}
682b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
683f8829a4aSRandall Stewart 		sctp_log_fr(cur_rtt, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME);
684f8829a4aSRandall Stewart 		sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME);
68580fefe0aSRandall Stewart 	}
686f8829a4aSRandall Stewart 	/*
687f8829a4aSRandall Stewart 	 * Our rwnd will be incorrect here since we are not adding back the
688f8829a4aSRandall Stewart 	 * cnt * mbuf but we will fix that down below.
689f8829a4aSRandall Stewart 	 */
690f8829a4aSRandall Stewart 	orig_flight = net->flight_size;
691c105859eSRandall Stewart 	orig_tf = stcb->asoc.total_flight;
692c105859eSRandall Stewart 
693f8829a4aSRandall Stewart 	net->fast_retran_ip = 0;
694f8829a4aSRandall Stewart 	/* Now on to each chunk */
69544fbe462SRandall Stewart 	cnt_abandoned = 0;
696f8829a4aSRandall Stewart 	num_mk = cnt_mk = 0;
697f8829a4aSRandall Stewart 	tsnfirst = tsnlast = 0;
69883416c88SRandall Stewart #ifndef INVARIANTS
699df6e0cc3SRandall Stewart start_again:
70083416c88SRandall Stewart #endif
701f8829a4aSRandall Stewart 	chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
702f8829a4aSRandall Stewart 	for (; chk != NULL; chk = tp2) {
703f8829a4aSRandall Stewart 		tp2 = TAILQ_NEXT(chk, sctp_next);
704f8829a4aSRandall Stewart 		if ((compare_with_wrap(stcb->asoc.last_acked_seq,
705f8829a4aSRandall Stewart 		    chk->rec.data.TSN_seq,
706f8829a4aSRandall Stewart 		    MAX_TSN)) ||
707f8829a4aSRandall Stewart 		    (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) {
708f8829a4aSRandall Stewart 			/* Strange case our list got out of order? */
709df6e0cc3SRandall Stewart 			SCTP_PRINTF("Our list is out of order? last_acked:%x chk:%x",
710df6e0cc3SRandall Stewart 			    (unsigned int)stcb->asoc.last_acked_seq, (unsigned int)chk->rec.data.TSN_seq);
711df6e0cc3SRandall Stewart 			recovery_cnt++;
712df6e0cc3SRandall Stewart #ifdef INVARIANTS
713df6e0cc3SRandall Stewart 			panic("last acked >= chk on sent-Q");
714df6e0cc3SRandall Stewart #else
715df6e0cc3SRandall Stewart 			SCTP_PRINTF("Recover attempts a restart cnt:%d\n", recovery_cnt);
716df6e0cc3SRandall Stewart 			sctp_recover_sent_list(stcb);
717df6e0cc3SRandall Stewart 			if (recovery_cnt < 10) {
718df6e0cc3SRandall Stewart 				goto start_again;
719df6e0cc3SRandall Stewart 			} else {
720df6e0cc3SRandall Stewart 				SCTP_PRINTF("Recovery fails %d times??\n", recovery_cnt);
721df6e0cc3SRandall Stewart 			}
722df6e0cc3SRandall Stewart #endif
723f8829a4aSRandall Stewart 		}
724f8829a4aSRandall Stewart 		if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) {
725f8829a4aSRandall Stewart 			/*
726f8829a4aSRandall Stewart 			 * found one to mark: If it is less than
727f8829a4aSRandall Stewart 			 * DATAGRAM_ACKED it MUST not be a skipped or marked
728f8829a4aSRandall Stewart 			 * TSN but instead one that is either already set
729f8829a4aSRandall Stewart 			 * for retransmission OR one that needs
730f8829a4aSRandall Stewart 			 * retransmission.
731f8829a4aSRandall Stewart 			 */
732f8829a4aSRandall Stewart 
733f8829a4aSRandall Stewart 			/* validate its been outstanding long enough */
734b3f1ea41SRandall Stewart 			if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
735f8829a4aSRandall Stewart 				sctp_log_fr(chk->rec.data.TSN_seq,
736f8829a4aSRandall Stewart 				    chk->sent_rcv_time.tv_sec,
737f8829a4aSRandall Stewart 				    chk->sent_rcv_time.tv_usec,
738f8829a4aSRandall Stewart 				    SCTP_FR_T3_MARK_TIME);
73980fefe0aSRandall Stewart 			}
740f8829a4aSRandall Stewart 			if ((chk->sent_rcv_time.tv_sec > min_wait.tv_sec) && (window_probe == 0)) {
741f8829a4aSRandall Stewart 				/*
742f8829a4aSRandall Stewart 				 * we have reached a chunk that was sent
743f8829a4aSRandall Stewart 				 * some seconds past our min.. forget it we
744f8829a4aSRandall Stewart 				 * will find no more to send.
745f8829a4aSRandall Stewart 				 */
746b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
747f8829a4aSRandall Stewart 					sctp_log_fr(0,
748f8829a4aSRandall Stewart 					    chk->sent_rcv_time.tv_sec,
749f8829a4aSRandall Stewart 					    chk->sent_rcv_time.tv_usec,
750f8829a4aSRandall Stewart 					    SCTP_FR_T3_STOPPED);
75180fefe0aSRandall Stewart 				}
752f8829a4aSRandall Stewart 				continue;
753f8829a4aSRandall Stewart 			} else if ((chk->sent_rcv_time.tv_sec == min_wait.tv_sec) &&
754f8829a4aSRandall Stewart 			    (window_probe == 0)) {
755f8829a4aSRandall Stewart 				/*
756f8829a4aSRandall Stewart 				 * we must look at the micro seconds to
757f8829a4aSRandall Stewart 				 * know.
758f8829a4aSRandall Stewart 				 */
759f8829a4aSRandall Stewart 				if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
760f8829a4aSRandall Stewart 					/*
761f8829a4aSRandall Stewart 					 * ok it was sent after our boundary
762f8829a4aSRandall Stewart 					 * time.
763f8829a4aSRandall Stewart 					 */
764b3f1ea41SRandall Stewart 					if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
765f8829a4aSRandall Stewart 						sctp_log_fr(0,
766f8829a4aSRandall Stewart 						    chk->sent_rcv_time.tv_sec,
767f8829a4aSRandall Stewart 						    chk->sent_rcv_time.tv_usec,
768f8829a4aSRandall Stewart 						    SCTP_FR_T3_STOPPED);
76980fefe0aSRandall Stewart 					}
770f8829a4aSRandall Stewart 					continue;
771f8829a4aSRandall Stewart 				}
772f8829a4aSRandall Stewart 			}
773810ec536SMichael Tuexen 			if (stcb->asoc.peer_supports_prsctp && PR_SCTP_TTL_ENABLED(chk->flags)) {
774f8829a4aSRandall Stewart 				/* Is it expired? */
775*99ddc825SMichael Tuexen 				if (timevalcmp(&now, &chk->rec.data.timetodrop, >)) {
776f8829a4aSRandall Stewart 					/* Yes so drop it */
777f8829a4aSRandall Stewart 					if (chk->data) {
778ad81507eSRandall Stewart 						(void)sctp_release_pr_sctp_chunk(stcb,
779f8829a4aSRandall Stewart 						    chk,
780f8829a4aSRandall Stewart 						    (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
7810c0982b8SRandall Stewart 						    SCTP_SO_NOT_LOCKED);
78244fbe462SRandall Stewart 						cnt_abandoned++;
783f8829a4aSRandall Stewart 					}
784f8829a4aSRandall Stewart 					continue;
785f8829a4aSRandall Stewart 				}
786830d754dSRandall Stewart 			}
787810ec536SMichael Tuexen 			if (stcb->asoc.peer_supports_prsctp && PR_SCTP_RTX_ENABLED(chk->flags)) {
788f8829a4aSRandall Stewart 				/* Has it been retransmitted tv_sec times? */
789f8829a4aSRandall Stewart 				if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) {
790f8829a4aSRandall Stewart 					if (chk->data) {
791ad81507eSRandall Stewart 						(void)sctp_release_pr_sctp_chunk(stcb,
792f8829a4aSRandall Stewart 						    chk,
793f8829a4aSRandall Stewart 						    (SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
7940c0982b8SRandall Stewart 						    SCTP_SO_NOT_LOCKED);
79544fbe462SRandall Stewart 						cnt_abandoned++;
796f8829a4aSRandall Stewart 					}
797f8829a4aSRandall Stewart 					continue;
798f8829a4aSRandall Stewart 				}
799830d754dSRandall Stewart 			}
800c105859eSRandall Stewart 			if (chk->sent < SCTP_DATAGRAM_RESEND) {
801f8829a4aSRandall Stewart 				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
802f8829a4aSRandall Stewart 				num_mk++;
803f8829a4aSRandall Stewart 				if (fir == 0) {
804f8829a4aSRandall Stewart 					fir = 1;
805f8829a4aSRandall Stewart 					tsnfirst = chk->rec.data.TSN_seq;
806f8829a4aSRandall Stewart 				}
807f8829a4aSRandall Stewart 				tsnlast = chk->rec.data.TSN_seq;
808b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
809f8829a4aSRandall Stewart 					sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
810f8829a4aSRandall Stewart 					    0, SCTP_FR_T3_MARKED);
81180fefe0aSRandall Stewart 				}
81242551e99SRandall Stewart 				if (chk->rec.data.chunk_was_revoked) {
81342551e99SRandall Stewart 					/* deflate the cwnd */
81442551e99SRandall Stewart 					chk->whoTo->cwnd -= chk->book_size;
81542551e99SRandall Stewart 					chk->rec.data.chunk_was_revoked = 0;
81642551e99SRandall Stewart 				}
817f42a358aSRandall Stewart 				net->marked_retrans++;
818f42a358aSRandall Stewart 				stcb->asoc.marked_retrans++;
819b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
820c105859eSRandall Stewart 					sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO,
821a5d547adSRandall Stewart 					    chk->whoTo->flight_size,
822a5d547adSRandall Stewart 					    chk->book_size,
823c105859eSRandall Stewart 					    (uintptr_t) chk->whoTo,
824a5d547adSRandall Stewart 					    chk->rec.data.TSN_seq);
82580fefe0aSRandall Stewart 				}
826c105859eSRandall Stewart 				sctp_flight_size_decrease(chk);
827c105859eSRandall Stewart 				sctp_total_flight_decrease(stcb, chk);
828f8829a4aSRandall Stewart 				stcb->asoc.peers_rwnd += chk->send_size;
829b3f1ea41SRandall Stewart 				stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh);
830c105859eSRandall Stewart 			}
831c105859eSRandall Stewart 			chk->sent = SCTP_DATAGRAM_RESEND;
832c105859eSRandall Stewart 			SCTP_STAT_INCR(sctps_markedretrans);
833f8829a4aSRandall Stewart 
834f8829a4aSRandall Stewart 			/* reset the TSN for striking and other FR stuff */
835f8829a4aSRandall Stewart 			chk->rec.data.doing_fast_retransmit = 0;
836f8829a4aSRandall Stewart 			/* Clear any time so NO RTT is being done */
837f8829a4aSRandall Stewart 			chk->do_rtt = 0;
838f8829a4aSRandall Stewart 			if (alt != net) {
839f8829a4aSRandall Stewart 				sctp_free_remote_addr(chk->whoTo);
840f8829a4aSRandall Stewart 				chk->no_fr_allowed = 1;
841f8829a4aSRandall Stewart 				chk->whoTo = alt;
842f8829a4aSRandall Stewart 				atomic_add_int(&alt->ref_count, 1);
843f8829a4aSRandall Stewart 			} else {
844f8829a4aSRandall Stewart 				chk->no_fr_allowed = 0;
845f8829a4aSRandall Stewart 				if (TAILQ_EMPTY(&stcb->asoc.send_queue)) {
846f8829a4aSRandall Stewart 					chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq;
847f8829a4aSRandall Stewart 				} else {
848f8829a4aSRandall Stewart 					chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.TSN_seq;
849f8829a4aSRandall Stewart 				}
850f8829a4aSRandall Stewart 			}
851ad21a364SRandall Stewart 			/*
852ad21a364SRandall Stewart 			 * CMT: Do not allow FRs on retransmitted TSNs.
853ad21a364SRandall Stewart 			 */
85420083c2eSMichael Tuexen 			if (stcb->asoc.sctp_cmt_on_off == 1) {
855f8829a4aSRandall Stewart 				chk->no_fr_allowed = 1;
856f8829a4aSRandall Stewart 			}
85744fbe462SRandall Stewart #ifdef THIS_SHOULD_NOT_BE_DONE
858f8829a4aSRandall Stewart 		} else if (chk->sent == SCTP_DATAGRAM_ACKED) {
859f8829a4aSRandall Stewart 			/* remember highest acked one */
860f8829a4aSRandall Stewart 			could_be_sent = chk;
86144fbe462SRandall Stewart #endif
862f8829a4aSRandall Stewart 		}
863f8829a4aSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
864f8829a4aSRandall Stewart 			cnt_mk++;
865f8829a4aSRandall Stewart 		}
866f8829a4aSRandall Stewart 	}
867c105859eSRandall Stewart 	if ((orig_flight - net->flight_size) != (orig_tf - stcb->asoc.total_flight)) {
868c105859eSRandall Stewart 		/* we did not subtract the same things? */
869c105859eSRandall Stewart 		audit_tf = 1;
870c105859eSRandall Stewart 	}
871b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_EARLYFR_LOGGING_ENABLE | SCTP_FR_LOGGING_ENABLE)) {
872f8829a4aSRandall Stewart 		sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT);
87380fefe0aSRandall Stewart 	}
874f8829a4aSRandall Stewart #ifdef SCTP_DEBUG
875f8829a4aSRandall Stewart 	if (num_mk) {
876ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n",
877ad81507eSRandall Stewart 		    tsnlast);
878ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%ld\n",
879f8829a4aSRandall Stewart 		    num_mk, (u_long)stcb->asoc.peers_rwnd);
880ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n",
881ad81507eSRandall Stewart 		    tsnlast);
882ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%d\n",
883f8829a4aSRandall Stewart 		    num_mk,
884ad81507eSRandall Stewart 		    (int)stcb->asoc.peers_rwnd);
885f8829a4aSRandall Stewart 	}
886f8829a4aSRandall Stewart #endif
887f8829a4aSRandall Stewart 	*num_marked = num_mk;
88844fbe462SRandall Stewart 	*num_abandoned = cnt_abandoned;
8896c065bbeSRandall Stewart 	/*
8906c065bbeSRandall Stewart 	 * Now check for a ECN Echo that may be stranded And include the
8916c065bbeSRandall Stewart 	 * cnt_mk'd to have all resends in the control queue.
8926c065bbeSRandall Stewart 	 */
8936c065bbeSRandall Stewart 	TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
8946c065bbeSRandall Stewart 		if (chk->sent == SCTP_DATAGRAM_RESEND) {
8956c065bbeSRandall Stewart 			cnt_mk++;
8966c065bbeSRandall Stewart 		}
8976c065bbeSRandall Stewart 		if ((chk->whoTo == net) &&
8986c065bbeSRandall Stewart 		    (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) {
8996c065bbeSRandall Stewart 			sctp_free_remote_addr(chk->whoTo);
9006c065bbeSRandall Stewart 			chk->whoTo = alt;
9016c065bbeSRandall Stewart 			if (chk->sent != SCTP_DATAGRAM_RESEND) {
9026c065bbeSRandall Stewart 				chk->sent = SCTP_DATAGRAM_RESEND;
9036c065bbeSRandall Stewart 				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
9046c065bbeSRandall Stewart 				cnt_mk++;
9056c065bbeSRandall Stewart 			}
9066c065bbeSRandall Stewart 			atomic_add_int(&alt->ref_count, 1);
9076c065bbeSRandall Stewart 		}
9086c065bbeSRandall Stewart 	}
90944fbe462SRandall Stewart #ifdef THIS_SHOULD_NOT_BE_DONE
910f8829a4aSRandall Stewart 	if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) {
911f8829a4aSRandall Stewart 		/* fix it so we retransmit the highest acked anyway */
912f8829a4aSRandall Stewart 		sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
913f8829a4aSRandall Stewart 		cnt_mk++;
914f8829a4aSRandall Stewart 		could_be_sent->sent = SCTP_DATAGRAM_RESEND;
915f8829a4aSRandall Stewart 	}
91644fbe462SRandall Stewart #endif
917f8829a4aSRandall Stewart 	if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) {
918a5d547adSRandall Stewart #ifdef INVARIANTS
91918e198d3SRandall Stewart 		SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d we marked:%d this time\n",
92018e198d3SRandall Stewart 		    cnt_mk, stcb->asoc.sent_queue_retran_cnt, num_mk);
921f8829a4aSRandall Stewart #endif
922f8829a4aSRandall Stewart #ifndef SCTP_AUDITING_ENABLED
923f8829a4aSRandall Stewart 		stcb->asoc.sent_queue_retran_cnt = cnt_mk;
924f8829a4aSRandall Stewart #endif
925f8829a4aSRandall Stewart 	}
926f8829a4aSRandall Stewart 	if (audit_tf) {
927ad81507eSRandall Stewart 		SCTPDBG(SCTP_DEBUG_TIMER4,
928ad81507eSRandall Stewart 		    "Audit total flight due to negative value net:%p\n",
929f8829a4aSRandall Stewart 		    net);
930f8829a4aSRandall Stewart 		stcb->asoc.total_flight = 0;
931f8829a4aSRandall Stewart 		stcb->asoc.total_flight_count = 0;
932f8829a4aSRandall Stewart 		/* Clear all networks flight size */
933f8829a4aSRandall Stewart 		TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) {
934f8829a4aSRandall Stewart 			lnets->flight_size = 0;
935ad81507eSRandall Stewart 			SCTPDBG(SCTP_DEBUG_TIMER4,
936ad81507eSRandall Stewart 			    "Net:%p c-f cwnd:%d ssthresh:%d\n",
937f8829a4aSRandall Stewart 			    lnets, lnets->cwnd, lnets->ssthresh);
938f8829a4aSRandall Stewart 		}
939f8829a4aSRandall Stewart 		TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
940f8829a4aSRandall Stewart 			if (chk->sent < SCTP_DATAGRAM_RESEND) {
941b3f1ea41SRandall Stewart 				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
942a5d547adSRandall Stewart 					sctp_misc_ints(SCTP_FLIGHT_LOG_UP,
943a5d547adSRandall Stewart 					    chk->whoTo->flight_size,
944a5d547adSRandall Stewart 					    chk->book_size,
945c105859eSRandall Stewart 					    (uintptr_t) chk->whoTo,
946a5d547adSRandall Stewart 					    chk->rec.data.TSN_seq);
94780fefe0aSRandall Stewart 				}
948c105859eSRandall Stewart 				sctp_flight_size_increase(chk);
949c105859eSRandall Stewart 				sctp_total_flight_increase(stcb, chk);
950f8829a4aSRandall Stewart 			}
951f8829a4aSRandall Stewart 		}
952f8829a4aSRandall Stewart 	}
953f8829a4aSRandall Stewart 	/*
954f8829a4aSRandall Stewart 	 * Setup the ecn nonce re-sync point. We do this since
955f8829a4aSRandall Stewart 	 * retranmissions are NOT setup for ECN. This means that do to
956f8829a4aSRandall Stewart 	 * Karn's rule, we don't know the total of the peers ecn bits.
957f8829a4aSRandall Stewart 	 */
958f8829a4aSRandall Stewart 	chk = TAILQ_FIRST(&stcb->asoc.send_queue);
959f8829a4aSRandall Stewart 	if (chk == NULL) {
960f8829a4aSRandall Stewart 		stcb->asoc.nonce_resync_tsn = stcb->asoc.sending_seq;
961f8829a4aSRandall Stewart 	} else {
962f8829a4aSRandall Stewart 		stcb->asoc.nonce_resync_tsn = chk->rec.data.TSN_seq;
963f8829a4aSRandall Stewart 	}
964f8829a4aSRandall Stewart 	stcb->asoc.nonce_wait_for_ecne = 0;
965f8829a4aSRandall Stewart 	stcb->asoc.nonce_sum_check = 0;
966f8829a4aSRandall Stewart 	/* We return 1 if we only have a window probe outstanding */
967f8829a4aSRandall Stewart 	return (0);
968f8829a4aSRandall Stewart }
969f8829a4aSRandall Stewart 
970f8829a4aSRandall Stewart 
971f8829a4aSRandall Stewart int
972f8829a4aSRandall Stewart sctp_t3rxt_timer(struct sctp_inpcb *inp,
973f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
974f8829a4aSRandall Stewart     struct sctp_nets *net)
975f8829a4aSRandall Stewart {
976f8829a4aSRandall Stewart 	struct sctp_nets *alt;
97744fbe462SRandall Stewart 	int win_probe, num_mk, num_abandoned;
978f8829a4aSRandall Stewart 
979b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) {
980562a89b5SRandall Stewart 		sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT);
98180fefe0aSRandall Stewart 	}
982b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
983f8829a4aSRandall Stewart 		struct sctp_nets *lnet;
984f8829a4aSRandall Stewart 
985f8829a4aSRandall Stewart 		TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
986f8829a4aSRandall Stewart 			if (net == lnet) {
987f8829a4aSRandall Stewart 				sctp_log_cwnd(stcb, lnet, 1, SCTP_CWND_LOG_FROM_T3);
988f8829a4aSRandall Stewart 			} else {
989f8829a4aSRandall Stewart 				sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_LOG_FROM_T3);
990f8829a4aSRandall Stewart 			}
991f8829a4aSRandall Stewart 		}
992f8829a4aSRandall Stewart 	}
993f8829a4aSRandall Stewart 	/* Find an alternate and mark those for retransmission */
994f8829a4aSRandall Stewart 	if ((stcb->asoc.peers_rwnd == 0) &&
995f8829a4aSRandall Stewart 	    (stcb->asoc.total_flight < net->mtu)) {
996f8829a4aSRandall Stewart 		SCTP_STAT_INCR(sctps_timowindowprobe);
997f8829a4aSRandall Stewart 		win_probe = 1;
998f8829a4aSRandall Stewart 	} else {
999f8829a4aSRandall Stewart 		win_probe = 0;
1000f8829a4aSRandall Stewart 	}
1001c105859eSRandall Stewart 
1002b54d3a6cSRandall Stewart 	/*
1003b54d3a6cSRandall Stewart 	 * JRS 5/14/07 - If CMT PF is on and the destination if not already
1004b54d3a6cSRandall Stewart 	 * in PF state, set the destination to PF state and store the
1005b54d3a6cSRandall Stewart 	 * current time as the time that the destination was last active. In
1006b54d3a6cSRandall Stewart 	 * addition, find an alternate destination with PF-based
1007b54d3a6cSRandall Stewart 	 * find_alt_net().
1008b54d3a6cSRandall Stewart 	 */
100920083c2eSMichael Tuexen 	if ((stcb->asoc.sctp_cmt_on_off == 1) &&
101020083c2eSMichael Tuexen 	    (stcb->asoc.sctp_cmt_pf > 0)) {
1011b54d3a6cSRandall Stewart 		if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) {
1012b54d3a6cSRandall Stewart 			net->dest_state |= SCTP_ADDR_PF;
101318e198d3SRandall Stewart 			net->last_active = sctp_get_tick_count();
1014b54d3a6cSRandall Stewart 			SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from active to PF.\n",
1015b54d3a6cSRandall Stewart 			    net);
1016b54d3a6cSRandall Stewart 		}
1017b54d3a6cSRandall Stewart 		alt = sctp_find_alternate_net(stcb, net, 2);
101820083c2eSMichael Tuexen 	} else if (stcb->asoc.sctp_cmt_on_off == 1) {
1019c105859eSRandall Stewart 		/*
1020c105859eSRandall Stewart 		 * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being
1021c105859eSRandall Stewart 		 * used, then pick dest with largest ssthresh for any
1022c105859eSRandall Stewart 		 * retransmission.
1023c105859eSRandall Stewart 		 */
1024c105859eSRandall Stewart 		alt = net;
1025c105859eSRandall Stewart 		alt = sctp_find_alternate_net(stcb, alt, 1);
1026c105859eSRandall Stewart 		/*
1027c105859eSRandall Stewart 		 * CUCv2: If a different dest is picked for the
1028c105859eSRandall Stewart 		 * retransmission, then new (rtx-)pseudo_cumack needs to be
1029c105859eSRandall Stewart 		 * tracked for orig dest. Let CUCv2 track new (rtx-)
1030c105859eSRandall Stewart 		 * pseudo-cumack always.
1031c105859eSRandall Stewart 		 */
1032c105859eSRandall Stewart 		net->find_pseudo_cumack = 1;
1033c105859eSRandall Stewart 		net->find_rtx_pseudo_cumack = 1;
1034c105859eSRandall Stewart 	} else {		/* CMT is OFF */
1035f8829a4aSRandall Stewart 		alt = sctp_find_alternate_net(stcb, net, 0);
1036c105859eSRandall Stewart 	}
103744fbe462SRandall Stewart 	num_mk = 0;
103844fbe462SRandall Stewart 	num_abandoned = 0;
103944fbe462SRandall Stewart 	(void)sctp_mark_all_for_resend(stcb, net, alt, win_probe,
104044fbe462SRandall Stewart 	    &num_mk, &num_abandoned);
1041f8829a4aSRandall Stewart 	/* FR Loss recovery just ended with the T3. */
1042f8829a4aSRandall Stewart 	stcb->asoc.fast_retran_loss_recovery = 0;
1043f8829a4aSRandall Stewart 
1044f8829a4aSRandall Stewart 	/* CMT FR loss recovery ended with the T3 */
1045f8829a4aSRandall Stewart 	net->fast_retran_loss_recovery = 0;
1046f8829a4aSRandall Stewart 
1047f8829a4aSRandall Stewart 	/*
1048f8829a4aSRandall Stewart 	 * setup the sat loss recovery that prevents satellite cwnd advance.
1049f8829a4aSRandall Stewart 	 */
1050f8829a4aSRandall Stewart 	stcb->asoc.sat_t3_loss_recovery = 1;
1051f8829a4aSRandall Stewart 	stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq;
1052f8829a4aSRandall Stewart 
1053f8829a4aSRandall Stewart 	/* Backoff the timer and cwnd */
105444fbe462SRandall Stewart 	sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned);
1055f8829a4aSRandall Stewart 	if (win_probe == 0) {
1056f8829a4aSRandall Stewart 		/* We don't do normal threshold management on window probes */
1057f8829a4aSRandall Stewart 		if (sctp_threshold_management(inp, stcb, net,
1058f8829a4aSRandall Stewart 		    stcb->asoc.max_send_times)) {
1059f8829a4aSRandall Stewart 			/* Association was destroyed */
1060f8829a4aSRandall Stewart 			return (1);
1061f8829a4aSRandall Stewart 		} else {
1062f8829a4aSRandall Stewart 			if (net != stcb->asoc.primary_destination) {
1063f8829a4aSRandall Stewart 				/* send a immediate HB if our RTO is stale */
1064f8829a4aSRandall Stewart 				struct timeval now;
1065f8829a4aSRandall Stewart 				unsigned int ms_goneby;
1066f8829a4aSRandall Stewart 
10676e55db54SRandall Stewart 				(void)SCTP_GETTIME_TIMEVAL(&now);
1068f8829a4aSRandall Stewart 				if (net->last_sent_time.tv_sec) {
1069f8829a4aSRandall Stewart 					ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
1070f8829a4aSRandall Stewart 				} else {
1071f8829a4aSRandall Stewart 					ms_goneby = 0;
1072f8829a4aSRandall Stewart 				}
1073f8829a4aSRandall Stewart 				if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
1074f8829a4aSRandall Stewart 					/*
1075f8829a4aSRandall Stewart 					 * no recent feed back in an RTO or
1076f8829a4aSRandall Stewart 					 * more, request a RTT update
1077f8829a4aSRandall Stewart 					 */
1078b54d3a6cSRandall Stewart 					if (sctp_send_hb(stcb, 1, net) < 0)
1079830d754dSRandall Stewart 						/*
1080830d754dSRandall Stewart 						 * Less than 0 means we lost
1081830d754dSRandall Stewart 						 * the assoc
1082830d754dSRandall Stewart 						 */
1083830d754dSRandall Stewart 						return (1);
1084f8829a4aSRandall Stewart 				}
1085f8829a4aSRandall Stewart 			}
1086f8829a4aSRandall Stewart 		}
1087f8829a4aSRandall Stewart 	} else {
1088f8829a4aSRandall Stewart 		/*
1089f8829a4aSRandall Stewart 		 * For a window probe we don't penalize the net's but only
1090f8829a4aSRandall Stewart 		 * the association. This may fail it if SACKs are not coming
1091f8829a4aSRandall Stewart 		 * back. If sack's are coming with rwnd locked at 0, we will
1092f8829a4aSRandall Stewart 		 * continue to hold things waiting for rwnd to raise
1093f8829a4aSRandall Stewart 		 */
1094f8829a4aSRandall Stewart 		if (sctp_threshold_management(inp, stcb, NULL,
1095f8829a4aSRandall Stewart 		    stcb->asoc.max_send_times)) {
1096f8829a4aSRandall Stewart 			/* Association was destroyed */
1097f8829a4aSRandall Stewart 			return (1);
1098f8829a4aSRandall Stewart 		}
1099f8829a4aSRandall Stewart 	}
1100f8829a4aSRandall Stewart 	if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
1101f8829a4aSRandall Stewart 		/* Move all pending over too */
11029eea4a2dSMichael Tuexen 		sctp_move_chunks_from_net(stcb, net);
110317205eccSRandall Stewart 
110417205eccSRandall Stewart 		/*
110517205eccSRandall Stewart 		 * Get the address that failed, to force a new src address
110617205eccSRandall Stewart 		 * selecton and a route allocation.
110717205eccSRandall Stewart 		 */
110817205eccSRandall Stewart 		if (net->ro._s_addr) {
110917205eccSRandall Stewart 			sctp_free_ifa(net->ro._s_addr);
111017205eccSRandall Stewart 			net->ro._s_addr = NULL;
111117205eccSRandall Stewart 		}
111217205eccSRandall Stewart 		net->src_addr_selected = 0;
111317205eccSRandall Stewart 
111417205eccSRandall Stewart 		/* Force a route allocation too */
111517205eccSRandall Stewart 		if (net->ro.ro_rt) {
111617205eccSRandall Stewart 			RTFREE(net->ro.ro_rt);
111717205eccSRandall Stewart 			net->ro.ro_rt = NULL;
111817205eccSRandall Stewart 		}
1119f8829a4aSRandall Stewart 		/* Was it our primary? */
1120f8829a4aSRandall Stewart 		if ((stcb->asoc.primary_destination == net) && (alt != net)) {
1121f8829a4aSRandall Stewart 			/*
1122f8829a4aSRandall Stewart 			 * Yes, note it as such and find an alternate note:
1123f8829a4aSRandall Stewart 			 * this means HB code must use this to resent the
1124f8829a4aSRandall Stewart 			 * primary if it goes active AND if someone does a
1125f8829a4aSRandall Stewart 			 * change-primary then this flag must be cleared
1126f8829a4aSRandall Stewart 			 * from any net structures.
1127f8829a4aSRandall Stewart 			 */
1128f8829a4aSRandall Stewart 			if (sctp_set_primary_addr(stcb,
1129f8829a4aSRandall Stewart 			    (struct sockaddr *)NULL,
1130f8829a4aSRandall Stewart 			    alt) == 0) {
1131f8829a4aSRandall Stewart 				net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
1132f8829a4aSRandall Stewart 			}
1133f8829a4aSRandall Stewart 		}
113420083c2eSMichael Tuexen 	} else if ((stcb->asoc.sctp_cmt_on_off == 1) &&
113520083c2eSMichael Tuexen 		    (stcb->asoc.sctp_cmt_pf > 0) &&
113620083c2eSMichael Tuexen 	    ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) {
1137b54d3a6cSRandall Stewart 		/*
1138b54d3a6cSRandall Stewart 		 * JRS 5/14/07 - If the destination hasn't failed completely
1139b54d3a6cSRandall Stewart 		 * but is in PF state, a PF-heartbeat needs to be sent
1140b54d3a6cSRandall Stewart 		 * manually.
1141b54d3a6cSRandall Stewart 		 */
1142b54d3a6cSRandall Stewart 		if (sctp_send_hb(stcb, 1, net) < 0)
1143830d754dSRandall Stewart 			/* Return less than 0 means we lost the association */
1144830d754dSRandall Stewart 			return (1);
1145f8829a4aSRandall Stewart 	}
1146f8829a4aSRandall Stewart 	/*
1147f8829a4aSRandall Stewart 	 * Special case for cookie-echo'ed case, we don't do output but must
1148f8829a4aSRandall Stewart 	 * await the COOKIE-ACK before retransmission
1149f8829a4aSRandall Stewart 	 */
1150f8829a4aSRandall Stewart 	if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
1151f8829a4aSRandall Stewart 		/*
1152f8829a4aSRandall Stewart 		 * Here we just reset the timer and start again since we
1153f8829a4aSRandall Stewart 		 * have not established the asoc
1154f8829a4aSRandall Stewart 		 */
1155f8829a4aSRandall Stewart 		sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
1156f8829a4aSRandall Stewart 		return (0);
1157f8829a4aSRandall Stewart 	}
1158f8829a4aSRandall Stewart 	if (stcb->asoc.peer_supports_prsctp) {
1159f8829a4aSRandall Stewart 		struct sctp_tmit_chunk *lchk;
1160f8829a4aSRandall Stewart 
1161f8829a4aSRandall Stewart 		lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc);
1162f8829a4aSRandall Stewart 		/* C3. See if we need to send a Fwd-TSN */
1163f8829a4aSRandall Stewart 		if (compare_with_wrap(stcb->asoc.advanced_peer_ack_point,
1164f8829a4aSRandall Stewart 		    stcb->asoc.last_acked_seq, MAX_TSN)) {
1165f8829a4aSRandall Stewart 			/*
1166f8829a4aSRandall Stewart 			 * ISSUE with ECN, see FWD-TSN processing for notes
1167f8829a4aSRandall Stewart 			 * on issues that will occur when the ECN NONCE
1168f8829a4aSRandall Stewart 			 * stuff is put into SCTP for cross checking.
1169f8829a4aSRandall Stewart 			 */
1170f8829a4aSRandall Stewart 			send_forward_tsn(stcb, &stcb->asoc);
1171f8829a4aSRandall Stewart 			if (lchk) {
1172f8829a4aSRandall Stewart 				/* Assure a timer is up */
1173f8829a4aSRandall Stewart 				sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo);
1174f8829a4aSRandall Stewart 			}
1175f8829a4aSRandall Stewart 		}
1176f8829a4aSRandall Stewart 	}
1177b3f1ea41SRandall Stewart 	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
1178f8829a4aSRandall Stewart 		sctp_log_cwnd(stcb, net, net->cwnd, SCTP_CWND_LOG_FROM_RTX);
117980fefe0aSRandall Stewart 	}
1180f8829a4aSRandall Stewart 	return (0);
1181f8829a4aSRandall Stewart }
1182f8829a4aSRandall Stewart 
1183f8829a4aSRandall Stewart int
1184f8829a4aSRandall Stewart sctp_t1init_timer(struct sctp_inpcb *inp,
1185f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
1186f8829a4aSRandall Stewart     struct sctp_nets *net)
1187f8829a4aSRandall Stewart {
1188f8829a4aSRandall Stewart 	/* bump the thresholds */
1189f8829a4aSRandall Stewart 	if (stcb->asoc.delayed_connection) {
1190f8829a4aSRandall Stewart 		/*
1191f8829a4aSRandall Stewart 		 * special hook for delayed connection. The library did NOT
1192f8829a4aSRandall Stewart 		 * complete the rest of its sends.
1193f8829a4aSRandall Stewart 		 */
1194f8829a4aSRandall Stewart 		stcb->asoc.delayed_connection = 0;
1195ceaad40aSRandall Stewart 		sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED);
1196f8829a4aSRandall Stewart 		return (0);
1197f8829a4aSRandall Stewart 	}
1198f8829a4aSRandall Stewart 	if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) {
1199f8829a4aSRandall Stewart 		return (0);
1200f8829a4aSRandall Stewart 	}
1201f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, net,
1202f8829a4aSRandall Stewart 	    stcb->asoc.max_init_times)) {
1203f8829a4aSRandall Stewart 		/* Association was destroyed */
1204f8829a4aSRandall Stewart 		return (1);
1205f8829a4aSRandall Stewart 	}
1206f8829a4aSRandall Stewart 	stcb->asoc.dropped_special_cnt = 0;
120744fbe462SRandall Stewart 	sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0, 0);
1208f8829a4aSRandall Stewart 	if (stcb->asoc.initial_init_rto_max < net->RTO) {
1209f8829a4aSRandall Stewart 		net->RTO = stcb->asoc.initial_init_rto_max;
1210f8829a4aSRandall Stewart 	}
1211f8829a4aSRandall Stewart 	if (stcb->asoc.numnets > 1) {
1212f8829a4aSRandall Stewart 		/* If we have more than one addr use it */
1213f8829a4aSRandall Stewart 		struct sctp_nets *alt;
1214f8829a4aSRandall Stewart 
1215f8829a4aSRandall Stewart 		alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0);
1216f8829a4aSRandall Stewart 		if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) {
12179eea4a2dSMichael Tuexen 			sctp_move_chunks_from_net(stcb, stcb->asoc.primary_destination);
1218f8829a4aSRandall Stewart 			stcb->asoc.primary_destination = alt;
1219f8829a4aSRandall Stewart 		}
1220f8829a4aSRandall Stewart 	}
1221f8829a4aSRandall Stewart 	/* Send out a new init */
1222ceaad40aSRandall Stewart 	sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED);
1223f8829a4aSRandall Stewart 	return (0);
1224f8829a4aSRandall Stewart }
1225f8829a4aSRandall Stewart 
1226f8829a4aSRandall Stewart /*
1227f8829a4aSRandall Stewart  * For cookie and asconf we actually need to find and mark for resend, then
1228f8829a4aSRandall Stewart  * increment the resend counter (after all the threshold management stuff of
1229f8829a4aSRandall Stewart  * course).
1230f8829a4aSRandall Stewart  */
1231f8829a4aSRandall Stewart int
1232f8829a4aSRandall Stewart sctp_cookie_timer(struct sctp_inpcb *inp,
1233f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
1234f8829a4aSRandall Stewart     struct sctp_nets *net)
1235f8829a4aSRandall Stewart {
1236f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1237f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *cookie;
1238f8829a4aSRandall Stewart 
1239f8829a4aSRandall Stewart 	/* first before all else we must find the cookie */
1240f8829a4aSRandall Stewart 	TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) {
1241f8829a4aSRandall Stewart 		if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) {
1242f8829a4aSRandall Stewart 			break;
1243f8829a4aSRandall Stewart 		}
1244f8829a4aSRandall Stewart 	}
1245f8829a4aSRandall Stewart 	if (cookie == NULL) {
1246f8829a4aSRandall Stewart 		if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
1247f8829a4aSRandall Stewart 			/* FOOBAR! */
1248f8829a4aSRandall Stewart 			struct mbuf *oper;
1249f8829a4aSRandall Stewart 
1250f8829a4aSRandall Stewart 			oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
1251f8829a4aSRandall Stewart 			    0, M_DONTWAIT, 1, MT_DATA);
1252f8829a4aSRandall Stewart 			if (oper) {
1253f8829a4aSRandall Stewart 				struct sctp_paramhdr *ph;
1254f8829a4aSRandall Stewart 				uint32_t *ippp;
1255f8829a4aSRandall Stewart 
1256139bc87fSRandall Stewart 				SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) +
1257f8829a4aSRandall Stewart 				    sizeof(uint32_t);
1258f8829a4aSRandall Stewart 				ph = mtod(oper, struct sctp_paramhdr *);
1259f8829a4aSRandall Stewart 				ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
1260139bc87fSRandall Stewart 				ph->param_length = htons(SCTP_BUF_LEN(oper));
1261f8829a4aSRandall Stewart 				ippp = (uint32_t *) (ph + 1);
1262b54d3a6cSRandall Stewart 				*ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
1263f8829a4aSRandall Stewart 			}
1264b54d3a6cSRandall Stewart 			inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_4;
1265f8829a4aSRandall Stewart 			sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR,
1266ceaad40aSRandall Stewart 			    oper, SCTP_SO_NOT_LOCKED);
1267f8829a4aSRandall Stewart 		} else {
1268a5d547adSRandall Stewart #ifdef INVARIANTS
1269f8829a4aSRandall Stewart 			panic("Cookie timer expires in wrong state?");
1270f8829a4aSRandall Stewart #else
1271ad81507eSRandall Stewart 			SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc));
1272f8829a4aSRandall Stewart 			return (0);
1273f8829a4aSRandall Stewart #endif
1274f8829a4aSRandall Stewart 		}
1275f8829a4aSRandall Stewart 		return (0);
1276f8829a4aSRandall Stewart 	}
1277f8829a4aSRandall Stewart 	/* Ok we found the cookie, threshold management next */
1278f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, cookie->whoTo,
1279f8829a4aSRandall Stewart 	    stcb->asoc.max_init_times)) {
1280f8829a4aSRandall Stewart 		/* Assoc is over */
1281f8829a4aSRandall Stewart 		return (1);
1282f8829a4aSRandall Stewart 	}
1283f8829a4aSRandall Stewart 	/*
1284f8829a4aSRandall Stewart 	 * cleared theshold management now lets backoff the address & select
1285f8829a4aSRandall Stewart 	 * an alternate
1286f8829a4aSRandall Stewart 	 */
1287f8829a4aSRandall Stewart 	stcb->asoc.dropped_special_cnt = 0;
128844fbe462SRandall Stewart 	sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0);
1289f8829a4aSRandall Stewart 	alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0);
1290f8829a4aSRandall Stewart 	if (alt != cookie->whoTo) {
1291f8829a4aSRandall Stewart 		sctp_free_remote_addr(cookie->whoTo);
1292f8829a4aSRandall Stewart 		cookie->whoTo = alt;
1293f8829a4aSRandall Stewart 		atomic_add_int(&alt->ref_count, 1);
1294f8829a4aSRandall Stewart 	}
1295f8829a4aSRandall Stewart 	/* Now mark the retran info */
1296f8829a4aSRandall Stewart 	if (cookie->sent != SCTP_DATAGRAM_RESEND) {
1297f8829a4aSRandall Stewart 		sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1298f8829a4aSRandall Stewart 	}
1299f8829a4aSRandall Stewart 	cookie->sent = SCTP_DATAGRAM_RESEND;
1300f8829a4aSRandall Stewart 	/*
1301f8829a4aSRandall Stewart 	 * Now call the output routine to kick out the cookie again, Note we
1302f8829a4aSRandall Stewart 	 * don't mark any chunks for retran so that FR will need to kick in
1303f8829a4aSRandall Stewart 	 * to move these (or a send timer).
1304f8829a4aSRandall Stewart 	 */
1305f8829a4aSRandall Stewart 	return (0);
1306f8829a4aSRandall Stewart }
1307f8829a4aSRandall Stewart 
1308f8829a4aSRandall Stewart int
1309f8829a4aSRandall Stewart sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1310f8829a4aSRandall Stewart     struct sctp_nets *net)
1311f8829a4aSRandall Stewart {
1312f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1313f8829a4aSRandall Stewart 	struct sctp_tmit_chunk *strrst = NULL, *chk = NULL;
1314f8829a4aSRandall Stewart 
1315f8829a4aSRandall Stewart 	if (stcb->asoc.stream_reset_outstanding == 0) {
1316f8829a4aSRandall Stewart 		return (0);
1317f8829a4aSRandall Stewart 	}
1318f8829a4aSRandall Stewart 	/* find the existing STRRESET, we use the seq number we sent out on */
1319ad81507eSRandall Stewart 	(void)sctp_find_stream_reset(stcb, stcb->asoc.str_reset_seq_out, &strrst);
1320f8829a4aSRandall Stewart 	if (strrst == NULL) {
1321f8829a4aSRandall Stewart 		return (0);
1322f8829a4aSRandall Stewart 	}
1323f8829a4aSRandall Stewart 	/* do threshold management */
1324f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, strrst->whoTo,
1325f8829a4aSRandall Stewart 	    stcb->asoc.max_send_times)) {
1326f8829a4aSRandall Stewart 		/* Assoc is over */
1327f8829a4aSRandall Stewart 		return (1);
1328f8829a4aSRandall Stewart 	}
1329f8829a4aSRandall Stewart 	/*
1330f8829a4aSRandall Stewart 	 * cleared theshold management now lets backoff the address & select
1331f8829a4aSRandall Stewart 	 * an alternate
1332f8829a4aSRandall Stewart 	 */
133344fbe462SRandall Stewart 	sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0, 0);
1334f8829a4aSRandall Stewart 	alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0);
1335f8829a4aSRandall Stewart 	sctp_free_remote_addr(strrst->whoTo);
1336f8829a4aSRandall Stewart 	strrst->whoTo = alt;
1337f8829a4aSRandall Stewart 	atomic_add_int(&alt->ref_count, 1);
1338f8829a4aSRandall Stewart 
1339f8829a4aSRandall Stewart 	/* See if a ECN Echo is also stranded */
1340f8829a4aSRandall Stewart 	TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
1341f8829a4aSRandall Stewart 		if ((chk->whoTo == net) &&
1342f8829a4aSRandall Stewart 		    (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) {
1343f8829a4aSRandall Stewart 			sctp_free_remote_addr(chk->whoTo);
1344f8829a4aSRandall Stewart 			if (chk->sent != SCTP_DATAGRAM_RESEND) {
1345f8829a4aSRandall Stewart 				chk->sent = SCTP_DATAGRAM_RESEND;
1346f8829a4aSRandall Stewart 				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1347f8829a4aSRandall Stewart 			}
1348f8829a4aSRandall Stewart 			chk->whoTo = alt;
1349f8829a4aSRandall Stewart 			atomic_add_int(&alt->ref_count, 1);
1350f8829a4aSRandall Stewart 		}
1351f8829a4aSRandall Stewart 	}
1352f8829a4aSRandall Stewart 	if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
1353f8829a4aSRandall Stewart 		/*
1354f8829a4aSRandall Stewart 		 * If the address went un-reachable, we need to move to
1355f8829a4aSRandall Stewart 		 * alternates for ALL chk's in queue
1356f8829a4aSRandall Stewart 		 */
13579eea4a2dSMichael Tuexen 		sctp_move_chunks_from_net(stcb, net);
1358f8829a4aSRandall Stewart 	}
1359f8829a4aSRandall Stewart 	/* mark the retran info */
1360f8829a4aSRandall Stewart 	if (strrst->sent != SCTP_DATAGRAM_RESEND)
1361f8829a4aSRandall Stewart 		sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1362f8829a4aSRandall Stewart 	strrst->sent = SCTP_DATAGRAM_RESEND;
1363f8829a4aSRandall Stewart 
1364f8829a4aSRandall Stewart 	/* restart the timer */
1365f8829a4aSRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo);
1366f8829a4aSRandall Stewart 	return (0);
1367f8829a4aSRandall Stewart }
1368f8829a4aSRandall Stewart 
1369f8829a4aSRandall Stewart int
1370f8829a4aSRandall Stewart sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1371f8829a4aSRandall Stewart     struct sctp_nets *net)
1372f8829a4aSRandall Stewart {
1373f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1374c54a18d2SRandall Stewart 	struct sctp_tmit_chunk *asconf, *chk, *nchk;
1375f8829a4aSRandall Stewart 
13761b649582SRandall Stewart 	/* is this a first send, or a retransmission? */
1377c54a18d2SRandall Stewart 	if (TAILQ_EMPTY(&stcb->asoc.asconf_send_queue)) {
1378f8829a4aSRandall Stewart 		/* compose a new ASCONF chunk and send it */
13793232788eSRandall Stewart 		sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
1380f8829a4aSRandall Stewart 	} else {
13811b649582SRandall Stewart 		/*
13821b649582SRandall Stewart 		 * Retransmission of the existing ASCONF is needed
13831b649582SRandall Stewart 		 */
1384f8829a4aSRandall Stewart 
1385f8829a4aSRandall Stewart 		/* find the existing ASCONF */
1386c54a18d2SRandall Stewart 		asconf = TAILQ_FIRST(&stcb->asoc.asconf_send_queue);
1387f8829a4aSRandall Stewart 		if (asconf == NULL) {
1388f8829a4aSRandall Stewart 			return (0);
1389f8829a4aSRandall Stewart 		}
1390f8829a4aSRandall Stewart 		/* do threshold management */
1391f8829a4aSRandall Stewart 		if (sctp_threshold_management(inp, stcb, asconf->whoTo,
1392f8829a4aSRandall Stewart 		    stcb->asoc.max_send_times)) {
1393f8829a4aSRandall Stewart 			/* Assoc is over */
1394f8829a4aSRandall Stewart 			return (1);
1395f8829a4aSRandall Stewart 		}
1396f8829a4aSRandall Stewart 		if (asconf->snd_count > stcb->asoc.max_send_times) {
1397f8829a4aSRandall Stewart 			/*
13981b649582SRandall Stewart 			 * Something is rotten: our peer is not responding
13991b649582SRandall Stewart 			 * to ASCONFs but apparently is to other chunks.
14001b649582SRandall Stewart 			 * i.e. it is not properly handling the chunk type
14011b649582SRandall Stewart 			 * upper bits. Mark this peer as ASCONF incapable
14021b649582SRandall Stewart 			 * and cleanup.
1403f8829a4aSRandall Stewart 			 */
1404ad81507eSRandall Stewart 			SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n");
1405f8829a4aSRandall Stewart 			sctp_asconf_cleanup(stcb, net);
1406f8829a4aSRandall Stewart 			return (0);
1407f8829a4aSRandall Stewart 		}
1408f8829a4aSRandall Stewart 		/*
14091b649582SRandall Stewart 		 * cleared threshold management, so now backoff the net and
14101b649582SRandall Stewart 		 * select an alternate
1411f8829a4aSRandall Stewart 		 */
141244fbe462SRandall Stewart 		sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0, 0);
1413f8829a4aSRandall Stewart 		alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0);
1414c54a18d2SRandall Stewart 		if (asconf->whoTo != alt) {
1415f8829a4aSRandall Stewart 			sctp_free_remote_addr(asconf->whoTo);
1416f8829a4aSRandall Stewart 			asconf->whoTo = alt;
1417f8829a4aSRandall Stewart 			atomic_add_int(&alt->ref_count, 1);
1418c54a18d2SRandall Stewart 		}
14191b649582SRandall Stewart 		/* See if an ECN Echo is also stranded */
1420f8829a4aSRandall Stewart 		TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
1421f8829a4aSRandall Stewart 			if ((chk->whoTo == net) &&
1422f8829a4aSRandall Stewart 			    (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) {
1423f8829a4aSRandall Stewart 				sctp_free_remote_addr(chk->whoTo);
1424f8829a4aSRandall Stewart 				chk->whoTo = alt;
1425f8829a4aSRandall Stewart 				if (chk->sent != SCTP_DATAGRAM_RESEND) {
1426f8829a4aSRandall Stewart 					chk->sent = SCTP_DATAGRAM_RESEND;
1427f8829a4aSRandall Stewart 					sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1428f8829a4aSRandall Stewart 				}
1429f8829a4aSRandall Stewart 				atomic_add_int(&alt->ref_count, 1);
1430f8829a4aSRandall Stewart 			}
1431f8829a4aSRandall Stewart 		}
1432c54a18d2SRandall Stewart 		for (chk = asconf; chk; chk = nchk) {
1433c54a18d2SRandall Stewart 			nchk = TAILQ_NEXT(chk, sctp_next);
1434c54a18d2SRandall Stewart 			if (chk->whoTo != alt) {
1435c54a18d2SRandall Stewart 				sctp_free_remote_addr(chk->whoTo);
1436c54a18d2SRandall Stewart 				chk->whoTo = alt;
1437c54a18d2SRandall Stewart 				atomic_add_int(&alt->ref_count, 1);
1438c54a18d2SRandall Stewart 			}
1439c54a18d2SRandall Stewart 			if (asconf->sent != SCTP_DATAGRAM_RESEND && chk->sent != SCTP_DATAGRAM_UNSENT)
1440c54a18d2SRandall Stewart 				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1441c54a18d2SRandall Stewart 			chk->sent = SCTP_DATAGRAM_RESEND;
1442c54a18d2SRandall Stewart 		}
1443f8829a4aSRandall Stewart 		if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
1444f8829a4aSRandall Stewart 			/*
1445f8829a4aSRandall Stewart 			 * If the address went un-reachable, we need to move
14461b649582SRandall Stewart 			 * to the alternate for ALL chunks in queue
1447f8829a4aSRandall Stewart 			 */
14489eea4a2dSMichael Tuexen 			sctp_move_chunks_from_net(stcb, net);
1449f8829a4aSRandall Stewart 		}
1450f8829a4aSRandall Stewart 		/* mark the retran info */
1451f8829a4aSRandall Stewart 		if (asconf->sent != SCTP_DATAGRAM_RESEND)
1452f8829a4aSRandall Stewart 			sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1453f8829a4aSRandall Stewart 		asconf->sent = SCTP_DATAGRAM_RESEND;
1454c54a18d2SRandall Stewart 
1455c54a18d2SRandall Stewart 		/* send another ASCONF if any and we can do */
1456c54a18d2SRandall Stewart 		sctp_send_asconf(stcb, alt, SCTP_ADDR_NOT_LOCKED);
1457f8829a4aSRandall Stewart 	}
1458f8829a4aSRandall Stewart 	return (0);
1459f8829a4aSRandall Stewart }
1460f8829a4aSRandall Stewart 
1461851b7298SRandall Stewart /* Mobility adaptation */
146204ee05e8SRandall Stewart void
1463851b7298SRandall Stewart sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1464851b7298SRandall Stewart     struct sctp_nets *net)
1465851b7298SRandall Stewart {
1466851b7298SRandall Stewart 	if (stcb->asoc.deleted_primary == NULL) {
1467851b7298SRandall Stewart 		SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n");
1468851b7298SRandall Stewart 		sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED);
146904ee05e8SRandall Stewart 		return;
1470851b7298SRandall Stewart 	}
1471851b7298SRandall Stewart 	SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: finished to keep deleted primary ");
1472851b7298SRandall Stewart 	SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa);
1473851b7298SRandall Stewart 	sctp_free_remote_addr(stcb->asoc.deleted_primary);
1474851b7298SRandall Stewart 	stcb->asoc.deleted_primary = NULL;
1475851b7298SRandall Stewart 	sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED);
147604ee05e8SRandall Stewart 	return;
1477851b7298SRandall Stewart }
1478851b7298SRandall Stewart 
1479f8829a4aSRandall Stewart /*
1480f8829a4aSRandall Stewart  * For the shutdown and shutdown-ack, we do not keep one around on the
1481f8829a4aSRandall Stewart  * control queue. This means we must generate a new one and call the general
1482f8829a4aSRandall Stewart  * chunk output routine, AFTER having done threshold management.
1483f8829a4aSRandall Stewart  */
1484f8829a4aSRandall Stewart int
1485f8829a4aSRandall Stewart sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1486f8829a4aSRandall Stewart     struct sctp_nets *net)
1487f8829a4aSRandall Stewart {
1488f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1489f8829a4aSRandall Stewart 
1490f8829a4aSRandall Stewart 	/* first threshold managment */
1491f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
1492f8829a4aSRandall Stewart 		/* Assoc is over */
1493f8829a4aSRandall Stewart 		return (1);
1494f8829a4aSRandall Stewart 	}
1495f8829a4aSRandall Stewart 	/* second select an alternative */
1496f8829a4aSRandall Stewart 	alt = sctp_find_alternate_net(stcb, net, 0);
1497f8829a4aSRandall Stewart 
1498f8829a4aSRandall Stewart 	/* third generate a shutdown into the queue for out net */
1499f8829a4aSRandall Stewart 	if (alt) {
1500f8829a4aSRandall Stewart 		sctp_send_shutdown(stcb, alt);
1501f8829a4aSRandall Stewart 	} else {
1502f8829a4aSRandall Stewart 		/*
1503f8829a4aSRandall Stewart 		 * if alt is NULL, there is no dest to send to??
1504f8829a4aSRandall Stewart 		 */
1505f8829a4aSRandall Stewart 		return (0);
1506f8829a4aSRandall Stewart 	}
1507f8829a4aSRandall Stewart 	/* fourth restart timer */
1508f8829a4aSRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt);
1509f8829a4aSRandall Stewart 	return (0);
1510f8829a4aSRandall Stewart }
1511f8829a4aSRandall Stewart 
1512f8829a4aSRandall Stewart int
1513f8829a4aSRandall Stewart sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1514f8829a4aSRandall Stewart     struct sctp_nets *net)
1515f8829a4aSRandall Stewart {
1516f8829a4aSRandall Stewart 	struct sctp_nets *alt;
1517f8829a4aSRandall Stewart 
1518f8829a4aSRandall Stewart 	/* first threshold managment */
1519f8829a4aSRandall Stewart 	if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
1520f8829a4aSRandall Stewart 		/* Assoc is over */
1521f8829a4aSRandall Stewart 		return (1);
1522f8829a4aSRandall Stewart 	}
1523f8829a4aSRandall Stewart 	/* second select an alternative */
1524f8829a4aSRandall Stewart 	alt = sctp_find_alternate_net(stcb, net, 0);
1525f8829a4aSRandall Stewart 
1526f8829a4aSRandall Stewart 	/* third generate a shutdown into the queue for out net */
1527f8829a4aSRandall Stewart 	sctp_send_shutdown_ack(stcb, alt);
1528f8829a4aSRandall Stewart 
1529f8829a4aSRandall Stewart 	/* fourth restart timer */
1530f8829a4aSRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt);
1531f8829a4aSRandall Stewart 	return (0);
1532f8829a4aSRandall Stewart }
1533f8829a4aSRandall Stewart 
1534f8829a4aSRandall Stewart static void
1535f8829a4aSRandall Stewart sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
1536f8829a4aSRandall Stewart     struct sctp_tcb *stcb)
1537f8829a4aSRandall Stewart {
1538f8829a4aSRandall Stewart 	struct sctp_stream_out *outs;
1539f8829a4aSRandall Stewart 	struct sctp_stream_queue_pending *sp;
1540f8829a4aSRandall Stewart 	unsigned int chks_in_queue = 0;
1541f8829a4aSRandall Stewart 	int being_filled = 0;
1542f8829a4aSRandall Stewart 
1543f8829a4aSRandall Stewart 	/*
1544f8829a4aSRandall Stewart 	 * This function is ONLY called when the send/sent queues are empty.
1545f8829a4aSRandall Stewart 	 */
1546f8829a4aSRandall Stewart 	if ((stcb == NULL) || (inp == NULL))
1547f8829a4aSRandall Stewart 		return;
1548f8829a4aSRandall Stewart 
1549f8829a4aSRandall Stewart 	if (stcb->asoc.sent_queue_retran_cnt) {
1550ad81507eSRandall Stewart 		SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n",
1551f8829a4aSRandall Stewart 		    stcb->asoc.sent_queue_retran_cnt);
1552f8829a4aSRandall Stewart 		stcb->asoc.sent_queue_retran_cnt = 0;
1553f8829a4aSRandall Stewart 	}
1554f8829a4aSRandall Stewart 	SCTP_TCB_SEND_LOCK(stcb);
1555f8829a4aSRandall Stewart 	if (TAILQ_EMPTY(&stcb->asoc.out_wheel)) {
1556f8829a4aSRandall Stewart 		int i, cnt = 0;
1557f8829a4aSRandall Stewart 
1558f8829a4aSRandall Stewart 		/* Check to see if a spoke fell off the wheel */
1559f8829a4aSRandall Stewart 		for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
1560f8829a4aSRandall Stewart 			if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
1561f8829a4aSRandall Stewart 				sctp_insert_on_wheel(stcb, &stcb->asoc, &stcb->asoc.strmout[i], 1);
1562f8829a4aSRandall Stewart 				cnt++;
1563f8829a4aSRandall Stewart 			}
1564f8829a4aSRandall Stewart 		}
1565f8829a4aSRandall Stewart 		if (cnt) {
1566f8829a4aSRandall Stewart 			/* yep, we lost a spoke or two */
1567ad81507eSRandall Stewart 			SCTP_PRINTF("Found an additional %d streams NOT on outwheel, corrected\n", cnt);
1568f8829a4aSRandall Stewart 		} else {
1569f8829a4aSRandall Stewart 			/* no spokes lost, */
1570f8829a4aSRandall Stewart 			stcb->asoc.total_output_queue_size = 0;
1571f8829a4aSRandall Stewart 		}
1572f8829a4aSRandall Stewart 		SCTP_TCB_SEND_UNLOCK(stcb);
1573f8829a4aSRandall Stewart 		return;
1574f8829a4aSRandall Stewart 	}
1575f8829a4aSRandall Stewart 	SCTP_TCB_SEND_UNLOCK(stcb);
1576f8829a4aSRandall Stewart 	/* Check to see if some data queued, if so report it */
1577f8829a4aSRandall Stewart 	TAILQ_FOREACH(outs, &stcb->asoc.out_wheel, next_spoke) {
1578f8829a4aSRandall Stewart 		if (!TAILQ_EMPTY(&outs->outqueue)) {
1579f8829a4aSRandall Stewart 			TAILQ_FOREACH(sp, &outs->outqueue, next) {
1580f8829a4aSRandall Stewart 				if (sp->msg_is_complete)
1581f8829a4aSRandall Stewart 					being_filled++;
1582f8829a4aSRandall Stewart 				chks_in_queue++;
1583f8829a4aSRandall Stewart 			}
1584f8829a4aSRandall Stewart 		}
1585f8829a4aSRandall Stewart 	}
1586f8829a4aSRandall Stewart 	if (chks_in_queue != stcb->asoc.stream_queue_cnt) {
1587ad81507eSRandall Stewart 		SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n",
1588f8829a4aSRandall Stewart 		    stcb->asoc.stream_queue_cnt, chks_in_queue);
1589f8829a4aSRandall Stewart 	}
1590f8829a4aSRandall Stewart 	if (chks_in_queue) {
1591f8829a4aSRandall Stewart 		/* call the output queue function */
1592ceaad40aSRandall Stewart 		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1593f8829a4aSRandall Stewart 		if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
1594f8829a4aSRandall Stewart 		    (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
1595f8829a4aSRandall Stewart 			/*
1596f8829a4aSRandall Stewart 			 * Probably should go in and make it go back through
1597f8829a4aSRandall Stewart 			 * and add fragments allowed
1598f8829a4aSRandall Stewart 			 */
1599f8829a4aSRandall Stewart 			if (being_filled == 0) {
1600ad81507eSRandall Stewart 				SCTP_PRINTF("Still nothing moved %d chunks are stuck\n",
1601f8829a4aSRandall Stewart 				    chks_in_queue);
1602f8829a4aSRandall Stewart 			}
1603f8829a4aSRandall Stewart 		}
1604f8829a4aSRandall Stewart 	} else {
1605ad81507eSRandall Stewart 		SCTP_PRINTF("Found no chunks on any queue tot:%lu\n",
1606f8829a4aSRandall Stewart 		    (u_long)stcb->asoc.total_output_queue_size);
1607f8829a4aSRandall Stewart 		stcb->asoc.total_output_queue_size = 0;
1608f8829a4aSRandall Stewart 	}
1609f8829a4aSRandall Stewart }
1610f8829a4aSRandall Stewart 
1611f8829a4aSRandall Stewart int
1612f8829a4aSRandall Stewart sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1613f8829a4aSRandall Stewart     struct sctp_nets *net, int cnt_of_unconf)
1614f8829a4aSRandall Stewart {
1615b54d3a6cSRandall Stewart 	int ret;
1616b54d3a6cSRandall Stewart 
1617f8829a4aSRandall Stewart 	if (net) {
1618f8829a4aSRandall Stewart 		if (net->hb_responded == 0) {
161942551e99SRandall Stewart 			if (net->ro._s_addr) {
162042551e99SRandall Stewart 				/*
162142551e99SRandall Stewart 				 * Invalidate the src address if we did not
162242551e99SRandall Stewart 				 * get a response last time.
162342551e99SRandall Stewart 				 */
162442551e99SRandall Stewart 				sctp_free_ifa(net->ro._s_addr);
162542551e99SRandall Stewart 				net->ro._s_addr = NULL;
162642551e99SRandall Stewart 				net->src_addr_selected = 0;
162742551e99SRandall Stewart 			}
162844fbe462SRandall Stewart 			sctp_backoff_on_timeout(stcb, net, 1, 0, 0);
1629f8829a4aSRandall Stewart 		}
1630f8829a4aSRandall Stewart 		/* Zero PBA, if it needs it */
1631f8829a4aSRandall Stewart 		if (net->partial_bytes_acked) {
1632f8829a4aSRandall Stewart 			net->partial_bytes_acked = 0;
1633f8829a4aSRandall Stewart 		}
1634f8829a4aSRandall Stewart 	}
1635f8829a4aSRandall Stewart 	if ((stcb->asoc.total_output_queue_size > 0) &&
1636f8829a4aSRandall Stewart 	    (TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
1637f8829a4aSRandall Stewart 	    (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
1638f8829a4aSRandall Stewart 		sctp_audit_stream_queues_for_size(inp, stcb);
1639f8829a4aSRandall Stewart 	}
1640f8829a4aSRandall Stewart 	/* Send a new HB, this will do threshold managment, pick a new dest */
1641f8829a4aSRandall Stewart 	if (cnt_of_unconf == 0) {
1642f8829a4aSRandall Stewart 		if (sctp_send_hb(stcb, 0, NULL) < 0) {
1643f8829a4aSRandall Stewart 			return (1);
1644f8829a4aSRandall Stewart 		}
1645f8829a4aSRandall Stewart 	} else {
1646f8829a4aSRandall Stewart 		/*
1647f8829a4aSRandall Stewart 		 * this will send out extra hb's up to maxburst if there are
1648f8829a4aSRandall Stewart 		 * any unconfirmed addresses.
1649f8829a4aSRandall Stewart 		 */
1650d61a0ae0SRandall Stewart 		uint32_t cnt_sent = 0;
1651f8829a4aSRandall Stewart 
1652f8829a4aSRandall Stewart 		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1653f8829a4aSRandall Stewart 			if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
1654f8829a4aSRandall Stewart 			    (net->dest_state & SCTP_ADDR_REACHABLE)) {
1655f8829a4aSRandall Stewart 				cnt_sent++;
165642551e99SRandall Stewart 				if (net->hb_responded == 0) {
165742551e99SRandall Stewart 					/* Did we respond last time? */
165842551e99SRandall Stewart 					if (net->ro._s_addr) {
165942551e99SRandall Stewart 						sctp_free_ifa(net->ro._s_addr);
166042551e99SRandall Stewart 						net->ro._s_addr = NULL;
166142551e99SRandall Stewart 						net->src_addr_selected = 0;
166242551e99SRandall Stewart 					}
166342551e99SRandall Stewart 				}
1664b54d3a6cSRandall Stewart 				ret = sctp_send_hb(stcb, 1, net);
1665b54d3a6cSRandall Stewart 				if (ret < 0)
1666b54d3a6cSRandall Stewart 					return 1;
1667b54d3a6cSRandall Stewart 				else if (ret == 0) {
1668f8829a4aSRandall Stewart 					break;
1669f8829a4aSRandall Stewart 				}
1670b3f1ea41SRandall Stewart 				if (cnt_sent >= SCTP_BASE_SYSCTL(sctp_hb_maxburst))
1671f8829a4aSRandall Stewart 					break;
1672f8829a4aSRandall Stewart 			}
1673f8829a4aSRandall Stewart 		}
1674f8829a4aSRandall Stewart 	}
1675f8829a4aSRandall Stewart 	return (0);
1676f8829a4aSRandall Stewart }
1677f8829a4aSRandall Stewart 
1678f8829a4aSRandall Stewart int
1679f8829a4aSRandall Stewart sctp_is_hb_timer_running(struct sctp_tcb *stcb)
1680f8829a4aSRandall Stewart {
1681139bc87fSRandall Stewart 	if (SCTP_OS_TIMER_PENDING(&stcb->asoc.hb_timer.timer)) {
1682f8829a4aSRandall Stewart 		/* its running */
1683f8829a4aSRandall Stewart 		return (1);
1684f8829a4aSRandall Stewart 	} else {
1685f8829a4aSRandall Stewart 		/* nope */
1686f8829a4aSRandall Stewart 		return (0);
1687f8829a4aSRandall Stewart 	}
1688f8829a4aSRandall Stewart }
1689f8829a4aSRandall Stewart 
1690f8829a4aSRandall Stewart int
1691f8829a4aSRandall Stewart sctp_is_sack_timer_running(struct sctp_tcb *stcb)
1692f8829a4aSRandall Stewart {
1693139bc87fSRandall Stewart 	if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
1694f8829a4aSRandall Stewart 		/* its running */
1695f8829a4aSRandall Stewart 		return (1);
1696f8829a4aSRandall Stewart 	} else {
1697f8829a4aSRandall Stewart 		/* nope */
1698f8829a4aSRandall Stewart 		return (0);
1699f8829a4aSRandall Stewart 	}
1700f8829a4aSRandall Stewart }
1701f8829a4aSRandall Stewart 
1702f8829a4aSRandall Stewart #define SCTP_NUMBER_OF_MTU_SIZES 18
1703f8829a4aSRandall Stewart static uint32_t mtu_sizes[] = {
1704f8829a4aSRandall Stewart 	68,
1705f8829a4aSRandall Stewart 	296,
1706f8829a4aSRandall Stewart 	508,
1707f8829a4aSRandall Stewart 	512,
1708f8829a4aSRandall Stewart 	544,
1709f8829a4aSRandall Stewart 	576,
1710f8829a4aSRandall Stewart 	1006,
1711f8829a4aSRandall Stewart 	1492,
1712f8829a4aSRandall Stewart 	1500,
1713f8829a4aSRandall Stewart 	1536,
1714f8829a4aSRandall Stewart 	2002,
1715f8829a4aSRandall Stewart 	2048,
1716f8829a4aSRandall Stewart 	4352,
1717f8829a4aSRandall Stewart 	4464,
1718f8829a4aSRandall Stewart 	8166,
1719f8829a4aSRandall Stewart 	17914,
1720f8829a4aSRandall Stewart 	32000,
1721f8829a4aSRandall Stewart 	65535
1722f8829a4aSRandall Stewart };
1723f8829a4aSRandall Stewart 
1724f8829a4aSRandall Stewart 
1725f8829a4aSRandall Stewart static uint32_t
1726f8829a4aSRandall Stewart sctp_getnext_mtu(struct sctp_inpcb *inp, uint32_t cur_mtu)
1727f8829a4aSRandall Stewart {
1728f8829a4aSRandall Stewart 	/* select another MTU that is just bigger than this one */
1729f8829a4aSRandall Stewart 	int i;
1730f8829a4aSRandall Stewart 
1731f8829a4aSRandall Stewart 	for (i = 0; i < SCTP_NUMBER_OF_MTU_SIZES; i++) {
1732f8829a4aSRandall Stewart 		if (cur_mtu < mtu_sizes[i]) {
1733f8829a4aSRandall Stewart 			/* no max_mtu is bigger than this one */
1734f8829a4aSRandall Stewart 			return (mtu_sizes[i]);
1735f8829a4aSRandall Stewart 		}
1736f8829a4aSRandall Stewart 	}
1737f8829a4aSRandall Stewart 	/* here return the highest allowable */
1738f8829a4aSRandall Stewart 	return (cur_mtu);
1739f8829a4aSRandall Stewart }
1740f8829a4aSRandall Stewart 
1741f8829a4aSRandall Stewart 
1742f8829a4aSRandall Stewart void
1743f8829a4aSRandall Stewart sctp_pathmtu_timer(struct sctp_inpcb *inp,
1744f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
1745f8829a4aSRandall Stewart     struct sctp_nets *net)
1746f8829a4aSRandall Stewart {
1747c54a18d2SRandall Stewart 	uint32_t next_mtu, mtu;
1748f8829a4aSRandall Stewart 
1749f8829a4aSRandall Stewart 	next_mtu = sctp_getnext_mtu(inp, net->mtu);
175017205eccSRandall Stewart 
1751c54a18d2SRandall Stewart 	if ((next_mtu > net->mtu) && (net->port == 0)) {
175217205eccSRandall Stewart 		if ((net->src_addr_selected == 0) ||
175317205eccSRandall Stewart 		    (net->ro._s_addr == NULL) ||
175417205eccSRandall Stewart 		    (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
1755ad81507eSRandall Stewart 			if ((net->ro._s_addr != NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
175617205eccSRandall Stewart 				sctp_free_ifa(net->ro._s_addr);
175717205eccSRandall Stewart 				net->ro._s_addr = NULL;
175817205eccSRandall Stewart 				net->src_addr_selected = 0;
1759ad81507eSRandall Stewart 			} else if (net->ro._s_addr == NULL) {
1760c54a18d2SRandall Stewart #if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE)
1761c54a18d2SRandall Stewart 				if (net->ro._l_addr.sa.sa_family == AF_INET6) {
1762c54a18d2SRandall Stewart 					struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1763c54a18d2SRandall Stewart 
1764c54a18d2SRandall Stewart 					/* KAME hack: embed scopeid */
1765482444b4SRandall Stewart 					(void)sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone));
1766c54a18d2SRandall Stewart 				}
1767c54a18d2SRandall Stewart #endif
1768c54a18d2SRandall Stewart 
176917205eccSRandall Stewart 				net->ro._s_addr = sctp_source_address_selection(inp,
177017205eccSRandall Stewart 				    stcb,
177117205eccSRandall Stewart 				    (sctp_route_t *) & net->ro,
177217205eccSRandall Stewart 				    net, 0, stcb->asoc.vrf_id);
1773c54a18d2SRandall Stewart #if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE)
1774c54a18d2SRandall Stewart 				if (net->ro._l_addr.sa.sa_family == AF_INET6) {
1775c54a18d2SRandall Stewart 					struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1776c54a18d2SRandall Stewart 
1777c54a18d2SRandall Stewart 					(void)sa6_recoverscope(sin6);
1778c54a18d2SRandall Stewart 				}
1779c54a18d2SRandall Stewart #endif				/* INET6 */
1780ad81507eSRandall Stewart 			}
178117205eccSRandall Stewart 			if (net->ro._s_addr)
178217205eccSRandall Stewart 				net->src_addr_selected = 1;
178317205eccSRandall Stewart 		}
178417205eccSRandall Stewart 		if (net->ro._s_addr) {
178517205eccSRandall Stewart 			mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt);
1786830d754dSRandall Stewart 			if (net->port) {
1787830d754dSRandall Stewart 				mtu -= sizeof(struct udphdr);
1788830d754dSRandall Stewart 			}
178917205eccSRandall Stewart 			if (mtu > next_mtu) {
1790f8829a4aSRandall Stewart 				net->mtu = next_mtu;
1791f8829a4aSRandall Stewart 			}
1792f8829a4aSRandall Stewart 		}
1793f8829a4aSRandall Stewart 	}
1794f8829a4aSRandall Stewart 	/* restart the timer */
1795f8829a4aSRandall Stewart 	sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
1796f8829a4aSRandall Stewart }
1797f8829a4aSRandall Stewart 
1798f8829a4aSRandall Stewart void
1799f8829a4aSRandall Stewart sctp_autoclose_timer(struct sctp_inpcb *inp,
1800f8829a4aSRandall Stewart     struct sctp_tcb *stcb,
1801f8829a4aSRandall Stewart     struct sctp_nets *net)
1802f8829a4aSRandall Stewart {
1803f8829a4aSRandall Stewart 	struct timeval tn, *tim_touse;
1804f8829a4aSRandall Stewart 	struct sctp_association *asoc;
1805f8829a4aSRandall Stewart 	int ticks_gone_by;
1806f8829a4aSRandall Stewart 
18076e55db54SRandall Stewart 	(void)SCTP_GETTIME_TIMEVAL(&tn);
1808f8829a4aSRandall Stewart 	if (stcb->asoc.sctp_autoclose_ticks &&
1809f8829a4aSRandall Stewart 	    sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) {
1810f8829a4aSRandall Stewart 		/* Auto close is on */
1811f8829a4aSRandall Stewart 		asoc = &stcb->asoc;
1812f8829a4aSRandall Stewart 		/* pick the time to use */
1813f8829a4aSRandall Stewart 		if (asoc->time_last_rcvd.tv_sec >
1814f8829a4aSRandall Stewart 		    asoc->time_last_sent.tv_sec) {
1815f8829a4aSRandall Stewart 			tim_touse = &asoc->time_last_rcvd;
1816f8829a4aSRandall Stewart 		} else {
1817f8829a4aSRandall Stewart 			tim_touse = &asoc->time_last_sent;
1818f8829a4aSRandall Stewart 		}
1819f8829a4aSRandall Stewart 		/* Now has long enough transpired to autoclose? */
1820f8829a4aSRandall Stewart 		ticks_gone_by = SEC_TO_TICKS(tn.tv_sec - tim_touse->tv_sec);
1821f8829a4aSRandall Stewart 		if ((ticks_gone_by > 0) &&
1822f8829a4aSRandall Stewart 		    (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) {
1823f8829a4aSRandall Stewart 			/*
1824f8829a4aSRandall Stewart 			 * autoclose time has hit, call the output routine,
1825f8829a4aSRandall Stewart 			 * which should do nothing just to be SURE we don't
1826f8829a4aSRandall Stewart 			 * have hanging data. We can then safely check the
1827f8829a4aSRandall Stewart 			 * queues and know that we are clear to send
1828f8829a4aSRandall Stewart 			 * shutdown
1829f8829a4aSRandall Stewart 			 */
1830ceaad40aSRandall Stewart 			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
1831f8829a4aSRandall Stewart 			/* Are we clean? */
1832f8829a4aSRandall Stewart 			if (TAILQ_EMPTY(&asoc->send_queue) &&
1833f8829a4aSRandall Stewart 			    TAILQ_EMPTY(&asoc->sent_queue)) {
1834f8829a4aSRandall Stewart 				/*
1835f8829a4aSRandall Stewart 				 * there is nothing queued to send, so I'm
1836f8829a4aSRandall Stewart 				 * done...
1837f8829a4aSRandall Stewart 				 */
1838f42a358aSRandall Stewart 				if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
1839f8829a4aSRandall Stewart 					/* only send SHUTDOWN 1st time thru */
1840f8829a4aSRandall Stewart 					sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
1841f42a358aSRandall Stewart 					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
1842f42a358aSRandall Stewart 					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1843f8829a4aSRandall Stewart 						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1844f42a358aSRandall Stewart 					}
1845c4739e2fSRandall Stewart 					SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
1846b201f536SRandall Stewart 					SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
1847f8829a4aSRandall Stewart 					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1848f8829a4aSRandall Stewart 					    stcb->sctp_ep, stcb,
1849f8829a4aSRandall Stewart 					    asoc->primary_destination);
1850f8829a4aSRandall Stewart 					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1851f8829a4aSRandall Stewart 					    stcb->sctp_ep, stcb,
1852f8829a4aSRandall Stewart 					    asoc->primary_destination);
1853f8829a4aSRandall Stewart 				}
1854f8829a4aSRandall Stewart 			}
1855f8829a4aSRandall Stewart 		} else {
1856f8829a4aSRandall Stewart 			/*
1857f8829a4aSRandall Stewart 			 * No auto close at this time, reset t-o to check
1858f8829a4aSRandall Stewart 			 * later
1859f8829a4aSRandall Stewart 			 */
1860f8829a4aSRandall Stewart 			int tmp;
1861f8829a4aSRandall Stewart 
1862f8829a4aSRandall Stewart 			/* fool the timer startup to use the time left */
1863f8829a4aSRandall Stewart 			tmp = asoc->sctp_autoclose_ticks;
1864f8829a4aSRandall Stewart 			asoc->sctp_autoclose_ticks -= ticks_gone_by;
1865f8829a4aSRandall Stewart 			sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb,
1866f8829a4aSRandall Stewart 			    net);
1867f8829a4aSRandall Stewart 			/* restore the real tick value */
1868f8829a4aSRandall Stewart 			asoc->sctp_autoclose_ticks = tmp;
1869f8829a4aSRandall Stewart 		}
1870f8829a4aSRandall Stewart 	}
1871f8829a4aSRandall Stewart }
1872