00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #ifndef lint
00044 static const char rcsid[] =
00045 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/sctp/sctp-multipleFastRtx.cc,v 1.3 2005/10/07 05:58:29 tomh Exp $ (UD/PEL)";
00046 #endif
00047
00048 #include "ip.h"
00049 #include "sctp-multipleFastRtx.h"
00050 #include "flags.h"
00051 #include "random.h"
00052 #include "template.h"
00053
00054 #include "sctpDebug.h"
00055
00056 #ifdef DMALLOC
00057 #include "dmalloc.h"
00058 #endif
00059
00060 #define MIN(x,y) (((x)<(y))?(x):(y))
00061 #define MAX(x,y) (((x)>(y))?(x):(y))
00062
00063 static class MultipleFastRtxSctpClass : public TclClass
00064 {
00065 public:
00066 MultipleFastRtxSctpClass() : TclClass("Agent/SCTP/MultipleFastRtx") {}
00067 TclObject* create(int, const char*const*)
00068 {
00069 return (new MultipleFastRtxSctpAgent());
00070 }
00071 } classSctpMultipleFastRtx;
00072
00073 MultipleFastRtxSctpAgent::MultipleFastRtxSctpAgent() : SctpAgent()
00074 {
00075 }
00076
00077 void MultipleFastRtxSctpAgent::delay_bind_init_all()
00078 {
00079 delay_bind_init_one("mfrCount_");
00080 SctpAgent::delay_bind_init_all();
00081 }
00082
00083 int MultipleFastRtxSctpAgent::delay_bind_dispatch(const char *cpVarName,
00084 const char *cpLocalName,
00085 TclObject *opTracer)
00086 {
00087 if(delay_bind(cpVarName, cpLocalName, "mfrCount_", &tiMfrCount, opTracer))
00088 return TCL_OK;
00089
00090 return SctpAgent::delay_bind_dispatch(cpVarName, cpLocalName, opTracer);
00091 }
00092
00093 void MultipleFastRtxSctpAgent::TraceAll()
00094 {
00095 char cpOutString[500];
00096 Node_S *spCurrNode = NULL;
00097 SctpDest_S *spCurrDest = NULL;
00098 double dCurrTime = Scheduler::instance().clock();
00099
00100 for(spCurrNode = sDestList.spHead;
00101 spCurrNode != NULL;
00102 spCurrNode = spCurrNode->spNext)
00103 {
00104 spCurrDest = (SctpDest_S *) spCurrNode->vpData;
00105 SetSource(spCurrDest);
00106 sprintf(cpOutString,
00107 "time: %-8.5f "
00108 "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
00109 "cwnd: %d pba: %d out: %d ssthresh: %d peerRwnd: %d "
00110 "rto: %-6.3f srtt: %-6.3f rttvar: %-6.3f "
00111 "assocErrors: %d pathErrors: %d dstatus: %s isPrimary: %s "
00112 "frCount: %d mfrCount: %d timeoutCount: %d rcdCount: %d\n",
00113 dCurrTime,
00114 addr(), port(), spCurrDest->iNsAddr, spCurrDest->iNsPort,
00115 spCurrDest->iCwnd, spCurrDest->iPartialBytesAcked,
00116 spCurrDest->iOutstandingBytes, spCurrDest->iSsthresh,
00117 uiPeerRwnd,
00118 spCurrDest->dRto, spCurrDest->dSrtt,
00119 spCurrDest->dRttVar,
00120 iAssocErrorCount,
00121 spCurrDest->iErrorCount,
00122 spCurrDest->eStatus ? "ACTIVE" : "INACTIVE",
00123 (spCurrDest == spPrimaryDest) ? "TRUE" : "FALSE",
00124 int(tiFrCount),
00125
00126 int(tiMfrCount),
00127
00128 spCurrDest->iTimeoutCount,
00129 spCurrDest->iRcdCount);
00130 if(channel_)
00131 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00132 }
00133
00134 sprintf(cpOutString, "\n");
00135 if(channel_)
00136 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00137 }
00138
00139 void MultipleFastRtxSctpAgent::TraceVar(const char* cpVar)
00140 {
00141 char cpOutString[500];
00142 Node_S *spCurrNode = NULL;
00143 SctpDest_S *spCurrDest = NULL;
00144 double dCurrTime = Scheduler::instance().clock();
00145
00146 if(!strcmp(cpVar, "cwnd_"))
00147 for(spCurrNode = sDestList.spHead;
00148 spCurrNode != NULL;
00149 spCurrNode = spCurrNode->spNext)
00150 {
00151 spCurrDest = (SctpDest_S *) spCurrNode->vpData;
00152 SetSource(spCurrDest);
00153 sprintf(cpOutString,
00154 "time: %-8.5f "
00155 "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
00156 "cwnd: %d pba: %d out: %d ssthresh: %d peerRwnd: %d\n",
00157 dCurrTime,
00158 addr(), port(),
00159 spCurrDest->iNsAddr, spCurrDest->iNsPort,
00160 spCurrDest->iCwnd, spCurrDest->iPartialBytesAcked,
00161 spCurrDest->iOutstandingBytes, spCurrDest->iSsthresh,
00162 uiPeerRwnd);
00163 if(channel_)
00164 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00165 }
00166
00167 else if(!strcmp(cpVar, "rto_"))
00168 for(spCurrNode = sDestList.spHead;
00169 spCurrNode != NULL;
00170 spCurrNode = spCurrNode->spNext)
00171 {
00172 spCurrDest = (SctpDest_S *) spCurrNode->vpData;
00173 SetSource(spCurrDest);
00174 sprintf(cpOutString,
00175 "time: %-8.5f "
00176 "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
00177 "rto: %-6.3f srtt: %-6.3f rttvar: %-6.3f\n",
00178 dCurrTime,
00179 addr(), port(),
00180 spCurrDest->iNsAddr, spCurrDest->iNsPort,
00181 spCurrDest->dRto, spCurrDest->dSrtt,
00182 spCurrDest->dRttVar);
00183 if(channel_)
00184 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00185 }
00186
00187 else if(!strcmp(cpVar, "errorCount_"))
00188 for(spCurrNode = sDestList.spHead;
00189 spCurrNode != NULL;
00190 spCurrNode = spCurrNode->spNext)
00191 {
00192 spCurrDest = (SctpDest_S *) spCurrNode->vpData;
00193 SetSource(spCurrDest);
00194 sprintf(cpOutString,
00195 "time: %-8.5f "
00196 "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
00197 "assocErrors: %d pathErrors: %d dstatus: %s isPrimary: %s\n",
00198 dCurrTime,
00199 addr(), port(),
00200 spCurrDest->iNsAddr, spCurrDest->iNsPort,
00201 iAssocErrorCount,
00202 spCurrDest->iErrorCount,
00203 spCurrDest->eStatus ? "ACTIVE" : "INACTIVE",
00204 (spCurrDest == spPrimaryDest) ? "TRUE" : "FALSE");
00205 if(channel_)
00206 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00207 }
00208
00209 else if(!strcmp(cpVar, "frCount_"))
00210 {
00211 sprintf(cpOutString,
00212 "time: %-8.5f "
00213 "frCount: %d\n",
00214 dCurrTime,
00215 int(*((TracedInt*) cpVar)) );
00216 if(channel_)
00217 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00218 }
00219
00220
00221 else if(!strcmp(cpVar, "mfrCount_"))
00222 {
00223 sprintf(cpOutString,
00224 "time: %-8.5f "
00225 "mfrCount: %d\n",
00226 dCurrTime,
00227 int(*((TracedInt*) cpVar)) );
00228 if(channel_)
00229 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00230 }
00231
00232
00233 else if(!strcmp(cpVar, "timeoutCount_"))
00234 {
00235 for(spCurrNode = sDestList.spHead;
00236 spCurrNode != NULL;
00237 spCurrNode = spCurrNode->spNext)
00238 {
00239 spCurrDest = (SctpDest_S *) spCurrNode->vpData;
00240 SetSource(spCurrDest);
00241 sprintf(cpOutString,
00242 "time: %-8.5f "
00243 "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
00244 "timeoutCount: %d\n",
00245 dCurrTime,
00246 addr(), port(),
00247 spCurrDest->iNsAddr, spCurrDest->iNsPort,
00248 spCurrDest->iTimeoutCount);
00249 if(channel_)
00250 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00251 }
00252 }
00253
00254 else if(!strcmp(cpVar, "rcdCount_"))
00255 {
00256 for(spCurrNode = sDestList.spHead;
00257 spCurrNode != NULL;
00258 spCurrNode = spCurrNode->spNext)
00259 {
00260 spCurrDest = (SctpDest_S *) spCurrNode->vpData;
00261 SetSource(spCurrDest);
00262 sprintf(cpOutString,
00263 "time: %-8.5f "
00264 "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
00265 "rcdCount: %d\n",
00266 dCurrTime,
00267 addr(), port(),
00268 spCurrDest->iNsAddr, spCurrDest->iNsPort,
00269 spCurrDest->iRcdCount);
00270 if(channel_)
00271 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00272 }
00273 }
00274
00275 else
00276 {
00277 sprintf(cpOutString,
00278 "time: %-8.5f "
00279 "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d %s: %s\n",
00280 dCurrTime, addr(), port(), daddr(), dport(),
00281 cpVar, "ERROR (unepected trace variable)");
00282 if(channel_)
00283 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00284 }
00285
00286 sprintf(cpOutString, "\n");
00287 if(channel_)
00288 (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
00289 }
00290
00291
00292 void MultipleFastRtxSctpAgent::AddToSendBuffer(SctpDataChunkHdr_S *spChunk,
00293 int iChunkSize,
00294 u_int uiReliability,
00295 SctpDest_S *spDest)
00296 {
00297 DBG_I(AddToSendBuffer);
00298 DBG_PL(AddToSendBuffer, "spDest=%p iChunkSize=%d"),
00299 spDest, iChunkSize DBG_PR;
00300
00301 Node_S *spNewNode = new Node_S;
00302 spNewNode->eType = NODE_TYPE_SEND_BUFFER;
00303 spNewNode->vpData = new SctpSendBufferNode_S;
00304
00305 SctpSendBufferNode_S * spNewNodeData
00306 = (SctpSendBufferNode_S *) spNewNode->vpData;
00307
00308
00309
00310
00311
00312 spNewNodeData->spChunk = (SctpDataChunkHdr_S *) new u_char[iChunkSize];
00313 memcpy(spNewNodeData->spChunk, spChunk, iChunkSize);
00314
00315 spNewNodeData->eAdvancedAcked = FALSE;
00316 spNewNodeData->eGapAcked = FALSE;
00317 spNewNodeData->eAddedToPartialBytesAcked = FALSE;
00318 spNewNodeData->iNumMissingReports = 0;
00319 spNewNodeData->iUnrelRtxLimit = uiReliability;
00320 spNewNodeData->eMarkedForRtx = NO_RTX;
00321 spNewNodeData->eIneligibleForFastRtx = FALSE;
00322 spNewNodeData->iNumTxs = 1;
00323 spNewNodeData->spDest = spDest;
00324
00325
00326 spNewNodeData->uiFastRtxRecover = 0;
00327
00328
00329
00330
00331
00332 if(spDest->eRtoPending == FALSE)
00333 {
00334 spNewNodeData->dTxTimestamp = Scheduler::instance().clock();
00335 spDest->eRtoPending = TRUE;
00336 }
00337 else
00338 spNewNodeData->dTxTimestamp = 0;
00339
00340 InsertNode(&sSendBuffer, sSendBuffer.spTail, spNewNode, NULL);
00341
00342 DBG_X(AddToSendBuffer);
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352 void MultipleFastRtxSctpAgent::SendBufferDequeueUpTo(u_int uiTsn)
00353 {
00354 DBG_I(SendBufferDequeueUpTo);
00355
00356 Node_S *spDeleteNode = NULL;
00357 Node_S *spCurrNode = sSendBuffer.spHead;
00358 SctpSendBufferNode_S *spCurrNodeData = NULL;
00359
00360 iAssocErrorCount = 0;
00361
00362 while(spCurrNode != NULL &&
00363 ((SctpSendBufferNode_S*)spCurrNode->vpData)->spChunk->uiTsn <= uiTsn)
00364 {
00365 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00366
00367
00368
00369
00370
00371 if((spCurrNodeData->eGapAcked == FALSE) &&
00372 (spCurrNodeData->eAdvancedAcked == FALSE) )
00373 {
00374 uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
00375
00376 spCurrNodeData->spDest->iNumNewlyAckedBytes
00377 += spCurrNodeData->spChunk->sHdr.usLength;
00378
00379
00380
00381
00382
00383 if(spCurrNodeData->spDest->iCwnd >spCurrNodeData->spDest->iSsthresh &&
00384 ( spCurrNodeData->spDest->iOutstandingBytes
00385 >= spCurrNodeData->spDest->iCwnd) )
00386 {
00387 spCurrNodeData->spDest->iPartialBytesAcked
00388 += spCurrNodeData->spChunk->sHdr.usLength;
00389 }
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 if(spCurrNodeData->uiFastRtxRecover > 0)
00401 eApplyMaxBurst = TRUE;
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413 if(spCurrNodeData->spDest->eRtoPending == TRUE &&
00414 spCurrNodeData->dTxTimestamp > 0 &&
00415 spCurrNodeData->iNumTxs == 1 &&
00416 spCurrNodeData->eGapAcked == FALSE &&
00417 spCurrNodeData->eAdvancedAcked == FALSE)
00418 {
00419
00420
00421
00422
00423
00424
00425 if(spCurrNodeData->eMarkedForRtx != TIMEOUT_RTX)
00426 RttUpdate(spCurrNodeData->dTxTimestamp, spCurrNodeData->spDest);
00427 spCurrNodeData->spDest->eRtoPending = FALSE;
00428 }
00429
00430
00431
00432 if(spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
00433 StopT3RtxTimer(spCurrNodeData->spDest);
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 if(spCurrNodeData->spDest->iErrorCount != 0 &&
00449 spCurrNodeData->eMarkedForRtx != TIMEOUT_RTX &&
00450 spCurrNodeData->eGapAcked == FALSE)
00451 {
00452 DBG_PL(SendBufferDequeueUpTo,
00453 "clearing error counter for %p with tsn=%lu"),
00454 spCurrNodeData->spDest, spCurrNodeData->spChunk->uiTsn DBG_PR;
00455
00456 spCurrNodeData->spDest->iErrorCount = 0;
00457 tiErrorCount++;
00458 spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
00459 if(spCurrNodeData->spDest == spPrimaryDest &&
00460 spNewTxDest != spPrimaryDest)
00461 {
00462 DBG_PL(SendBufferDequeueUpTo,
00463 "primary recovered... migrating back from %p to %p"),
00464 spNewTxDest, spPrimaryDest DBG_PR;
00465 spNewTxDest = spPrimaryDest;
00466 }
00467 }
00468
00469 spDeleteNode = spCurrNode;
00470 spCurrNode = spCurrNode->spNext;
00471 DeleteNode(&sSendBuffer, spDeleteNode);
00472 spDeleteNode = NULL;
00473 }
00474
00475 DBG_X(SendBufferDequeueUpTo);
00476 }
00477
00478
00479
00480 Boolean_E MultipleFastRtxSctpAgent::ProcessGapAckBlocks(u_char *ucpSackChunk,
00481 Boolean_E eNewCumAck)
00482 {
00483 DBG_I(ProcessGapAckBlocks);
00484
00485 Boolean_E eFastRtxNeeded = FALSE;
00486 u_int uiHighestTsnSacked = uiHighestTsnNewlyAcked;
00487 u_int uiStartTsn;
00488 u_int uiEndTsn;
00489 Node_S *spCurrNode = NULL;
00490 SctpSendBufferNode_S *spCurrNodeData = NULL;
00491 Node_S *spCurrDestNode = NULL;
00492 SctpDest_S *spCurrDestNodeData = NULL;
00493
00494 SctpSackChunk_S *spSackChunk = (SctpSackChunk_S *) ucpSackChunk;
00495
00496 u_short usNumGapAcksProcessed = 0;
00497 SctpGapAckBlock_S *spCurrGapAck
00498 = (SctpGapAckBlock_S *) (ucpSackChunk + sizeof(SctpSackChunk_S));
00499
00500
00501 u_int uiHighestOutstandingTsn = GetHighestOutstandingTsn();
00502
00503
00504
00505 Boolean_E eFrInvoked = FALSE;
00506 Boolean_E eMfrInvoked = FALSE;
00507
00508
00509 DBG_PL(ProcessGapAckBlocks,"CumAck=%d"), spSackChunk->uiCumAck DBG_PR;
00510
00511 if(sSendBuffer.spHead == NULL)
00512 {
00513
00514
00515
00516 }
00517
00518 else
00519 {
00520
00521
00522
00523 for(spCurrDestNode = sDestList.spHead;
00524 spCurrDestNode != NULL;
00525 spCurrDestNode = spCurrDestNode->spNext)
00526 {
00527 spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
00528 spCurrDestNodeData->spFirstOutstanding = NULL;
00529 }
00530
00531 for(spCurrNode = sSendBuffer.spHead;
00532 (spCurrNode != NULL) &&
00533 (usNumGapAcksProcessed != spSackChunk->usNumGapAckBlocks);
00534 spCurrNode = spCurrNode->spNext)
00535 {
00536 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00537
00538
00539
00540 if(spCurrNodeData->spDest->spFirstOutstanding == NULL &&
00541 spCurrNodeData->eGapAcked == FALSE &&
00542 spCurrNodeData->eAdvancedAcked == FALSE)
00543 {
00544
00545
00546 spCurrNodeData->spDest->spFirstOutstanding = spCurrNodeData;
00547 }
00548
00549 DBG_PL(ProcessGapAckBlocks, "--> rtx list chunk begin") DBG_PR;
00550
00551 DBG_PL(ProcessGapAckBlocks, " TSN=%d"),
00552 spCurrNodeData->spChunk->uiTsn
00553 DBG_PR;
00554
00555 DBG_PL(ProcessGapAckBlocks, " %s=%s %s=%s"),
00556 "eGapAcked",
00557 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE",
00558 "eAddedToPartialBytesAcked",
00559 spCurrNodeData->eAddedToPartialBytesAcked ? "TRUE" : "FALSE"
00560 DBG_PR;
00561
00562 DBG_PL(ProcessGapAckBlocks, " NumMissingReports=%d NumTxs=%d"),
00563 spCurrNodeData->iNumMissingReports,
00564 spCurrNodeData->iNumTxs
00565 DBG_PR;
00566
00567 DBG_PL(ProcessGapAckBlocks, "<-- rtx list chunk end") DBG_PR;
00568
00569 DBG_PL(ProcessGapAckBlocks,"GapAckBlock StartOffset=%d EndOffset=%d"),
00570 spCurrGapAck->usStartOffset, spCurrGapAck->usEndOffset DBG_PR;
00571
00572 uiStartTsn = spSackChunk->uiCumAck + spCurrGapAck->usStartOffset;
00573 uiEndTsn = spSackChunk->uiCumAck + spCurrGapAck->usEndOffset;
00574
00575 DBG_PL(ProcessGapAckBlocks, "GapAckBlock StartTsn=%d EndTsn=%d"),
00576 uiStartTsn, uiEndTsn DBG_PR;
00577
00578 if(spCurrNodeData->spChunk->uiTsn < uiStartTsn)
00579 {
00580
00581
00582
00583
00584
00585
00586
00587 if(spCurrNodeData->eGapAcked == TRUE)
00588 {
00589 DBG_PL(ProcessGapAckBlocks,
00590 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00591 spCurrNodeData->spChunk->uiTsn DBG_PR;
00592 spCurrNodeData->eGapAcked = FALSE;
00593 spCurrNodeData->spDest->iOutstandingBytes
00594 += spCurrNodeData->spChunk->sHdr.usLength;
00595
00596
00597
00598
00599
00600
00601
00602
00603 }
00604 }
00605 else if((uiStartTsn <= spCurrNodeData->spChunk->uiTsn) &&
00606 (spCurrNodeData->spChunk->uiTsn <= uiEndTsn) )
00607 {
00608
00609
00610 DBG_PL(ProcessGapAckBlocks, "gap ack acks this chunk: %s%s"),
00611 "eGapAcked=",
00612 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE"
00613 DBG_PR;
00614
00615
00616
00617
00618
00619
00620 if(uiHighestTsnSacked < spCurrNodeData->spChunk->uiTsn)
00621 uiHighestTsnSacked = spCurrNodeData->spChunk->uiTsn;
00622
00623 if(spCurrNodeData->eGapAcked == FALSE)
00624 {
00625 DBG_PL(ProcessGapAckBlocks, "setting eGapAcked=TRUE") DBG_PR;
00626 spCurrNodeData->eGapAcked = TRUE;
00627
00628
00629
00630
00631 if(uiHighestTsnNewlyAcked < spCurrNodeData->spChunk->uiTsn)
00632 uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
00633
00634 if(spCurrNodeData->eAdvancedAcked == FALSE)
00635 {
00636 spCurrNodeData->spDest->iNumNewlyAckedBytes
00637 += spCurrNodeData->spChunk->sHdr.usLength;
00638 }
00639
00640
00641
00642
00643
00644 if(( spCurrNodeData->spDest->iCwnd
00645 > spCurrNodeData->spDest->iSsthresh) &&
00646 eNewCumAck == TRUE &&
00647 spCurrNodeData->eAddedToPartialBytesAcked == FALSE)
00648 {
00649 DBG_PL(ProcessGapAckBlocks,
00650 "setting eAddedToPartiallyBytesAcked=TRUE") DBG_PR;
00651
00652 spCurrNodeData->eAddedToPartialBytesAcked = TRUE;
00653
00654 spCurrNodeData->spDest->iPartialBytesAcked
00655 += spCurrNodeData->spChunk->sHdr.usLength;
00656 }
00657
00658
00659
00660
00661
00662
00663
00664 if(spCurrNodeData->spDest->eRtoPending == TRUE &&
00665 spCurrNodeData->dTxTimestamp > 0 &&
00666 spCurrNodeData->iNumTxs == 1 &&
00667 spCurrNodeData->eAdvancedAcked == FALSE)
00668 {
00669
00670
00671
00672
00673
00674
00675
00676 if(spCurrNodeData->eMarkedForRtx != TIMEOUT_RTX)
00677 RttUpdate(spCurrNodeData->dTxTimestamp,
00678 spCurrNodeData->spDest);
00679 spCurrNodeData->spDest->eRtoPending = FALSE;
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689 if(spCurrNodeData->spDest->spFirstOutstanding
00690 == spCurrNodeData)
00691
00692 {
00693 if(spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
00694 StopT3RtxTimer(spCurrNodeData->spDest);
00695 }
00696
00697 iAssocErrorCount = 0;
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715 if(spCurrNodeData->spDest->iErrorCount != 0 &&
00716 spCurrNodeData->eMarkedForRtx != TIMEOUT_RTX)
00717 {
00718 DBG_PL(ProcessGapAckBlocks,
00719 "clearing error counter for %p with tsn=%lu"),
00720 spCurrNodeData->spDest,
00721 spCurrNodeData->spChunk->uiTsn DBG_PR;
00722
00723 spCurrNodeData->spDest->iErrorCount = 0;
00724 tiErrorCount++;
00725 spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
00726 if(spCurrNodeData->spDest == spPrimaryDest &&
00727 spNewTxDest != spPrimaryDest)
00728 {
00729 DBG_PL(ProcessGapAckBlocks,
00730 "primary recovered... "
00731 "migrating back from %p to %p"),
00732 spNewTxDest, spPrimaryDest DBG_PR;
00733 spNewTxDest = spPrimaryDest;
00734 }
00735 }
00736
00737 spCurrNodeData->eMarkedForRtx = NO_RTX;
00738 }
00739 }
00740 else if(spCurrNodeData->spChunk->uiTsn > uiEndTsn)
00741 {
00742
00743
00744
00745 usNumGapAcksProcessed++;
00746
00747
00748
00749 if(usNumGapAcksProcessed != spSackChunk->usNumGapAckBlocks)
00750 {
00751 DBG_PL(ProcessGapAckBlocks, "jump to next gap ack block")
00752 DBG_PR;
00753
00754 spCurrGapAck
00755 = ((SctpGapAckBlock_S *)
00756 (ucpSackChunk + sizeof(SctpSackChunk_S)
00757 + (usNumGapAcksProcessed * sizeof(SctpGapAckBlock_S))));
00758 }
00759
00760
00761
00762
00763
00764 if(spCurrNodeData->eGapAcked == TRUE)
00765 {
00766 DBG_PL(ProcessGapAckBlocks,
00767 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00768 spCurrNodeData->spChunk->uiTsn DBG_PR;
00769 spCurrNodeData->eGapAcked = FALSE;
00770 spCurrNodeData->spDest->iOutstandingBytes
00771 += spCurrNodeData->spChunk->sHdr.usLength;
00772
00773
00774
00775
00776
00777
00778
00779
00780 }
00781 }
00782 }
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792 for(; spCurrNode != NULL; spCurrNode = spCurrNode->spNext)
00793 {
00794
00795
00796 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00797
00798
00799
00800
00801
00802 if(spCurrNodeData->eGapAcked == TRUE)
00803 {
00804 DBG_PL(ProcessGapAckBlocks,
00805 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00806 spCurrNodeData->spChunk->uiTsn DBG_PR;
00807 spCurrNodeData->eGapAcked = FALSE;
00808 spCurrNodeData->spDest->iOutstandingBytes
00809 += spCurrNodeData->spChunk->sHdr.usLength;
00810
00811
00812
00813
00814
00815
00816
00817 }
00818 }
00819
00820 DBG_PL(ProcessGapAckBlocks, "now incrementing missing reports...") DBG_PR;
00821 DBG_PL(ProcessGapAckBlocks, "uiHighestTsnNewlyAcked=%d"),
00822 uiHighestTsnNewlyAcked DBG_PR;
00823
00824 for(spCurrNode = sSendBuffer.spHead;
00825 spCurrNode != NULL;
00826 spCurrNode = spCurrNode->spNext)
00827 {
00828 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00829
00830 DBG_PL(ProcessGapAckBlocks, "TSN=%d eGapAcked=%s"),
00831 spCurrNodeData->spChunk->uiTsn,
00832 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE"
00833 DBG_PR;
00834
00835 if(spCurrNodeData->eGapAcked == FALSE)
00836 {
00837
00838
00839
00840
00841
00842 if(( (spCurrNodeData->spChunk->uiTsn < uiHighestTsnNewlyAcked) ||
00843 (eNewCumAck == TRUE &&
00844 uiHighestTsnNewlyAcked <= uiRecover &&
00845 spCurrNodeData->spChunk->uiTsn < uiHighestTsnSacked) ) &&
00846 uiHighestTsnNewlyAcked > spCurrNodeData->uiFastRtxRecover)
00847 {
00848 spCurrNodeData->iNumMissingReports++;
00849 DBG_PL(ProcessGapAckBlocks,
00850 "incrementing missing report for TSN=%d to %d"),
00851 spCurrNodeData->spChunk->uiTsn,
00852 spCurrNodeData->iNumMissingReports
00853 DBG_PR;
00854
00855 if(spCurrNodeData->iNumMissingReports == iFastRtxTrigger &&
00856 spCurrNodeData->eAdvancedAcked == FALSE)
00857 {
00858 if(spCurrNodeData->uiFastRtxRecover == 0)
00859 eFrInvoked = TRUE;
00860 else
00861 eMfrInvoked = TRUE;
00862
00863 spCurrNodeData->iNumMissingReports = 0;
00864 MarkChunkForRtx(spCurrNodeData, FAST_RTX);
00865 eFastRtxNeeded = TRUE;
00866 spCurrNodeData->uiFastRtxRecover =uiHighestOutstandingTsn;
00867
00868 DBG_PL(ProcessGapAckBlocks,
00869 "resetting missing report for TSN=%d to 0"),
00870 spCurrNodeData->spChunk->uiTsn
00871 DBG_PR;
00872 DBG_PL(ProcessGapAckBlocks,
00873 "setting uiFastRtxRecover=%d"),
00874 spCurrNodeData->uiFastRtxRecover
00875 DBG_PR;
00876 }
00877 }
00878
00879 }
00880 }
00881 }
00882
00883
00884 if(eFrInvoked == TRUE)
00885 tiFrCount++;
00886 if(eMfrInvoked == TRUE)
00887 tiMfrCount++;
00888
00889
00890 DBG_PL(ProcessGapAckBlocks, "eFastRtxNeeded=%s"),
00891 eFastRtxNeeded ? "TRUE" : "FALSE" DBG_PR;
00892 DBG_X(ProcessGapAckBlocks);
00893 return eFastRtxNeeded;
00894 }