diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/sctp/transport.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/sctp/transport.c')
-rw-r--r-- | net/sctp/transport.c | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/net/sctp/transport.c b/net/sctp/transport.c new file mode 100644 index 000000000000..f30882e1e96a --- /dev/null +++ b/net/sctp/transport.c | |||
@@ -0,0 +1,514 @@ | |||
1 | /* SCTP kernel reference Implementation | ||
2 | * Copyright (c) 1999-2000 Cisco, Inc. | ||
3 | * Copyright (c) 1999-2001 Motorola, Inc. | ||
4 | * Copyright (c) 2001-2003 International Business Machines Corp. | ||
5 | * Copyright (c) 2001 Intel Corp. | ||
6 | * Copyright (c) 2001 La Monte H.P. Yarroll | ||
7 | * | ||
8 | * This file is part of the SCTP kernel reference Implementation | ||
9 | * | ||
10 | * This module provides the abstraction for an SCTP tranport representing | ||
11 | * a remote transport address. For local transport addresses, we just use | ||
12 | * union sctp_addr. | ||
13 | * | ||
14 | * The SCTP reference implementation is free software; | ||
15 | * you can redistribute it and/or modify it under the terms of | ||
16 | * the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2, or (at your option) | ||
18 | * any later version. | ||
19 | * | ||
20 | * The SCTP reference implementation is distributed in the hope that it | ||
21 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied | ||
22 | * ************************ | ||
23 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
24 | * See the GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with GNU CC; see the file COPYING. If not, write to | ||
28 | * the Free Software Foundation, 59 Temple Place - Suite 330, | ||
29 | * Boston, MA 02111-1307, USA. | ||
30 | * | ||
31 | * Please send any bug reports or fixes you make to the | ||
32 | * email address(es): | ||
33 | * lksctp developers <lksctp-developers@lists.sourceforge.net> | ||
34 | * | ||
35 | * Or submit a bug report through the following website: | ||
36 | * http://www.sf.net/projects/lksctp | ||
37 | * | ||
38 | * Written or modified by: | ||
39 | * La Monte H.P. Yarroll <piggy@acm.org> | ||
40 | * Karl Knutson <karl@athena.chicago.il.us> | ||
41 | * Jon Grimm <jgrimm@us.ibm.com> | ||
42 | * Xingang Guo <xingang.guo@intel.com> | ||
43 | * Hui Huang <hui.huang@nokia.com> | ||
44 | * Sridhar Samudrala <sri@us.ibm.com> | ||
45 | * Ardelle Fan <ardelle.fan@intel.com> | ||
46 | * | ||
47 | * Any bugs reported given to us we will try to fix... any fixes shared will | ||
48 | * be incorporated into the next SCTP release. | ||
49 | */ | ||
50 | |||
51 | #include <linux/types.h> | ||
52 | #include <net/sctp/sctp.h> | ||
53 | #include <net/sctp/sm.h> | ||
54 | |||
55 | /* 1st Level Abstractions. */ | ||
56 | |||
57 | /* Initialize a new transport from provided memory. */ | ||
58 | static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, | ||
59 | const union sctp_addr *addr, | ||
60 | int gfp) | ||
61 | { | ||
62 | /* Copy in the address. */ | ||
63 | peer->ipaddr = *addr; | ||
64 | peer->af_specific = sctp_get_af_specific(addr->sa.sa_family); | ||
65 | peer->asoc = NULL; | ||
66 | |||
67 | peer->dst = NULL; | ||
68 | memset(&peer->saddr, 0, sizeof(union sctp_addr)); | ||
69 | |||
70 | /* From 6.3.1 RTO Calculation: | ||
71 | * | ||
72 | * C1) Until an RTT measurement has been made for a packet sent to the | ||
73 | * given destination transport address, set RTO to the protocol | ||
74 | * parameter 'RTO.Initial'. | ||
75 | */ | ||
76 | peer->rtt = 0; | ||
77 | peer->rto = sctp_rto_initial; | ||
78 | peer->rttvar = 0; | ||
79 | peer->srtt = 0; | ||
80 | peer->rto_pending = 0; | ||
81 | |||
82 | peer->last_time_heard = jiffies; | ||
83 | peer->last_time_used = jiffies; | ||
84 | peer->last_time_ecne_reduced = jiffies; | ||
85 | |||
86 | peer->active = SCTP_ACTIVE; | ||
87 | peer->hb_allowed = 0; | ||
88 | |||
89 | /* Initialize the default path max_retrans. */ | ||
90 | peer->max_retrans = sctp_max_retrans_path; | ||
91 | peer->error_count = 0; | ||
92 | |||
93 | INIT_LIST_HEAD(&peer->transmitted); | ||
94 | INIT_LIST_HEAD(&peer->send_ready); | ||
95 | INIT_LIST_HEAD(&peer->transports); | ||
96 | |||
97 | /* Set up the retransmission timer. */ | ||
98 | init_timer(&peer->T3_rtx_timer); | ||
99 | peer->T3_rtx_timer.function = sctp_generate_t3_rtx_event; | ||
100 | peer->T3_rtx_timer.data = (unsigned long)peer; | ||
101 | |||
102 | /* Set up the heartbeat timer. */ | ||
103 | init_timer(&peer->hb_timer); | ||
104 | peer->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; | ||
105 | peer->hb_timer.function = sctp_generate_heartbeat_event; | ||
106 | peer->hb_timer.data = (unsigned long)peer; | ||
107 | |||
108 | atomic_set(&peer->refcnt, 1); | ||
109 | peer->dead = 0; | ||
110 | |||
111 | peer->malloced = 0; | ||
112 | |||
113 | /* Initialize the state information for SFR-CACC */ | ||
114 | peer->cacc.changeover_active = 0; | ||
115 | peer->cacc.cycling_changeover = 0; | ||
116 | peer->cacc.next_tsn_at_change = 0; | ||
117 | peer->cacc.cacc_saw_newack = 0; | ||
118 | |||
119 | return peer; | ||
120 | } | ||
121 | |||
122 | /* Allocate and initialize a new transport. */ | ||
123 | struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp) | ||
124 | { | ||
125 | struct sctp_transport *transport; | ||
126 | |||
127 | transport = t_new(struct sctp_transport, gfp); | ||
128 | if (!transport) | ||
129 | goto fail; | ||
130 | |||
131 | if (!sctp_transport_init(transport, addr, gfp)) | ||
132 | goto fail_init; | ||
133 | |||
134 | transport->malloced = 1; | ||
135 | SCTP_DBG_OBJCNT_INC(transport); | ||
136 | |||
137 | return transport; | ||
138 | |||
139 | fail_init: | ||
140 | kfree(transport); | ||
141 | |||
142 | fail: | ||
143 | return NULL; | ||
144 | } | ||
145 | |||
146 | /* This transport is no longer needed. Free up if possible, or | ||
147 | * delay until it last reference count. | ||
148 | */ | ||
149 | void sctp_transport_free(struct sctp_transport *transport) | ||
150 | { | ||
151 | transport->dead = 1; | ||
152 | |||
153 | /* Try to delete the heartbeat timer. */ | ||
154 | if (del_timer(&transport->hb_timer)) | ||
155 | sctp_transport_put(transport); | ||
156 | |||
157 | /* Delete the T3_rtx timer if it's active. | ||
158 | * There is no point in not doing this now and letting | ||
159 | * structure hang around in memory since we know | ||
160 | * the tranport is going away. | ||
161 | */ | ||
162 | if (timer_pending(&transport->T3_rtx_timer) && | ||
163 | del_timer(&transport->T3_rtx_timer)) | ||
164 | sctp_transport_put(transport); | ||
165 | |||
166 | |||
167 | sctp_transport_put(transport); | ||
168 | } | ||
169 | |||
170 | /* Destroy the transport data structure. | ||
171 | * Assumes there are no more users of this structure. | ||
172 | */ | ||
173 | static void sctp_transport_destroy(struct sctp_transport *transport) | ||
174 | { | ||
175 | SCTP_ASSERT(transport->dead, "Transport is not dead", return); | ||
176 | |||
177 | if (transport->asoc) | ||
178 | sctp_association_put(transport->asoc); | ||
179 | |||
180 | sctp_packet_free(&transport->packet); | ||
181 | |||
182 | dst_release(transport->dst); | ||
183 | kfree(transport); | ||
184 | SCTP_DBG_OBJCNT_DEC(transport); | ||
185 | } | ||
186 | |||
187 | /* Start T3_rtx timer if it is not already running and update the heartbeat | ||
188 | * timer. This routine is called every time a DATA chunk is sent. | ||
189 | */ | ||
190 | void sctp_transport_reset_timers(struct sctp_transport *transport) | ||
191 | { | ||
192 | /* RFC 2960 6.3.2 Retransmission Timer Rules | ||
193 | * | ||
194 | * R1) Every time a DATA chunk is sent to any address(including a | ||
195 | * retransmission), if the T3-rtx timer of that address is not running | ||
196 | * start it running so that it will expire after the RTO of that | ||
197 | * address. | ||
198 | */ | ||
199 | |||
200 | if (!timer_pending(&transport->T3_rtx_timer)) | ||
201 | if (!mod_timer(&transport->T3_rtx_timer, | ||
202 | jiffies + transport->rto)) | ||
203 | sctp_transport_hold(transport); | ||
204 | |||
205 | /* When a data chunk is sent, reset the heartbeat interval. */ | ||
206 | if (!mod_timer(&transport->hb_timer, | ||
207 | sctp_transport_timeout(transport))) | ||
208 | sctp_transport_hold(transport); | ||
209 | } | ||
210 | |||
211 | /* This transport has been assigned to an association. | ||
212 | * Initialize fields from the association or from the sock itself. | ||
213 | * Register the reference count in the association. | ||
214 | */ | ||
215 | void sctp_transport_set_owner(struct sctp_transport *transport, | ||
216 | struct sctp_association *asoc) | ||
217 | { | ||
218 | transport->asoc = asoc; | ||
219 | sctp_association_hold(asoc); | ||
220 | } | ||
221 | |||
222 | /* Initialize the pmtu of a transport. */ | ||
223 | void sctp_transport_pmtu(struct sctp_transport *transport) | ||
224 | { | ||
225 | struct dst_entry *dst; | ||
226 | |||
227 | dst = transport->af_specific->get_dst(NULL, &transport->ipaddr, NULL); | ||
228 | |||
229 | if (dst) { | ||
230 | transport->pmtu = dst_mtu(dst); | ||
231 | dst_release(dst); | ||
232 | } else | ||
233 | transport->pmtu = SCTP_DEFAULT_MAXSEGMENT; | ||
234 | } | ||
235 | |||
236 | /* Caches the dst entry and source address for a transport's destination | ||
237 | * address. | ||
238 | */ | ||
239 | void sctp_transport_route(struct sctp_transport *transport, | ||
240 | union sctp_addr *saddr, struct sctp_sock *opt) | ||
241 | { | ||
242 | struct sctp_association *asoc = transport->asoc; | ||
243 | struct sctp_af *af = transport->af_specific; | ||
244 | union sctp_addr *daddr = &transport->ipaddr; | ||
245 | struct dst_entry *dst; | ||
246 | |||
247 | dst = af->get_dst(asoc, daddr, saddr); | ||
248 | |||
249 | if (saddr) | ||
250 | memcpy(&transport->saddr, saddr, sizeof(union sctp_addr)); | ||
251 | else | ||
252 | af->get_saddr(asoc, dst, daddr, &transport->saddr); | ||
253 | |||
254 | transport->dst = dst; | ||
255 | if (dst) { | ||
256 | transport->pmtu = dst_mtu(dst); | ||
257 | |||
258 | /* Initialize sk->sk_rcv_saddr, if the transport is the | ||
259 | * association's active path for getsockname(). | ||
260 | */ | ||
261 | if (asoc && (transport == asoc->peer.active_path)) | ||
262 | af->to_sk_saddr(&transport->saddr, asoc->base.sk); | ||
263 | } else | ||
264 | transport->pmtu = SCTP_DEFAULT_MAXSEGMENT; | ||
265 | } | ||
266 | |||
267 | /* Hold a reference to a transport. */ | ||
268 | void sctp_transport_hold(struct sctp_transport *transport) | ||
269 | { | ||
270 | atomic_inc(&transport->refcnt); | ||
271 | } | ||
272 | |||
273 | /* Release a reference to a transport and clean up | ||
274 | * if there are no more references. | ||
275 | */ | ||
276 | void sctp_transport_put(struct sctp_transport *transport) | ||
277 | { | ||
278 | if (atomic_dec_and_test(&transport->refcnt)) | ||
279 | sctp_transport_destroy(transport); | ||
280 | } | ||
281 | |||
282 | /* Update transport's RTO based on the newly calculated RTT. */ | ||
283 | void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) | ||
284 | { | ||
285 | /* Check for valid transport. */ | ||
286 | SCTP_ASSERT(tp, "NULL transport", return); | ||
287 | |||
288 | /* We should not be doing any RTO updates unless rto_pending is set. */ | ||
289 | SCTP_ASSERT(tp->rto_pending, "rto_pending not set", return); | ||
290 | |||
291 | if (tp->rttvar || tp->srtt) { | ||
292 | /* 6.3.1 C3) When a new RTT measurement R' is made, set | ||
293 | * RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'| | ||
294 | * SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R' | ||
295 | */ | ||
296 | |||
297 | /* Note: The above algorithm has been rewritten to | ||
298 | * express rto_beta and rto_alpha as inverse powers | ||
299 | * of two. | ||
300 | * For example, assuming the default value of RTO.Alpha of | ||
301 | * 1/8, rto_alpha would be expressed as 3. | ||
302 | */ | ||
303 | tp->rttvar = tp->rttvar - (tp->rttvar >> sctp_rto_beta) | ||
304 | + ((abs(tp->srtt - rtt)) >> sctp_rto_beta); | ||
305 | tp->srtt = tp->srtt - (tp->srtt >> sctp_rto_alpha) | ||
306 | + (rtt >> sctp_rto_alpha); | ||
307 | } else { | ||
308 | /* 6.3.1 C2) When the first RTT measurement R is made, set | ||
309 | * SRTT <- R, RTTVAR <- R/2. | ||
310 | */ | ||
311 | tp->srtt = rtt; | ||
312 | tp->rttvar = rtt >> 1; | ||
313 | } | ||
314 | |||
315 | /* 6.3.1 G1) Whenever RTTVAR is computed, if RTTVAR = 0, then | ||
316 | * adjust RTTVAR <- G, where G is the CLOCK GRANULARITY. | ||
317 | */ | ||
318 | if (tp->rttvar == 0) | ||
319 | tp->rttvar = SCTP_CLOCK_GRANULARITY; | ||
320 | |||
321 | /* 6.3.1 C3) After the computation, update RTO <- SRTT + 4 * RTTVAR. */ | ||
322 | tp->rto = tp->srtt + (tp->rttvar << 2); | ||
323 | |||
324 | /* 6.3.1 C6) Whenever RTO is computed, if it is less than RTO.Min | ||
325 | * seconds then it is rounded up to RTO.Min seconds. | ||
326 | */ | ||
327 | if (tp->rto < tp->asoc->rto_min) | ||
328 | tp->rto = tp->asoc->rto_min; | ||
329 | |||
330 | /* 6.3.1 C7) A maximum value may be placed on RTO provided it is | ||
331 | * at least RTO.max seconds. | ||
332 | */ | ||
333 | if (tp->rto > tp->asoc->rto_max) | ||
334 | tp->rto = tp->asoc->rto_max; | ||
335 | |||
336 | tp->rtt = rtt; | ||
337 | |||
338 | /* Reset rto_pending so that a new RTT measurement is started when a | ||
339 | * new data chunk is sent. | ||
340 | */ | ||
341 | tp->rto_pending = 0; | ||
342 | |||
343 | SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d " | ||
344 | "rttvar: %d, rto: %d\n", __FUNCTION__, | ||
345 | tp, rtt, tp->srtt, tp->rttvar, tp->rto); | ||
346 | } | ||
347 | |||
348 | /* This routine updates the transport's cwnd and partial_bytes_acked | ||
349 | * parameters based on the bytes acked in the received SACK. | ||
350 | */ | ||
351 | void sctp_transport_raise_cwnd(struct sctp_transport *transport, | ||
352 | __u32 sack_ctsn, __u32 bytes_acked) | ||
353 | { | ||
354 | __u32 cwnd, ssthresh, flight_size, pba, pmtu; | ||
355 | |||
356 | cwnd = transport->cwnd; | ||
357 | flight_size = transport->flight_size; | ||
358 | |||
359 | /* The appropriate cwnd increase algorithm is performed if, and only | ||
360 | * if the cumulative TSN has advanced and the congestion window is | ||
361 | * being fully utilized. | ||
362 | */ | ||
363 | if ((transport->asoc->ctsn_ack_point >= sack_ctsn) || | ||
364 | (flight_size < cwnd)) | ||
365 | return; | ||
366 | |||
367 | ssthresh = transport->ssthresh; | ||
368 | pba = transport->partial_bytes_acked; | ||
369 | pmtu = transport->asoc->pmtu; | ||
370 | |||
371 | if (cwnd <= ssthresh) { | ||
372 | /* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less | ||
373 | * than or equal to ssthresh an SCTP endpoint MUST use the | ||
374 | * slow start algorithm to increase cwnd only if the current | ||
375 | * congestion window is being fully utilized and an incoming | ||
376 | * SACK advances the Cumulative TSN Ack Point. Only when these | ||
377 | * two conditions are met can the cwnd be increased otherwise | ||
378 | * the cwnd MUST not be increased. If these conditions are met | ||
379 | * then cwnd MUST be increased by at most the lesser of | ||
380 | * 1) the total size of the previously outstanding DATA | ||
381 | * chunk(s) acknowledged, and 2) the destination's path MTU. | ||
382 | */ | ||
383 | if (bytes_acked > pmtu) | ||
384 | cwnd += pmtu; | ||
385 | else | ||
386 | cwnd += bytes_acked; | ||
387 | SCTP_DEBUG_PRINTK("%s: SLOW START: transport: %p, " | ||
388 | "bytes_acked: %d, cwnd: %d, ssthresh: %d, " | ||
389 | "flight_size: %d, pba: %d\n", | ||
390 | __FUNCTION__, | ||
391 | transport, bytes_acked, cwnd, | ||
392 | ssthresh, flight_size, pba); | ||
393 | } else { | ||
394 | /* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, | ||
395 | * upon each SACK arrival that advances the Cumulative TSN Ack | ||
396 | * Point, increase partial_bytes_acked by the total number of | ||
397 | * bytes of all new chunks acknowledged in that SACK including | ||
398 | * chunks acknowledged by the new Cumulative TSN Ack and by | ||
399 | * Gap Ack Blocks. | ||
400 | * | ||
401 | * When partial_bytes_acked is equal to or greater than cwnd | ||
402 | * and before the arrival of the SACK the sender had cwnd or | ||
403 | * more bytes of data outstanding (i.e., before arrival of the | ||
404 | * SACK, flightsize was greater than or equal to cwnd), | ||
405 | * increase cwnd by MTU, and reset partial_bytes_acked to | ||
406 | * (partial_bytes_acked - cwnd). | ||
407 | */ | ||
408 | pba += bytes_acked; | ||
409 | if (pba >= cwnd) { | ||
410 | cwnd += pmtu; | ||
411 | pba = ((cwnd < pba) ? (pba - cwnd) : 0); | ||
412 | } | ||
413 | SCTP_DEBUG_PRINTK("%s: CONGESTION AVOIDANCE: " | ||
414 | "transport: %p, bytes_acked: %d, cwnd: %d, " | ||
415 | "ssthresh: %d, flight_size: %d, pba: %d\n", | ||
416 | __FUNCTION__, | ||
417 | transport, bytes_acked, cwnd, | ||
418 | ssthresh, flight_size, pba); | ||
419 | } | ||
420 | |||
421 | transport->cwnd = cwnd; | ||
422 | transport->partial_bytes_acked = pba; | ||
423 | } | ||
424 | |||
425 | /* This routine is used to lower the transport's cwnd when congestion is | ||
426 | * detected. | ||
427 | */ | ||
428 | void sctp_transport_lower_cwnd(struct sctp_transport *transport, | ||
429 | sctp_lower_cwnd_t reason) | ||
430 | { | ||
431 | switch (reason) { | ||
432 | case SCTP_LOWER_CWND_T3_RTX: | ||
433 | /* RFC 2960 Section 7.2.3, sctpimpguide | ||
434 | * When the T3-rtx timer expires on an address, SCTP should | ||
435 | * perform slow start by: | ||
436 | * ssthresh = max(cwnd/2, 4*MTU) | ||
437 | * cwnd = 1*MTU | ||
438 | * partial_bytes_acked = 0 | ||
439 | */ | ||
440 | transport->ssthresh = max(transport->cwnd/2, | ||
441 | 4*transport->asoc->pmtu); | ||
442 | transport->cwnd = transport->asoc->pmtu; | ||
443 | break; | ||
444 | |||
445 | case SCTP_LOWER_CWND_FAST_RTX: | ||
446 | /* RFC 2960 7.2.4 Adjust the ssthresh and cwnd of the | ||
447 | * destination address(es) to which the missing DATA chunks | ||
448 | * were last sent, according to the formula described in | ||
449 | * Section 7.2.3. | ||
450 | * | ||
451 | * RFC 2960 7.2.3, sctpimpguide Upon detection of packet | ||
452 | * losses from SACK (see Section 7.2.4), An endpoint | ||
453 | * should do the following: | ||
454 | * ssthresh = max(cwnd/2, 4*MTU) | ||
455 | * cwnd = ssthresh | ||
456 | * partial_bytes_acked = 0 | ||
457 | */ | ||
458 | transport->ssthresh = max(transport->cwnd/2, | ||
459 | 4*transport->asoc->pmtu); | ||
460 | transport->cwnd = transport->ssthresh; | ||
461 | break; | ||
462 | |||
463 | case SCTP_LOWER_CWND_ECNE: | ||
464 | /* RFC 2481 Section 6.1.2. | ||
465 | * If the sender receives an ECN-Echo ACK packet | ||
466 | * then the sender knows that congestion was encountered in the | ||
467 | * network on the path from the sender to the receiver. The | ||
468 | * indication of congestion should be treated just as a | ||
469 | * congestion loss in non-ECN Capable TCP. That is, the TCP | ||
470 | * source halves the congestion window "cwnd" and reduces the | ||
471 | * slow start threshold "ssthresh". | ||
472 | * A critical condition is that TCP does not react to | ||
473 | * congestion indications more than once every window of | ||
474 | * data (or more loosely more than once every round-trip time). | ||
475 | */ | ||
476 | if ((jiffies - transport->last_time_ecne_reduced) > | ||
477 | transport->rtt) { | ||
478 | transport->ssthresh = max(transport->cwnd/2, | ||
479 | 4*transport->asoc->pmtu); | ||
480 | transport->cwnd = transport->ssthresh; | ||
481 | transport->last_time_ecne_reduced = jiffies; | ||
482 | } | ||
483 | break; | ||
484 | |||
485 | case SCTP_LOWER_CWND_INACTIVE: | ||
486 | /* RFC 2960 Section 7.2.1, sctpimpguide | ||
487 | * When the endpoint does not transmit data on a given | ||
488 | * transport address, the cwnd of the transport address | ||
489 | * should be adjusted to max(cwnd/2, 4*MTU) per RTO. | ||
490 | * NOTE: Although the draft recommends that this check needs | ||
491 | * to be done every RTO interval, we do it every hearbeat | ||
492 | * interval. | ||
493 | */ | ||
494 | if ((jiffies - transport->last_time_used) > transport->rto) | ||
495 | transport->cwnd = max(transport->cwnd/2, | ||
496 | 4*transport->asoc->pmtu); | ||
497 | break; | ||
498 | }; | ||
499 | |||
500 | transport->partial_bytes_acked = 0; | ||
501 | SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: " | ||
502 | "%d ssthresh: %d\n", __FUNCTION__, | ||
503 | transport, reason, | ||
504 | transport->cwnd, transport->ssthresh); | ||
505 | } | ||
506 | |||
507 | /* What is the next timeout value for this transport? */ | ||
508 | unsigned long sctp_transport_timeout(struct sctp_transport *t) | ||
509 | { | ||
510 | unsigned long timeout; | ||
511 | timeout = t->hb_interval + t->rto + sctp_jitter(t->rto); | ||
512 | timeout += jiffies; | ||
513 | return timeout; | ||
514 | } | ||