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