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