1 /* $Id$
2 * --------------------------------------------------------------------------
3 *
4 * //===== //===== ===//=== //===// // // //===//
5 * // // // // // // // // //
6 * //====// // // //===// // // //===<<
7 * // // // // // // // //
8 * ======// //===== // // //===== // //===//
9 *
10 * -------------- An SCTP implementation according to RFC 4960 --------------
11 *
12 * Copyright (C) 2000 by Siemens AG, Munich, Germany.
13 * Copyright (C) 2001-2004 Andreas Jungmaier
14 * Copyright (C) 2004-2019 Thomas Dreibholz
15 *
16 * Acknowledgements:
17 * Realized in co-operation between Siemens AG and the University of
18 * Duisburg-Essen, Institute for Experimental Mathematics, Computer
19 * Networking Technology group.
20 * This work was partially funded by the Bundesministerium fuer Bildung und
21 * Forschung (BMBF) of the Federal Republic of Germany
22 * (Förderkennzeichen 01AK045).
23 * The authors alone are responsible for the contents.
24 *
25 * This library is free software: you can redistribute it and/or modify it
26 * under the terms of the GNU Lesser General Public License as published by
27 * the Free Software Foundation, either version 2.1 of the License, or
28 * (at your option) any later version.
29 *
30 * This library is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU Lesser General Public License
36 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37 *
38 * Contact: sctp-discussion@sctp.de
39 * dreibh@iem.uni-due.de
40 * tuexen@fh-muenster.de
41 * andreas.jungmaier@web.de
42 */
43
44 #include "globals.h"
45 #include "chunkHandler.h"
46 #include "SCTP-control.h"
47 #include "adaptation.h"
48 #include "bundling.h"
49 #include "pathmanagement.h"
50
51 /*------------------------ defines -----------------------------------------------------------*/
52 #define RTO_ALPHA 0.125
53 #define RTO_BETA 0.25
54
55
56 /*----------------------- Typedefs ------------------------------------------------------------*/
57
58
59 /**
60 * this struct contains the necessary data per (destination or) path.
61 * There may be more than one within an association
62 */
63 typedef struct PATHDATA
64 {
65 /*@{ */
66 /** operational state of pathmanagement for one path */
67 short state;
68 /** true if heartbeat is enabled */
69 boolean heartbeatEnabled;
70 /** true as long as RTO-Calc. has been done */
71 boolean firstRTO;
72 /** Only once per HB-intervall */
73 boolean timerBackoff;
74 /** set to true when data chunks are acknowledged */
75 boolean chunksAcked;
76 /** TRUE, if chunks have been sent over that path within last RTO */
77 boolean chunksSent;
78 /** set to true when a heartbeat is sent. */
79 boolean heartbeatSent;
80 /** set to true when a hearbeat is acknowledged and to false when a
81 heartbeat is sent when the heartbeat timer expires. */
82 boolean heartbeatAcked;
83 /** Counter for retransmissions on a single path */
84 unsigned int pathRetranscount;
85 /** Retransmission time out used for all retrans. timers */
86 unsigned int rto;
87 /** smoothed round trip time */
88 unsigned int srtt;
89 /** round trip time variation */
90 unsigned int rttvar;
91 /** defines the rate at which heartbeats are sent */
92 unsigned int heartbeatIntervall;
93 /** ID of the heartbeat timer */
94 TimerID hearbeatTimer;
95 /** time of last rto update */
96 struct timeval rto_update;
97 /** ID of path */
98 unsigned int pathID;
99 /*@} */
100 } PathData;
101
102
103 /**
104 * this struct contains all necessary data for one instance of the path management
105 * module. There is one such module per existing association.
106 */
107 typedef struct PATHMANDATA
108 {
109 /*@{ */
110 /** stores the current primary path */
111 short primaryPath;
112 /** the number of paths used by this assoc. */
113 short numberOfPaths;
114 /** Counter for all retransmissions over all paths */
115 unsigned int peerRetranscount;
116 /** pointer to path-specific data */
117 PathData *pathData;
118 /** association-ID */
119 unsigned int associationID;
120 /** maximum retransmissions per path parameter */
121 int maxPathRetransmissions;
122 /** initial RTO, a configurable parameter */
123 int rto_initial;
124 /** minimum RTO, a configurable parameter */
125 int rto_min;
126 /** maximum RTO, a configurable parameter */
127 int rto_max;
128 /*@} */
129 } PathmanData;
130
131
132 /*----------------------Declares ----------------------------------------------------------------*/
133
134 /**
135 * this pointer is set to point to the current asssociation's path management struct
136 * it becomes zero after we have treated an incoming/outgoing datagram
137 */
138 PathmanData *pmData;
139
140 /*-------------------------- Function Implementations -------------------------------------------*/
141
142 /*------------------- Internal Functions --------------------------------------------------------*/
143
144 /**
145 return the current system time converted to a value of milliseconds.
146 MSB of tv_sec field are removed in order
147 to make representation in millisecs possible. This done by taking the remainder of
148 a division by 1728000 = 20x24x60x60, restarting millisecs count every 20 days.
149 @return unsigned 32 bit value representing system time in milliseconds. Hmmmh.
150 */
pm_getTime(void)151 unsigned int pm_getTime(void)
152 {
153 unsigned int curTimeMilli;
154 struct timeval curTime;
155
156 adl_gettime(&curTime);
157
158 /* modulo operation overlfows every 20 days */
159 curTimeMilli = (curTime.tv_sec % 1728000) * 1000 + curTime.tv_usec / 1000;
160
161 return curTimeMilli;
162 } /* end: pm_ sctp_getTime */
163
164
165 /**
166 * handleChunksRetransmitted is called whenever datachunks are retransmitted or a hearbeat-request
167 * has not been acknowledged within the current heartbeat-intervall. It increases path- and peer-
168 * retransmission counters and compares these counters to the corresonding thresholds.
169 * @param pathID index to the path that CAUSED retransmission
170 * @return TRUE if association was deleted, FALSE if not
171 */
handleChunksRetransmitted(short pathID)172 static gboolean handleChunksRetransmitted(short pathID)
173 {
174 short pID;
175 boolean allPathsInactive;
176 PathmanData *old_pmData;
177
178 if (!pmData->pathData) {
179 error_logi(ERROR_MAJOR, "handleChunksRetransmitted(%d): Path Data Structures not initialized yet, returning !", pathID);
180 return FALSE;
181 }
182
183 event_logiii(INTERNAL_EVENT_0,
184 "handleChunksRetransmitted(%d) : path-rtx-count==%u, peer-rtx-count==%u",
185 pathID, pmData->pathData[pathID].pathRetranscount, pmData->peerRetranscount);
186
187 if (pmData->pathData[pathID].state == PM_PATH_UNCONFIRMED) {
188
189 pmData->pathData[pathID].pathRetranscount++;
190
191 } else if (pmData->pathData[pathID].state == PM_ACTIVE) {
192
193 pmData->pathData[pathID].pathRetranscount++;
194 pmData->peerRetranscount++;
195
196 } else {
197 event_log(INTERNAL_EVENT_0,
198 "handleChunksRetransmitted: ignored, because already inactive");
199 return FALSE;
200 }
201
202 if (pmData->peerRetranscount >= (unsigned int)sci_getMaxAssocRetransmissions()) {
203 mdi_deleteCurrentAssociation();
204 mdi_communicationLostNotif(SCTP_COMM_LOST_EXCEEDED_RETRANSMISSIONS);
205 mdi_clearAssociationData();
206
207 event_log(INTERNAL_EVENT_0, "handleChunksRetransmitted: communication lost");
208 return TRUE;
209 }
210
211 if (pmData->pathData[pathID].pathRetranscount >= (unsigned int)pmData->maxPathRetransmissions) {
212 /* Set state of this path to inactive and notify change of state to ULP */
213 pmData->pathData[pathID].state = PM_INACTIVE;
214 event_logi(INTERNAL_EVENT_0, "handleChunksRetransmitted: path %d to INACTIVE ", pathID);
215 /* check if an active path is left */
216 allPathsInactive = TRUE;
217 for (pID = 0; pID < pmData->numberOfPaths; pID++) {
218 if (pmData->pathData[pID].state == PM_ACTIVE) {
219 allPathsInactive = FALSE;
220 }
221 }
222 if (allPathsInactive) {
223 /* No active parts are left, communication lost to ULP */
224 mdi_deleteCurrentAssociation();
225 mdi_communicationLostNotif(SCTP_COMM_LOST_ENDPOINT_UNREACHABLE);
226 /* will be called later anyway !
227 mdi_clearAssociationData(); */
228 event_log(INTERNAL_EVENT_0,
229 "handleChunksRetransmitted: communication lost (all paths are INACTIVE)");
230 return TRUE;
231 } else {
232 old_pmData = pmData;
233 mdi_networkStatusChangeNotif(pathID, PM_INACTIVE);
234 pmData = old_pmData;
235 }
236 }
237
238 return FALSE;
239 } /* end: handleChunksRetransmitted */
240
241
242
243
244 /**
245 * Function is used to update RTT, SRTT, RTO values after chunks have been acked.
246 * CHECKME : this function is called too often with RTO == 0;
247 * Is there one update per RTT ?
248 * @param pathID index of the path where data was acked
249 * @param newRTT new RTT measured, when data was acked, or zero if it was retransmitted
250 */
handleChunksAcked(short pathID,unsigned int newRTT)251 static void handleChunksAcked(short pathID, unsigned int newRTT)
252 {
253
254 if (!pmData->pathData) {
255 error_logi(ERROR_MAJOR, "handleChunksAcked(%d): Path Data Structures not initialized yet, returning !", pathID);
256 return;
257 }
258
259 event_logii(INTERNAL_EVENT_0, "handleChunksAcked: pathID: %u, new RTT: %u msecs", pathID, newRTT);
260
261 if (newRTT > 0) {
262 /* RTO measurement done */
263 /* calculate new RTO, SRTT and RTTVAR */
264 if (pmData->pathData[pathID].firstRTO) {
265 pmData->pathData[pathID].srtt = newRTT;
266 pmData->pathData[pathID].rttvar = max(newRTT / 2, GRANULARITY);;
267 pmData->pathData[pathID].rto = max(min(newRTT * 3, (unsigned int)pmData->rto_max), (unsigned int)pmData->rto_min);
268 pmData->pathData[pathID].firstRTO = FALSE;
269 } else {
270 pmData->pathData[pathID].rttvar = (unsigned int)
271 ((1. - RTO_BETA) * pmData->pathData[pathID].rttvar +
272 RTO_BETA * abs((int)pmData->pathData[pathID].srtt - (int)newRTT));
273 pmData->pathData[pathID].rttvar = max((unsigned int)pmData->pathData[pathID].rttvar, GRANULARITY);
274
275 pmData->pathData[pathID].srtt = (unsigned int)
276 ((1. - RTO_ALPHA) * pmData->pathData[pathID].srtt + RTO_ALPHA * newRTT);
277
278 pmData->pathData[pathID].rto = pmData->pathData[pathID].srtt +
279 4 * pmData->pathData[pathID].rttvar;
280 pmData->pathData[pathID].rto = max(min((unsigned int)pmData->pathData[pathID].rto, (unsigned int)pmData->rto_max), (unsigned int)pmData->rto_min);
281 }
282 event_logiii(INTERNAL_EVENT_0,
283 "handleChunksAcked: RTO update done: RTTVAR: %u msecs, SRTT: %u msecs, RTO: %u msecs",
284 pmData->pathData[pathID].rttvar,
285 pmData->pathData[pathID].srtt, pmData->pathData[pathID].rto);
286 } else {
287 event_log(INTERNAL_EVENT_0, "handleChunksAcked: chunks acked without RTO-update");
288 }
289
290 /* reset counters */
291 pmData->pathData[pathID].pathRetranscount = 0;
292 pmData->peerRetranscount = 0;
293 } /* end: handleChunksAcked */
294
295
296
297 /*----------------- Functions to answer peer HB requests -----------------------------------------*/
298
299 /**
300 pm_heartbeat is called when a heartbeat was received from the peer.
301 This function just takes that chunk, and sends it back.
302 @param heartbeatChunk pointer to the heartbeat chunk
303 @param source_address address we received the HB chunk from (and where it is echoed)
304 */
pm_heartbeat(SCTP_heartbeat * heartbeatChunk,unsigned int source_address)305 void pm_heartbeat(SCTP_heartbeat * heartbeatChunk, unsigned int source_address)
306 {
307 heartbeatChunk->chunk_header.chunk_id = CHUNK_HBACK;
308
309 bu_put_Ctrl_Chunk((SCTP_simple_chunk *) heartbeatChunk, &source_address);
310 bu_sendAllChunks(&source_address);
311 } /* end: pm_heartbeat */
312
313
314
315 /*------------------- Signals --------------------------------------------------------------------*/
316
317 /*------------------- Signals from the Unix-Interface --------------------------------------------*/
318
319 /**
320 pm_heartbeatTimer is called by the adaption-layer when the heartbeat timer expires.
321 It may set the path to inactive, or restart timer, or even cause COMM LOST
322 As all timer callbacks, it takes three arguments (two pointers to necessary data)
323 @param timerID ID of the HB timer that expired.
324 @param associationIDvoid pointer to the association-ID
325 @param pathIDvoid pointer to the path-ID
326 */
pm_heartbeatTimer(TimerID timerID,void * associationIDvoid,void * pathIDvoid)327 void pm_heartbeatTimer(TimerID timerID, void *associationIDvoid, void *pathIDvoid)
328 {
329 unsigned int associationID;
330 unsigned int pathID;
331 ChunkID heartbeatCID;
332 gboolean removed_association = FALSE;
333
334 associationID = *((unsigned int *) associationIDvoid);
335 pathID = *((unsigned int *) pathIDvoid);
336 if (mdi_setAssociationData(associationID)) {
337 /* error log: expired timer refers to a non existent association. */
338 error_logi(ERROR_MAJOR,
339 "init timer expired association %08u does not exist", associationID);
340 return;
341 }
342 pmData = (PathmanData *) mdi_readPathMan();
343 if (pmData == NULL) {
344 error_log(ERROR_MAJOR, "pm_heartbeatTimer: mdi_readPathMan failed");
345 mdi_clearAssociationData();
346 return;
347 }
348 if (!(pathID >= 0 && pathID < (unsigned int)pmData->numberOfPaths)) {
349 error_logi(ERROR_MAJOR, "pm_heartbeatTimer: invalid path ID %d", pathID);
350 mdi_clearAssociationData();
351 return;
352 }
353 event_logi(INTERNAL_EVENT_0, "Heartbeat timer expired for path %u", pathID);
354
355 if (pmData->pathData[pathID].heartbeatSent && !pmData->pathData[pathID].heartbeatAcked) {
356 /* Heartbeat has been sent and not acknowledged: handle as retransmission */
357 if (pmData->pathData[pathID].state == PM_ACTIVE) {
358 /* Handling of unacked heartbeats is the same as that of unacked data chunks.
359 The state after calling pm_chunksRetransmitted may have changed to inactive. */
360 removed_association = handleChunksRetransmitted((short)pathID);
361 if (removed_association)
362 event_logi(INTERNAL_EVENT_0, "Association was removed by handleChunksRetransmitted(%u)!!!!",pathID);
363 } else if (pmData->pathData[pathID].state == PM_INACTIVE) {
364 /* path already inactive, dont increase counter etc. */
365 ;
366 }
367
368 if (!removed_association) {
369 if (!pmData->pathData[pathID].timerBackoff) {
370 /* Timer backoff */
371 pmData->pathData[pathID].rto = min(2 * pmData->pathData[pathID].rto, (unsigned int)pmData->rto_max);
372 event_logii(VERBOSE, "Backing off timer : Path %d, RTO= %u", pathID,pmData->pathData[pathID].rto);
373 }
374 }
375 }
376
377 if (!removed_association &&
378 !pmData->pathData[pathID].chunksAcked &&
379 pmData->pathData[pathID].heartbeatEnabled &&
380 !pmData->pathData[pathID].chunksSent) {
381 /* Remark: If commLost is detected in handleChunksRetransmitted, the current association
382 is marked for deletetion. Doing so, all timers are stop. The HB-timers are
383 stopped by calling pm_disableHB in mdi_deleteCurrentAssociation. This is why
384 heartBeatEnabled is checked above.
385 */
386 /* send heartbeat if no chunks have been acked in the last HB-intervall (path is idle). */
387 event_log(VERBOSE, "--------------> Sending HB");
388 heartbeatCID = ch_makeHeartbeat(pm_getTime(), pathID);
389 bu_put_Ctrl_Chunk(ch_chunkString(heartbeatCID), &pathID);
390 bu_sendAllChunks(&pathID);
391 ch_deleteChunk(heartbeatCID);
392 pmData->pathData[pathID].heartbeatSent = TRUE;
393 } else if (!removed_association) {
394 pmData->pathData[pathID].heartbeatSent = FALSE;
395 }
396
397 if (!removed_association) {
398 if (pmData->pathData[pathID].heartbeatEnabled) {
399 /* heartbeat could have been disabled when the association went down after commLost
400 detected in handleChunksRetransmitted */
401 pmData->pathData[pathID].hearbeatTimer =
402 adl_startTimer(pmData->pathData[pathID].heartbeatIntervall +
403 pmData->pathData[pathID].rto,
404 &pm_heartbeatTimer,
405 TIMER_TYPE_HEARTBEAT,
406 (void *) &pmData->associationID,
407 (void *) &pmData->pathData[pathID].pathID);
408
409 /* reset this flag, so we can check, whether the path was idle */
410 pmData->pathData[pathID].chunksSent = FALSE;
411
412 event_logiii(INTERNAL_EVENT_0,
413 "Heartbeat timer started with %u msecs for path %u, RTO=%u msecs",
414 (pmData->pathData[pathID].heartbeatIntervall+pmData->pathData[pathID].rto), pathID,
415 pmData->pathData[pathID].rto);
416 }
417 }
418
419 if (!removed_association) {
420 pmData->pathData[pathID].heartbeatAcked = FALSE;
421 pmData->pathData[pathID].timerBackoff = FALSE;
422 pmData->pathData[pathID].chunksAcked = FALSE;
423 }
424 mdi_clearAssociationData();
425 } /* end: pm_heartbeatTimer */
426
427
428 /**
429 * simple function that sends a heartbeat chunk to the indicated address
430 * @param pathID index to the address, where HB is to be sent to
431 */
pm_doHB(gshort pathID)432 int pm_doHB(gshort pathID)
433 {
434 ChunkID heartbeatCID;
435 guint32 pid;
436
437 pmData = (PathmanData *) mdi_readPathMan();
438
439 if (pmData == NULL) {
440 error_log(ERROR_MAJOR, "pm_doHB: mdi_readPathMan failed");
441 return SCTP_MODULE_NOT_FOUND;
442 }
443 if (!pmData->pathData) {
444 error_logi(ERROR_MAJOR, "pm_doHB(%d): Path Data Structures not initialized yet, returning !", pathID);
445 return SCTP_UNSPECIFIED_ERROR;
446 }
447
448 if (!(pathID >= 0 && pathID < pmData->numberOfPaths)) {
449 error_logi(ERROR_MAJOR, "pm_doHB : invalid path ID: %d", pathID);
450 return SCTP_PARAMETER_PROBLEM;
451 }
452 pid = (guint32)pathID;
453 heartbeatCID = ch_makeHeartbeat(pm_getTime(), pathID);
454 bu_put_Ctrl_Chunk(ch_chunkString(heartbeatCID),&pid);
455 bu_sendAllChunks(&pid);
456 ch_deleteChunk(heartbeatCID);
457 pmData->pathData[pathID].heartbeatSent = TRUE;
458
459 return SCTP_SUCCESS;
460 }
461
462
463 /**
464 * pm_heartbeatAck is called when a heartbeat acknowledgement was received from the peer.
465 * checks RTTs, normally resets error counters, may set path back to ACTIVE state
466 * @param heartbeatChunk pointer to the received heartbeat ack chunk
467 */
pm_heartbeatAck(SCTP_heartbeat * heartbeatChunk)468 void pm_heartbeatAck(SCTP_heartbeat * heartbeatChunk)
469 {
470 unsigned int roundtripTime;
471 unsigned int sendingTime;
472 short pathID;
473 ChunkID heartbeatCID;
474 PathmanData *old_pmData = NULL;
475 gboolean hbSignatureOkay = FALSE;
476
477 pmData = (PathmanData *) mdi_readPathMan();
478
479 if (pmData == NULL) {
480 error_log(ERROR_MAJOR, "pm_heartbeatAck: mdi_readPathMan failed");
481 return;
482 }
483 if (!pmData->pathData) {
484 error_log(ERROR_MAJOR, "pm_heartbeatAck: Path Data Structures not initialized yet, returning !");
485 return;
486 }
487
488 heartbeatCID = ch_makeChunk((SCTP_simple_chunk *) heartbeatChunk);
489 pathID = ch_HBpathID(heartbeatCID);
490 sendingTime = ch_HBsendingTime(heartbeatCID);
491 roundtripTime = pm_getTime() - sendingTime;
492 event_logii(INTERNAL_EVENT_0, "HBAck for path %u, RTT = %u msecs", pathID, roundtripTime);
493
494 hbSignatureOkay = ch_verifyHeartbeat(heartbeatCID);
495 event_logi(EXTERNAL_EVENT, "HB Signature is %s", (hbSignatureOkay == TRUE)?"correct":"FALSE");
496
497 if (hbSignatureOkay == FALSE) {
498 error_log(ERROR_FATAL, "pm_heartbeatAck: FALSE SIGNATURE !!!!!!!!!!!!!!!");
499 return;
500 }
501
502 ch_forgetChunk(heartbeatCID);
503
504 if (!(pathID >= 0 && pathID < pmData->numberOfPaths)) {
505 error_logi(ERROR_MAJOR, "pm_heartbeatAck: invalid path ID %d", pathID);
506 return;
507 }
508
509 /* this also resets error counters */
510 handleChunksAcked(pathID, roundtripTime);
511
512 if (pmData->pathData[pathID].state == PM_INACTIVE || pmData->pathData[pathID].state == PM_PATH_UNCONFIRMED) {
513 /* Handling of acked heartbeats is the simular that that of acked data chunks. */
514 /* change to the active state */
515 pmData->pathData[pathID].state = PM_ACTIVE;
516 event_logi(INTERNAL_EVENT_0, "pathID %d changed to ACTIVE", pathID);
517 old_pmData = pmData;
518 mdi_networkStatusChangeNotif(pathID, PM_ACTIVE);
519 pmData = old_pmData;
520
521 /* restart timer with new RTO */
522 sctp_stopTimer(pmData->pathData[pathID].hearbeatTimer);
523 pmData->pathData[pathID].hearbeatTimer =
524 adl_startTimer( (pmData->pathData[pathID].heartbeatIntervall + pmData->pathData[pathID].rto),
525 &pm_heartbeatTimer,
526 TIMER_TYPE_HEARTBEAT,
527 (void *) &pmData->associationID,
528 (void *) &pmData->pathData[pathID].pathID);
529 }
530 pmData->pathData[pathID].heartbeatAcked = TRUE;
531 pmData->pathData[pathID].timerBackoff = FALSE;
532
533 } /* end: pm_heartbeatAck */
534
535
536
537 /*------------------- Signals from SCTP internal modules -----------------------------------------*/
538
539 /**
540 * pm_chunksAcked is called by reliable transfer whenever chunks have been acknowledged.
541 * @param pathID last path-ID where chunks were sent to (and thus probably acked from)
542 * @param newRTT the newly determined RTT in milliseconds, and 0 if retransmitted chunks had been acked
543 */
pm_chunksAcked(short pathID,unsigned int newRTT)544 void pm_chunksAcked(short pathID, unsigned int newRTT)
545 {
546 struct timeval now;
547
548 pmData = (PathmanData *) mdi_readPathMan();
549
550 if (pmData == NULL) {
551 error_log(ERROR_MAJOR, "pm_chunksAcked: mdi_readPathMan failed");
552 return;
553 }
554 if (!pmData->pathData) {
555 error_logii(ERROR_MAJOR, "pm_chunksAcked(%d, %u): Path Data Structures not initialized yet, returning !",
556 pathID, newRTT);
557 return;
558 }
559
560 if (!(pathID >= 0 && pathID < pmData->numberOfPaths)) {
561 error_logi(ERROR_MAJOR, "pm_chunksAcked: invalid path ID: %d", pathID);
562 return;
563 }
564
565 if (newRTT > (unsigned int)pmData->rto_max)
566 error_logi(ERROR_MINOR, "pm_chunksAcked: Warning: RTO > RTO_MAX: %d", newRTT);
567
568 newRTT = min(newRTT, (unsigned int)pmData->rto_max);
569
570 if (pmData->pathData[pathID].state == PM_ACTIVE) {
571 /* Update RTO only if is the first data chunk acknowldged in this RTT intervall. */
572 adl_gettime(&now);
573 if (timercmp(&now, &(pmData->pathData[pathID].rto_update), < )) {
574 event_logiiii(VERBOSE, "pm_chunksAcked: now %lu sec, %lu usec - no update before %lu sec, %lu usec",
575 now.tv_sec, now.tv_usec,
576 pmData->pathData[pathID].rto_update.tv_sec,
577 pmData->pathData[pathID].rto_update.tv_usec);
578 newRTT = 0;
579 } else {
580 if (newRTT != 0) {
581 /* only if actually new valid RTT measurement is taking place, do update the time */
582 pmData->pathData[pathID].rto_update = now;
583 adl_add_msecs_totime(&(pmData->pathData[pathID].rto_update), pmData->pathData[pathID].srtt);
584 }
585 }
586 handleChunksAcked(pathID, newRTT);
587 pmData->pathData[pathID].chunksAcked = TRUE;
588 } else {
589 /* FIX :::::::
590 we got an ACK possibly from on an inactive path */
591 /* immediately send out a Heartbeat on that path, then when we get */
592 /* a HB-ACK, we can set the path back to ACTIVE */
593 /* when original newRTT is 0 then we got a RTX-SACK, else if we are */
594 /* inactive, get ACTIVE */
595 /* Nay, nay nay ! stale acknowledgement, silently discard */
596 return;
597 }
598 } /* end: pm_chunksAcked */
599
600
601 /**
602 * helper function, that simply sets the chunksSent flag of this path management instance to TRUE
603 * @param pathID index of the address, where flag is set
604 */
pm_chunksSentOn(short pathID)605 void pm_chunksSentOn(short pathID)
606 {
607 pmData = (PathmanData *) mdi_readPathMan();
608
609 if (pmData == NULL) {
610 error_log(ERROR_MAJOR, "pm_chunksSentOn: mdi_readPathMan failed");
611 return;
612 }
613 if (pmData->pathData == NULL) {
614 error_logi(ERROR_MAJOR, "pm_chunksSentOn(%d): Path Data Structures not initialized yet, returning !", pathID);
615 return;
616 }
617
618 if (!(pathID >= 0 && pathID < pmData->numberOfPaths)) {
619 error_logi(ERROR_MAJOR, "pm_chunksSentOn: invalid path ID: %d", pathID);
620 return;
621 }
622 event_logi(VERBOSE, "Calling pm_chunksSentOn(%d)", pathID);
623 pmData->pathData[pathID].chunksSent = TRUE;
624
625 }
626
627
628 /**
629 pm_chunksRetransmitted is called by reliable transfer whenever chunks have been retransmitted.
630 @param pathID address index, where timeout has occurred (i.e. which caused retransmission)
631 */
pm_chunksRetransmitted(short pathID)632 gboolean pm_chunksRetransmitted(short pathID)
633 {
634 gboolean removed_association = FALSE;
635 pmData = (PathmanData *) mdi_readPathMan();
636
637 if (pmData == NULL) {
638 error_log(ERROR_MAJOR, "pm_chunksRetransmitted: mdi_readPathMan failed");
639 return removed_association;
640 }
641 if (pmData->pathData == NULL) {
642 error_logi(ERROR_MAJOR, "pm_chunksRetransmitted(%d): Path Data Structures not initialized yet, returning !", pathID);
643 return removed_association;
644 }
645
646 if (!(pathID >= 0 && pathID < pmData->numberOfPaths)) {
647 error_logi(ERROR_MAJOR, "pm_chunksRetransmitted: invalid path ID %d", pathID);
648 return removed_association;
649 }
650
651 if (pmData->pathData[pathID].state == PM_INACTIVE) {
652 /* stale acknowledgement, silently discard */
653 error_logi(ERROR_MINOR,
654 "pm_chunksRetransmitted: retransmissions over inactive path %d", pathID);
655 return removed_association;
656 } else {
657 removed_association = handleChunksRetransmitted(pathID);
658 }
659 return removed_association;
660 } /* end: pm_chunksRetransmitted */
661
662
663
664 /**
665 pm_rto_backoff is called by reliable transfer when the T3 retransmission timer expires.
666 Each call of this function may double the RTO (timer back off).
667 @param pathID index of the address where the timeout occurred
668 */
pm_rto_backoff(short pathID)669 void pm_rto_backoff(short pathID)
670 {
671 pmData = (PathmanData *) mdi_readPathMan();
672
673 if (pmData == NULL) {
674 error_log(ERROR_MAJOR, "pm_rto_backoff: mdi_readPathMan failed");
675 return;
676 }
677 if (pmData->pathData == NULL) {
678 error_logi(ERROR_MAJOR, "pm_rto_backoff(%d): Path Data Structures not initialized yet, returning !", pathID);
679 return;
680 }
681
682 if (!(pathID >= 0 && pathID < pmData->numberOfPaths)) {
683 error_logi(ERROR_MAJOR, "pm_rto_backoff: invalid path ID %d", pathID);
684 return;
685 }
686
687 if (pmData->pathData[pathID].state == PM_ACTIVE) {
688 /* Backoff timer anyway ! */
689 pmData->pathData[pathID].rto = min(2 * pmData->pathData[pathID].rto, (unsigned int)pmData->rto_max);
690
691 event_logii(INTERNAL_EVENT_0,
692 "pm_rto_backoff called for path %u: new RTO =%d",
693 pathID, pmData->pathData[pathID].rto);
694 pmData->pathData[pathID].timerBackoff = TRUE;
695 } else {
696 /* stale acknowledgement, silently discard */
697 error_logi(ERROR_MINOR, "pm_rto_backoff: timer backoff for an inactive path %d", pathID);
698 }
699 } /* end pm_rto_backoff */
700
701
702
703 /*------------------- Functions called by the ULP ------------------------------------------------*/
704
705 /**
706 pm_enableHB is called when ULP wants to enable heartbeat.
707 @param pathID index of address, where we sent the HBs to
708 @param hearbeatIntervall time in msecs, that is to be added to the RTT, before sending HB
709 @return error code, 0 for success, 1 for error (i.e. address index too large)
710 */
pm_enableHB(short pathID,unsigned int hearbeatIntervall)711 int pm_enableHB(short pathID, unsigned int hearbeatIntervall)
712 {
713 pmData = (PathmanData *) mdi_readPathMan();
714
715 if (pmData == NULL) {
716 error_log(ERROR_MAJOR, "pm_enableHB: mdi_readPathMan failed");
717 return SCTP_MODULE_NOT_FOUND;
718 }
719 if (pmData->pathData == NULL) {
720 error_logii(ERROR_MAJOR, "pm_enableHB(%d,%u): Path Data Structures not initialized yet, returning !",
721 pathID, hearbeatIntervall);
722 return SCTP_MODULE_NOT_FOUND;
723 }
724
725 if (!(pathID >= 0 && pathID < pmData->numberOfPaths)) {
726 error_logi(ERROR_MAJOR, "pm_enableHB: invalid path ID %d", pathID);
727 return SCTP_PARAMETER_PROBLEM;
728 }
729
730 pmData->pathData[pathID].heartbeatIntervall = hearbeatIntervall;
731
732 event_logii(VERBOSE, "pm_enableHB(%d): chose interval %u msecs",pathID,hearbeatIntervall);
733
734
735 if (!pmData->pathData[pathID].heartbeatEnabled) {
736 pmData->pathData[pathID].heartbeatEnabled = TRUE;
737
738 pmData->pathData[pathID].firstRTO = TRUE;
739 pmData->pathData[pathID].pathRetranscount = 0;
740 pmData->peerRetranscount = 0;
741
742 pmData->pathData[pathID].heartbeatSent = FALSE;
743 pmData->pathData[pathID].heartbeatAcked = FALSE;
744 pmData->pathData[pathID].timerBackoff = FALSE;
745 pmData->pathData[pathID].chunksAcked = FALSE;
746 pmData->pathData[pathID].chunksSent = FALSE;
747
748 pmData->pathData[pathID].rto = pmData->rto_initial;
749 pmData->pathData[pathID].srtt = pmData->rto_initial;
750 pmData->pathData[pathID].rttvar = 0;
751 pmData->pathData[pathID].hearbeatTimer =
752 adl_startTimer((pmData->pathData[pathID].heartbeatIntervall+pmData->pathData[pathID].rto),
753 &pm_heartbeatTimer,
754 TIMER_TYPE_HEARTBEAT,
755 (void *) &pmData->associationID,
756 (void *) &pmData->pathData[pathID].pathID);
757 event_logi(VERBOSE,
758 "pm_enableHB: started timer - going off in %u msecs",
759 pmData->pathData[pathID].heartbeatIntervall+pmData->pathData[pathID].rto);
760 } else {
761 pmData->pathData[pathID].hearbeatTimer =
762 adl_restartTimer(pmData->pathData[pathID].hearbeatTimer,
763 (pmData->pathData[pathID].heartbeatIntervall+pmData->pathData[pathID].rto));
764 pmData->pathData[pathID].chunksSent = FALSE;
765 event_logi(VERBOSE,
766 "pm_enableHB: restarted timer - going off in %u msecs",
767 pmData->pathData[pathID].heartbeatIntervall+pmData->pathData[pathID].rto);
768
769 }
770 return SCTP_SUCCESS;
771 } /* end: pm_enableHB */
772
773
774 /**
775 pm_disableAllHB is usually called on shutdown to disable all heartbeats.
776 */
pm_disableAllHB(void)777 void pm_disableAllHB(void)
778 {
779 short pathID;
780
781 pmData = (PathmanData *) mdi_readPathMan();
782
783 if (pmData == NULL) {
784 error_log(ERROR_MAJOR, "pm_disableAllHB: mdi_readPathMan failed");
785 return;
786 }
787
788 if (pmData->pathData == NULL) {
789 error_log(ERROR_MAJOR, "pm_disableAllHB: no paths set");
790 return;
791 }
792
793 for (pathID = 0; pathID < pmData->numberOfPaths; pathID++) {
794 if (pmData->pathData[pathID].heartbeatEnabled) {
795 sctp_stopTimer(pmData->pathData[pathID].hearbeatTimer);
796 pmData->pathData[pathID].hearbeatTimer = 0;
797 pmData->pathData[pathID].heartbeatEnabled = FALSE;
798 event_logi(INTERNAL_EVENT_0, "pm_disableAllHB: path %d disabled", (unsigned int) pathID);
799 }
800 }
801 } /* end: pm_disableAllHB */
802
803
804
805 /**
806 pm_disableHB is called to disable heartbeat for one specific path id.
807 @param pathID index of address, where HBs should not be sent anymore
808 @return error code: 0 for success, 1 for error (i.e. pathID too large)
809 */
pm_disableHB(short pathID)810 int pm_disableHB(short pathID)
811 {
812 pmData = (PathmanData *) mdi_readPathMan();
813
814 if (pmData == NULL) {
815 error_log(ERROR_MAJOR, "pm_disableHB: mdi_readPathMan failed");
816 return SCTP_MODULE_NOT_FOUND;
817 }
818
819 if (pmData->pathData == NULL) {
820 error_logi(ERROR_MAJOR, "pm_disableHB(%d): no paths set", pathID);
821 return SCTP_MODULE_NOT_FOUND;
822 }
823
824 if (!(pathID >= 0 && pathID < pmData->numberOfPaths)) {
825 error_logi(ERROR_MAJOR, "pm_disableHB: invalid path ID %d", pathID);
826 return SCTP_PARAMETER_PROBLEM;
827 }
828
829 if (pmData->pathData[pathID].heartbeatEnabled) {
830 sctp_stopTimer(pmData->pathData[pathID].hearbeatTimer);
831 pmData->pathData[pathID].hearbeatTimer = 0;
832 pmData->pathData[pathID].heartbeatEnabled = FALSE;
833 event_logi(INTERNAL_EVENT_0, "pm_disableHB: path %d disabled", (unsigned int) pathID);
834 }
835 return SCTP_SUCCESS;
836 } /* end: pm_disableHB */
837
838
839
840 /**
841 pm_setPrimaryPath sets the primary path.
842 @param pathID index of the address that is to become primary path
843 @return 0 if okay, else 1 if there was some error
844 */
pm_setPrimaryPath(short pathID)845 short pm_setPrimaryPath(short pathID)
846 {
847 pmData = (PathmanData *) mdi_readPathMan();
848
849 if (pmData == NULL) {
850 error_log(ERROR_MAJOR, "pm_setPrimaryPath: mdi_readPathMan failed");
851 return SCTP_MODULE_NOT_FOUND;
852 }
853 if (pmData->pathData == NULL) {
854 error_logi(ERROR_MAJOR, "pm_setPrimaryPath(%d): no paths set", pathID);
855 return SCTP_UNSPECIFIED_ERROR;
856 }
857
858 if (pathID >= 0 && pathID < pmData->numberOfPaths) {
859 if (pmData->pathData[pathID].state == PM_ACTIVE) {
860 pmData->primaryPath = pathID;
861 pmData->pathData[pathID].chunksSent = FALSE;
862 event_logi(INTERNAL_EVENT_0, "pm_setPrimaryPath: path %d is primary", pathID);
863 return SCTP_SUCCESS;
864 } else {
865 event_logi(INTERNAL_EVENT_0, "pm_setPrimaryPath: path %d not ACTIVE", pathID);
866 return SCTP_SPECIFIC_FUNCTION_ERROR;
867 }
868 } else {
869 error_logi(ERROR_MAJOR, "pm_setPrimaryPath: invalid path ID %d", pathID);
870 return SCTP_PARAMETER_PROBLEM;
871 }
872 } /* end: pm_setPrimaryPath */
873
874
875
876 /*------------------- Functions called by ULP to read pathmanagement state info ------------------*/
877
878 /**
879 * pm_readRTO returns the currently set RTO value in msecs for a certain path.
880 * @param pathID index of the address/path
881 * @return path's current RTO
882 */
pm_readRTO(short pathID)883 unsigned int pm_readRTO(short pathID)
884 {
885 pmData = (PathmanData *) mdi_readPathMan();
886
887 if (pmData == NULL) {
888 error_logi(ERROR_MAJOR, "pm_readRTO(%d): mdi_readPathMan failed", pathID);
889 return 0;
890 }
891
892 if (pathID >= 0 && pathID < pmData->numberOfPaths) {
893 if (pmData->pathData == NULL)
894 return pmData->rto_initial;
895 else
896 return pmData->pathData[pathID].rto;
897 } else {
898 error_logi(ERROR_MAJOR, "pm_readRTO(%d): invalid path ID", pathID);
899 return 0;
900 }
901 } /* end: pm_readRTO */
902
903 /**
904 pm_readRttVar returns the currently measured value for Round-Trip
905 time variation of a certain path.
906 @param pathID index of the address/path
907 @return path's current RTTvar in msecs, 0 if it's not set, 0xffffffff on error
908 */
pm_readRttVar(short pathID)909 unsigned int pm_readRttVar(short pathID)
910 {
911 pmData = (PathmanData *) mdi_readPathMan();
912
913 if (pmData == NULL) {
914 error_logi(ERROR_MAJOR, "pm_readRttVar(%d): mdi_readPathMan failed", pathID);
915 return 0xffffffff;
916 }
917 if (!pmData->pathData) {
918 error_logi(ERROR_MAJOR, "pm_readRttVAr(%d): Path Data Structures not initialized yet, returning !", pathID);
919 return 0;
920 }
921
922 if (pathID >= 0 && pathID < pmData->numberOfPaths)
923 return pmData->pathData[pathID].rttvar;
924 else {
925 error_logi(ERROR_MAJOR, "pm_readRttVar(%d): invalid path ID", pathID);
926 return 0xffffffff;
927 }
928 } /* end: pm_readRttVar */
929
930
931 /**
932 pm_readSRTT returns the currently set SRTT value for a certain path.
933 @param pathID index of the address/path
934 @return path's current smoothed round trip time, or 0xffffffff on error
935 */
pm_readSRTT(short pathID)936 unsigned int pm_readSRTT(short pathID)
937 {
938 pmData = (PathmanData *) mdi_readPathMan();
939
940 if (pmData == NULL) {
941 error_log(ERROR_MAJOR, "pm_readSRTT: mdi_readPathMan failed");
942 return 0xffffffff;
943 }
944
945 if (!pmData->pathData) {
946 event_logi(VERBOSE, "pm_readSRTT(%d): Path Data Structures not initialized, return RTO_INITIAL !", pathID);
947 return pmData->rto_initial;
948 }
949
950 if (pathID >= 0 && pathID < pmData->numberOfPaths)
951 return pmData->pathData[pathID].srtt;
952 else {
953 error_logi(ERROR_MAJOR, "pm_readSRTT: invalid path ID %d", pathID);
954 return 0xffffffff;
955 }
956 } /* end: pm_readSRTT */
957
958
959 /**
960 pm_readState returns the current state of the path.
961 @param pathID index of the questioned address
962 @return state of path (active/inactive)
963 */
pm_readState(short pathID)964 short pm_readState(short pathID)
965 {
966 pmData = (PathmanData *) mdi_readPathMan();
967
968 if (pmData == NULL) {
969 error_log(ERROR_MAJOR, "pm_readState: mdi_readPathMan failed");
970 return -1;
971 }
972 if (pmData->pathData == NULL) {
973 error_log(ERROR_MAJOR, "pm_readState: pathData==NULL failed");
974 return -1;
975 }
976
977 if (pathID >= 0 && pathID < pmData->numberOfPaths) {
978 if (pmData->pathData == NULL)
979 return PM_INACTIVE;
980 else
981 return pmData->pathData[pathID].state;
982 } else {
983 error_logi(ERROR_MAJOR, "pm_readState: invalid path ID %d", pathID);
984 return -1;
985 }
986 } /* end: pm_readState */
987
988
989
990 /**
991 pm_readPrimaryPath is used to determine the current primary path
992 @return index to the primary path
993 */
pm_readPrimaryPath(void)994 unsigned short pm_readPrimaryPath(void)
995 {
996 pmData = (PathmanData *) mdi_readPathMan();
997
998 if (pmData == NULL) {
999 event_log(ERROR_MAJOR, "pm_readPrimaryPath: pathmanagement-instance does not exist");
1000 return 0xFFFF;
1001 } else {
1002 return pmData->primaryPath;
1003 }
1004 } /* end: pm_readPrimaryPath */
1005
1006 /**
1007 pm_getMaxPathRetransmisions is used to get the current maxPathRetransmissions
1008 parameter value
1009 @return maxPathRetransmissions of the current instance
1010 */
pm_getMaxPathRetransmisions(void)1011 int pm_getMaxPathRetransmisions(void)
1012 {
1013 pmData = (PathmanData *) mdi_readPathMan();
1014
1015 if (pmData == NULL) {
1016 event_log(ERROR_MAJOR, "pm_getMaxPathRetransmisions(): pathmanagement-instance does not exist");
1017 return -1;
1018 } else {
1019 return pmData->maxPathRetransmissions;
1020 }
1021 } /* end: pm_getMaxPathRetransmisions(void) */
1022
1023 /**
1024 pm_setMaxPathRetransmisions is used to get the current maxPathRetransmissions
1025 parameter value
1026 @param new_max new value for maxPathRetransmissions parameter
1027 @return 0 for success, -1 for error
1028 */
pm_setMaxPathRetransmisions(int new_max)1029 int pm_setMaxPathRetransmisions(int new_max)
1030 {
1031 pmData = (PathmanData *) mdi_readPathMan();
1032
1033 if (pmData == NULL) {
1034 event_log(ERROR_MAJOR, "pm_setMaxPathRetransmisions(): pathmanagement-instance does not exist");
1035 return -1;
1036 } else {
1037 pmData->maxPathRetransmissions = new_max;
1038 }
1039 return 0;
1040 } /* end: pm_setMaxPathRetransmisions(void) */
1041
1042 /**
1043 pm_getRtoInitial is used to get the current rto_initial parameter value
1044 @return rto_initial on success, -1 for error
1045 */
pm_getRtoInitial(void)1046 int pm_getRtoInitial(void)
1047 {
1048 pmData = (PathmanData *) mdi_readPathMan();
1049
1050 if (pmData == NULL) {
1051 event_log(ERROR_MAJOR, "pm_getRtoInitial(): pathmanagement-instance does not exist");
1052 return -1;
1053 }
1054 return pmData->rto_initial;
1055 } /* end: pm_getRtoInitial() */
1056
1057 /**
1058 pm_getRtoInitial is used to get the current rto_initial parameter value
1059 @return 0 on success, -1 for error
1060 */
pm_setRtoInitial(int new_rto_initial)1061 int pm_setRtoInitial(int new_rto_initial)
1062 {
1063 pmData = (PathmanData *) mdi_readPathMan();
1064
1065 if (pmData == NULL) {
1066 event_log(ERROR_MAJOR, "pm_setRtoInitial(): pathmanagement-instance does not exist");
1067 return -1;
1068 }
1069 pmData->rto_initial = new_rto_initial;
1070 return 0;
1071 } /* end: pm_setRtoInitial() */
1072
1073
pm_setRtoMin(int new_rto_min)1074 int pm_setRtoMin(int new_rto_min)
1075 {
1076 pmData = (PathmanData *) mdi_readPathMan();
1077
1078 if (pmData == NULL) {
1079 event_log(ERROR_MAJOR, "pm_setRtoMin(): pathmanagement-instance does not exist");
1080 return -1;
1081 }
1082 pmData->rto_min = new_rto_min;
1083 return 0;
1084 } /* end: pm_setRtoMin() */
1085
pm_getRtoMin(void)1086 int pm_getRtoMin(void)
1087 {
1088 pmData = (PathmanData *) mdi_readPathMan();
1089
1090 if (pmData == NULL) {
1091 event_log(ERROR_MAJOR, "pm_getRtoMin(): pathmanagement-instance does not exist");
1092 return -1;
1093 }
1094 return pmData->rto_min;
1095 } /* end: pm_getRtoMin() */
1096
pm_setRtoMax(int new_rto_max)1097 int pm_setRtoMax(int new_rto_max)
1098 {
1099 pmData = (PathmanData *) mdi_readPathMan();
1100
1101 if (pmData == NULL) {
1102 event_log(ERROR_MAJOR, "pm_setRtoMax(): pathmanagement-instance does not exist");
1103 return -1;
1104 }
1105 pmData->rto_max = new_rto_max;
1106 return 0;
1107 } /* end: pm_setRtoMax() */
1108
pm_getRtoMax(void)1109 int pm_getRtoMax(void)
1110 {
1111 pmData = (PathmanData *) mdi_readPathMan();
1112
1113 if (pmData == NULL) {
1114 event_log(ERROR_MAJOR, "pm_getRtoMax(): pathmanagement-instance does not exist");
1115 return 60000;
1116 }
1117 return pmData->rto_max;
1118 } /* end: pm_getRtoMax() */
1119
1120
pm_setHBInterval(unsigned int new_interval)1121 int pm_setHBInterval(unsigned int new_interval)
1122 {
1123 int count;
1124
1125 pmData = (PathmanData *) mdi_readPathMan();
1126
1127 if (pmData == NULL) {
1128 event_log(ERROR_MAJOR, "pm_setHBInterval(): pathmanagement-instance does not exist");
1129 return -1;
1130 }
1131 if (pmData->pathData == NULL) {
1132 event_log(ERROR_MAJOR, "pm_setHBInterval(): path structures do not exist");
1133 return -1;
1134 }
1135 for (count = 0; count < pmData->numberOfPaths; count++) {
1136 pmData->pathData[count].heartbeatIntervall = new_interval;
1137 }
1138 return 0;
1139 }
1140
pm_getHBInterval(short pathID,unsigned int * current_interval)1141 int pm_getHBInterval(short pathID, unsigned int* current_interval)
1142 {
1143 pmData = (PathmanData *) mdi_readPathMan();
1144
1145 if (pmData == NULL) {
1146 event_log(ERROR_MAJOR, "pm_getHBInterval(): pathmanagement-instance does not exist");
1147 return -1;
1148 }
1149 if (pmData->pathData == NULL) {
1150 event_log(ERROR_MAJOR, "pm_getHBInterval(): path structures do not exist");
1151 return -1;
1152 }
1153 if (pathID >= 0 && pathID < pmData->numberOfPaths) {
1154 *current_interval = pmData->pathData[pathID].heartbeatIntervall;
1155 } else {
1156 error_logi(ERROR_MAJOR, "pm_getHBInterval: invalid path ID %d", pathID);
1157 *current_interval = 0;
1158 return -1;
1159 }
1160 return 0;
1161 }
1162
1163 /*------------------- Functions called to create, init and delete pathman-instances --------------*/
1164
1165 /**
1166 pm_setPaths modufies number of paths and sets the primary path.
1167 This is required for association setup, where the local ULP provides
1168 only one path and the peer may provide additional paths.
1169 This function also initializes the path structures and starts the heartbeat timer for each
1170 path. For this reason it is recommended to call this function when communication up is called.
1171 @params noOfPaths number of paths to the destination endpoint
1172 @param primaryPathID index to the address that is to be used as primary address
1173 */
pm_setPaths(short noOfPaths,short primaryPathID)1174 short pm_setPaths(short noOfPaths, short primaryPathID)
1175 {
1176 PathmanData *pmData;
1177 int b,i,j = 0;
1178
1179 pmData = (PathmanData *) mdi_readPathMan();
1180
1181 if (pmData == NULL) {
1182 error_log(ERROR_MAJOR, "pm_setPrimaryPath: mdi_readPathMan failed");
1183 return 1;
1184 }
1185
1186 pmData->pathData = (PathData *) malloc(noOfPaths * sizeof(PathData));
1187
1188 if (!pmData->pathData)
1189 error_log(ERROR_FATAL, "pm_setPaths: out of memory");
1190
1191 if (primaryPathID >= 0 && primaryPathID < noOfPaths) {
1192 pmData->primaryPath = primaryPathID;
1193 pmData->numberOfPaths = noOfPaths;
1194 pmData->peerRetranscount = 0;
1195
1196
1197 for (i = 0; i < noOfPaths; i++) {
1198 pmData->pathData[i].state = PM_PATH_UNCONFIRMED;
1199 if (i == primaryPathID) {
1200 pmData->pathData[i].state = PM_ACTIVE;
1201 }
1202 pmData->pathData[i].heartbeatEnabled = TRUE;
1203 pmData->pathData[i].firstRTO = TRUE;
1204 pmData->pathData[i].pathRetranscount = 0;
1205 pmData->pathData[i].rto = pmData->rto_initial;
1206 pmData->pathData[i].srtt = pmData->rto_initial;
1207 pmData->pathData[i].rttvar = 0;
1208
1209 pmData->pathData[i].heartbeatSent = FALSE;
1210 pmData->pathData[i].heartbeatAcked = FALSE;
1211 pmData->pathData[i].timerBackoff = FALSE;
1212 pmData->pathData[i].chunksAcked = FALSE;
1213 pmData->pathData[i].chunksSent = FALSE;
1214
1215 pmData->pathData[i].heartbeatIntervall = PM_INITIAL_HB_INTERVAL;
1216 pmData->pathData[i].hearbeatTimer = 0;
1217 pmData->pathData[i].pathID = i;
1218
1219 b = mdi_getDefaultMaxBurst();
1220
1221 if (i != primaryPathID) {
1222 j++;
1223 if (j < b) {
1224 pmData->pathData[i].hearbeatTimer =
1225 adl_startTimer(j, /* send HB quickly on first usually four unconfirmed paths */
1226 &pm_heartbeatTimer,
1227 TIMER_TYPE_HEARTBEAT,
1228 (void *) &pmData->associationID,
1229 (void *) &pmData->pathData[i].pathID);
1230 } else {
1231 pmData->pathData[i].hearbeatTimer =
1232 adl_startTimer(pmData->pathData[i].rto * (j-b), /* send HB more slowly on other paths */
1233 &pm_heartbeatTimer,
1234 TIMER_TYPE_HEARTBEAT,
1235 (void *) &pmData->associationID,
1236 (void *) &pmData->pathData[i].pathID);
1237 }
1238 } else {
1239 pmData->pathData[i].hearbeatTimer =
1240 adl_startTimer(pmData->pathData[i].heartbeatIntervall+pmData->pathData[i].rto,
1241 &pm_heartbeatTimer,
1242 TIMER_TYPE_HEARTBEAT,
1243 (void *) &pmData->associationID,
1244 (void *) &pmData->pathData[i].pathID);
1245 }
1246 /* after RTO we can do next RTO update */
1247 adl_gettime(&(pmData->pathData[i].rto_update));
1248
1249 }
1250
1251 event_log(INTERNAL_EVENT_0, "pm_setPaths called ");
1252
1253 return 0;
1254 } else {
1255 error_log(ERROR_MAJOR, "pm_setPaths: invalid path ID");
1256 return 1;
1257 }
1258 } /* end: pm_setPaths */
1259
1260
1261
1262 /**
1263 * pm_newPathman creates a new instance of pathmanagement. There is one pathmanagement instance
1264 * per association. WATCH IT : this needs to be fixed ! pathData is NULL, but may accidentally be
1265 * referenced !
1266 * @param numberOfPaths number of paths of the association
1267 * @param primaryPath initial primary path
1268 * @param sctpInstance pointer to the SCTP instance
1269 * @return pointer to the newly created path management instance !
1270 */
pm_newPathman(short numberOfPaths,short primaryPath,void * sctpInstance)1271 void *pm_newPathman(short numberOfPaths, short primaryPath, void* sctpInstance)
1272 {
1273 PathmanData *pmData;
1274
1275 pmData = (PathmanData *) malloc(sizeof(PathmanData));
1276 if (!pmData)
1277 error_log(ERROR_FATAL, "pm_setPaths: out of memory");
1278 pmData->pathData = NULL;
1279
1280 pmData->primaryPath = primaryPath;
1281 pmData->numberOfPaths = numberOfPaths;
1282 pmData->associationID = mdi_readAssociationID();
1283 pmData->maxPathRetransmissions = mdi_getDefaultPathMaxRetransmits(sctpInstance);
1284 pmData->rto_initial = mdi_getDefaultRtoInitial(sctpInstance);
1285 pmData->rto_min = mdi_getDefaultRtoMin(sctpInstance);
1286 pmData->rto_max = mdi_getDefaultRtoMax(sctpInstance);
1287 return pmData;
1288 } /* end: pm_newPathman */
1289
1290
1291
1292 /**
1293 * Deletes the instance pointed to by pathmanPtr.
1294 * @param pathmanPtr pointer to the instance that is to be deleted
1295 */
pm_deletePathman(void * pathmanPtr)1296 void pm_deletePathman(void *pathmanPtr)
1297 {
1298 int i;
1299 PathmanData *pmData;
1300
1301 event_log(INTERNAL_EVENT_0, "deleting pathmanagement");
1302
1303 pmData = (PathmanData *) pathmanPtr;
1304
1305 if (pmData != NULL && pmData->pathData != NULL) {
1306 for (i = 0; i < pmData->numberOfPaths; i++) {
1307 if (pmData->pathData[i].hearbeatTimer != 0) {
1308 adl_stopTimer(pmData->pathData[i].hearbeatTimer);
1309 pmData->pathData[i].hearbeatTimer = 0;
1310 }
1311 }
1312 }
1313
1314 event_log(VVERBOSE, "stopped timers");
1315
1316 free(pmData->pathData);
1317 free(pmData);
1318 } /* end: pm_deletePathman */
1319