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