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