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-timestamp.cc,v 1.3 2005/10/07 05:58:29 tomh Exp $ (UD/PEL)";
00044 #endif
00045
00046 #include "ip.h"
00047 #include "sctp-timestamp.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 TimestampSctpClass : public TclClass
00062 {
00063 public:
00064 TimestampSctpClass() : TclClass("Agent/SCTP/Timestamp") {}
00065 TclObject* create(int, const char*const*)
00066 {
00067 return (new TimestampSctpAgent());
00068 }
00069 } classSctpTimestamp;
00070
00071 TimestampSctpAgent::TimestampSctpAgent() : SctpAgent()
00072 {
00073 }
00074
00075 void TimestampSctpAgent::delay_bind_init_all()
00076 {
00077
00078 SctpAgent::delay_bind_init_all();
00079 }
00080
00081 int TimestampSctpAgent::delay_bind_dispatch(const char *cpVarName,
00082 const char *cpLocalName,
00083 TclObject *opTracer)
00084 {
00085 return SctpAgent::delay_bind_dispatch(cpVarName, cpLocalName, opTracer);
00086 }
00087
00088 void TimestampSctpAgent::OptionReset()
00089 {
00090 DBG_I(OptionReset);
00091
00092 eNeedTimestampEcho = FALSE;
00093
00094 DBG_X(OptionReset);
00095 }
00096
00097
00098
00099 u_int TimestampSctpAgent::ControlChunkReservation()
00100 {
00101 DBG_I(ControlChunkReservation);
00102 DBG_PL(ControlChunkReservation, "returning %d"),
00103 sizeof(SctpTimestampChunk_S) DBG_PR;
00104 DBG_X(ControlChunkReservation);
00105 return sizeof(SctpTimestampChunk_S);
00106 }
00107
00108
00109
00110
00111 int TimestampSctpAgent::BundleControlChunks(u_char *ucpOutData)
00112 {
00113 DBG_I(BundleControlChunks);
00114 SctpTimestampChunk_S *spTimestampChunk = (SctpTimestampChunk_S *) ucpOutData;
00115
00116 spTimestampChunk->sHdr.usLength = sizeof(SctpTimestampChunk_S);
00117
00118
00119
00120
00121
00122 if((eSendNewDataChunks == TRUE || eMarkedChunksPending == TRUE) &&
00123 eSackChunkNeeded == FALSE &&
00124 eForwardTsnNeeded == FALSE)
00125 {
00126 spTimestampChunk->sHdr.ucType = SCTP_CHUNK_TIMESTAMP;
00127 spTimestampChunk->sHdr.ucFlags |= SCTP_TIMESTAMP_FLAG_TS;
00128 spTimestampChunk->fTimestamp = (float) Scheduler::instance().clock();
00129 }
00130 if(eNeedTimestampEcho == TRUE)
00131 {
00132 spTimestampChunk->sHdr.ucType = SCTP_CHUNK_TIMESTAMP;
00133 spTimestampChunk->sHdr.ucFlags |= SCTP_TIMESTAMP_FLAG_ECHO;
00134 spTimestampChunk->fEcho = fOutTimestampEcho;
00135 eNeedTimestampEcho = FALSE;
00136 }
00137
00138 DBG_PL(BundleControlChunks, "returning %d"),
00139 spTimestampChunk->sHdr.usLength DBG_PR;
00140 DBG_X(BundleControlChunks);
00141 return spTimestampChunk->sHdr.usLength;
00142 }
00143
00144 void TimestampSctpAgent::AddToSendBuffer(SctpDataChunkHdr_S *spChunk,
00145 int iChunkSize,
00146 u_int uiReliability,
00147 SctpDest_S *spDest)
00148 {
00149 DBG_I(AddToSendBuffer);
00150 DBG_PL(AddToSendBuffer, "spDest=%p iChunkSize=%d"),
00151 spDest, iChunkSize DBG_PR;
00152
00153 Node_S *spNewNode = new Node_S;
00154 spNewNode->eType = NODE_TYPE_SEND_BUFFER;
00155 spNewNode->vpData = new SctpSendBufferNode_S;
00156
00157 SctpSendBufferNode_S * spNewNodeData
00158 = (SctpSendBufferNode_S *) spNewNode->vpData;
00159
00160
00161
00162
00163
00164 spNewNodeData->spChunk = (SctpDataChunkHdr_S *) new u_char[iChunkSize];
00165 memcpy(spNewNodeData->spChunk, spChunk, iChunkSize);
00166
00167 spNewNodeData->eAdvancedAcked = FALSE;
00168 spNewNodeData->eGapAcked = FALSE;
00169 spNewNodeData->eAddedToPartialBytesAcked = FALSE;
00170 spNewNodeData->iNumMissingReports = 0;
00171 spNewNodeData->iUnrelRtxLimit = uiReliability;
00172 spNewNodeData->eMarkedForRtx = NO_RTX;
00173 spNewNodeData->eIneligibleForFastRtx = FALSE;
00174 spNewNodeData->iNumTxs = 1;
00175 spNewNodeData->spDest = spDest;
00176
00177
00178 spNewNodeData->dTxTimestamp = Scheduler::instance().clock();
00179
00180
00181 InsertNode(&sSendBuffer, sSendBuffer.spTail, spNewNode, NULL);
00182
00183 DBG_X(AddToSendBuffer);
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193 void TimestampSctpAgent::SendBufferDequeueUpTo(u_int uiTsn)
00194 {
00195 DBG_I(SendBufferDequeueUpTo);
00196
00197 Node_S *spDeleteNode = NULL;
00198 Node_S *spCurrNode = sSendBuffer.spHead;
00199 SctpSendBufferNode_S *spCurrNodeData = NULL;
00200
00201 iAssocErrorCount = 0;
00202
00203 while(spCurrNode != NULL &&
00204 ((SctpSendBufferNode_S*)spCurrNode->vpData)->spChunk->uiTsn <= uiTsn)
00205 {
00206 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00207
00208
00209
00210
00211
00212 if((spCurrNodeData->eGapAcked == FALSE) &&
00213 (spCurrNodeData->eAdvancedAcked == FALSE) )
00214 {
00215 uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
00216
00217 spCurrNodeData->spDest->iNumNewlyAckedBytes
00218 += spCurrNodeData->spChunk->sHdr.usLength;
00219
00220
00221
00222
00223
00224 if(spCurrNodeData->spDest->iCwnd >spCurrNodeData->spDest->iSsthresh &&
00225 ( spCurrNodeData->spDest->iOutstandingBytes
00226 >= spCurrNodeData->spDest->iCwnd) )
00227 {
00228 spCurrNodeData->spDest->iPartialBytesAcked
00229 += spCurrNodeData->spChunk->sHdr.usLength;
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 if(spCurrNodeData->eIneligibleForFastRtx == TRUE)
00243 eApplyMaxBurst = TRUE;
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 if(fInTimestampEcho == (float) spCurrNodeData->dTxTimestamp &&
00254 spCurrNodeData->eGapAcked == FALSE &&
00255 spCurrNodeData->eAdvancedAcked == FALSE)
00256 {
00257 RttUpdate(spCurrNodeData->dTxTimestamp, spCurrNodeData->spDest);
00258 }
00259
00260
00261
00262
00263
00264
00265 if(spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
00266 StopT3RtxTimer(spCurrNodeData->spDest);
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 if(spCurrNodeData->spDest->iErrorCount != 0 &&
00282 spCurrNodeData->eMarkedForRtx != TIMEOUT_RTX &&
00283 spCurrNodeData->eGapAcked == FALSE)
00284 {
00285 DBG_PL(SendBufferDequeueUpTo,
00286 "clearing error counter for %p with tsn=%lu"),
00287 spCurrNodeData->spDest, spCurrNodeData->spChunk->uiTsn DBG_PR;
00288
00289 spCurrNodeData->spDest->iErrorCount = 0;
00290 tiErrorCount++;
00291 spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
00292 if(spCurrNodeData->spDest == spPrimaryDest &&
00293 spNewTxDest != spPrimaryDest)
00294 {
00295 DBG_PL(SendBufferDequeueUpTo,
00296 "primary recovered... migrating back from %p to %p"),
00297 spNewTxDest, spPrimaryDest DBG_PR;
00298 spNewTxDest = spPrimaryDest;
00299 }
00300 }
00301
00302 spDeleteNode = spCurrNode;
00303 spCurrNode = spCurrNode->spNext;
00304 DeleteNode(&sSendBuffer, spDeleteNode);
00305 spDeleteNode = NULL;
00306 }
00307
00308 DBG_X(SendBufferDequeueUpTo);
00309 }
00310
00311
00312
00313
00314
00315
00316
00317 void TimestampSctpAgent::RtxMarkedChunks(SctpRtxLimit_E eLimit)
00318 {
00319 DBG_I(RtxMarkedChunks);
00320
00321 u_char ucpOutData[uiMaxPayloadSize];
00322 u_char *ucpCurrOutData = ucpOutData;
00323 int iBundledControlChunkSize = 0;
00324 int iCurrSize = 0;
00325 int iOutDataSize = 0;
00326 Node_S *spCurrBuffNode = NULL;
00327 SctpSendBufferNode_S *spCurrBuffNodeData = NULL;
00328 SctpDataChunkHdr_S *spCurrChunk;
00329 SctpDest_S *spRtxDest = NULL;
00330 Node_S *spCurrDestNode = NULL;
00331 SctpDest_S *spCurrDestNodeData = NULL;
00332 Boolean_E eControlChunkBundled = FALSE;
00333 int iNumPacketsSent = 0;
00334
00335 memset(ucpOutData, 0, uiMaxPayloadSize);
00336
00337 uiBurstLength = 0;
00338
00339
00340
00341 for(spCurrDestNode = sDestList.spHead;
00342 spCurrDestNode != NULL;
00343 spCurrDestNode = spCurrDestNode->spNext)
00344 {
00345 spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
00346 spCurrDestNodeData->spFirstOutstanding = NULL;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 for(spCurrBuffNode = sSendBuffer.spHead;
00362 spCurrBuffNode != NULL;
00363 spCurrBuffNode = spCurrBuffNode->spNext)
00364 {
00365 spCurrBuffNodeData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
00366
00367 if(spCurrBuffNodeData->eMarkedForRtx != NO_RTX)
00368 {
00369 spCurrChunk = spCurrBuffNodeData->spChunk;
00370
00371 if(spRtxDest == NULL)
00372 {
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 switch(eRtxToAlt)
00386 {
00387 case RTX_TO_ALT_OFF:
00388 if(spCurrBuffNodeData->spDest->eStatus
00389 == SCTP_DEST_STATUS_ACTIVE)
00390 {
00391 spRtxDest = spCurrBuffNodeData->spDest;
00392 }
00393 else
00394 {
00395 spRtxDest = GetNextDest(spCurrBuffNodeData->spDest);
00396 }
00397 break;
00398
00399 case RTX_TO_ALT_ON:
00400 spRtxDest = GetNextDest(spCurrBuffNodeData->spDest);
00401 break;
00402
00403 case RTX_TO_ALT_TIMEOUTS_ONLY:
00404 if(spCurrBuffNodeData->eMarkedForRtx == FAST_RTX &&
00405 spCurrBuffNodeData->spDest->eStatus
00406 == SCTP_DEST_STATUS_ACTIVE)
00407 {
00408 spRtxDest = spCurrBuffNodeData->spDest;
00409 }
00410 else
00411 {
00412 spRtxDest = GetNextDest(spCurrBuffNodeData->spDest);
00413 }
00414 break;
00415 }
00416 }
00417
00418 spCurrBuffNodeData->spDest->iOutstandingBytes
00419 -= spCurrChunk->sHdr.usLength;
00420 }
00421 }
00422
00423 spCurrBuffNode = sSendBuffer.spHead;
00424
00425 while( (eLimit == RTX_LIMIT_ONE_PACKET &&
00426 iNumPacketsSent < 1 &&
00427 spCurrBuffNode != NULL) ||
00428 (eLimit == RTX_LIMIT_CWND &&
00429 spRtxDest->iOutstandingBytes < spRtxDest->iCwnd &&
00430 spCurrBuffNode != NULL) )
00431 {
00432 DBG_PL(RtxMarkedChunks,
00433 "eLimit=%s pktsSent=%d out=%d cwnd=%d spCurrBuffNode=%p"),
00434 (eLimit == RTX_LIMIT_ONE_PACKET) ? "ONE_PACKET" : "CWND",
00435 iNumPacketsSent, spRtxDest->iOutstandingBytes, spRtxDest->iCwnd,
00436 spCurrBuffNode
00437 DBG_PR;
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 for(eControlChunkBundled = FALSE;
00448 spCurrBuffNode != NULL;
00449 spCurrBuffNode = spCurrBuffNode->spNext)
00450 {
00451 spCurrBuffNodeData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
00452
00453
00454
00455 if(spCurrBuffNodeData->spDest->spFirstOutstanding == NULL &&
00456 spCurrBuffNodeData->eGapAcked == FALSE &&
00457 spCurrBuffNodeData->eAdvancedAcked == FALSE)
00458 {
00459
00460
00461 spCurrBuffNodeData->spDest->spFirstOutstanding
00462 = spCurrBuffNodeData;
00463 }
00464
00465
00466
00467 if(spCurrBuffNodeData->eMarkedForRtx != NO_RTX)
00468 {
00469 spCurrChunk = spCurrBuffNodeData->spChunk;
00470
00471
00472
00473
00474 if(eControlChunkBundled == FALSE)
00475 {
00476 eControlChunkBundled = TRUE;
00477 iBundledControlChunkSize =BundleControlChunks(ucpCurrOutData);
00478 ucpCurrOutData += iBundledControlChunkSize;
00479 iOutDataSize += iBundledControlChunkSize;
00480 }
00481
00482
00483
00484 if((iOutDataSize + spCurrChunk->sHdr.usLength)
00485 > (int) uiMaxPayloadSize)
00486 break;
00487
00488
00489
00490 if(spCurrBuffNodeData->spDest->eRtoPending == TRUE &&
00491 spCurrBuffNodeData->dTxTimestamp > 0)
00492 {
00493 spCurrBuffNodeData->dTxTimestamp = 0;
00494 spCurrBuffNodeData->spDest->eRtoPending = FALSE;
00495 }
00496
00497
00498
00499
00500
00501
00502 if(spCurrBuffNodeData->spDest->spFirstOutstanding
00503 == spCurrBuffNodeData)
00504 {
00505 if(spCurrBuffNodeData->spDest->iOutstandingBytes > 0)
00506 StartT3RtxTimer(spCurrBuffNodeData->spDest);
00507 }
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 if(spRtxDest->spFirstOutstanding == NULL ||
00520 spCurrChunk->uiTsn <
00521 spRtxDest->spFirstOutstanding->spChunk->uiTsn)
00522 {
00523
00524
00525 spRtxDest->spFirstOutstanding = spCurrBuffNodeData;
00526 StartT3RtxTimer(spRtxDest);
00527 }
00528
00529 memcpy(ucpCurrOutData, spCurrChunk, spCurrChunk->sHdr.usLength);
00530 iCurrSize = spCurrChunk->sHdr.usLength;
00531
00532
00533
00534
00535 if( (iCurrSize % 4) != 0 )
00536 iCurrSize += 4 - (iCurrSize % 4);
00537
00538 ucpCurrOutData += iCurrSize;
00539 iOutDataSize += iCurrSize;
00540 spCurrBuffNodeData->spDest = spRtxDest;
00541 spCurrBuffNodeData->iNumTxs++;
00542 spCurrBuffNodeData->eMarkedForRtx = NO_RTX;
00543
00544
00545 spCurrBuffNodeData->dTxTimestamp = Scheduler::instance().clock();
00546
00547
00548
00549
00550 spSctpTrace[uiNumChunks].eType = SCTP_CHUNK_DATA;
00551 spSctpTrace[uiNumChunks].uiTsn = spCurrChunk->uiTsn;
00552 spSctpTrace[uiNumChunks].usStreamId = spCurrChunk->usStreamId;
00553 spSctpTrace[uiNumChunks].usStreamSeqNum
00554 = spCurrChunk->usStreamSeqNum;
00555 uiNumChunks++;
00556
00557
00558
00559 spCurrBuffNodeData->spDest->iOutstandingBytes
00560 += spCurrChunk->sHdr.usLength;
00561 uiPeerRwnd -= spCurrChunk->sHdr.usLength;
00562 DBG_PL(RtxMarkedChunks, "spDest->iOutstandingBytes=%d"),
00563 spCurrBuffNodeData->spDest->iOutstandingBytes DBG_PR;
00564
00565 DBG_PL(RtxMarkedChunks, "TSN=%d"), spCurrChunk->uiTsn DBG_PR;
00566 }
00567 else if(spCurrBuffNodeData->eAdvancedAcked == TRUE)
00568 {
00569 if(spCurrBuffNodeData->spDest->spFirstOutstanding
00570 == spCurrBuffNodeData)
00571 {
00572
00573
00574
00575
00576
00577
00578
00579 if(spCurrBuffNodeData->spDest->iOutstandingBytes > 0)
00580 StartT3RtxTimer(spCurrBuffNodeData->spDest);
00581 else
00582 StopT3RtxTimer(spCurrBuffNodeData->spDest);
00583 }
00584 }
00585 }
00586
00587
00588
00589 if(iOutDataSize > 0)
00590 {
00591 SendPacket(ucpOutData, iOutDataSize, spRtxDest);
00592 if(spRtxDest->eRtxTimerIsRunning == FALSE)
00593 StartT3RtxTimer(spRtxDest);
00594 iNumPacketsSent++;
00595 iOutDataSize = 0;
00596 ucpCurrOutData = ucpOutData;
00597 memset(ucpOutData, 0, uiMaxPayloadSize);
00598
00599 spRtxDest->opCwndDegradeTimer->resched(spRtxDest->dRto);
00600
00601
00602
00603
00604
00605 if(eUseMaxBurst == MAX_BURST_USAGE_ON)
00606 if( (eApplyMaxBurst == TRUE) && (uiBurstLength++ >= MAX_BURST) )
00607 {
00608
00609
00610 eApplyMaxBurst = FALSE;
00611 break;
00612 }
00613 }
00614 }
00615
00616
00617
00618
00619 for(spCurrBuffNode = sSendBuffer.spHead;
00620 spCurrBuffNode != NULL;
00621 spCurrBuffNode = spCurrBuffNode->spNext)
00622 {
00623 spCurrBuffNodeData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
00624
00625 if(spCurrBuffNodeData->eMarkedForRtx != NO_RTX)
00626 {
00627 spCurrChunk = spCurrBuffNodeData->spChunk;
00628 spCurrBuffNodeData->spDest->iOutstandingBytes
00629 += spCurrChunk->sHdr.usLength;
00630 }
00631 }
00632
00633
00634
00635
00636
00637
00638 eMarkedChunksPending = AnyMarkedChunks();
00639
00640 DBG_X(RtxMarkedChunks);
00641 }
00642
00643
00644
00645 Boolean_E TimestampSctpAgent::ProcessGapAckBlocks(u_char *ucpSackChunk,
00646 Boolean_E eNewCumAck)
00647 {
00648 DBG_I(ProcessGapAckBlocks);
00649
00650 Boolean_E eFastRtxNeeded = FALSE;
00651 u_int uiHighestTsnSacked = uiHighestTsnNewlyAcked;
00652 u_int uiStartTsn;
00653 u_int uiEndTsn;
00654 Node_S *spCurrNode = NULL;
00655 SctpSendBufferNode_S *spCurrNodeData = NULL;
00656 Node_S *spCurrDestNode = NULL;
00657 SctpDest_S *spCurrDestNodeData = NULL;
00658
00659 SctpSackChunk_S *spSackChunk = (SctpSackChunk_S *) ucpSackChunk;
00660
00661 u_short usNumGapAcksProcessed = 0;
00662 SctpGapAckBlock_S *spCurrGapAck
00663 = (SctpGapAckBlock_S *) (ucpSackChunk + sizeof(SctpSackChunk_S));
00664
00665 DBG_PL(ProcessGapAckBlocks,"CumAck=%d"), spSackChunk->uiCumAck DBG_PR;
00666
00667 if(sSendBuffer.spHead == NULL)
00668 {
00669
00670
00671
00672 }
00673
00674 else
00675 {
00676
00677
00678
00679 for(spCurrDestNode = sDestList.spHead;
00680 spCurrDestNode != NULL;
00681 spCurrDestNode = spCurrDestNode->spNext)
00682 {
00683 spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
00684 spCurrDestNodeData->spFirstOutstanding = NULL;
00685 }
00686
00687 for(spCurrNode = sSendBuffer.spHead;
00688 (spCurrNode != NULL) &&
00689 (usNumGapAcksProcessed != spSackChunk->usNumGapAckBlocks);
00690 spCurrNode = spCurrNode->spNext)
00691 {
00692 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00693
00694
00695
00696 if(spCurrNodeData->spDest->spFirstOutstanding == NULL &&
00697 spCurrNodeData->eGapAcked == FALSE &&
00698 spCurrNodeData->eAdvancedAcked == FALSE)
00699 {
00700
00701
00702 spCurrNodeData->spDest->spFirstOutstanding = spCurrNodeData;
00703 }
00704
00705 DBG_PL(ProcessGapAckBlocks, "--> rtx list chunk begin") DBG_PR;
00706
00707 DBG_PL(ProcessGapAckBlocks, " TSN=%d"),
00708 spCurrNodeData->spChunk->uiTsn
00709 DBG_PR;
00710
00711 DBG_PL(ProcessGapAckBlocks, " %s=%s %s=%s"),
00712 "eGapAcked",
00713 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE",
00714 "eAddedToPartialBytesAcked",
00715 spCurrNodeData->eAddedToPartialBytesAcked ? "TRUE" : "FALSE"
00716 DBG_PR;
00717
00718 DBG_PL(ProcessGapAckBlocks, " NumMissingReports=%d NumTxs=%d"),
00719 spCurrNodeData->iNumMissingReports,
00720 spCurrNodeData->iNumTxs
00721 DBG_PR;
00722
00723 DBG_PL(ProcessGapAckBlocks, "<-- rtx list chunk end") DBG_PR;
00724
00725 DBG_PL(ProcessGapAckBlocks,"GapAckBlock StartOffset=%d EndOffset=%d"),
00726 spCurrGapAck->usStartOffset, spCurrGapAck->usEndOffset DBG_PR;
00727
00728 uiStartTsn = spSackChunk->uiCumAck + spCurrGapAck->usStartOffset;
00729 uiEndTsn = spSackChunk->uiCumAck + spCurrGapAck->usEndOffset;
00730
00731 DBG_PL(ProcessGapAckBlocks, "GapAckBlock StartTsn=%d EndTsn=%d"),
00732 uiStartTsn, uiEndTsn DBG_PR;
00733
00734 if(spCurrNodeData->spChunk->uiTsn < uiStartTsn)
00735 {
00736
00737
00738
00739
00740
00741
00742
00743 if(spCurrNodeData->eGapAcked == TRUE)
00744 {
00745 DBG_PL(ProcessGapAckBlocks,
00746 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00747 spCurrNodeData->spChunk->uiTsn DBG_PR;
00748 spCurrNodeData->eGapAcked = FALSE;
00749 spCurrNodeData->spDest->iOutstandingBytes
00750 += spCurrNodeData->spChunk->sHdr.usLength;
00751
00752
00753
00754
00755
00756
00757
00758
00759 }
00760 }
00761 else if((uiStartTsn <= spCurrNodeData->spChunk->uiTsn) &&
00762 (spCurrNodeData->spChunk->uiTsn <= uiEndTsn) )
00763 {
00764
00765
00766 DBG_PL(ProcessGapAckBlocks, "gap ack acks this chunk: %s%s"),
00767 "eGapAcked=",
00768 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE"
00769 DBG_PR;
00770
00771
00772
00773
00774
00775
00776 if(uiHighestTsnSacked < spCurrNodeData->spChunk->uiTsn)
00777 uiHighestTsnSacked = spCurrNodeData->spChunk->uiTsn;
00778
00779 if(spCurrNodeData->eGapAcked == FALSE)
00780 {
00781 DBG_PL(ProcessGapAckBlocks, "setting eGapAcked=TRUE") DBG_PR;
00782 spCurrNodeData->eGapAcked = TRUE;
00783
00784
00785
00786
00787 if(uiHighestTsnNewlyAcked < spCurrNodeData->spChunk->uiTsn)
00788 uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
00789
00790 if(spCurrNodeData->eAdvancedAcked == FALSE)
00791 {
00792 spCurrNodeData->spDest->iNumNewlyAckedBytes
00793 += spCurrNodeData->spChunk->sHdr.usLength;
00794 }
00795
00796
00797
00798
00799
00800 if(( spCurrNodeData->spDest->iCwnd
00801 > spCurrNodeData->spDest->iSsthresh) &&
00802 eNewCumAck == TRUE &&
00803 spCurrNodeData->eAddedToPartialBytesAcked == FALSE)
00804 {
00805 DBG_PL(ProcessGapAckBlocks,
00806 "setting eAddedToPartiallyBytesAcked=TRUE") DBG_PR;
00807
00808 spCurrNodeData->eAddedToPartialBytesAcked = TRUE;
00809
00810 spCurrNodeData->spDest->iPartialBytesAcked
00811 += spCurrNodeData->spChunk->sHdr.usLength;
00812 }
00813
00814
00815
00816
00817
00818
00819
00820
00821 if(fInTimestampEcho == (float) spCurrNodeData->dTxTimestamp &&
00822 spCurrNodeData->eAdvancedAcked == FALSE)
00823 {
00824 RttUpdate(spCurrNodeData->dTxTimestamp,
00825 spCurrNodeData->spDest);
00826 }
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838 if(spCurrNodeData->spDest->spFirstOutstanding
00839 == spCurrNodeData)
00840
00841 {
00842 if(spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
00843 StopT3RtxTimer(spCurrNodeData->spDest);
00844 }
00845
00846 iAssocErrorCount = 0;
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864 if(spCurrNodeData->spDest->iErrorCount != 0 &&
00865 spCurrNodeData->eMarkedForRtx != TIMEOUT_RTX)
00866 {
00867 DBG_PL(ProcessGapAckBlocks,
00868 "clearing error counter for %p with tsn=%lu"),
00869 spCurrNodeData->spDest,
00870 spCurrNodeData->spChunk->uiTsn DBG_PR;
00871
00872 spCurrNodeData->spDest->iErrorCount = 0;
00873 tiErrorCount++;
00874 spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
00875 if(spCurrNodeData->spDest == spPrimaryDest &&
00876 spNewTxDest != spPrimaryDest)
00877 {
00878 DBG_PL(ProcessGapAckBlocks,
00879 "primary recovered... "
00880 "migrating back from %p to %p"),
00881 spNewTxDest, spPrimaryDest DBG_PR;
00882 spNewTxDest = spPrimaryDest;
00883 }
00884 }
00885 spCurrNodeData->eMarkedForRtx = NO_RTX;
00886 }
00887 }
00888 else if(spCurrNodeData->spChunk->uiTsn > uiEndTsn)
00889 {
00890
00891
00892
00893 usNumGapAcksProcessed++;
00894
00895
00896
00897 if(usNumGapAcksProcessed != spSackChunk->usNumGapAckBlocks)
00898 {
00899 DBG_PL(ProcessGapAckBlocks, "jump to next gap ack block")
00900 DBG_PR;
00901
00902 spCurrGapAck
00903 = ((SctpGapAckBlock_S *)
00904 (ucpSackChunk + sizeof(SctpSackChunk_S)
00905 + (usNumGapAcksProcessed * sizeof(SctpGapAckBlock_S))));
00906 }
00907
00908
00909
00910
00911
00912 if(spCurrNodeData->eGapAcked == TRUE)
00913 {
00914 DBG_PL(ProcessGapAckBlocks,
00915 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00916 spCurrNodeData->spChunk->uiTsn DBG_PR;
00917 spCurrNodeData->eGapAcked = FALSE;
00918 spCurrNodeData->spDest->iOutstandingBytes
00919 += spCurrNodeData->spChunk->sHdr.usLength;
00920
00921
00922
00923
00924
00925
00926
00927
00928 }
00929 }
00930 }
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940 for(; spCurrNode != NULL; spCurrNode = spCurrNode->spNext)
00941 {
00942
00943
00944 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00945
00946
00947
00948
00949
00950 if(spCurrNodeData->eGapAcked == TRUE)
00951 {
00952 DBG_PL(ProcessGapAckBlocks,
00953 "out of order SACK? setting TSN=%d eGapAcked=FALSE"),
00954 spCurrNodeData->spChunk->uiTsn DBG_PR;
00955 spCurrNodeData->eGapAcked = FALSE;
00956 spCurrNodeData->spDest->iOutstandingBytes
00957 += spCurrNodeData->spChunk->sHdr.usLength;
00958
00959
00960
00961
00962
00963
00964
00965 }
00966 }
00967
00968 DBG_PL(ProcessGapAckBlocks, "now incrementing missing reports...") DBG_PR;
00969 DBG_PL(ProcessGapAckBlocks, "uiHighestTsnNewlyAcked=%d"),
00970 uiHighestTsnNewlyAcked DBG_PR;
00971
00972 for(spCurrNode = sSendBuffer.spHead;
00973 spCurrNode != NULL;
00974 spCurrNode = spCurrNode->spNext)
00975 {
00976 spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
00977
00978 DBG_PL(ProcessGapAckBlocks, "TSN=%d eGapAcked=%s"),
00979 spCurrNodeData->spChunk->uiTsn,
00980 spCurrNodeData->eGapAcked ? "TRUE" : "FALSE"
00981 DBG_PR;
00982
00983 if(spCurrNodeData->eGapAcked == FALSE)
00984 {
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997 if( (spCurrNodeData->spChunk->uiTsn < uiHighestTsnNewlyAcked) ||
00998 (eNewCumAck == TRUE &&
00999 uiHighestTsnNewlyAcked <= uiRecover &&
01000 spCurrNodeData->spChunk->uiTsn < uiHighestTsnSacked))
01001 {
01002 spCurrNodeData->iNumMissingReports++;
01003 DBG_PL(ProcessGapAckBlocks,
01004 "incrementing missing report for TSN=%d to %d"),
01005 spCurrNodeData->spChunk->uiTsn,
01006 spCurrNodeData->iNumMissingReports
01007 DBG_PR;
01008
01009 if(spCurrNodeData->iNumMissingReports >= iFastRtxTrigger &&
01010 spCurrNodeData->eIneligibleForFastRtx == FALSE &&
01011 spCurrNodeData->eAdvancedAcked == FALSE)
01012 {
01013 MarkChunkForRtx(spCurrNodeData, FAST_RTX);
01014 eFastRtxNeeded = TRUE;
01015 spCurrNodeData->eIneligibleForFastRtx = TRUE;
01016 DBG_PL(ProcessGapAckBlocks,
01017 "setting eFastRtxNeeded = TRUE") DBG_PR;
01018 }
01019 }
01020 }
01021 }
01022 }
01023
01024 if(eFastRtxNeeded == TRUE)
01025 tiFrCount++;
01026
01027 DBG_PL(ProcessGapAckBlocks, "eFastRtxNeeded=%s"),
01028 eFastRtxNeeded ? "TRUE" : "FALSE" DBG_PR;
01029 DBG_X(ProcessGapAckBlocks);
01030 return eFastRtxNeeded;
01031 }
01032
01033
01034
01035
01036 void TimestampSctpAgent::ProcessOptionChunk(u_char *ucpInChunk)
01037 {
01038 DBG_I(ProcessOptionChunk);
01039 double dCurrTime = Scheduler::instance().clock();
01040
01041 switch( ((SctpChunkHdr_S *)ucpInChunk)->ucType)
01042 {
01043 case SCTP_CHUNK_TIMESTAMP:
01044 ProcessTimestampChunk((SctpTimestampChunk_S *) ucpInChunk);
01045 break;
01046
01047 default:
01048 DBG_PL(ProcessOptionChunk, "unexpected chunk type (unknown: %d) at %f"),
01049 ((SctpChunkHdr_S *)ucpInChunk)->ucType, dCurrTime DBG_PR;
01050 printf("[ProcessOptionChunk] unexpected chunk type (unknown: %d) at %f\n",
01051 ((SctpChunkHdr_S *)ucpInChunk)->ucType, dCurrTime);
01052 break;
01053 }
01054
01055 DBG_X(ProcessOptionChunk);
01056 }
01057
01058 void TimestampSctpAgent::ProcessTimestampChunk(SctpTimestampChunk_S
01059 *spTimestampChunk)
01060 {
01061 DBG_I(ProcessTimestampChunk);
01062
01063
01064
01065
01066
01067 if(spTimestampChunk->sHdr.ucFlags & SCTP_TIMESTAMP_FLAG_TS)
01068 {
01069 if(eNeedTimestampEcho == FALSE)
01070 {
01071 eNeedTimestampEcho = TRUE;
01072 fOutTimestampEcho = spTimestampChunk->fTimestamp;
01073 DBG_PL(ProcessTimestampChunk, "timestamp=%f ...echoing!"),
01074 spTimestampChunk->fTimestamp DBG_PR;
01075 }
01076 else
01077 {
01078 DBG_PL(ProcessTimestampChunk,
01079 "timestamp=%f ...ignoring (already echoing one)"),
01080 spTimestampChunk->fTimestamp DBG_PR;
01081 }
01082 }
01083
01084 if(spTimestampChunk->sHdr.ucFlags & SCTP_TIMESTAMP_FLAG_ECHO)
01085 {
01086 fInTimestampEcho = spTimestampChunk->fEcho;
01087 DBG_PL(ProcessTimestampChunk, "echo=%f"),
01088 spTimestampChunk->fEcho DBG_PR;
01089 }
01090
01091 DBG_X(ProcessTimestampChunk);
01092 }