sctp_timer.c revision 1.3.14.2 1 1.3.14.2 jdolecek /* $KAME: sctp_timer.c,v 1.30 2005/06/16 18:29:25 jinmei Exp $ */
2 1.3.14.2 jdolecek /* $NetBSD: sctp_timer.c,v 1.3.14.2 2017/12/03 11:39:04 jdolecek Exp $ */
3 1.3.14.2 jdolecek
4 1.3.14.2 jdolecek /*
5 1.3.14.2 jdolecek * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
6 1.3.14.2 jdolecek * All rights reserved.
7 1.3.14.2 jdolecek *
8 1.3.14.2 jdolecek * Redistribution and use in source and binary forms, with or without
9 1.3.14.2 jdolecek * modification, are permitted provided that the following conditions
10 1.3.14.2 jdolecek * are met:
11 1.3.14.2 jdolecek * 1. Redistributions of source code must retain the above copyright
12 1.3.14.2 jdolecek * notice, this list of conditions and the following disclaimer.
13 1.3.14.2 jdolecek * 2. Redistributions in binary form must reproduce the above copyright
14 1.3.14.2 jdolecek * notice, this list of conditions and the following disclaimer in the
15 1.3.14.2 jdolecek * documentation and/or other materials provided with the distribution.
16 1.3.14.2 jdolecek * 3. Neither the name of the project nor the names of its contributors
17 1.3.14.2 jdolecek * may be used to endorse or promote products derived from this software
18 1.3.14.2 jdolecek * without specific prior written permission.
19 1.3.14.2 jdolecek *
20 1.3.14.2 jdolecek * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 1.3.14.2 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 1.3.14.2 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 1.3.14.2 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 1.3.14.2 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 1.3.14.2 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 1.3.14.2 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 1.3.14.2 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 1.3.14.2 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 1.3.14.2 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 1.3.14.2 jdolecek * SUCH DAMAGE.
31 1.3.14.2 jdolecek */
32 1.3.14.2 jdolecek #include <sys/cdefs.h>
33 1.3.14.2 jdolecek __KERNEL_RCSID(0, "$NetBSD: sctp_timer.c,v 1.3.14.2 2017/12/03 11:39:04 jdolecek Exp $");
34 1.3.14.2 jdolecek
35 1.3.14.2 jdolecek #ifdef _KERNEL_OPT
36 1.3.14.2 jdolecek #include "opt_inet.h"
37 1.3.14.2 jdolecek #include "opt_sctp.h"
38 1.3.14.2 jdolecek #endif /* _KERNEL_OPT */
39 1.3.14.2 jdolecek
40 1.3.14.2 jdolecek #include <sys/param.h>
41 1.3.14.2 jdolecek #include <sys/systm.h>
42 1.3.14.2 jdolecek #include <sys/malloc.h>
43 1.3.14.2 jdolecek #include <sys/mbuf.h>
44 1.3.14.2 jdolecek #include <sys/domain.h>
45 1.3.14.2 jdolecek #include <sys/protosw.h>
46 1.3.14.2 jdolecek #include <sys/socket.h>
47 1.3.14.2 jdolecek #include <sys/socketvar.h>
48 1.3.14.2 jdolecek #include <sys/proc.h>
49 1.3.14.2 jdolecek #include <sys/kernel.h>
50 1.3.14.2 jdolecek #include <sys/sysctl.h>
51 1.3.14.2 jdolecek #ifdef INET6
52 1.3.14.2 jdolecek #include <sys/domain.h>
53 1.3.14.2 jdolecek #endif
54 1.3.14.2 jdolecek
55 1.3.14.2 jdolecek #include <machine/limits.h>
56 1.3.14.2 jdolecek
57 1.3.14.2 jdolecek #include <net/if.h>
58 1.3.14.2 jdolecek #include <net/if_types.h>
59 1.3.14.2 jdolecek #include <net/route.h>
60 1.3.14.2 jdolecek #include <netinet/in.h>
61 1.3.14.2 jdolecek #include <netinet/in_systm.h>
62 1.3.14.2 jdolecek #define _IP_VHL
63 1.3.14.2 jdolecek #include <netinet/ip.h>
64 1.3.14.2 jdolecek #include <netinet/in_pcb.h>
65 1.3.14.2 jdolecek #include <netinet/in_var.h>
66 1.3.14.2 jdolecek #include <netinet/ip_var.h>
67 1.3.14.2 jdolecek
68 1.3.14.2 jdolecek #ifdef INET6
69 1.3.14.2 jdolecek #include <netinet/ip6.h>
70 1.3.14.2 jdolecek #include <netinet6/ip6_var.h>
71 1.3.14.2 jdolecek #endif /* INET6 */
72 1.3.14.2 jdolecek
73 1.3.14.2 jdolecek #include <netinet/sctp_pcb.h>
74 1.3.14.2 jdolecek
75 1.3.14.2 jdolecek #ifdef IPSEC
76 1.3.14.2 jdolecek #include <netipsec/ipsec.h>
77 1.3.14.2 jdolecek #include <netipsec/key.h>
78 1.3.14.2 jdolecek #endif /* IPSEC */
79 1.3.14.2 jdolecek #ifdef INET6
80 1.3.14.2 jdolecek #include <netinet6/sctp6_var.h>
81 1.3.14.2 jdolecek #endif
82 1.3.14.2 jdolecek #include <netinet/sctp_var.h>
83 1.3.14.2 jdolecek #include <netinet/sctp_timer.h>
84 1.3.14.2 jdolecek #include <netinet/sctputil.h>
85 1.3.14.2 jdolecek #include <netinet/sctp_output.h>
86 1.3.14.2 jdolecek #include <netinet/sctp_hashdriver.h>
87 1.3.14.2 jdolecek #include <netinet/sctp_header.h>
88 1.3.14.2 jdolecek #include <netinet/sctp_indata.h>
89 1.3.14.2 jdolecek #include <netinet/sctp_asconf.h>
90 1.3.14.2 jdolecek
91 1.3.14.2 jdolecek #include <netinet/sctp.h>
92 1.3.14.2 jdolecek #include <netinet/sctp_uio.h>
93 1.3.14.2 jdolecek
94 1.3.14.2 jdolecek #include <net/net_osdep.h>
95 1.3.14.2 jdolecek
96 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
97 1.3.14.2 jdolecek extern u_int32_t sctp_debug_on;
98 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
99 1.3.14.2 jdolecek
100 1.3.14.2 jdolecek void
101 1.3.14.2 jdolecek sctp_audit_retranmission_queue(struct sctp_association *asoc)
102 1.3.14.2 jdolecek {
103 1.3.14.2 jdolecek struct sctp_tmit_chunk *chk;
104 1.3.14.2 jdolecek
105 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
106 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
107 1.3.14.2 jdolecek printf("Audit invoked on send queue cnt:%d onqueue:%d\n",
108 1.3.14.2 jdolecek asoc->sent_queue_retran_cnt,
109 1.3.14.2 jdolecek asoc->sent_queue_cnt);
110 1.3.14.2 jdolecek }
111 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
112 1.3.14.2 jdolecek asoc->sent_queue_retran_cnt = 0;
113 1.3.14.2 jdolecek asoc->sent_queue_cnt = 0;
114 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
115 1.3.14.2 jdolecek if (chk->sent == SCTP_DATAGRAM_RESEND) {
116 1.3.14.2 jdolecek asoc->sent_queue_retran_cnt++;
117 1.3.14.2 jdolecek }
118 1.3.14.2 jdolecek asoc->sent_queue_cnt++;
119 1.3.14.2 jdolecek }
120 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
121 1.3.14.2 jdolecek if (chk->sent == SCTP_DATAGRAM_RESEND) {
122 1.3.14.2 jdolecek asoc->sent_queue_retran_cnt++;
123 1.3.14.2 jdolecek }
124 1.3.14.2 jdolecek }
125 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
126 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
127 1.3.14.2 jdolecek printf("Audit completes retran:%d onqueue:%d\n",
128 1.3.14.2 jdolecek asoc->sent_queue_retran_cnt,
129 1.3.14.2 jdolecek asoc->sent_queue_cnt);
130 1.3.14.2 jdolecek }
131 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
132 1.3.14.2 jdolecek }
133 1.3.14.2 jdolecek
134 1.3.14.2 jdolecek int
135 1.3.14.2 jdolecek sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
136 1.3.14.2 jdolecek struct sctp_nets *net, uint16_t threshold)
137 1.3.14.2 jdolecek {
138 1.3.14.2 jdolecek if (net) {
139 1.3.14.2 jdolecek net->error_count++;
140 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
141 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
142 1.3.14.2 jdolecek printf("Error count for %p now %d thresh:%d\n",
143 1.3.14.2 jdolecek net, net->error_count,
144 1.3.14.2 jdolecek net->failure_threshold);
145 1.3.14.2 jdolecek }
146 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
147 1.3.14.2 jdolecek if (net->error_count >= net->failure_threshold) {
148 1.3.14.2 jdolecek /* We had a threshold failure */
149 1.3.14.2 jdolecek if (net->dest_state & SCTP_ADDR_REACHABLE) {
150 1.3.14.2 jdolecek net->dest_state &= ~SCTP_ADDR_REACHABLE;
151 1.3.14.2 jdolecek net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
152 1.3.14.2 jdolecek if (net == stcb->asoc.primary_destination) {
153 1.3.14.2 jdolecek net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
154 1.3.14.2 jdolecek }
155 1.3.14.2 jdolecek sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
156 1.3.14.2 jdolecek stcb,
157 1.3.14.2 jdolecek SCTP_FAILED_THRESHOLD,
158 1.3.14.2 jdolecek (void *)net);
159 1.3.14.2 jdolecek }
160 1.3.14.2 jdolecek }
161 1.3.14.2 jdolecek /*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE
162 1.3.14.2 jdolecek *********ROUTING CODE
163 1.3.14.2 jdolecek */
164 1.3.14.2 jdolecek /*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE
165 1.3.14.2 jdolecek *********ROUTING CODE
166 1.3.14.2 jdolecek */
167 1.3.14.2 jdolecek }
168 1.3.14.2 jdolecek if (stcb == NULL)
169 1.3.14.2 jdolecek return (0);
170 1.3.14.2 jdolecek
171 1.3.14.2 jdolecek if (net) {
172 1.3.14.2 jdolecek if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) {
173 1.3.14.2 jdolecek stcb->asoc.overall_error_count++;
174 1.3.14.2 jdolecek }
175 1.3.14.2 jdolecek } else {
176 1.3.14.2 jdolecek stcb->asoc.overall_error_count++;
177 1.3.14.2 jdolecek }
178 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
179 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
180 1.3.14.2 jdolecek printf("Overall error count for %p now %d thresh:%u state:%x\n",
181 1.3.14.2 jdolecek &stcb->asoc,
182 1.3.14.2 jdolecek stcb->asoc.overall_error_count,
183 1.3.14.2 jdolecek (u_int)threshold,
184 1.3.14.2 jdolecek ((net == NULL) ? (u_int)0 : (u_int)net->dest_state));
185 1.3.14.2 jdolecek }
186 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
187 1.3.14.2 jdolecek /* We specifically do not do >= to give the assoc one more
188 1.3.14.2 jdolecek * change before we fail it.
189 1.3.14.2 jdolecek */
190 1.3.14.2 jdolecek if (stcb->asoc.overall_error_count > threshold) {
191 1.3.14.2 jdolecek /* Abort notification sends a ULP notify */
192 1.3.14.2 jdolecek struct mbuf *oper;
193 1.3.14.2 jdolecek MGET(oper, M_DONTWAIT, MT_DATA);
194 1.3.14.2 jdolecek if (oper) {
195 1.3.14.2 jdolecek struct sctp_paramhdr *ph;
196 1.3.14.2 jdolecek u_int32_t *ippp;
197 1.3.14.2 jdolecek
198 1.3.14.2 jdolecek oper->m_len = sizeof(struct sctp_paramhdr) +
199 1.3.14.2 jdolecek sizeof(*ippp);
200 1.3.14.2 jdolecek ph = mtod(oper, struct sctp_paramhdr *);
201 1.3.14.2 jdolecek ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
202 1.3.14.2 jdolecek ph->param_length = htons(oper->m_len);
203 1.3.14.2 jdolecek ippp = (u_int32_t *)(ph + 1);
204 1.3.14.2 jdolecek *ippp = htonl(0x40000001);
205 1.3.14.2 jdolecek }
206 1.3.14.2 jdolecek sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper);
207 1.3.14.2 jdolecek return (1);
208 1.3.14.2 jdolecek }
209 1.3.14.2 jdolecek return (0);
210 1.3.14.2 jdolecek }
211 1.3.14.2 jdolecek
212 1.3.14.2 jdolecek struct sctp_nets *
213 1.3.14.2 jdolecek sctp_find_alternate_net(struct sctp_tcb *stcb,
214 1.3.14.2 jdolecek struct sctp_nets *net)
215 1.3.14.2 jdolecek {
216 1.3.14.2 jdolecek /* Find and return an alternate network if possible */
217 1.3.14.2 jdolecek struct sctp_nets *alt, *mnet;
218 1.3.14.2 jdolecek struct rtentry *rt;
219 1.3.14.2 jdolecek int once;
220 1.3.14.2 jdolecek
221 1.3.14.2 jdolecek if (stcb->asoc.numnets == 1) {
222 1.3.14.2 jdolecek /* No others but net */
223 1.3.14.2 jdolecek return (TAILQ_FIRST(&stcb->asoc.nets));
224 1.3.14.2 jdolecek }
225 1.3.14.2 jdolecek mnet = net;
226 1.3.14.2 jdolecek once = 0;
227 1.3.14.2 jdolecek
228 1.3.14.2 jdolecek if (mnet == NULL) {
229 1.3.14.2 jdolecek mnet = TAILQ_FIRST(&stcb->asoc.nets);
230 1.3.14.2 jdolecek }
231 1.3.14.2 jdolecek do {
232 1.3.14.2 jdolecek alt = TAILQ_NEXT(mnet, sctp_next);
233 1.3.14.2 jdolecek if (alt == NULL) {
234 1.3.14.2 jdolecek once++;
235 1.3.14.2 jdolecek if (once > 1) {
236 1.3.14.2 jdolecek break;
237 1.3.14.2 jdolecek }
238 1.3.14.2 jdolecek alt = TAILQ_FIRST(&stcb->asoc.nets);
239 1.3.14.2 jdolecek }
240 1.3.14.2 jdolecek rt = rtcache_validate(&alt->ro);
241 1.3.14.2 jdolecek if (rt == NULL) {
242 1.3.14.2 jdolecek alt->src_addr_selected = 0;
243 1.3.14.2 jdolecek }
244 1.3.14.2 jdolecek if (
245 1.3.14.2 jdolecek ((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) &&
246 1.3.14.2 jdolecek (rt != NULL) &&
247 1.3.14.2 jdolecek (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))
248 1.3.14.2 jdolecek ) {
249 1.3.14.2 jdolecek /* Found a reachable address */
250 1.3.14.2 jdolecek rtcache_unref(rt, &alt->ro);
251 1.3.14.2 jdolecek break;
252 1.3.14.2 jdolecek }
253 1.3.14.2 jdolecek rtcache_unref(rt, &alt->ro);
254 1.3.14.2 jdolecek mnet = alt;
255 1.3.14.2 jdolecek } while (alt != NULL);
256 1.3.14.2 jdolecek
257 1.3.14.2 jdolecek if (alt == NULL) {
258 1.3.14.2 jdolecek /* Case where NO insv network exists (dormant state) */
259 1.3.14.2 jdolecek /* we rotate destinations */
260 1.3.14.2 jdolecek once = 0;
261 1.3.14.2 jdolecek mnet = net;
262 1.3.14.2 jdolecek do {
263 1.3.14.2 jdolecek alt = TAILQ_NEXT(mnet, sctp_next);
264 1.3.14.2 jdolecek if (alt == NULL) {
265 1.3.14.2 jdolecek once++;
266 1.3.14.2 jdolecek if (once > 1) {
267 1.3.14.2 jdolecek break;
268 1.3.14.2 jdolecek }
269 1.3.14.2 jdolecek alt = TAILQ_FIRST(&stcb->asoc.nets);
270 1.3.14.2 jdolecek }
271 1.3.14.2 jdolecek if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) &&
272 1.3.14.2 jdolecek (alt != net)) {
273 1.3.14.2 jdolecek /* Found an alternate address */
274 1.3.14.2 jdolecek break;
275 1.3.14.2 jdolecek }
276 1.3.14.2 jdolecek mnet = alt;
277 1.3.14.2 jdolecek } while (alt != NULL);
278 1.3.14.2 jdolecek }
279 1.3.14.2 jdolecek if (alt == NULL) {
280 1.3.14.2 jdolecek return (net);
281 1.3.14.2 jdolecek }
282 1.3.14.2 jdolecek return (alt);
283 1.3.14.2 jdolecek }
284 1.3.14.2 jdolecek
285 1.3.14.2 jdolecek static void
286 1.3.14.2 jdolecek sctp_backoff_on_timeout(struct sctp_tcb *stcb,
287 1.3.14.2 jdolecek struct sctp_nets *net,
288 1.3.14.2 jdolecek int win_probe,
289 1.3.14.2 jdolecek int num_marked)
290 1.3.14.2 jdolecek {
291 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
292 1.3.14.2 jdolecek int oldRTO;
293 1.3.14.2 jdolecek
294 1.3.14.2 jdolecek oldRTO = net->RTO;
295 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
296 1.3.14.2 jdolecek net->RTO <<= 1;
297 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
298 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
299 1.3.14.2 jdolecek printf("Timer doubles from %d ms -to-> %d ms\n",
300 1.3.14.2 jdolecek oldRTO, net->RTO);
301 1.3.14.2 jdolecek }
302 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
303 1.3.14.2 jdolecek
304 1.3.14.2 jdolecek if (net->RTO > stcb->asoc.maxrto) {
305 1.3.14.2 jdolecek net->RTO = stcb->asoc.maxrto;
306 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
307 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
308 1.3.14.2 jdolecek printf("Growth capped by maxrto %d\n",
309 1.3.14.2 jdolecek net->RTO);
310 1.3.14.2 jdolecek }
311 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
312 1.3.14.2 jdolecek }
313 1.3.14.2 jdolecek
314 1.3.14.2 jdolecek
315 1.3.14.2 jdolecek if ((win_probe == 0) && num_marked) {
316 1.3.14.2 jdolecek /* We don't apply penalty to window probe scenarios */
317 1.3.14.2 jdolecek #ifdef SCTP_CWND_LOGGING
318 1.3.14.2 jdolecek int old_cwnd=net->cwnd;
319 1.3.14.2 jdolecek #endif
320 1.3.14.2 jdolecek net->ssthresh = net->cwnd >> 1;
321 1.3.14.2 jdolecek if (net->ssthresh < (net->mtu << 1)) {
322 1.3.14.2 jdolecek net->ssthresh = (net->mtu << 1);
323 1.3.14.2 jdolecek }
324 1.3.14.2 jdolecek net->cwnd = net->mtu;
325 1.3.14.2 jdolecek /* floor of 1 mtu */
326 1.3.14.2 jdolecek if (net->cwnd < net->mtu)
327 1.3.14.2 jdolecek net->cwnd = net->mtu;
328 1.3.14.2 jdolecek #ifdef SCTP_CWND_LOGGING
329 1.3.14.2 jdolecek sctp_log_cwnd(net, net->cwnd-old_cwnd, SCTP_CWND_LOG_FROM_RTX);
330 1.3.14.2 jdolecek #endif
331 1.3.14.2 jdolecek
332 1.3.14.2 jdolecek net->partial_bytes_acked = 0;
333 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
334 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
335 1.3.14.2 jdolecek printf("collapse cwnd to 1MTU ssthresh to %d\n",
336 1.3.14.2 jdolecek net->ssthresh);
337 1.3.14.2 jdolecek }
338 1.3.14.2 jdolecek #endif
339 1.3.14.2 jdolecek
340 1.3.14.2 jdolecek }
341 1.3.14.2 jdolecek }
342 1.3.14.2 jdolecek
343 1.3.14.2 jdolecek
344 1.3.14.2 jdolecek static int
345 1.3.14.2 jdolecek sctp_mark_all_for_resend(struct sctp_tcb *stcb,
346 1.3.14.2 jdolecek struct sctp_nets *net,
347 1.3.14.2 jdolecek struct sctp_nets *alt,
348 1.3.14.2 jdolecek int *num_marked)
349 1.3.14.2 jdolecek {
350 1.3.14.2 jdolecek
351 1.3.14.2 jdolecek /*
352 1.3.14.2 jdolecek * Mark all chunks (well not all) that were sent to *net for retransmission.
353 1.3.14.2 jdolecek * Move them to alt for there destination as well... We only
354 1.3.14.2 jdolecek * mark chunks that have been outstanding long enough to have
355 1.3.14.2 jdolecek * received feed-back.
356 1.3.14.2 jdolecek */
357 1.3.14.2 jdolecek struct sctp_tmit_chunk *chk, *tp2;
358 1.3.14.2 jdolecek struct sctp_nets *lnets;
359 1.3.14.2 jdolecek struct timeval now, min_wait, tv;
360 1.3.14.2 jdolecek int cur_rto;
361 1.3.14.2 jdolecek int win_probes, non_win_probes, orig_rwnd, audit_tf, num_mk, fir;
362 1.3.14.2 jdolecek unsigned int cnt_mk;
363 1.3.14.2 jdolecek u_int32_t orig_flight;
364 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
365 1.3.14.2 jdolecek u_int32_t tsnfirst, tsnlast;
366 1.3.14.2 jdolecek #endif
367 1.3.14.2 jdolecek
368 1.3.14.2 jdolecek /* none in flight now */
369 1.3.14.2 jdolecek audit_tf = 0;
370 1.3.14.2 jdolecek fir=0;
371 1.3.14.2 jdolecek /* figure out how long a data chunk must be pending
372 1.3.14.2 jdolecek * before we can mark it ..
373 1.3.14.2 jdolecek */
374 1.3.14.2 jdolecek SCTP_GETTIME_TIMEVAL(&now);
375 1.3.14.2 jdolecek /* get cur rto in micro-seconds */
376 1.3.14.2 jdolecek cur_rto = (((net->lastsa >> 2) + net->lastsv) >> 1);
377 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
378 1.3.14.2 jdolecek sctp_log_fr(cur_rto, 0, 0, SCTP_FR_T3_MARK_TIME);
379 1.3.14.2 jdolecek #endif
380 1.3.14.2 jdolecek cur_rto *= 1000;
381 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
382 1.3.14.2 jdolecek sctp_log_fr(cur_rto, 0, 0, SCTP_FR_T3_MARK_TIME);
383 1.3.14.2 jdolecek #endif
384 1.3.14.2 jdolecek tv.tv_sec = cur_rto / 1000000;
385 1.3.14.2 jdolecek tv.tv_usec = cur_rto % 1000000;
386 1.3.14.2 jdolecek #ifndef __FreeBSD__
387 1.3.14.2 jdolecek timersub(&now, &tv, &min_wait);
388 1.3.14.2 jdolecek #else
389 1.3.14.2 jdolecek min_wait = now;
390 1.3.14.2 jdolecek timevalsub(&min_wait, &tv);
391 1.3.14.2 jdolecek #endif
392 1.3.14.2 jdolecek if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
393 1.3.14.2 jdolecek /*
394 1.3.14.2 jdolecek * if we hit here, we don't
395 1.3.14.2 jdolecek * have enough seconds on the clock to account
396 1.3.14.2 jdolecek * for the RTO. We just let the lower seconds
397 1.3.14.2 jdolecek * be the bounds and don't worry about it. This
398 1.3.14.2 jdolecek * may mean we will mark a lot more than we should.
399 1.3.14.2 jdolecek */
400 1.3.14.2 jdolecek min_wait.tv_sec = min_wait.tv_usec = 0;
401 1.3.14.2 jdolecek }
402 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
403 1.3.14.2 jdolecek sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME);
404 1.3.14.2 jdolecek sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME);
405 1.3.14.2 jdolecek #endif
406 1.3.14.2 jdolecek if (stcb->asoc.total_flight >= net->flight_size) {
407 1.3.14.2 jdolecek stcb->asoc.total_flight -= net->flight_size;
408 1.3.14.2 jdolecek } else {
409 1.3.14.2 jdolecek audit_tf = 1;
410 1.3.14.2 jdolecek stcb->asoc.total_flight = 0;
411 1.3.14.2 jdolecek }
412 1.3.14.2 jdolecek /* Our rwnd will be incorrect here since we are not adding
413 1.3.14.2 jdolecek * back the cnt * mbuf but we will fix that down below.
414 1.3.14.2 jdolecek */
415 1.3.14.2 jdolecek orig_rwnd = stcb->asoc.peers_rwnd;
416 1.3.14.2 jdolecek orig_flight = net->flight_size;
417 1.3.14.2 jdolecek stcb->asoc.peers_rwnd += net->flight_size;
418 1.3.14.2 jdolecek net->flight_size = 0;
419 1.3.14.2 jdolecek net->rto_pending = 0;
420 1.3.14.2 jdolecek net->fast_retran_ip= 0;
421 1.3.14.2 jdolecek win_probes = non_win_probes = 0;
422 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
423 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
424 1.3.14.2 jdolecek printf("Marking ALL un-acked for retransmission at t3-timeout\n");
425 1.3.14.2 jdolecek }
426 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
427 1.3.14.2 jdolecek /* Now on to each chunk */
428 1.3.14.2 jdolecek num_mk = cnt_mk = 0;
429 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
430 1.3.14.2 jdolecek tsnlast = tsnfirst = 0;
431 1.3.14.2 jdolecek #endif
432 1.3.14.2 jdolecek chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
433 1.3.14.2 jdolecek for (;chk != NULL; chk = tp2) {
434 1.3.14.2 jdolecek tp2 = TAILQ_NEXT(chk, sctp_next);
435 1.3.14.2 jdolecek if ((compare_with_wrap(stcb->asoc.last_acked_seq,
436 1.3.14.2 jdolecek chk->rec.data.TSN_seq,
437 1.3.14.2 jdolecek MAX_TSN)) ||
438 1.3.14.2 jdolecek (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) {
439 1.3.14.2 jdolecek /* Strange case our list got out of order? */
440 1.3.14.2 jdolecek printf("Our list is out of order?\n");
441 1.3.14.2 jdolecek TAILQ_REMOVE(&stcb->asoc.sent_queue, chk, sctp_next);
442 1.3.14.2 jdolecek if (chk->data) {
443 1.3.14.2 jdolecek sctp_release_pr_sctp_chunk(stcb, chk, 0xffff,
444 1.3.14.2 jdolecek &stcb->asoc.sent_queue);
445 1.3.14.2 jdolecek if (chk->flags & SCTP_PR_SCTP_BUFFER) {
446 1.3.14.2 jdolecek stcb->asoc.sent_queue_cnt_removeable--;
447 1.3.14.2 jdolecek }
448 1.3.14.2 jdolecek }
449 1.3.14.2 jdolecek stcb->asoc.sent_queue_cnt--;
450 1.3.14.2 jdolecek sctp_free_remote_addr(chk->whoTo);
451 1.3.14.2 jdolecek sctppcbinfo.ipi_count_chunk--;
452 1.3.14.2 jdolecek if ((int)sctppcbinfo.ipi_count_chunk < 0) {
453 1.3.14.2 jdolecek panic("Chunk count is going negative");
454 1.3.14.2 jdolecek }
455 1.3.14.2 jdolecek SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
456 1.3.14.2 jdolecek sctppcbinfo.ipi_gencnt_chunk++;
457 1.3.14.2 jdolecek continue;
458 1.3.14.2 jdolecek }
459 1.3.14.2 jdolecek if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) {
460 1.3.14.2 jdolecek /* found one to mark:
461 1.3.14.2 jdolecek * If it is less than DATAGRAM_ACKED it MUST
462 1.3.14.2 jdolecek * not be a skipped or marked TSN but instead
463 1.3.14.2 jdolecek * one that is either already set for retransmission OR
464 1.3.14.2 jdolecek * one that needs retransmission.
465 1.3.14.2 jdolecek */
466 1.3.14.2 jdolecek
467 1.3.14.2 jdolecek /* validate its been outstanding long enough */
468 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
469 1.3.14.2 jdolecek sctp_log_fr(chk->rec.data.TSN_seq,
470 1.3.14.2 jdolecek chk->sent_rcv_time.tv_sec,
471 1.3.14.2 jdolecek chk->sent_rcv_time.tv_usec,
472 1.3.14.2 jdolecek SCTP_FR_T3_MARK_TIME);
473 1.3.14.2 jdolecek #endif
474 1.3.14.2 jdolecek if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) {
475 1.3.14.2 jdolecek /* we have reached a chunk that was sent some
476 1.3.14.2 jdolecek * seconds past our min.. forget it we will
477 1.3.14.2 jdolecek * find no more to send.
478 1.3.14.2 jdolecek */
479 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
480 1.3.14.2 jdolecek sctp_log_fr(0,
481 1.3.14.2 jdolecek chk->sent_rcv_time.tv_sec,
482 1.3.14.2 jdolecek chk->sent_rcv_time.tv_usec,
483 1.3.14.2 jdolecek SCTP_FR_T3_STOPPED);
484 1.3.14.2 jdolecek #endif
485 1.3.14.2 jdolecek continue;
486 1.3.14.2 jdolecek } else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) {
487 1.3.14.2 jdolecek /* we must look at the micro seconds to know.
488 1.3.14.2 jdolecek */
489 1.3.14.2 jdolecek if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
490 1.3.14.2 jdolecek /* ok it was sent after our boundary time. */
491 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
492 1.3.14.2 jdolecek sctp_log_fr(0,
493 1.3.14.2 jdolecek chk->sent_rcv_time.tv_sec,
494 1.3.14.2 jdolecek chk->sent_rcv_time.tv_usec,
495 1.3.14.2 jdolecek SCTP_FR_T3_STOPPED);
496 1.3.14.2 jdolecek #endif
497 1.3.14.2 jdolecek continue;
498 1.3.14.2 jdolecek }
499 1.3.14.2 jdolecek }
500 1.3.14.2 jdolecek if (stcb->asoc.total_flight_count > 0) {
501 1.3.14.2 jdolecek stcb->asoc.total_flight_count--;
502 1.3.14.2 jdolecek }
503 1.3.14.2 jdolecek if ((chk->flags & (SCTP_PR_SCTP_ENABLED|SCTP_PR_SCTP_BUFFER)) == SCTP_PR_SCTP_ENABLED) {
504 1.3.14.2 jdolecek /* Is it expired? */
505 1.3.14.2 jdolecek if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) ||
506 1.3.14.2 jdolecek ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) &&
507 1.3.14.2 jdolecek (now.tv_usec > chk->rec.data.timetodrop.tv_usec))) {
508 1.3.14.2 jdolecek /* Yes so drop it */
509 1.3.14.2 jdolecek if (chk->data) {
510 1.3.14.2 jdolecek sctp_release_pr_sctp_chunk(stcb,
511 1.3.14.2 jdolecek chk,
512 1.3.14.2 jdolecek (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT),
513 1.3.14.2 jdolecek &stcb->asoc.sent_queue);
514 1.3.14.2 jdolecek }
515 1.3.14.2 jdolecek }
516 1.3.14.2 jdolecek continue;
517 1.3.14.2 jdolecek }
518 1.3.14.2 jdolecek if (chk->sent != SCTP_DATAGRAM_RESEND) {
519 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt++;
520 1.3.14.2 jdolecek num_mk++;
521 1.3.14.2 jdolecek if (fir == 0) {
522 1.3.14.2 jdolecek fir = 1;
523 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
524 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
525 1.3.14.2 jdolecek printf("First TSN marked was %x\n",
526 1.3.14.2 jdolecek chk->rec.data.TSN_seq);
527 1.3.14.2 jdolecek }
528 1.3.14.2 jdolecek #endif
529 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
530 1.3.14.2 jdolecek tsnfirst = chk->rec.data.TSN_seq;
531 1.3.14.2 jdolecek #endif
532 1.3.14.2 jdolecek }
533 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
534 1.3.14.2 jdolecek tsnlast = chk->rec.data.TSN_seq;
535 1.3.14.2 jdolecek sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
536 1.3.14.2 jdolecek 0, SCTP_FR_T3_MARKED);
537 1.3.14.2 jdolecek
538 1.3.14.2 jdolecek #endif
539 1.3.14.2 jdolecek }
540 1.3.14.2 jdolecek chk->sent = SCTP_DATAGRAM_RESEND;
541 1.3.14.2 jdolecek /* reset the TSN for striking and other FR stuff */
542 1.3.14.2 jdolecek chk->rec.data.doing_fast_retransmit = 0;
543 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
544 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER3) {
545 1.3.14.2 jdolecek printf("mark TSN:%x for retransmission\n", chk->rec.data.TSN_seq);
546 1.3.14.2 jdolecek }
547 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
548 1.3.14.2 jdolecek /* Clear any time so NO RTT is being done */
549 1.3.14.2 jdolecek chk->do_rtt = 0;
550 1.3.14.2 jdolecek /* Bump up the count */
551 1.3.14.2 jdolecek if (compare_with_wrap(chk->rec.data.TSN_seq,
552 1.3.14.2 jdolecek stcb->asoc.t3timeout_highest_marked,
553 1.3.14.2 jdolecek MAX_TSN)) {
554 1.3.14.2 jdolecek /* TSN_seq > than t3timeout so update */
555 1.3.14.2 jdolecek stcb->asoc.t3timeout_highest_marked = chk->rec.data.TSN_seq;
556 1.3.14.2 jdolecek }
557 1.3.14.2 jdolecek if (alt != net) {
558 1.3.14.2 jdolecek sctp_free_remote_addr(chk->whoTo);
559 1.3.14.2 jdolecek chk->whoTo = alt;
560 1.3.14.2 jdolecek alt->ref_count++;
561 1.3.14.2 jdolecek }
562 1.3.14.2 jdolecek if ((chk->rec.data.state_flags & SCTP_WINDOW_PROBE) !=
563 1.3.14.2 jdolecek SCTP_WINDOW_PROBE) {
564 1.3.14.2 jdolecek non_win_probes++;
565 1.3.14.2 jdolecek } else {
566 1.3.14.2 jdolecek chk->rec.data.state_flags &= ~SCTP_WINDOW_PROBE;
567 1.3.14.2 jdolecek win_probes++;
568 1.3.14.2 jdolecek }
569 1.3.14.2 jdolecek }
570 1.3.14.2 jdolecek if (chk->sent == SCTP_DATAGRAM_RESEND) {
571 1.3.14.2 jdolecek cnt_mk++;
572 1.3.14.2 jdolecek }
573 1.3.14.2 jdolecek }
574 1.3.14.2 jdolecek
575 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
576 1.3.14.2 jdolecek sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT);
577 1.3.14.2 jdolecek #endif
578 1.3.14.2 jdolecek /* compensate for the number we marked */
579 1.3.14.2 jdolecek stcb->asoc.peers_rwnd += (num_mk /* * sizeof(struct mbuf)*/);
580 1.3.14.2 jdolecek
581 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
582 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
583 1.3.14.2 jdolecek if (num_mk) {
584 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
585 1.3.14.2 jdolecek printf("LAST TSN marked was %x\n", tsnlast);
586 1.3.14.2 jdolecek #endif
587 1.3.14.2 jdolecek printf("Num marked for retransmission was %d peer-rwd:%ld\n",
588 1.3.14.2 jdolecek num_mk, (u_long)stcb->asoc.peers_rwnd);
589 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
590 1.3.14.2 jdolecek printf("LAST TSN marked was %x\n", tsnlast);
591 1.3.14.2 jdolecek #endif
592 1.3.14.2 jdolecek printf("Num marked for retransmission was %d peer-rwd:%d\n",
593 1.3.14.2 jdolecek num_mk,
594 1.3.14.2 jdolecek (int)stcb->asoc.peers_rwnd
595 1.3.14.2 jdolecek );
596 1.3.14.2 jdolecek }
597 1.3.14.2 jdolecek }
598 1.3.14.2 jdolecek #endif
599 1.3.14.2 jdolecek *num_marked = num_mk;
600 1.3.14.2 jdolecek if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) {
601 1.3.14.2 jdolecek printf("Local Audit says there are %d for retran asoc cnt:%d\n",
602 1.3.14.2 jdolecek cnt_mk, stcb->asoc.sent_queue_retran_cnt);
603 1.3.14.2 jdolecek #ifndef SCTP_AUDITING_ENABLED
604 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt = cnt_mk;
605 1.3.14.2 jdolecek #endif
606 1.3.14.2 jdolecek }
607 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
608 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER3) {
609 1.3.14.2 jdolecek printf("**************************\n");
610 1.3.14.2 jdolecek }
611 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
612 1.3.14.2 jdolecek
613 1.3.14.2 jdolecek /* Now check for a ECN Echo that may be stranded */
614 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
615 1.3.14.2 jdolecek if ((chk->whoTo == net) &&
616 1.3.14.2 jdolecek (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
617 1.3.14.2 jdolecek sctp_free_remote_addr(chk->whoTo);
618 1.3.14.2 jdolecek chk->whoTo = alt;
619 1.3.14.2 jdolecek if (chk->sent != SCTP_DATAGRAM_RESEND) {
620 1.3.14.2 jdolecek chk->sent = SCTP_DATAGRAM_RESEND;
621 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt++;
622 1.3.14.2 jdolecek }
623 1.3.14.2 jdolecek alt->ref_count++;
624 1.3.14.2 jdolecek }
625 1.3.14.2 jdolecek }
626 1.3.14.2 jdolecek if ((orig_rwnd == 0) && (stcb->asoc.total_flight == 0) &&
627 1.3.14.2 jdolecek (orig_flight <= net->mtu)) {
628 1.3.14.2 jdolecek /*
629 1.3.14.2 jdolecek * If the LAST packet sent was not acked and our rwnd is 0
630 1.3.14.2 jdolecek * then we are in a win-probe state.
631 1.3.14.2 jdolecek */
632 1.3.14.2 jdolecek win_probes = 1;
633 1.3.14.2 jdolecek non_win_probes = 0;
634 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
635 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
636 1.3.14.2 jdolecek printf("WIN_PROBE set via o_rwnd=0 tf=0 and all:%d fit in mtu:%d\n",
637 1.3.14.2 jdolecek orig_flight, net->mtu);
638 1.3.14.2 jdolecek }
639 1.3.14.2 jdolecek #endif
640 1.3.14.2 jdolecek }
641 1.3.14.2 jdolecek
642 1.3.14.2 jdolecek if (audit_tf) {
643 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
644 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
645 1.3.14.2 jdolecek printf("Audit total flight due to negative value net:%p\n",
646 1.3.14.2 jdolecek net);
647 1.3.14.2 jdolecek }
648 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
649 1.3.14.2 jdolecek stcb->asoc.total_flight = 0;
650 1.3.14.2 jdolecek stcb->asoc.total_flight_count = 0;
651 1.3.14.2 jdolecek /* Clear all networks flight size */
652 1.3.14.2 jdolecek TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) {
653 1.3.14.2 jdolecek lnets->flight_size = 0;
654 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
655 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
656 1.3.14.2 jdolecek printf("Net:%p c-f cwnd:%d ssthresh:%d\n",
657 1.3.14.2 jdolecek lnets, lnets->cwnd, lnets->ssthresh);
658 1.3.14.2 jdolecek }
659 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
660 1.3.14.2 jdolecek }
661 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
662 1.3.14.2 jdolecek if (chk->sent < SCTP_DATAGRAM_RESEND) {
663 1.3.14.2 jdolecek stcb->asoc.total_flight += chk->book_size;
664 1.3.14.2 jdolecek chk->whoTo->flight_size += chk->book_size;
665 1.3.14.2 jdolecek stcb->asoc.total_flight_count++;
666 1.3.14.2 jdolecek }
667 1.3.14.2 jdolecek }
668 1.3.14.2 jdolecek }
669 1.3.14.2 jdolecek /* Setup the ecn nonce re-sync point. We
670 1.3.14.2 jdolecek * do this since retranmissions are NOT
671 1.3.14.2 jdolecek * setup for ECN. This means that do to
672 1.3.14.2 jdolecek * Karn's rule, we don't know the total
673 1.3.14.2 jdolecek * of the peers ecn bits.
674 1.3.14.2 jdolecek */
675 1.3.14.2 jdolecek chk = TAILQ_FIRST(&stcb->asoc.send_queue);
676 1.3.14.2 jdolecek if (chk == NULL) {
677 1.3.14.2 jdolecek stcb->asoc.nonce_resync_tsn = stcb->asoc.sending_seq;
678 1.3.14.2 jdolecek } else {
679 1.3.14.2 jdolecek stcb->asoc.nonce_resync_tsn = chk->rec.data.TSN_seq;
680 1.3.14.2 jdolecek }
681 1.3.14.2 jdolecek stcb->asoc.nonce_wait_for_ecne = 0;
682 1.3.14.2 jdolecek stcb->asoc.nonce_sum_check = 0;
683 1.3.14.2 jdolecek /* We return 1 if we only have a window probe outstanding */
684 1.3.14.2 jdolecek if (win_probes && (non_win_probes == 0)) {
685 1.3.14.2 jdolecek return (1);
686 1.3.14.2 jdolecek }
687 1.3.14.2 jdolecek return (0);
688 1.3.14.2 jdolecek }
689 1.3.14.2 jdolecek
690 1.3.14.2 jdolecek static void
691 1.3.14.2 jdolecek sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb,
692 1.3.14.2 jdolecek struct sctp_nets *net,
693 1.3.14.2 jdolecek struct sctp_nets *alt)
694 1.3.14.2 jdolecek {
695 1.3.14.2 jdolecek struct sctp_association *asoc;
696 1.3.14.2 jdolecek struct sctp_stream_out *outs;
697 1.3.14.2 jdolecek struct sctp_tmit_chunk *chk;
698 1.3.14.2 jdolecek
699 1.3.14.2 jdolecek if (net == alt)
700 1.3.14.2 jdolecek /* nothing to do */
701 1.3.14.2 jdolecek return;
702 1.3.14.2 jdolecek
703 1.3.14.2 jdolecek asoc = &stcb->asoc;
704 1.3.14.2 jdolecek
705 1.3.14.2 jdolecek /*
706 1.3.14.2 jdolecek * now through all the streams checking for chunks sent to our
707 1.3.14.2 jdolecek * bad network.
708 1.3.14.2 jdolecek */
709 1.3.14.2 jdolecek TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
710 1.3.14.2 jdolecek /* now clean up any chunks here */
711 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &outs->outqueue, sctp_next) {
712 1.3.14.2 jdolecek if (chk->whoTo == net) {
713 1.3.14.2 jdolecek sctp_free_remote_addr(chk->whoTo);
714 1.3.14.2 jdolecek chk->whoTo = alt;
715 1.3.14.2 jdolecek alt->ref_count++;
716 1.3.14.2 jdolecek }
717 1.3.14.2 jdolecek }
718 1.3.14.2 jdolecek }
719 1.3.14.2 jdolecek /* Now check the pending queue */
720 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
721 1.3.14.2 jdolecek if (chk->whoTo == net) {
722 1.3.14.2 jdolecek sctp_free_remote_addr(chk->whoTo);
723 1.3.14.2 jdolecek chk->whoTo = alt;
724 1.3.14.2 jdolecek alt->ref_count++;
725 1.3.14.2 jdolecek }
726 1.3.14.2 jdolecek }
727 1.3.14.2 jdolecek
728 1.3.14.2 jdolecek }
729 1.3.14.2 jdolecek
730 1.3.14.2 jdolecek int
731 1.3.14.2 jdolecek sctp_t3rxt_timer(struct sctp_inpcb *inp,
732 1.3.14.2 jdolecek struct sctp_tcb *stcb,
733 1.3.14.2 jdolecek struct sctp_nets *net)
734 1.3.14.2 jdolecek {
735 1.3.14.2 jdolecek struct sctp_nets *alt;
736 1.3.14.2 jdolecek int win_probe, num_mk;
737 1.3.14.2 jdolecek
738 1.3.14.2 jdolecek
739 1.3.14.2 jdolecek #ifdef SCTP_FR_LOGGING
740 1.3.14.2 jdolecek sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT);
741 1.3.14.2 jdolecek #endif
742 1.3.14.2 jdolecek /* Find an alternate and mark those for retransmission */
743 1.3.14.2 jdolecek alt = sctp_find_alternate_net(stcb, net);
744 1.3.14.2 jdolecek win_probe = sctp_mark_all_for_resend(stcb, net, alt, &num_mk);
745 1.3.14.2 jdolecek
746 1.3.14.2 jdolecek /* FR Loss recovery just ended with the T3. */
747 1.3.14.2 jdolecek stcb->asoc.fast_retran_loss_recovery = 0;
748 1.3.14.2 jdolecek
749 1.3.14.2 jdolecek /* setup the sat loss recovery that prevents
750 1.3.14.2 jdolecek * satellite cwnd advance.
751 1.3.14.2 jdolecek */
752 1.3.14.2 jdolecek stcb->asoc.sat_t3_loss_recovery = 1;
753 1.3.14.2 jdolecek stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq;
754 1.3.14.2 jdolecek
755 1.3.14.2 jdolecek /* Backoff the timer and cwnd */
756 1.3.14.2 jdolecek sctp_backoff_on_timeout(stcb, net, win_probe, num_mk);
757 1.3.14.2 jdolecek if (win_probe == 0) {
758 1.3.14.2 jdolecek /* We don't do normal threshold management on window probes */
759 1.3.14.2 jdolecek if (sctp_threshold_management(inp, stcb, net,
760 1.3.14.2 jdolecek stcb->asoc.max_send_times)) {
761 1.3.14.2 jdolecek /* Association was destroyed */
762 1.3.14.2 jdolecek return (1);
763 1.3.14.2 jdolecek } else {
764 1.3.14.2 jdolecek if (net != stcb->asoc.primary_destination) {
765 1.3.14.2 jdolecek /* send a immediate HB if our RTO is stale */
766 1.3.14.2 jdolecek struct timeval now;
767 1.3.14.2 jdolecek unsigned int ms_goneby;
768 1.3.14.2 jdolecek SCTP_GETTIME_TIMEVAL(&now);
769 1.3.14.2 jdolecek if (net->last_sent_time.tv_sec) {
770 1.3.14.2 jdolecek ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
771 1.3.14.2 jdolecek } else {
772 1.3.14.2 jdolecek ms_goneby = 0;
773 1.3.14.2 jdolecek }
774 1.3.14.2 jdolecek if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
775 1.3.14.2 jdolecek /* no recent feed back in an RTO or more, request a RTT update */
776 1.3.14.2 jdolecek sctp_send_hb(stcb, 1, net);
777 1.3.14.2 jdolecek }
778 1.3.14.2 jdolecek }
779 1.3.14.2 jdolecek }
780 1.3.14.2 jdolecek } else {
781 1.3.14.2 jdolecek /*
782 1.3.14.2 jdolecek * For a window probe we don't penalize the net's but only
783 1.3.14.2 jdolecek * the association. This may fail it if SACKs are not coming
784 1.3.14.2 jdolecek * back. If sack's are coming with rwnd locked at 0, we will
785 1.3.14.2 jdolecek * continue to hold things waiting for rwnd to raise
786 1.3.14.2 jdolecek */
787 1.3.14.2 jdolecek if (sctp_threshold_management(inp, stcb, NULL,
788 1.3.14.2 jdolecek stcb->asoc.max_send_times)) {
789 1.3.14.2 jdolecek /* Association was destroyed */
790 1.3.14.2 jdolecek return (1);
791 1.3.14.2 jdolecek }
792 1.3.14.2 jdolecek }
793 1.3.14.2 jdolecek if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
794 1.3.14.2 jdolecek /* Move all pending over too */
795 1.3.14.2 jdolecek sctp_move_all_chunks_to_alt(stcb, net, alt);
796 1.3.14.2 jdolecek /* Was it our primary? */
797 1.3.14.2 jdolecek if ((stcb->asoc.primary_destination == net) && (alt != net)) {
798 1.3.14.2 jdolecek /*
799 1.3.14.2 jdolecek * Yes, note it as such and find an alternate
800 1.3.14.2 jdolecek * note: this means HB code must use this to resent
801 1.3.14.2 jdolecek * the primary if it goes active AND if someone does
802 1.3.14.2 jdolecek * a change-primary then this flag must be cleared
803 1.3.14.2 jdolecek * from any net structures.
804 1.3.14.2 jdolecek */
805 1.3.14.2 jdolecek if (sctp_set_primary_addr(stcb,
806 1.3.14.2 jdolecek (struct sockaddr *)NULL,
807 1.3.14.2 jdolecek alt) == 0) {
808 1.3.14.2 jdolecek net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
809 1.3.14.2 jdolecek net->src_addr_selected = 0;
810 1.3.14.2 jdolecek }
811 1.3.14.2 jdolecek }
812 1.3.14.2 jdolecek }
813 1.3.14.2 jdolecek /*
814 1.3.14.2 jdolecek * Special case for cookie-echo'ed case, we don't do output
815 1.3.14.2 jdolecek * but must await the COOKIE-ACK before retransmission
816 1.3.14.2 jdolecek */
817 1.3.14.2 jdolecek if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
818 1.3.14.2 jdolecek /*
819 1.3.14.2 jdolecek * Here we just reset the timer and start again since we
820 1.3.14.2 jdolecek * have not established the asoc
821 1.3.14.2 jdolecek */
822 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
823 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
824 1.3.14.2 jdolecek printf("Special cookie case return\n");
825 1.3.14.2 jdolecek }
826 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
827 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
828 1.3.14.2 jdolecek return (0);
829 1.3.14.2 jdolecek }
830 1.3.14.2 jdolecek if (stcb->asoc.peer_supports_prsctp) {
831 1.3.14.2 jdolecek struct sctp_tmit_chunk *lchk;
832 1.3.14.2 jdolecek lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc);
833 1.3.14.2 jdolecek /* C3. See if we need to send a Fwd-TSN */
834 1.3.14.2 jdolecek if (compare_with_wrap(stcb->asoc.advanced_peer_ack_point,
835 1.3.14.2 jdolecek stcb->asoc.last_acked_seq, MAX_TSN)) {
836 1.3.14.2 jdolecek /*
837 1.3.14.2 jdolecek * ISSUE with ECN, see FWD-TSN processing for notes
838 1.3.14.2 jdolecek * on issues that will occur when the ECN NONCE stuff
839 1.3.14.2 jdolecek * is put into SCTP for cross checking.
840 1.3.14.2 jdolecek */
841 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
842 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
843 1.3.14.2 jdolecek printf("Forward TSN time\n");
844 1.3.14.2 jdolecek }
845 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
846 1.3.14.2 jdolecek send_forward_tsn(stcb, &stcb->asoc);
847 1.3.14.2 jdolecek if (lchk) {
848 1.3.14.2 jdolecek /* Assure a timer is up */
849 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo);
850 1.3.14.2 jdolecek }
851 1.3.14.2 jdolecek }
852 1.3.14.2 jdolecek }
853 1.3.14.2 jdolecek return (0);
854 1.3.14.2 jdolecek }
855 1.3.14.2 jdolecek
856 1.3.14.2 jdolecek int
857 1.3.14.2 jdolecek sctp_t1init_timer(struct sctp_inpcb *inp,
858 1.3.14.2 jdolecek struct sctp_tcb *stcb,
859 1.3.14.2 jdolecek struct sctp_nets *net)
860 1.3.14.2 jdolecek {
861 1.3.14.2 jdolecek /* bump the thresholds */
862 1.3.14.2 jdolecek if (stcb->asoc.delayed_connection) {
863 1.3.14.2 jdolecek /* special hook for delayed connection. The
864 1.3.14.2 jdolecek * library did NOT complete the rest of its
865 1.3.14.2 jdolecek * sends.
866 1.3.14.2 jdolecek */
867 1.3.14.2 jdolecek stcb->asoc.delayed_connection = 0;
868 1.3.14.2 jdolecek sctp_send_initiate(inp, stcb);
869 1.3.14.2 jdolecek return (0);
870 1.3.14.2 jdolecek }
871 1.3.14.2 jdolecek if (sctp_threshold_management(inp, stcb, net,
872 1.3.14.2 jdolecek stcb->asoc.max_init_times)) {
873 1.3.14.2 jdolecek /* Association was destroyed */
874 1.3.14.2 jdolecek return (1);
875 1.3.14.2 jdolecek }
876 1.3.14.2 jdolecek stcb->asoc.dropped_special_cnt = 0;
877 1.3.14.2 jdolecek sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0);
878 1.3.14.2 jdolecek if (stcb->asoc.initial_init_rto_max < net->RTO) {
879 1.3.14.2 jdolecek net->RTO = stcb->asoc.initial_init_rto_max;
880 1.3.14.2 jdolecek }
881 1.3.14.2 jdolecek if (stcb->asoc.numnets > 1) {
882 1.3.14.2 jdolecek /* If we have more than one addr use it */
883 1.3.14.2 jdolecek struct sctp_nets *alt;
884 1.3.14.2 jdolecek alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination);
885 1.3.14.2 jdolecek if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) {
886 1.3.14.2 jdolecek sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt);
887 1.3.14.2 jdolecek stcb->asoc.primary_destination = alt;
888 1.3.14.2 jdolecek }
889 1.3.14.2 jdolecek }
890 1.3.14.2 jdolecek /* Send out a new init */
891 1.3.14.2 jdolecek sctp_send_initiate(inp, stcb);
892 1.3.14.2 jdolecek return (0);
893 1.3.14.2 jdolecek }
894 1.3.14.2 jdolecek
895 1.3.14.2 jdolecek /*
896 1.3.14.2 jdolecek * For cookie and asconf we actually need to find and mark for resend,
897 1.3.14.2 jdolecek * then increment the resend counter (after all the threshold management
898 1.3.14.2 jdolecek * stuff of course).
899 1.3.14.2 jdolecek */
900 1.3.14.2 jdolecek int sctp_cookie_timer(struct sctp_inpcb *inp,
901 1.3.14.2 jdolecek struct sctp_tcb *stcb,
902 1.3.14.2 jdolecek struct sctp_nets *net)
903 1.3.14.2 jdolecek {
904 1.3.14.2 jdolecek struct sctp_nets *alt;
905 1.3.14.2 jdolecek struct sctp_tmit_chunk *cookie;
906 1.3.14.2 jdolecek /* first before all else we must find the cookie */
907 1.3.14.2 jdolecek TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) {
908 1.3.14.2 jdolecek if (cookie->rec.chunk_id == SCTP_COOKIE_ECHO) {
909 1.3.14.2 jdolecek break;
910 1.3.14.2 jdolecek }
911 1.3.14.2 jdolecek }
912 1.3.14.2 jdolecek if (cookie == NULL) {
913 1.3.14.2 jdolecek if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
914 1.3.14.2 jdolecek /* FOOBAR! */
915 1.3.14.2 jdolecek struct mbuf *oper;
916 1.3.14.2 jdolecek MGET(oper, M_DONTWAIT, MT_DATA);
917 1.3.14.2 jdolecek if (oper) {
918 1.3.14.2 jdolecek struct sctp_paramhdr *ph;
919 1.3.14.2 jdolecek u_int32_t *ippp;
920 1.3.14.2 jdolecek
921 1.3.14.2 jdolecek oper->m_len = sizeof(struct sctp_paramhdr) +
922 1.3.14.2 jdolecek sizeof(*ippp);
923 1.3.14.2 jdolecek ph = mtod(oper, struct sctp_paramhdr *);
924 1.3.14.2 jdolecek ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
925 1.3.14.2 jdolecek ph->param_length = htons(oper->m_len);
926 1.3.14.2 jdolecek ippp = (u_int32_t *)(ph + 1);
927 1.3.14.2 jdolecek *ippp = htonl(0x40000002);
928 1.3.14.2 jdolecek }
929 1.3.14.2 jdolecek sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR,
930 1.3.14.2 jdolecek oper);
931 1.3.14.2 jdolecek }
932 1.3.14.2 jdolecek return (1);
933 1.3.14.2 jdolecek }
934 1.3.14.2 jdolecek /* Ok we found the cookie, threshold management next */
935 1.3.14.2 jdolecek if (sctp_threshold_management(inp, stcb, cookie->whoTo,
936 1.3.14.2 jdolecek stcb->asoc.max_init_times)) {
937 1.3.14.2 jdolecek /* Assoc is over */
938 1.3.14.2 jdolecek return (1);
939 1.3.14.2 jdolecek }
940 1.3.14.2 jdolecek /*
941 1.3.14.2 jdolecek * cleared theshold management now lets backoff the address &
942 1.3.14.2 jdolecek * select an alternate
943 1.3.14.2 jdolecek */
944 1.3.14.2 jdolecek stcb->asoc.dropped_special_cnt = 0;
945 1.3.14.2 jdolecek sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0);
946 1.3.14.2 jdolecek alt = sctp_find_alternate_net(stcb, cookie->whoTo);
947 1.3.14.2 jdolecek if (alt != cookie->whoTo) {
948 1.3.14.2 jdolecek sctp_free_remote_addr(cookie->whoTo);
949 1.3.14.2 jdolecek cookie->whoTo = alt;
950 1.3.14.2 jdolecek alt->ref_count++;
951 1.3.14.2 jdolecek }
952 1.3.14.2 jdolecek /* Now mark the retran info */
953 1.3.14.2 jdolecek if (cookie->sent != SCTP_DATAGRAM_RESEND) {
954 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt++;
955 1.3.14.2 jdolecek }
956 1.3.14.2 jdolecek cookie->sent = SCTP_DATAGRAM_RESEND;
957 1.3.14.2 jdolecek /*
958 1.3.14.2 jdolecek * Now call the output routine to kick out the cookie again, Note we
959 1.3.14.2 jdolecek * don't mark any chunks for retran so that FR will need to kick in
960 1.3.14.2 jdolecek * to move these (or a send timer).
961 1.3.14.2 jdolecek */
962 1.3.14.2 jdolecek return (0);
963 1.3.14.2 jdolecek }
964 1.3.14.2 jdolecek
965 1.3.14.2 jdolecek int sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
966 1.3.14.2 jdolecek struct sctp_nets *net)
967 1.3.14.2 jdolecek {
968 1.3.14.2 jdolecek struct sctp_nets *alt;
969 1.3.14.2 jdolecek struct sctp_tmit_chunk *strrst, *chk;
970 1.3.14.2 jdolecek struct sctp_stream_reset_req *strreq;
971 1.3.14.2 jdolecek /* find the existing STRRESET */
972 1.3.14.2 jdolecek TAILQ_FOREACH(strrst, &stcb->asoc.control_send_queue,
973 1.3.14.2 jdolecek sctp_next) {
974 1.3.14.2 jdolecek if (strrst->rec.chunk_id == SCTP_STREAM_RESET) {
975 1.3.14.2 jdolecek /* is it what we want */
976 1.3.14.2 jdolecek strreq = mtod(strrst->data, struct sctp_stream_reset_req *);
977 1.3.14.2 jdolecek if (strreq->sr_req.ph.param_type == ntohs(SCTP_STR_RESET_REQUEST)) {
978 1.3.14.2 jdolecek break;
979 1.3.14.2 jdolecek }
980 1.3.14.2 jdolecek }
981 1.3.14.2 jdolecek }
982 1.3.14.2 jdolecek if (strrst == NULL) {
983 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
984 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
985 1.3.14.2 jdolecek printf("Strange, strreset timer fires, but I can't find an str-reset?\n");
986 1.3.14.2 jdolecek }
987 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
988 1.3.14.2 jdolecek return (0);
989 1.3.14.2 jdolecek }
990 1.3.14.2 jdolecek /* do threshold management */
991 1.3.14.2 jdolecek if (sctp_threshold_management(inp, stcb, strrst->whoTo,
992 1.3.14.2 jdolecek stcb->asoc.max_send_times)) {
993 1.3.14.2 jdolecek /* Assoc is over */
994 1.3.14.2 jdolecek return (1);
995 1.3.14.2 jdolecek }
996 1.3.14.2 jdolecek
997 1.3.14.2 jdolecek /*
998 1.3.14.2 jdolecek * cleared theshold management
999 1.3.14.2 jdolecek * now lets backoff the address & select an alternate
1000 1.3.14.2 jdolecek */
1001 1.3.14.2 jdolecek sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0);
1002 1.3.14.2 jdolecek alt = sctp_find_alternate_net(stcb, strrst->whoTo);
1003 1.3.14.2 jdolecek sctp_free_remote_addr(strrst->whoTo);
1004 1.3.14.2 jdolecek strrst->whoTo = alt;
1005 1.3.14.2 jdolecek alt->ref_count++;
1006 1.3.14.2 jdolecek
1007 1.3.14.2 jdolecek /* See if a ECN Echo is also stranded */
1008 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
1009 1.3.14.2 jdolecek if ((chk->whoTo == net) &&
1010 1.3.14.2 jdolecek (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
1011 1.3.14.2 jdolecek sctp_free_remote_addr(chk->whoTo);
1012 1.3.14.2 jdolecek if (chk->sent != SCTP_DATAGRAM_RESEND) {
1013 1.3.14.2 jdolecek chk->sent = SCTP_DATAGRAM_RESEND;
1014 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt++;
1015 1.3.14.2 jdolecek }
1016 1.3.14.2 jdolecek chk->whoTo = alt;
1017 1.3.14.2 jdolecek alt->ref_count++;
1018 1.3.14.2 jdolecek }
1019 1.3.14.2 jdolecek }
1020 1.3.14.2 jdolecek if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
1021 1.3.14.2 jdolecek /*
1022 1.3.14.2 jdolecek * If the address went un-reachable, we need to move
1023 1.3.14.2 jdolecek * to alternates for ALL chk's in queue
1024 1.3.14.2 jdolecek */
1025 1.3.14.2 jdolecek sctp_move_all_chunks_to_alt(stcb, net, alt);
1026 1.3.14.2 jdolecek }
1027 1.3.14.2 jdolecek /* mark the retran info */
1028 1.3.14.2 jdolecek if (strrst->sent != SCTP_DATAGRAM_RESEND)
1029 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt++;
1030 1.3.14.2 jdolecek strrst->sent = SCTP_DATAGRAM_RESEND;
1031 1.3.14.2 jdolecek
1032 1.3.14.2 jdolecek /* restart the timer */
1033 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo);
1034 1.3.14.2 jdolecek return (0);
1035 1.3.14.2 jdolecek }
1036 1.3.14.2 jdolecek
1037 1.3.14.2 jdolecek int sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1038 1.3.14.2 jdolecek struct sctp_nets *net)
1039 1.3.14.2 jdolecek {
1040 1.3.14.2 jdolecek struct sctp_nets *alt;
1041 1.3.14.2 jdolecek struct sctp_tmit_chunk *asconf, *chk;
1042 1.3.14.2 jdolecek
1043 1.3.14.2 jdolecek /* is this the first send, or a retransmission? */
1044 1.3.14.2 jdolecek if (stcb->asoc.asconf_sent == 0) {
1045 1.3.14.2 jdolecek /* compose a new ASCONF chunk and send it */
1046 1.3.14.2 jdolecek sctp_send_asconf(stcb, net);
1047 1.3.14.2 jdolecek } else {
1048 1.3.14.2 jdolecek /* Retransmission of the existing ASCONF needed... */
1049 1.3.14.2 jdolecek
1050 1.3.14.2 jdolecek /* find the existing ASCONF */
1051 1.3.14.2 jdolecek TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue,
1052 1.3.14.2 jdolecek sctp_next) {
1053 1.3.14.2 jdolecek if (asconf->rec.chunk_id == SCTP_ASCONF) {
1054 1.3.14.2 jdolecek break;
1055 1.3.14.2 jdolecek }
1056 1.3.14.2 jdolecek }
1057 1.3.14.2 jdolecek if (asconf == NULL) {
1058 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
1059 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1060 1.3.14.2 jdolecek printf("Strange, asconf timer fires, but I can't find an asconf?\n");
1061 1.3.14.2 jdolecek }
1062 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
1063 1.3.14.2 jdolecek return (0);
1064 1.3.14.2 jdolecek }
1065 1.3.14.2 jdolecek /* do threshold management */
1066 1.3.14.2 jdolecek if (sctp_threshold_management(inp, stcb, asconf->whoTo,
1067 1.3.14.2 jdolecek stcb->asoc.max_send_times)) {
1068 1.3.14.2 jdolecek /* Assoc is over */
1069 1.3.14.2 jdolecek return (1);
1070 1.3.14.2 jdolecek }
1071 1.3.14.2 jdolecek
1072 1.3.14.2 jdolecek /* PETER? FIX? How will the following code ever run? If
1073 1.3.14.2 jdolecek * the max_send_times is hit, threshold managment will
1074 1.3.14.2 jdolecek * blow away the association?
1075 1.3.14.2 jdolecek */
1076 1.3.14.2 jdolecek if (asconf->snd_count > stcb->asoc.max_send_times) {
1077 1.3.14.2 jdolecek /*
1078 1.3.14.2 jdolecek * Something is rotten, peer is not responding to
1079 1.3.14.2 jdolecek * ASCONFs but maybe is to data etc. e.g. it is not
1080 1.3.14.2 jdolecek * properly handling the chunk type upper bits
1081 1.3.14.2 jdolecek * Mark this peer as ASCONF incapable and cleanup
1082 1.3.14.2 jdolecek */
1083 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
1084 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1085 1.3.14.2 jdolecek printf("asconf_timer: Peer has not responded to our repeated ASCONFs\n");
1086 1.3.14.2 jdolecek }
1087 1.3.14.2 jdolecek #endif /* SCTP_DEBUG */
1088 1.3.14.2 jdolecek sctp_asconf_cleanup(stcb, net);
1089 1.3.14.2 jdolecek return (0);
1090 1.3.14.2 jdolecek }
1091 1.3.14.2 jdolecek /*
1092 1.3.14.2 jdolecek * cleared theshold management
1093 1.3.14.2 jdolecek * now lets backoff the address & select an alternate
1094 1.3.14.2 jdolecek */
1095 1.3.14.2 jdolecek sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0);
1096 1.3.14.2 jdolecek alt = sctp_find_alternate_net(stcb, asconf->whoTo);
1097 1.3.14.2 jdolecek sctp_free_remote_addr(asconf->whoTo);
1098 1.3.14.2 jdolecek asconf->whoTo = alt;
1099 1.3.14.2 jdolecek alt->ref_count++;
1100 1.3.14.2 jdolecek
1101 1.3.14.2 jdolecek /* See if a ECN Echo is also stranded */
1102 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
1103 1.3.14.2 jdolecek if ((chk->whoTo == net) &&
1104 1.3.14.2 jdolecek (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
1105 1.3.14.2 jdolecek sctp_free_remote_addr(chk->whoTo);
1106 1.3.14.2 jdolecek chk->whoTo = alt;
1107 1.3.14.2 jdolecek if (chk->sent != SCTP_DATAGRAM_RESEND) {
1108 1.3.14.2 jdolecek chk->sent = SCTP_DATAGRAM_RESEND;
1109 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt++;
1110 1.3.14.2 jdolecek }
1111 1.3.14.2 jdolecek alt->ref_count++;
1112 1.3.14.2 jdolecek
1113 1.3.14.2 jdolecek }
1114 1.3.14.2 jdolecek }
1115 1.3.14.2 jdolecek if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
1116 1.3.14.2 jdolecek /*
1117 1.3.14.2 jdolecek * If the address went un-reachable, we need to move
1118 1.3.14.2 jdolecek * to alternates for ALL chk's in queue
1119 1.3.14.2 jdolecek */
1120 1.3.14.2 jdolecek sctp_move_all_chunks_to_alt(stcb, net, alt);
1121 1.3.14.2 jdolecek }
1122 1.3.14.2 jdolecek /* mark the retran info */
1123 1.3.14.2 jdolecek if (asconf->sent != SCTP_DATAGRAM_RESEND)
1124 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt++;
1125 1.3.14.2 jdolecek asconf->sent = SCTP_DATAGRAM_RESEND;
1126 1.3.14.2 jdolecek }
1127 1.3.14.2 jdolecek return (0);
1128 1.3.14.2 jdolecek }
1129 1.3.14.2 jdolecek
1130 1.3.14.2 jdolecek /*
1131 1.3.14.2 jdolecek * For the shutdown and shutdown-ack, we do not keep one around on the
1132 1.3.14.2 jdolecek * control queue. This means we must generate a new one and call the general
1133 1.3.14.2 jdolecek * chunk output routine, AFTER having done threshold
1134 1.3.14.2 jdolecek * management.
1135 1.3.14.2 jdolecek */
1136 1.3.14.2 jdolecek int
1137 1.3.14.2 jdolecek sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1138 1.3.14.2 jdolecek struct sctp_nets *net)
1139 1.3.14.2 jdolecek {
1140 1.3.14.2 jdolecek struct sctp_nets *alt;
1141 1.3.14.2 jdolecek /* first threshold managment */
1142 1.3.14.2 jdolecek if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
1143 1.3.14.2 jdolecek /* Assoc is over */
1144 1.3.14.2 jdolecek return (1);
1145 1.3.14.2 jdolecek }
1146 1.3.14.2 jdolecek /* second select an alternative */
1147 1.3.14.2 jdolecek alt = sctp_find_alternate_net(stcb, net);
1148 1.3.14.2 jdolecek
1149 1.3.14.2 jdolecek /* third generate a shutdown into the queue for out net */
1150 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
1151 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
1152 1.3.14.2 jdolecek printf("%s:%d sends a shutdown\n",
1153 1.3.14.2 jdolecek __FILE__,
1154 1.3.14.2 jdolecek __LINE__
1155 1.3.14.2 jdolecek );
1156 1.3.14.2 jdolecek }
1157 1.3.14.2 jdolecek #endif
1158 1.3.14.2 jdolecek if (alt) {
1159 1.3.14.2 jdolecek sctp_send_shutdown(stcb, alt);
1160 1.3.14.2 jdolecek } else {
1161 1.3.14.2 jdolecek /* if alt is NULL, there is no dest
1162 1.3.14.2 jdolecek * to send to??
1163 1.3.14.2 jdolecek */
1164 1.3.14.2 jdolecek return (0);
1165 1.3.14.2 jdolecek }
1166 1.3.14.2 jdolecek /* fourth restart timer */
1167 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt);
1168 1.3.14.2 jdolecek return (0);
1169 1.3.14.2 jdolecek }
1170 1.3.14.2 jdolecek
1171 1.3.14.2 jdolecek int sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1172 1.3.14.2 jdolecek struct sctp_nets *net)
1173 1.3.14.2 jdolecek {
1174 1.3.14.2 jdolecek struct sctp_nets *alt;
1175 1.3.14.2 jdolecek /* first threshold managment */
1176 1.3.14.2 jdolecek if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
1177 1.3.14.2 jdolecek /* Assoc is over */
1178 1.3.14.2 jdolecek return (1);
1179 1.3.14.2 jdolecek }
1180 1.3.14.2 jdolecek /* second select an alternative */
1181 1.3.14.2 jdolecek alt = sctp_find_alternate_net(stcb, net);
1182 1.3.14.2 jdolecek
1183 1.3.14.2 jdolecek /* third generate a shutdown into the queue for out net */
1184 1.3.14.2 jdolecek sctp_send_shutdown_ack(stcb, alt);
1185 1.3.14.2 jdolecek
1186 1.3.14.2 jdolecek /* fourth restart timer */
1187 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt);
1188 1.3.14.2 jdolecek return (0);
1189 1.3.14.2 jdolecek }
1190 1.3.14.2 jdolecek
1191 1.3.14.2 jdolecek static void
1192 1.3.14.2 jdolecek sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
1193 1.3.14.2 jdolecek struct sctp_tcb *stcb)
1194 1.3.14.2 jdolecek {
1195 1.3.14.2 jdolecek struct sctp_stream_out *outs;
1196 1.3.14.2 jdolecek struct sctp_tmit_chunk *chk;
1197 1.3.14.2 jdolecek unsigned int chks_in_queue=0;
1198 1.3.14.2 jdolecek
1199 1.3.14.2 jdolecek if ((stcb == NULL) || (inp == NULL))
1200 1.3.14.2 jdolecek return;
1201 1.3.14.2 jdolecek if (TAILQ_EMPTY(&stcb->asoc.out_wheel)) {
1202 1.3.14.2 jdolecek printf("Strange, out_wheel empty nothing on sent/send and tot=%lu?\n",
1203 1.3.14.2 jdolecek (u_long)stcb->asoc.total_output_queue_size);
1204 1.3.14.2 jdolecek stcb->asoc.total_output_queue_size = 0;
1205 1.3.14.2 jdolecek return;
1206 1.3.14.2 jdolecek }
1207 1.3.14.2 jdolecek if (stcb->asoc.sent_queue_retran_cnt) {
1208 1.3.14.2 jdolecek printf("Hmm, sent_queue_retran_cnt is non-zero %d\n",
1209 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt);
1210 1.3.14.2 jdolecek stcb->asoc.sent_queue_retran_cnt = 0;
1211 1.3.14.2 jdolecek }
1212 1.3.14.2 jdolecek /* Check to see if some data queued, if so report it */
1213 1.3.14.2 jdolecek TAILQ_FOREACH(outs, &stcb->asoc.out_wheel, next_spoke) {
1214 1.3.14.2 jdolecek if (!TAILQ_EMPTY(&outs->outqueue)) {
1215 1.3.14.2 jdolecek TAILQ_FOREACH(chk, &outs->outqueue, sctp_next) {
1216 1.3.14.2 jdolecek chks_in_queue++;
1217 1.3.14.2 jdolecek }
1218 1.3.14.2 jdolecek }
1219 1.3.14.2 jdolecek }
1220 1.3.14.2 jdolecek if (chks_in_queue != stcb->asoc.stream_queue_cnt) {
1221 1.3.14.2 jdolecek printf("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n",
1222 1.3.14.2 jdolecek stcb->asoc.stream_queue_cnt, chks_in_queue);
1223 1.3.14.2 jdolecek }
1224 1.3.14.2 jdolecek if (chks_in_queue) {
1225 1.3.14.2 jdolecek /* call the output queue function */
1226 1.3.14.2 jdolecek sctp_chunk_output(inp, stcb, 1);
1227 1.3.14.2 jdolecek if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
1228 1.3.14.2 jdolecek (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
1229 1.3.14.2 jdolecek /* Probably should go in and make it go back through and add fragments allowed */
1230 1.3.14.2 jdolecek printf("Still nothing moved %d chunks are stuck\n", chks_in_queue);
1231 1.3.14.2 jdolecek }
1232 1.3.14.2 jdolecek } else {
1233 1.3.14.2 jdolecek printf("Found no chunks on any queue tot:%lu\n",
1234 1.3.14.2 jdolecek (u_long)stcb->asoc.total_output_queue_size);
1235 1.3.14.2 jdolecek stcb->asoc.total_output_queue_size = 0;
1236 1.3.14.2 jdolecek }
1237 1.3.14.2 jdolecek }
1238 1.3.14.2 jdolecek
1239 1.3.14.2 jdolecek int
1240 1.3.14.2 jdolecek sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1241 1.3.14.2 jdolecek struct sctp_nets *net)
1242 1.3.14.2 jdolecek {
1243 1.3.14.2 jdolecek int cnt_of_unconf=0;
1244 1.3.14.2 jdolecek
1245 1.3.14.2 jdolecek if (net) {
1246 1.3.14.2 jdolecek if (net->hb_responded == 0) {
1247 1.3.14.2 jdolecek sctp_backoff_on_timeout(stcb, net, 1, 0);
1248 1.3.14.2 jdolecek }
1249 1.3.14.2 jdolecek /* Zero PBA, if it needs it */
1250 1.3.14.2 jdolecek if (net->partial_bytes_acked) {
1251 1.3.14.2 jdolecek net->partial_bytes_acked = 0;
1252 1.3.14.2 jdolecek }
1253 1.3.14.2 jdolecek }
1254 1.3.14.2 jdolecek TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1255 1.3.14.2 jdolecek if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
1256 1.3.14.2 jdolecek (net->dest_state & SCTP_ADDR_REACHABLE)) {
1257 1.3.14.2 jdolecek cnt_of_unconf++;
1258 1.3.14.2 jdolecek }
1259 1.3.14.2 jdolecek }
1260 1.3.14.2 jdolecek if ((stcb->asoc.total_output_queue_size > 0) &&
1261 1.3.14.2 jdolecek (TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
1262 1.3.14.2 jdolecek (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
1263 1.3.14.2 jdolecek sctp_audit_stream_queues_for_size(inp, stcb);
1264 1.3.14.2 jdolecek }
1265 1.3.14.2 jdolecek /* Send a new HB, this will do threshold managment, pick a new dest */
1266 1.3.14.2 jdolecek if (sctp_send_hb(stcb, 0, NULL) < 0) {
1267 1.3.14.2 jdolecek return (1);
1268 1.3.14.2 jdolecek }
1269 1.3.14.2 jdolecek if (cnt_of_unconf > 1) {
1270 1.3.14.2 jdolecek /*
1271 1.3.14.2 jdolecek * this will send out extra hb's up to maxburst if
1272 1.3.14.2 jdolecek * there are any unconfirmed addresses.
1273 1.3.14.2 jdolecek */
1274 1.3.14.2 jdolecek int cnt_sent = 1;
1275 1.3.14.2 jdolecek while ((cnt_sent < stcb->asoc.max_burst) && (cnt_of_unconf > 1)) {
1276 1.3.14.2 jdolecek if (sctp_send_hb(stcb, 0, NULL) == 0)
1277 1.3.14.2 jdolecek break;
1278 1.3.14.2 jdolecek cnt_of_unconf--;
1279 1.3.14.2 jdolecek cnt_sent++;
1280 1.3.14.2 jdolecek }
1281 1.3.14.2 jdolecek }
1282 1.3.14.2 jdolecek return (0);
1283 1.3.14.2 jdolecek }
1284 1.3.14.2 jdolecek
1285 1.3.14.2 jdolecek #define SCTP_NUMBER_OF_MTU_SIZES 18
1286 1.3.14.2 jdolecek static u_int32_t mtu_sizes[]={
1287 1.3.14.2 jdolecek 68,
1288 1.3.14.2 jdolecek 296,
1289 1.3.14.2 jdolecek 508,
1290 1.3.14.2 jdolecek 512,
1291 1.3.14.2 jdolecek 544,
1292 1.3.14.2 jdolecek 576,
1293 1.3.14.2 jdolecek 1006,
1294 1.3.14.2 jdolecek 1492,
1295 1.3.14.2 jdolecek 1500,
1296 1.3.14.2 jdolecek 1536,
1297 1.3.14.2 jdolecek 2002,
1298 1.3.14.2 jdolecek 2048,
1299 1.3.14.2 jdolecek 4352,
1300 1.3.14.2 jdolecek 4464,
1301 1.3.14.2 jdolecek 8166,
1302 1.3.14.2 jdolecek 17914,
1303 1.3.14.2 jdolecek 32000,
1304 1.3.14.2 jdolecek 65535
1305 1.3.14.2 jdolecek };
1306 1.3.14.2 jdolecek
1307 1.3.14.2 jdolecek
1308 1.3.14.2 jdolecek static u_int32_t
1309 1.3.14.2 jdolecek sctp_getnext_mtu(struct sctp_inpcb *inp, u_int32_t cur_mtu)
1310 1.3.14.2 jdolecek {
1311 1.3.14.2 jdolecek /* select another MTU that is just bigger than this one */
1312 1.3.14.2 jdolecek int i;
1313 1.3.14.2 jdolecek
1314 1.3.14.2 jdolecek for (i = 0; i < SCTP_NUMBER_OF_MTU_SIZES; i++) {
1315 1.3.14.2 jdolecek if (cur_mtu < mtu_sizes[i]) {
1316 1.3.14.2 jdolecek /* no max_mtu is bigger than this one */
1317 1.3.14.2 jdolecek return (mtu_sizes[i]);
1318 1.3.14.2 jdolecek }
1319 1.3.14.2 jdolecek }
1320 1.3.14.2 jdolecek /* here return the highest allowable */
1321 1.3.14.2 jdolecek return (cur_mtu);
1322 1.3.14.2 jdolecek }
1323 1.3.14.2 jdolecek
1324 1.3.14.2 jdolecek
1325 1.3.14.2 jdolecek void sctp_pathmtu_timer(struct sctp_inpcb *inp,
1326 1.3.14.2 jdolecek struct sctp_tcb *stcb,
1327 1.3.14.2 jdolecek struct sctp_nets *net)
1328 1.3.14.2 jdolecek {
1329 1.3.14.2 jdolecek u_int32_t next_mtu;
1330 1.3.14.2 jdolecek struct rtentry *rt;
1331 1.3.14.2 jdolecek
1332 1.3.14.2 jdolecek /* restart the timer in any case */
1333 1.3.14.2 jdolecek next_mtu = sctp_getnext_mtu(inp, net->mtu);
1334 1.3.14.2 jdolecek if (next_mtu <= net->mtu) {
1335 1.3.14.2 jdolecek /* nothing to do */
1336 1.3.14.2 jdolecek return;
1337 1.3.14.2 jdolecek }
1338 1.3.14.2 jdolecek rt = rtcache_validate(&net->ro);
1339 1.3.14.2 jdolecek if (rt != NULL) {
1340 1.3.14.2 jdolecek /* only if we have a route and interface do we
1341 1.3.14.2 jdolecek * set anything. Note we always restart
1342 1.3.14.2 jdolecek * the timer though just in case it is updated
1343 1.3.14.2 jdolecek * (i.e. the ifp) or route/ifp is populated.
1344 1.3.14.2 jdolecek */
1345 1.3.14.2 jdolecek if (rt->rt_ifp != NULL) {
1346 1.3.14.2 jdolecek if (rt->rt_ifp->if_mtu > next_mtu) {
1347 1.3.14.2 jdolecek /* ok it will fit out the door */
1348 1.3.14.2 jdolecek net->mtu = next_mtu;
1349 1.3.14.2 jdolecek }
1350 1.3.14.2 jdolecek }
1351 1.3.14.2 jdolecek rtcache_unref(rt, &net->ro);
1352 1.3.14.2 jdolecek }
1353 1.3.14.2 jdolecek /* restart the timer */
1354 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
1355 1.3.14.2 jdolecek }
1356 1.3.14.2 jdolecek
1357 1.3.14.2 jdolecek void sctp_autoclose_timer(struct sctp_inpcb *inp,
1358 1.3.14.2 jdolecek struct sctp_tcb *stcb,
1359 1.3.14.2 jdolecek struct sctp_nets *net)
1360 1.3.14.2 jdolecek {
1361 1.3.14.2 jdolecek struct timeval tn, *tim_touse;
1362 1.3.14.2 jdolecek struct sctp_association *asoc;
1363 1.3.14.2 jdolecek int ticks_gone_by;
1364 1.3.14.2 jdolecek
1365 1.3.14.2 jdolecek SCTP_GETTIME_TIMEVAL(&tn);
1366 1.3.14.2 jdolecek if (stcb->asoc.sctp_autoclose_ticks &&
1367 1.3.14.2 jdolecek (inp->sctp_flags & SCTP_PCB_FLAGS_AUTOCLOSE)) {
1368 1.3.14.2 jdolecek /* Auto close is on */
1369 1.3.14.2 jdolecek asoc = &stcb->asoc;
1370 1.3.14.2 jdolecek /* pick the time to use */
1371 1.3.14.2 jdolecek if (asoc->time_last_rcvd.tv_sec >
1372 1.3.14.2 jdolecek asoc->time_last_sent.tv_sec) {
1373 1.3.14.2 jdolecek tim_touse = &asoc->time_last_rcvd;
1374 1.3.14.2 jdolecek } else {
1375 1.3.14.2 jdolecek tim_touse = &asoc->time_last_sent;
1376 1.3.14.2 jdolecek }
1377 1.3.14.2 jdolecek /* Now has long enough transpired to autoclose? */
1378 1.3.14.2 jdolecek ticks_gone_by = ((tn.tv_sec - tim_touse->tv_sec) * hz);
1379 1.3.14.2 jdolecek if ((ticks_gone_by > 0) &&
1380 1.3.14.2 jdolecek (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) {
1381 1.3.14.2 jdolecek /*
1382 1.3.14.2 jdolecek * autoclose time has hit, call the output routine,
1383 1.3.14.2 jdolecek * which should do nothing just to be SURE we don't
1384 1.3.14.2 jdolecek * have hanging data. We can then safely check the
1385 1.3.14.2 jdolecek * queues and know that we are clear to send shutdown
1386 1.3.14.2 jdolecek */
1387 1.3.14.2 jdolecek sctp_chunk_output(inp, stcb, 9);
1388 1.3.14.2 jdolecek /* Are we clean? */
1389 1.3.14.2 jdolecek if (TAILQ_EMPTY(&asoc->send_queue) &&
1390 1.3.14.2 jdolecek TAILQ_EMPTY(&asoc->sent_queue)) {
1391 1.3.14.2 jdolecek /*
1392 1.3.14.2 jdolecek * there is nothing queued to send,
1393 1.3.14.2 jdolecek * so I'm done...
1394 1.3.14.2 jdolecek */
1395 1.3.14.2 jdolecek if (SCTP_GET_STATE(asoc) !=
1396 1.3.14.2 jdolecek SCTP_STATE_SHUTDOWN_SENT) {
1397 1.3.14.2 jdolecek /* only send SHUTDOWN 1st time thru */
1398 1.3.14.2 jdolecek #ifdef SCTP_DEBUG
1399 1.3.14.2 jdolecek if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
1400 1.3.14.2 jdolecek printf("%s:%d sends a shutdown\n",
1401 1.3.14.2 jdolecek __FILE__,
1402 1.3.14.2 jdolecek __LINE__
1403 1.3.14.2 jdolecek );
1404 1.3.14.2 jdolecek }
1405 1.3.14.2 jdolecek #endif
1406 1.3.14.2 jdolecek sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
1407 1.3.14.2 jdolecek asoc->state = SCTP_STATE_SHUTDOWN_SENT;
1408 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1409 1.3.14.2 jdolecek stcb->sctp_ep, stcb,
1410 1.3.14.2 jdolecek asoc->primary_destination);
1411 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1412 1.3.14.2 jdolecek stcb->sctp_ep, stcb,
1413 1.3.14.2 jdolecek asoc->primary_destination);
1414 1.3.14.2 jdolecek }
1415 1.3.14.2 jdolecek }
1416 1.3.14.2 jdolecek } else {
1417 1.3.14.2 jdolecek /*
1418 1.3.14.2 jdolecek * No auto close at this time, reset t-o to
1419 1.3.14.2 jdolecek * check later
1420 1.3.14.2 jdolecek */
1421 1.3.14.2 jdolecek int tmp;
1422 1.3.14.2 jdolecek /* fool the timer startup to use the time left */
1423 1.3.14.2 jdolecek tmp = asoc->sctp_autoclose_ticks;
1424 1.3.14.2 jdolecek asoc->sctp_autoclose_ticks -= ticks_gone_by;
1425 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb,
1426 1.3.14.2 jdolecek net);
1427 1.3.14.2 jdolecek /* restore the real tick value */
1428 1.3.14.2 jdolecek asoc->sctp_autoclose_ticks = tmp;
1429 1.3.14.2 jdolecek }
1430 1.3.14.2 jdolecek }
1431 1.3.14.2 jdolecek }
1432 1.3.14.2 jdolecek
1433 1.3.14.2 jdolecek void
1434 1.3.14.2 jdolecek sctp_iterator_timer(struct sctp_iterator *it)
1435 1.3.14.2 jdolecek {
1436 1.3.14.2 jdolecek int cnt= 0;
1437 1.3.14.2 jdolecek /* only one iterator can run at a
1438 1.3.14.2 jdolecek * time. This is the only way we
1439 1.3.14.2 jdolecek * can cleanly pull ep's from underneath
1440 1.3.14.2 jdolecek * all the running interators when a
1441 1.3.14.2 jdolecek * ep is freed.
1442 1.3.14.2 jdolecek */
1443 1.3.14.2 jdolecek SCTP_ITERATOR_LOCK();
1444 1.3.14.2 jdolecek if (it->inp == NULL) {
1445 1.3.14.2 jdolecek /* iterator is complete */
1446 1.3.14.2 jdolecek done_with_iterator:
1447 1.3.14.2 jdolecek SCTP_ITERATOR_UNLOCK();
1448 1.3.14.2 jdolecek SCTP_INP_INFO_WLOCK();
1449 1.3.14.2 jdolecek LIST_REMOVE(it, sctp_nxt_itr);
1450 1.3.14.2 jdolecek /* stopping the callout is not needed, in theory,
1451 1.3.14.2 jdolecek * but I am paranoid.
1452 1.3.14.2 jdolecek */
1453 1.3.14.2 jdolecek SCTP_INP_INFO_WUNLOCK();
1454 1.3.14.2 jdolecek callout_stop(&it->tmr.timer);
1455 1.3.14.2 jdolecek if (it->function_atend != NULL) {
1456 1.3.14.2 jdolecek (*it->function_atend)(it->pointer, it->val);
1457 1.3.14.2 jdolecek }
1458 1.3.14.2 jdolecek callout_destroy(&it->tmr.timer);
1459 1.3.14.2 jdolecek free(it, M_PCB);
1460 1.3.14.2 jdolecek return;
1461 1.3.14.2 jdolecek }
1462 1.3.14.2 jdolecek select_a_new_ep:
1463 1.3.14.2 jdolecek SCTP_INP_WLOCK(it->inp);
1464 1.3.14.2 jdolecek while ((it->pcb_flags) && ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) {
1465 1.3.14.2 jdolecek /* we do not like this ep */
1466 1.3.14.2 jdolecek if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
1467 1.3.14.2 jdolecek SCTP_INP_WUNLOCK(it->inp);
1468 1.3.14.2 jdolecek goto done_with_iterator;
1469 1.3.14.2 jdolecek }
1470 1.3.14.2 jdolecek SCTP_INP_WUNLOCK(it->inp);
1471 1.3.14.2 jdolecek it->inp = LIST_NEXT(it->inp, sctp_list);
1472 1.3.14.2 jdolecek if (it->inp == NULL) {
1473 1.3.14.2 jdolecek goto done_with_iterator;
1474 1.3.14.2 jdolecek }
1475 1.3.14.2 jdolecek SCTP_INP_WLOCK(it->inp);
1476 1.3.14.2 jdolecek }
1477 1.3.14.2 jdolecek if ((it->inp->inp_starting_point_for_iterator != NULL) &&
1478 1.3.14.2 jdolecek (it->inp->inp_starting_point_for_iterator != it)) {
1479 1.3.14.2 jdolecek printf("Iterator collision, we must wait for other iterator at %p\n",
1480 1.3.14.2 jdolecek it->inp);
1481 1.3.14.2 jdolecek SCTP_INP_WUNLOCK(it->inp);
1482 1.3.14.2 jdolecek goto start_timer_return;
1483 1.3.14.2 jdolecek }
1484 1.3.14.2 jdolecek /* now we do the actual write to this guy */
1485 1.3.14.2 jdolecek it->inp->inp_starting_point_for_iterator = it;
1486 1.3.14.2 jdolecek SCTP_INP_WUNLOCK(it->inp);
1487 1.3.14.2 jdolecek SCTP_INP_RLOCK(it->inp);
1488 1.3.14.2 jdolecek /* if we reach here we found a inp acceptable, now through each
1489 1.3.14.2 jdolecek * one that has the association in the right state
1490 1.3.14.2 jdolecek */
1491 1.3.14.2 jdolecek if (it->stcb == NULL) {
1492 1.3.14.2 jdolecek it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
1493 1.3.14.2 jdolecek }
1494 1.3.14.2 jdolecek if (it->stcb->asoc.stcb_starting_point_for_iterator == it) {
1495 1.3.14.2 jdolecek it->stcb->asoc.stcb_starting_point_for_iterator = NULL;
1496 1.3.14.2 jdolecek }
1497 1.3.14.2 jdolecek while (it->stcb) {
1498 1.3.14.2 jdolecek SCTP_TCB_LOCK(it->stcb);
1499 1.3.14.2 jdolecek if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
1500 1.3.14.2 jdolecek SCTP_TCB_UNLOCK(it->stcb);
1501 1.3.14.2 jdolecek it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
1502 1.3.14.2 jdolecek continue;
1503 1.3.14.2 jdolecek }
1504 1.3.14.2 jdolecek cnt++;
1505 1.3.14.2 jdolecek /* run function on this one */
1506 1.3.14.2 jdolecek SCTP_INP_RUNLOCK(it->inp);
1507 1.3.14.2 jdolecek (*it->function_toapply)(it->inp, it->stcb, it->pointer, it->val);
1508 1.3.14.2 jdolecek sctp_chunk_output(it->inp, it->stcb, 1);
1509 1.3.14.2 jdolecek SCTP_TCB_UNLOCK(it->stcb);
1510 1.3.14.2 jdolecek /* see if we have limited out */
1511 1.3.14.2 jdolecek if (cnt > SCTP_MAX_ITERATOR_AT_ONCE) {
1512 1.3.14.2 jdolecek it->stcb->asoc.stcb_starting_point_for_iterator = it;
1513 1.3.14.2 jdolecek start_timer_return:
1514 1.3.14.2 jdolecek SCTP_ITERATOR_UNLOCK();
1515 1.3.14.2 jdolecek sctp_timer_start(SCTP_TIMER_TYPE_ITERATOR, (struct sctp_inpcb *)it, NULL, NULL);
1516 1.3.14.2 jdolecek return;
1517 1.3.14.2 jdolecek }
1518 1.3.14.2 jdolecek SCTP_INP_RLOCK(it->inp);
1519 1.3.14.2 jdolecek it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
1520 1.3.14.2 jdolecek }
1521 1.3.14.2 jdolecek /* if we reach here, we ran out of stcb's in the inp we are looking at */
1522 1.3.14.2 jdolecek SCTP_INP_RUNLOCK(it->inp);
1523 1.3.14.2 jdolecek SCTP_INP_WLOCK(it->inp);
1524 1.3.14.2 jdolecek it->inp->inp_starting_point_for_iterator = NULL;
1525 1.3.14.2 jdolecek SCTP_INP_WUNLOCK(it->inp);
1526 1.3.14.2 jdolecek if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
1527 1.3.14.2 jdolecek it->inp = NULL;
1528 1.3.14.2 jdolecek } else {
1529 1.3.14.2 jdolecek SCTP_INP_INFO_RLOCK();
1530 1.3.14.2 jdolecek it->inp = LIST_NEXT(it->inp, sctp_list);
1531 1.3.14.2 jdolecek SCTP_INP_INFO_RUNLOCK();
1532 1.3.14.2 jdolecek }
1533 1.3.14.2 jdolecek if (it->inp == NULL) {
1534 1.3.14.2 jdolecek goto done_with_iterator;
1535 1.3.14.2 jdolecek }
1536 1.3.14.2 jdolecek goto select_a_new_ep;
1537 1.3.14.2 jdolecek }
1538