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 #ifndef lint
00042 static const char rcsid[] =
00043 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/sctp/sctp-newreno.cc,v 1.3 2005/07/13 03:51:27 tomh Exp $ (UD/PEL)";
00044 #endif
00045
00046 #include "ip.h"
00047 #include "sctp-newreno.h"
00048 #include "flags.h"
00049 #include "random.h"
00050 #include "template.h"
00051
00052 #include "sctpDebug.h"
00053
00054 #ifdef DMALLOC
00055 #include "dmalloc.h"
00056 #endif
00057
00058 #define MIN(x,y) (((x)<(y))?(x):(y))
00059 #define MAX(x,y) (((x)>(y))?(x):(y))
00060
00061 static class NewRenoSctpClass : public TclClass
00062 {
00063 public:
00064 NewRenoSctpClass() : TclClass("Agent/SCTP/Newreno") {}
00065 TclObject* create(int, const char*const*)
00066 {
00067 return (new NewRenoSctpAgent());
00068 }
00069 } classSctpNewReno;
00070
00071 NewRenoSctpAgent::NewRenoSctpAgent() : SctpAgent()
00072 {
00073 }
00074
00075 void NewRenoSctpAgent::delay_bind_init_all()
00076 {
00077 SctpAgent::delay_bind_init_all();
00078 }
00079
00080 int NewRenoSctpAgent::delay_bind_dispatch(const char *cpVarName,
00081 const char *cpLocalName,
00082 TclObject *opTracer)
00083 {
00084 return SctpAgent::delay_bind_dispatch(cpVarName, cpLocalName, opTracer);
00085 }
00086
00087 void NewRenoSctpAgent::OptionReset()
00088 {
00089 DBG_I(OptionReset);
00090 uiRecover = 0;
00091 DBG_X(OptionReset);
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101 void NewRenoSctpAgent::SendBufferDequeueUpTo(u_int uiTsn)
00102 {
00103 DBG_I(SendBufferDequeueUpTo);
00104
00105 Node_S *spDeleteNode = NULL;
00106 Node_S *spCurrNode = sSendBuffer.spHead;
00107 SctpSendBufferNode_S *spCurrNodeData = NULL;
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 uiAssocErrorCount = 0;
00118
00119 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00120
00121
00122 if(spCurrNodeData->spDest->uiErrorCount != 0)
00123 {
00124 spCurrNodeData->spDest->uiErrorCount = 0;
00125 tiErrorCount++;
00126 spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
00127 if(spCurrNodeData->spDest == spPrimaryDest &&
00128 spNewTxDest != spPrimaryDest)
00129 {
00130 DBG_PL(SendBufferDequeueUpTo,
00131 "primary recovered... migrating back from %p to %p"),
00132 spNewTxDest, spPrimaryDest DBG_PR;
00133 spNewTxDest = spPrimaryDest;
00134 }
00135 }
00136
00137 while(spCurrNode != NULL &&
00138 ((SctpSendBufferNode_S*)spCurrNode->vpData)->spChunk->uiTsn <= uiTsn)
00139 {
00140 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00141
00142
00143
00144
00145
00146 if((spCurrNodeData->eGapAcked == FALSE) &&
00147 (spCurrNodeData->eAdvancedAcked == FALSE) )
00148 {
00149
00150 uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
00151
00152
00153 spCurrNodeData->spDest->uiNumNewlyAckedBytes
00154 += spCurrNodeData->spChunk->sHdr.usLength;
00155
00156
00157
00158
00159
00160 if(spCurrNodeData->spDest->uiCwnd >spCurrNodeData->spDest->uiSsthresh &&
00161 ( spCurrNodeData->spDest->uiOutstandingBytes
00162 >= spCurrNodeData->spDest->uiCwnd) )
00163 {
00164 spCurrNodeData->spDest->uiPartialBytesAcked
00165 += spCurrNodeData->spChunk->sHdr.usLength;
00166 }
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 if(spCurrNodeData->eIneligibleForFastRtx == TRUE)
00179 eApplyMaxBurst = TRUE;
00180
00181
00182
00183
00184
00185
00186
00187
00188 if(spCurrNodeData->spDest->eRtoPending == TRUE &&
00189 spCurrNodeData->dTxTimestamp > 0 &&
00190 spCurrNodeData->iNumTxs == 1 &&
00191 spCurrNodeData->eGapAcked == FALSE &&
00192 spCurrNodeData->eAdvancedAcked == FALSE)
00193 {
00194 RttUpdate(spCurrNodeData->dTxTimestamp, spCurrNodeData->spDest);
00195 spCurrNodeData->spDest->eRtoPending = FALSE;
00196 }
00197
00198
00199
00200 if(spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
00201 StopT3RtxTimer(spCurrNodeData->spDest);
00202
00203 spDeleteNode = spCurrNode;
00204 spCurrNode = spCurrNode->spNext;
00205 DeleteNode(&sSendBuffer, spDeleteNode);
00206 spDeleteNode = NULL;
00207 }
00208
00209 DBG_X(SendBufferDequeueUpTo);
00210 }
00211
00212
00213
00214
00215
00216
00217 void NewRenoSctpAgent::FastRtx()
00218 {
00219 DBG_I(FastRtx);
00220
00221 Node_S *spCurrDestNode = NULL;
00222 SctpDest_S *spCurrDestData = NULL;
00223 Node_S *spCurrBuffNode = NULL;
00224 SctpSendBufferNode_S *spCurrBuffData = NULL;
00225 SctpSendBufferNode_S *spTailData = NULL;
00226
00227
00228
00229 for(spCurrDestNode = sDestList.spHead;
00230 spCurrDestNode != NULL;
00231 spCurrDestNode = spCurrDestNode->spNext)
00232 {
00233 spCurrDestData = (SctpDest_S *) spCurrDestNode->vpData;
00234 spCurrDestData->eCcApplied = FALSE;
00235 }
00236
00237
00238
00239
00240
00241 for(spCurrBuffNode = sSendBuffer.spHead;
00242 spCurrBuffNode != NULL;
00243 spCurrBuffNode = spCurrBuffNode->spNext)
00244 {
00245 spCurrBuffData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 if((spCurrBuffData->eMarkedForRtx == TRUE ||
00260 spCurrBuffData->eAdvancedAcked == TRUE) &&
00261 spCurrBuffData->spDest->eCcApplied == FALSE &&
00262 spCurrBuffData->spChunk->uiTsn > uiRecover)
00263
00264 {
00265
00266
00267 spCurrBuffData->spDest->uiSsthresh
00268 = MAX(spCurrBuffData->spDest->uiCwnd/2, 2*uiMaxPayloadSize);
00269 spCurrBuffData->spDest->uiCwnd = spCurrBuffData->spDest->uiSsthresh;
00270 spCurrBuffData->spDest->uiPartialBytesAcked = 0;
00271 tiCwnd++;
00272 spCurrBuffData->spDest->eCcApplied = TRUE;
00273
00274
00275
00276
00277 spTailData = (SctpSendBufferNode_S *) sSendBuffer.spTail->vpData;
00278 uiRecover = spTailData->spChunk->uiTsn;
00279 }
00280
00281
00282 }
00283
00284
00285
00286
00287 if(eMarkedChunksPending == TRUE)
00288 RtxMarkedChunks(RTX_LIMIT_ONE_PACKET);
00289
00290 DBG_X(FastRtx);
00291 }
00292
00293
00294
00295 Boolean_E NewRenoSctpAgent::ProcessGapAckBlocks(u_char *ucpSackChunk,
00296 Boolean_E eNewCumAck)
00297 {
00298 DBG_I(ProcessGapAckBlocks);
00299
00300 Boolean_E eFastRtxNeeded = FALSE;
00301 u_int uiHighestTsnSacked = uiHighestTsnNewlyAcked;
00302 u_int uiStartTsn;
00303 u_int uiEndTsn;
00304 Node_S *spCurrNode = NULL;
00305 SctpSendBufferNode_S *spCurrNodeData = NULL;
00306 Node_S *spCurrDestNode = NULL;
00307 SctpDest_S *spCurrDestNodeData = NULL;
00308 Boolean_E eFirstOutstanding = FALSE;
00309
00310 SctpSackChunk_S *spSackChunk = (SctpSackChunk_S *) ucpSackChunk;
00311
00312 u_short usNumGapAcksProcessed = 0;
00313 SctpGapAckBlock_S *spCurrGapAck
00314 = (SctpGapAckBlock_S *) (ucpSackChunk + sizeof(SctpSackChunk_S));
00315
00316 DBG_PL(ProcessGapAckBlocks,"CumAck=%d"), spSackChunk->uiCumAck DBG_PR;
00317
00318 if(sSendBuffer.spHead == NULL)
00319 {
00320
00321
00322
00323 }
00324
00325 else
00326 {
00327
00328
00329
00330 for(spCurrDestNode = sDestList.spHead;
00331 spCurrDestNode != NULL;
00332 spCurrDestNode = spCurrDestNode->spNext)
00333 {
00334 spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
00335 spCurrDestNodeData->eSeenFirstOutstanding = FALSE;
00336 }
00337
00338 for(spCurrNode = sSendBuffer.spHead;
00339 (spCurrNode != NULL) &&
00340 (usNumGapAcksProcessed != spSackChunk->usNumGapAckBlocks);
00341 spCurrNode = spCurrNode->spNext)
00342 {
00343 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00344
00345 DBG_PL(ProcessGapAckBlocks, "eSeenFirstOutstanding=%s"),
00346 spCurrNodeData->spDest->eSeenFirstOutstanding ? "TRUE" : "FALSE"
00347 DBG_PR;
00348
00349
00350
00351 if(spCurrNodeData->spDest->eSeenFirstOutstanding == FALSE &&
00352 spCurrNodeData->eGapAcked == FALSE &&
00353 spCurrNodeData->eAdvancedAcked == FALSE)
00354 {
00355
00356
00357 eFirstOutstanding = TRUE;
00358 spCurrNodeData->spDest->eSeenFirstOutstanding = TRUE;
00359 }
00360 else
00361 {
00362
00363
00364 eFirstOutstanding = FALSE;
00365 }
00366
00367 DBG_PL(ProcessGapAckBlocks, "eFirstOutstanding=%s"),
00368 eFirstOutstanding ? "TRUE" : "FALSE" DBG_PR;
00369
00370 DBG_PL(ProcessGapAckBlocks, "--> rtx list chunk begin") DBG_PR;
00371
00372 DBG_PL(ProcessGapAckBlocks, " TSN=%d"),
00373 spCurrNodeData->spChunk->uiTsn
00374 DBG_PR;
00375
00376 DBG_PL(ProcessGapAckBlocks, " %s=%s %s=%s"),
00377 "eGapAcked",
00378 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE",
00379 "eAddedToPartialBytesAcked",
00380 spCurrNodeData->eAddedToPartialBytesAcked ? "TRUE" : "FALSE"
00381 DBG_PR;
00382
00383 DBG_PL(ProcessGapAckBlocks, " NumMissingReports=%d NumTxs=%d"),
00384 spCurrNodeData->iNumMissingReports,
00385 spCurrNodeData->iNumTxs
00386 DBG_PR;
00387
00388 DBG_PL(ProcessGapAckBlocks, "<-- rtx list chunk end") DBG_PR;
00389
00390 DBG_PL(ProcessGapAckBlocks,"GapAckBlock StartOffset=%d EndOffset=%d"),
00391 spCurrGapAck->usStartOffset, spCurrGapAck->usEndOffset DBG_PR;
00392
00393 uiStartTsn = spSackChunk->uiCumAck + spCurrGapAck->usStartOffset;
00394 uiEndTsn = spSackChunk->uiCumAck + spCurrGapAck->usEndOffset;
00395
00396 DBG_PL(ProcessGapAckBlocks, "GapAckBlock StartTsn=%d EndTsn=%d"),
00397 uiStartTsn, uiEndTsn DBG_PR;
00398
00399 if(spCurrNodeData->spChunk->uiTsn < uiStartTsn)
00400 {
00401
00402
00403
00404
00405
00406
00407
00408 if(spCurrNodeData->eGapAcked == TRUE)
00409 {
00410 DBG_PL(ProcessGapAckBlocks,
00411 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00412 spCurrNodeData->spChunk->uiTsn DBG_PR;
00413 spCurrNodeData->eGapAcked = FALSE;
00414 spCurrNodeData->spDest->uiOutstandingBytes
00415 += spCurrNodeData->spChunk->sHdr.usLength;
00416
00417
00418
00419
00420
00421
00422
00423
00424 }
00425 }
00426 else if((uiStartTsn <= spCurrNodeData->spChunk->uiTsn) &&
00427 (spCurrNodeData->spChunk->uiTsn <= uiEndTsn) )
00428 {
00429
00430
00431 DBG_PL(ProcessGapAckBlocks, "gap ack acks this chunk: %s%s"),
00432 "eGapAcked=",
00433 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE"
00434 DBG_PR;
00435
00436
00437
00438
00439
00440
00441
00442
00443 if(uiHighestTsnSacked < spCurrNodeData->spChunk->uiTsn)
00444 uiHighestTsnSacked = spCurrNodeData->spChunk->uiTsn;
00445
00446
00447
00448 if(spCurrNodeData->eGapAcked == FALSE)
00449 {
00450 DBG_PL(ProcessGapAckBlocks, "setting eGapAcked=TRUE") DBG_PR;
00451 spCurrNodeData->eGapAcked = TRUE;
00452 spCurrNodeData->eMarkedForRtx = FALSE;
00453
00454
00455
00456
00457 if(uiHighestTsnNewlyAcked < spCurrNodeData->spChunk->uiTsn)
00458 uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
00459
00460 if(spCurrNodeData->eAdvancedAcked == FALSE)
00461 {
00462 spCurrNodeData->spDest->uiNumNewlyAckedBytes
00463 += spCurrNodeData->spChunk->sHdr.usLength;
00464 }
00465
00466
00467
00468
00469
00470 if(( spCurrNodeData->spDest->uiCwnd
00471 > spCurrNodeData->spDest->uiSsthresh) &&
00472 eNewCumAck == TRUE &&
00473 spCurrNodeData->eAddedToPartialBytesAcked == FALSE)
00474 {
00475 DBG_PL(ProcessGapAckBlocks,
00476 "setting eAddedToPartiallyBytesAcked=TRUE") DBG_PR;
00477
00478 spCurrNodeData->eAddedToPartialBytesAcked = TRUE;
00479
00480 spCurrNodeData->spDest->uiPartialBytesAcked
00481 += spCurrNodeData->spChunk->sHdr.usLength;
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491 if(spCurrNodeData->spDest->eRtoPending == TRUE &&
00492 spCurrNodeData->dTxTimestamp > 0 &&
00493 spCurrNodeData->iNumTxs == 1 &&
00494 spCurrNodeData->eAdvancedAcked == FALSE)
00495 {
00496 RttUpdate(spCurrNodeData->dTxTimestamp,
00497 spCurrNodeData->spDest);
00498 spCurrNodeData->spDest->eRtoPending = FALSE;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508 if(eFirstOutstanding == TRUE
00509 && spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
00510 StopT3RtxTimer(spCurrNodeData->spDest);
00511
00512 uiAssocErrorCount = 0;
00513
00514
00515
00516 if(spCurrNodeData->spDest->uiErrorCount != 0)
00517 {
00518 spCurrNodeData->spDest->uiErrorCount = 0;
00519 tiErrorCount++;
00520 spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
00521 if(spCurrNodeData->spDest == spPrimaryDest &&
00522 spNewTxDest != spPrimaryDest)
00523 {
00524 DBG_PL(ProcessGapAckBlocks,
00525 "primary recovered... "
00526 "migrating back from %p to %p"),
00527 spNewTxDest, spPrimaryDest DBG_PR;
00528 spNewTxDest = spPrimaryDest;
00529 }
00530 }
00531 }
00532 }
00533 else if(spCurrNodeData->spChunk->uiTsn > uiEndTsn)
00534 {
00535
00536
00537
00538 usNumGapAcksProcessed++;
00539
00540
00541
00542 if(usNumGapAcksProcessed != spSackChunk->usNumGapAckBlocks)
00543 {
00544 DBG_PL(ProcessGapAckBlocks, "jump to next gap ack block")
00545 DBG_PR;
00546
00547 spCurrGapAck
00548 = ((SctpGapAckBlock_S *)
00549 (ucpSackChunk + sizeof(SctpSackChunk_S)
00550 + (usNumGapAcksProcessed * sizeof(SctpGapAckBlock_S))));
00551 }
00552
00553
00554
00555
00556
00557 if(spCurrNodeData->eGapAcked == TRUE)
00558 {
00559 DBG_PL(ProcessGapAckBlocks,
00560 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00561 spCurrNodeData->spChunk->uiTsn DBG_PR;
00562 spCurrNodeData->eGapAcked = FALSE;
00563 spCurrNodeData->spDest->uiOutstandingBytes
00564 += spCurrNodeData->spChunk->sHdr.usLength;
00565
00566
00567
00568
00569
00570
00571
00572
00573 }
00574 }
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585 for(; spCurrNode != NULL; spCurrNode = spCurrNode->spNext)
00586 {
00587
00588
00589 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00590
00591
00592
00593
00594
00595 if(spCurrNodeData->eGapAcked == TRUE)
00596 {
00597 DBG_PL(ProcessGapAckBlocks,
00598 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00599 spCurrNodeData->spChunk->uiTsn DBG_PR;
00600 spCurrNodeData->eGapAcked = FALSE;
00601 spCurrNodeData->spDest->uiOutstandingBytes
00602 += spCurrNodeData->spChunk->sHdr.usLength;
00603
00604
00605
00606
00607
00608
00609
00610 }
00611 }
00612
00613 DBG_PL(ProcessGapAckBlocks, "now incrementing missing reports...") DBG_PR;
00614 DBG_PL(ProcessGapAckBlocks, "uiHighestTsnNewlyAcked=%d"),
00615 uiHighestTsnNewlyAcked DBG_PR;
00616
00617 for(spCurrNode = sSendBuffer.spHead;
00618 spCurrNode != NULL;
00619 spCurrNode = spCurrNode->spNext)
00620 {
00621 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00622
00623 DBG_PL(ProcessGapAckBlocks, "TSN=%d eGapAcked=%s"),
00624 spCurrNodeData->spChunk->uiTsn,
00625 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE"
00626 DBG_PR;
00627
00628 if(spCurrNodeData->eGapAcked == FALSE)
00629 {
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 if( (spCurrNodeData->spChunk->uiTsn < uiHighestTsnNewlyAcked) ||
00640 (eNewCumAck == TRUE &&
00641 uiHighestTsnNewlyAcked <= uiRecover &&
00642 spCurrNodeData->spChunk->uiTsn < uiHighestTsnSacked))
00643 {
00644 spCurrNodeData->iNumMissingReports++;
00645 DBG_PL(ProcessGapAckBlocks,
00646 "incrementing missing report for TSN=%d to %d"),
00647 spCurrNodeData->spChunk->uiTsn,
00648 spCurrNodeData->iNumMissingReports
00649 DBG_PR;
00650
00651 if(spCurrNodeData->iNumMissingReports >= FAST_RTX_TRIGGER &&
00652 spCurrNodeData->eIneligibleForFastRtx == FALSE &&
00653 spCurrNodeData->eAdvancedAcked == FALSE)
00654 {
00655 MarkChunkForRtx(spCurrNodeData);
00656 eFastRtxNeeded = TRUE;
00657 spCurrNodeData->eIneligibleForFastRtx = TRUE;
00658 DBG_PL(ProcessGapAckBlocks,
00659 "setting eFastRtxNeeded = TRUE") DBG_PR;
00660 }
00661 }
00662
00663 }
00664 }
00665 }
00666
00667 DBG_PL(ProcessGapAckBlocks, "eFastRtxNeeded=%s"),
00668 eFastRtxNeeded ? "TRUE" : "FALSE" DBG_PR;
00669 DBG_X(ProcessGapAckBlocks);
00670 return eFastRtxNeeded;
00671 }
00672
00673 void NewRenoSctpAgent::ProcessSackChunk(u_char *ucpSackChunk)
00674 {
00675 DBG_I(ProcessSackChunk);
00676
00677 SctpSackChunk_S *spSackChunk = (SctpSackChunk_S *) ucpSackChunk;
00678
00679 DBG_PL(ProcessSackChunk, "cum=%d arwnd=%d #gapacks=%d #duptsns=%d"),
00680 spSackChunk->uiCumAck, spSackChunk->uiArwnd,
00681 spSackChunk->usNumGapAckBlocks, spSackChunk->usNumDupTsns
00682 DBG_PR;
00683
00684 Boolean_E eFastRtxNeeded = FALSE;
00685 Boolean_E eNewCumAck = FALSE;
00686 Node_S *spCurrDestNode = NULL;
00687 SctpDest_S *spCurrDestNodeData = NULL;
00688 u_int uiTotalOutstanding = 0;
00689 int i = 0;
00690
00691
00692
00693 for(spCurrDestNode = sDestList.spHead;
00694 spCurrDestNode != NULL;
00695 spCurrDestNode = spCurrDestNode->spNext)
00696 {
00697 spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
00698 spCurrDestNodeData->uiNumNewlyAckedBytes = 0;
00699 spCurrDestNodeData->eSeenFirstOutstanding = FALSE;
00700 }
00701
00702 if(spSackChunk->uiCumAck < uiCumAckPoint)
00703 {
00704
00705
00706
00707 DBG_PL(ProcessSackChunk, "ignoring out of order sack!") DBG_PR;
00708 DBG_X(ProcessSackChunk);
00709 return;
00710 }
00711 else if(spSackChunk->uiCumAck > uiCumAckPoint)
00712 {
00713 eNewCumAck = TRUE;
00714 SendBufferDequeueUpTo(spSackChunk->uiCumAck);
00715 uiCumAckPoint = spSackChunk->uiCumAck;
00716 }
00717
00718 if(spSackChunk->usNumGapAckBlocks != 0)
00719 {
00720 eFastRtxNeeded = ProcessGapAckBlocks(ucpSackChunk, eNewCumAck);
00721 }
00722
00723 for(spCurrDestNode = sDestList.spHead;
00724 spCurrDestNode != NULL;
00725 spCurrDestNode = spCurrDestNode->spNext)
00726 {
00727 spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740 if(eNewCumAck == TRUE &&
00741 spCurrDestNodeData->uiNumNewlyAckedBytes > 0 &&
00742 spSackChunk->uiCumAck >= uiRecover)
00743 {
00744 AdjustCwnd(spCurrDestNodeData);
00745 }
00746
00747
00748
00749
00750
00751
00752 if(spCurrDestNodeData->uiNumNewlyAckedBytes <=
00753 spCurrDestNodeData->uiOutstandingBytes)
00754 {
00755 spCurrDestNodeData->uiOutstandingBytes
00756 -= spCurrDestNodeData->uiNumNewlyAckedBytes;
00757 }
00758 else
00759 spCurrDestNodeData->uiOutstandingBytes = 0;
00760
00761 DBG_PL(ProcessSackChunk,"Dest #%d (%d:%d) (%p): outstanding=%d, cwnd=%d"),
00762 ++i, spCurrDestNodeData->iNsAddr, spCurrDestNodeData->iNsPort,
00763 spCurrDestNodeData, spCurrDestNodeData->uiOutstandingBytes,
00764 spCurrDestNodeData->uiCwnd DBG_PR;
00765
00766 if(spCurrDestNodeData->uiOutstandingBytes == 0)
00767 {
00768
00769
00770 spCurrDestNodeData->uiPartialBytesAcked = 0;
00771
00772
00773
00774 if(spCurrDestNodeData->eRtxTimerIsRunning == TRUE)
00775 {
00776 DBG_PL(ProcessSackChunk, "Dest #%d (%p): stopping timer"),
00777 i, spCurrDestNodeData DBG_PR;
00778 StopT3RtxTimer(spCurrDestNodeData);
00779 }
00780 }
00781
00782
00783
00784
00785
00786 if(spCurrDestNodeData->uiOutstandingBytes > 0 &&
00787 spCurrDestNodeData->eRtxTimerIsRunning == FALSE)
00788 {
00789 StartT3RtxTimer(spCurrDestNodeData);
00790 }
00791 }
00792
00793 DBG_F(ProcessSackChunk, DumpSendBuffer());
00794
00795 AdvancePeerAckPoint();
00796
00797 if(eFastRtxNeeded == TRUE)
00798 FastRtx();
00799
00800
00801
00802
00803 else if( (eMarkedChunksPending = AnyMarkedChunks()) == TRUE)
00804 {
00805
00806
00807
00808
00809
00810 RtxMarkedChunks(RTX_LIMIT_CWND);
00811 }
00812
00813
00814
00815
00816
00817
00818
00819 uiTotalOutstanding = TotalOutstanding();
00820 if(uiTotalOutstanding <= spSackChunk->uiArwnd)
00821 uiPeerRwnd = (spSackChunk->uiArwnd - uiTotalOutstanding);
00822 else
00823 uiPeerRwnd = 0;
00824
00825 DBG_PL(ProcessSackChunk, "uiPeerRwnd=%d, uiArwnd=%d"), uiPeerRwnd,
00826 spSackChunk->uiArwnd DBG_PR;
00827 DBG_X(ProcessSackChunk);
00828 }
00829
00830