sctp.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:164k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 2006-2007 by the Protocol Engineering Lab, U of Delaware
  3.  * All rights reserved.
  4.  *
  5.  * Protocol Engineering Lab web page : http://pel.cis.udel.edu/
  6.  *
  7.  * Paul D. Amer        <amer@@cis,udel,edu>
  8.  * Armando L. Caro Jr. <acaro@@cis,udel,edu>
  9.  * Janardhan Iyengar   <iyengar@@cis,udel,edu>
  10.  * Preethi Natarajan   <nataraja@@cis,udel,edu>
  11.  * Nasif Ekiz          <nekiz@@cis,udel,edu>
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without
  14.  * modification, are permitted provided that the following conditions
  15.  * are met:
  16.  *
  17.  * 1. Redistributions of source code must retain the above copyright
  18.  *    notice, this list of conditions and the following disclaimer.
  19.  *
  20.  * 2. Redistributions in binary form must reproduce the above copyright
  21.  *    notice, this list of conditions and the following disclaimer in the
  22.  *    documentation and/or other materials provided with the distribution.
  23.  *
  24.  * 3. Neither the name of the University nor of the Laboratory may be used
  25.  *    to endorse or promote products derived from this software without
  26.  *    specific prior written permission.
  27.  *
  28.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  29.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  30.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  32.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  34.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  37.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  38.  * SUCH DAMAGE.
  39.  */
  40. #ifndef lint
  41. static const char rcsid[] =
  42. "@(#) $Header: /cvsroot/nsnam/ns-2/sctp/sctp.cc,v 1.14 2008/03/27 05:21:18 tom_henderson Exp $ (UD/PEL)";
  43. #endif
  44. #include "ip.h"
  45. #include "sctp.h"
  46. #include "flags.h"
  47. #include "random.h"
  48. #include "template.h"
  49. #include "sctpDebug.h"
  50. #ifdef DMALLOC
  51. #include "dmalloc.h"
  52. #endif
  53. #define MIN(x,y) (((x)<(y))?(x):(y))
  54. #define MAX(x,y) (((x)>(y))?(x):(y))
  55. int hdr_sctp::offset_;
  56. static class SCTPHeaderClass : public PacketHeaderClass 
  57. {
  58. public:
  59.   SCTPHeaderClass() : PacketHeaderClass("PacketHeader/SCTP",
  60. sizeof(hdr_sctp)) 
  61.   {
  62.     bind_offset(&hdr_sctp::offset_);
  63.   }
  64. } class_sctphdr;
  65. static class SctpClass : public TclClass 
  66. public:
  67.   SctpClass() : TclClass("Agent/SCTP") {}
  68.   TclObject* create(int, const char*const*) 
  69.   {
  70.     return (new SctpAgent());
  71.   }
  72. } classSctp;
  73. SctpAgent::SctpAgent() : Agent(PT_SCTP)
  74. {
  75.   fhpDebugFile = NULL;  // init
  76.   opCoreTarget = NULL;  // initialize to NULL in case multihoming isn't used.
  77.   memset(&sInterfaceList, 0, sizeof(List_S) );
  78.   memset(&sDestList, 0, sizeof(List_S) );
  79.   memset(&sAppLayerBuffer, 0, sizeof(List_S) );
  80.   memset(&sSendBuffer, 0, sizeof(List_S) );
  81.   memset(&sRecvTsnBlockList, 0, sizeof(List_S) );
  82.   memset(&sDupTsnList, 0, sizeof(List_S) );
  83.   spOutStreams = NULL;
  84.   opSackGenTimer = new SackGenTimer(this);
  85.   spSctpTrace = NULL;
  86.   opHeartbeatGenTimer = new HeartbeatGenTimer(this);
  87.   opT1InitTimer = new T1InitTimer(this);
  88.   opT1CookieTimer = new T1CookieTimer(this);
  89.   eState = SCTP_STATE_UNINITIALIZED;
  90. }
  91. SctpAgent::~SctpAgent()
  92. {
  93.   Node_S *spCurrNode = NULL;
  94.   Node_S *spPrevNode = NULL;
  95.   SctpDest_S *spDest = NULL;
  96.   delete opSackGenTimer;
  97.   opSackGenTimer = NULL;
  98.   delete opHeartbeatGenTimer;
  99.   opHeartbeatGenTimer = NULL;
  100.   delete opT1InitTimer;
  101.   opT1InitTimer = NULL;
  102.   delete opT1CookieTimer;
  103.   opT1CookieTimer = NULL;
  104.   if(spOutStreams != NULL)
  105.     delete spOutStreams;
  106.   for(spCurrNode = sInterfaceList.spHead;
  107.       spCurrNode != NULL;
  108.       spPrevNode = spCurrNode,spCurrNode=spCurrNode->spNext, delete spPrevNode)
  109.     {
  110.       delete (SctpInterface_S *) spCurrNode->vpData;
  111.       spCurrNode->vpData = NULL;
  112.     }
  113.   for(spCurrNode = sDestList.spHead;
  114.       spCurrNode != NULL;
  115.       spPrevNode = spCurrNode,spCurrNode=spCurrNode->spNext, delete spPrevNode)
  116.     {
  117.       spDest = (SctpDest_S *) spCurrNode->vpData;
  118.       if(spDest->opT3RtxTimer != NULL)
  119. {
  120.   delete spDest->opT3RtxTimer;
  121.   spDest->opT3RtxTimer = NULL;
  122. }
  123.       if(spDest->opCwndDegradeTimer != NULL)
  124. {
  125.   delete spDest->opCwndDegradeTimer;
  126.   spDest->opCwndDegradeTimer = NULL;
  127. }
  128.       if(spDest->opHeartbeatTimeoutTimer != NULL)
  129. {
  130.   delete spDest->opHeartbeatTimeoutTimer;
  131.   spDest->opHeartbeatTimeoutTimer = NULL;
  132. }
  133.       if(spDest->opRouteCacheFlushTimer != NULL)
  134. {
  135.   delete spDest->opRouteCacheFlushTimer;
  136.   spDest->opRouteCacheFlushTimer = NULL;
  137. }
  138.       if(spDest->opRouteCalcDelayTimer != NULL)
  139. {
  140.   delete spDest->opRouteCalcDelayTimer;
  141.   spDest->opRouteCalcDelayTimer = NULL;
  142. }
  143.       Packet::free(spDest->opRoutingAssistPacket);
  144.       spDest->opRoutingAssistPacket = NULL;
  145.       delete (SctpDest_S *) spCurrNode->vpData;  //spDest
  146.       spCurrNode->vpData = NULL;
  147.     }
  148.   if(spSctpTrace != NULL)
  149.     {
  150.       delete spSctpTrace;
  151.       spSctpTrace = NULL;
  152.     }
  153. }
  154. void SctpAgent::delay_bind_init_all()
  155. {
  156.   delay_bind_init_one("debugMask_");
  157.   delay_bind_init_one("debugFileIndex_");
  158.   delay_bind_init_one("associationMaxRetrans_");
  159.   delay_bind_init_one("pathMaxRetrans_");
  160.   delay_bind_init_one("changePrimaryThresh_");
  161.   delay_bind_init_one("maxInitRetransmits_");
  162.   delay_bind_init_one("heartbeatInterval_");
  163.   delay_bind_init_one("mtu_");
  164.   delay_bind_init_one("initialRwnd_");
  165.   delay_bind_init_one("initialSsthresh_");
  166.   delay_bind_init_one("ipHeaderSize_");
  167.   delay_bind_init_one("dataChunkSize_");
  168.   delay_bind_init_one("numOutStreams_");
  169.   delay_bind_init_one("useDelayedSacks_");
  170.   delay_bind_init_one("sackDelay_");
  171.   delay_bind_init_one("useMaxBurst_");
  172.   delay_bind_init_one("initialCwnd_");
  173.   delay_bind_init_one("initialRto_");
  174.   delay_bind_init_one("minRto_");
  175.   delay_bind_init_one("maxRto_");
  176.   delay_bind_init_one("fastRtxTrigger_");
  177.   delay_bind_init_one("numUnrelStreams_");
  178.   delay_bind_init_one("reliability_");
  179.   delay_bind_init_one("unordered_");
  180.   delay_bind_init_one("rtxToAlt_");
  181.   delay_bind_init_one("dormantAction_");
  182.   delay_bind_init_one("routeCacheLifetime_");
  183.   delay_bind_init_one("routeCalcDelay_");
  184.   delay_bind_init_one("trace_all_");
  185.   delay_bind_init_one("cwnd_");
  186.   delay_bind_init_one("rwnd_");
  187.   delay_bind_init_one("rto_");
  188.   delay_bind_init_one("errorCount_");
  189.   delay_bind_init_one("frCount_");
  190.   delay_bind_init_one("timeoutCount_");
  191.   delay_bind_init_one("rcdCount_");
  192.   Agent::delay_bind_init_all();
  193. }
  194. int SctpAgent::delay_bind_dispatch(const char *cpVarName, 
  195.    const char *cpLocalName, 
  196.    TclObject *opTracer)
  197. {
  198.   if(delay_bind(cpVarName, cpLocalName, "debugMask_", &uiDebugMask, opTracer)) 
  199.     return TCL_OK;
  200.   
  201.   if(delay_bind(cpVarName, cpLocalName, 
  202. "debugFileIndex_", &iDebugFileIndex, opTracer)) 
  203.     return TCL_OK;
  204.   
  205.   if(delay_bind(cpVarName, cpLocalName, 
  206. "associationMaxRetrans_", &uiAssociationMaxRetrans, opTracer)) 
  207.     return TCL_OK;
  208.   if(delay_bind(cpVarName, cpLocalName, 
  209. "pathMaxRetrans_", &uiPathMaxRetrans, opTracer)) 
  210.     return TCL_OK;
  211.   if(delay_bind(cpVarName, cpLocalName, 
  212. "changePrimaryThresh_", &uiChangePrimaryThresh, opTracer)) 
  213.     return TCL_OK;
  214.   if(delay_bind(cpVarName, cpLocalName, 
  215. "maxInitRetransmits_", &uiMaxInitRetransmits, opTracer)) 
  216.     return TCL_OK;
  217.   if(delay_bind(cpVarName, cpLocalName, 
  218. "heartbeatInterval_", &uiHeartbeatInterval, opTracer)) 
  219.     return TCL_OK;
  220.   if(delay_bind(cpVarName, cpLocalName, "mtu_", &uiMtu, opTracer)) 
  221.     return TCL_OK;
  222.   
  223.   if(delay_bind(cpVarName, cpLocalName, 
  224. "initialRwnd_", &uiInitialRwnd, opTracer)) 
  225.     return TCL_OK;
  226.   if(delay_bind(cpVarName, cpLocalName, 
  227. "initialSsthresh_", &iInitialSsthresh, opTracer)) 
  228.     return TCL_OK;
  229.   
  230.   if(delay_bind(cpVarName, cpLocalName, 
  231. "ipHeaderSize_", &uiIpHeaderSize, opTracer)) 
  232.     return TCL_OK;
  233.   if(delay_bind(cpVarName, cpLocalName, 
  234. "dataChunkSize_", &uiDataChunkSize, opTracer)) 
  235.     return TCL_OK;
  236.   
  237.   if(delay_bind(cpVarName, cpLocalName, 
  238. "numOutStreams_", &uiNumOutStreams, opTracer)) 
  239.     return TCL_OK;
  240.   if(delay_bind(cpVarName, cpLocalName, 
  241. "useDelayedSacks_", (int *) &eUseDelayedSacks, opTracer)) 
  242.     return TCL_OK;
  243.   if(delay_bind(cpVarName, cpLocalName, 
  244. "sackDelay_",  &dSackDelay, opTracer)) 
  245.     return TCL_OK;
  246.   if(delay_bind(cpVarName, cpLocalName, 
  247. "useMaxBurst_", (int *) &eUseMaxBurst, opTracer)) 
  248.     return TCL_OK;
  249.   if(delay_bind(cpVarName, cpLocalName, 
  250. "initialCwnd_", &iInitialCwnd, opTracer)) 
  251.     return TCL_OK;
  252.   if(delay_bind(cpVarName, cpLocalName, 
  253. "initialRto_", &dInitialRto, opTracer)) 
  254.     return TCL_OK;
  255.   if(delay_bind(cpVarName, cpLocalName, 
  256. "minRto_", &dMinRto, opTracer)) 
  257.     return TCL_OK;
  258.   if(delay_bind(cpVarName, cpLocalName, 
  259. "maxRto_", &dMaxRto, opTracer)) 
  260.     return TCL_OK;
  261.     
  262.   if(delay_bind(cpVarName, cpLocalName, 
  263. "fastRtxTrigger_", &iFastRtxTrigger, opTracer)) 
  264.     return TCL_OK;
  265.   if(delay_bind(cpVarName, cpLocalName, 
  266. "numUnrelStreams_", &uiNumUnrelStreams, opTracer)) 
  267.     return TCL_OK;
  268.   if(delay_bind(cpVarName, cpLocalName, 
  269. "reliability_", &uiReliability, opTracer)) 
  270.     return TCL_OK;
  271.   if(delay_bind(cpVarName, cpLocalName, 
  272. "unordered_", (int *) &eUnordered, opTracer)) 
  273.     return TCL_OK;
  274.   if(delay_bind(cpVarName, cpLocalName, 
  275. "rtxToAlt_", (int *) &eRtxToAlt, opTracer)) 
  276.     return TCL_OK;
  277.   if(delay_bind(cpVarName, cpLocalName, 
  278. "dormantAction_", (int *) &eDormantAction, opTracer)) 
  279.     return TCL_OK;
  280.   if(delay_bind(cpVarName, cpLocalName, 
  281. "routeCacheLifetime_", &dRouteCacheLifetime, opTracer)) 
  282.     return TCL_OK;
  283.   if(delay_bind(cpVarName, cpLocalName, 
  284. "routeCalcDelay_", &dRouteCalcDelay, opTracer)) 
  285.     return TCL_OK;
  286.   if(delay_bind(cpVarName, cpLocalName, "cwnd_", &tiCwnd, opTracer)) 
  287.     return TCL_OK;
  288.   if(delay_bind(cpVarName, cpLocalName, "rwnd_", &tiRwnd, opTracer)) 
  289.     return TCL_OK;
  290.   if(delay_bind(cpVarName, cpLocalName, "rto_", &tdRto, opTracer)) 
  291.     return TCL_OK;
  292.   if(delay_bind(cpVarName, cpLocalName, "errorCount_", &tiErrorCount,opTracer))
  293.     return TCL_OK;
  294.   if(delay_bind(cpVarName, cpLocalName, "frCount_", &tiFrCount, opTracer))
  295.     return TCL_OK;
  296.   if(delay_bind(cpVarName, cpLocalName, 
  297. "timeoutCount_", &tiTimeoutCount, opTracer))
  298.     return TCL_OK;
  299.   if(delay_bind(cpVarName, cpLocalName, "rcdCount_", &tiRcdCount, opTracer))
  300.     return TCL_OK;
  301.   if(delay_bind(cpVarName, cpLocalName, 
  302. "trace_all_", (int *) &eTraceAll, opTracer)) 
  303.     return TCL_OK;
  304.   return Agent::delay_bind_dispatch(cpVarName, cpLocalName, opTracer);
  305. }
  306. void SctpAgent::TraceAll()
  307. {
  308.   char cpOutString[500];
  309.   Node_S *spCurrNode = NULL;
  310.   SctpDest_S *spCurrDest = NULL;
  311.   double dCurrTime = Scheduler::instance().clock();
  312.   for(spCurrNode = sDestList.spHead;
  313.       spCurrNode != NULL;
  314.       spCurrNode = spCurrNode->spNext)
  315.     {
  316.       spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  317.       SetSource(spCurrDest); // gives us the correct source addr & port
  318.       sprintf(cpOutString,
  319.       "time: %-8.5f  "
  320.       "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
  321.       "cwnd: %d pba: %d out: %d ssthresh: %d rwnd: %d peerRwnd: %d "
  322.       "rto: %-6.3f srtt: %-6.3f rttvar: %-6.3f "
  323.       "assocErrors: %d pathErrors: %d dstatus: %s isPrimary: %s "
  324.       "frCount: %d timeoutCount: %d rcdCount: %dn",
  325.       dCurrTime,
  326.       addr(), port(), spCurrDest->iNsAddr, spCurrDest->iNsPort,
  327.       spCurrDest->iCwnd, spCurrDest->iPartialBytesAcked, 
  328.       spCurrDest->iOutstandingBytes, spCurrDest->iSsthresh, 
  329.       uiMyRwnd, uiPeerRwnd,
  330.       spCurrDest->dRto, spCurrDest->dSrtt, 
  331.       spCurrDest->dRttVar,
  332.       iAssocErrorCount,
  333.       spCurrDest->iErrorCount,
  334.       spCurrDest->eStatus ? "ACTIVE" : "INACTIVE",
  335.       (spCurrDest == spPrimaryDest) ? "TRUE" : "FALSE",
  336.       int(tiFrCount),
  337.       spCurrDest->iTimeoutCount,
  338.       spCurrDest->iRcdCount);
  339.       if(channel_)
  340. (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  341.     }
  342.   sprintf(cpOutString, "n");
  343.   if(channel_)
  344.     (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  345. }
  346. void SctpAgent::TraceVar(const char* cpVar)
  347. {
  348.   char cpOutString[500];
  349.   Node_S *spCurrNode = NULL;
  350.   SctpDest_S *spCurrDest = NULL;
  351.   double dCurrTime = Scheduler::instance().clock();
  352.   if(!strcmp(cpVar, "cwnd_"))
  353.     for(spCurrNode = sDestList.spHead;
  354. spCurrNode != NULL;
  355. spCurrNode = spCurrNode->spNext)
  356.       {
  357. spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  358. SetSource(spCurrDest); // gives us the correct source addr & port
  359. sprintf(cpOutString,
  360. "time: %-8.5f  "
  361. "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
  362. "cwnd: %d pba: %d out: %d ssthresh: %d peerRwnd: %dn",
  363. dCurrTime, 
  364. addr(), port(), 
  365. spCurrDest->iNsAddr, spCurrDest->iNsPort,
  366. spCurrDest->iCwnd, spCurrDest->iPartialBytesAcked, 
  367. spCurrDest->iOutstandingBytes, spCurrDest->iSsthresh, 
  368. uiPeerRwnd);
  369. if(channel_)
  370.   (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  371.       }
  372.   else if(!strcmp(cpVar, "rwnd_"))
  373.     {
  374.       sprintf(cpOutString, "time: %-8.5f rwnd: %d peerRwnd: %dn", 
  375.       dCurrTime, uiMyRwnd, uiPeerRwnd);
  376.       if(channel_)
  377.       (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  378.     }
  379.   
  380.   else if(!strcmp(cpVar, "rto_"))
  381.     for(spCurrNode = sDestList.spHead;
  382. spCurrNode != NULL;
  383. spCurrNode = spCurrNode->spNext)
  384.       {
  385. spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  386. SetSource(spCurrDest); // gives us the correct source addr & port
  387. sprintf(cpOutString,
  388. "time: %-8.5f  "
  389. "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
  390. "rto: %-6.3f srtt: %-6.3f rttvar: %-6.3fn",
  391. dCurrTime, 
  392. addr(), port(), 
  393. spCurrDest->iNsAddr, spCurrDest->iNsPort,
  394. spCurrDest->dRto, spCurrDest->dSrtt, 
  395. spCurrDest->dRttVar);
  396. if(channel_)
  397.   (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  398.       }
  399.   else if(!strcmp(cpVar, "errorCount_"))
  400.     for(spCurrNode = sDestList.spHead;
  401. spCurrNode != NULL;
  402. spCurrNode = spCurrNode->spNext)
  403.       {
  404. spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  405. SetSource(spCurrDest); // gives us the correct source addr & port
  406. sprintf(cpOutString, 
  407. "time: %-8.5f  "
  408. "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
  409. "assocErrors: %d pathErrors: %d dstatus: %s isPrimary: %sn",
  410. dCurrTime, 
  411. addr(), port(), 
  412. spCurrDest->iNsAddr, spCurrDest->iNsPort,
  413. iAssocErrorCount,
  414. spCurrDest->iErrorCount,
  415. spCurrDest->eStatus ? "ACTIVE" : "INACTIVE",
  416. (spCurrDest == spPrimaryDest) ? "TRUE" : "FALSE");
  417. if(channel_)
  418.   (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  419.       }
  420.   else if(!strcmp(cpVar, "frCount_"))
  421.     {
  422.       sprintf(cpOutString, 
  423.       "time: %-8.5f  "
  424.       "frCount: %dn",
  425.       dCurrTime, 
  426.       int(*((TracedInt*) cpVar)) );
  427.       if(channel_)
  428. (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  429.     }
  430.   else if(!strcmp(cpVar, "timeoutCount_"))
  431.     {
  432.     for(spCurrNode = sDestList.spHead;
  433. spCurrNode != NULL;
  434. spCurrNode = spCurrNode->spNext)
  435.       {
  436. spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  437. SetSource(spCurrDest); // gives us the correct source addr & port
  438. sprintf(cpOutString, 
  439. "time: %-8.5f  "
  440. "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
  441. "timeoutCount: %dn",
  442. dCurrTime, 
  443. addr(), port(), 
  444. spCurrDest->iNsAddr, spCurrDest->iNsPort,
  445. spCurrDest->iTimeoutCount);
  446. if(channel_)
  447.   (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  448.       }
  449.     }
  450.   else if(!strcmp(cpVar, "rcdCount_"))
  451.     {
  452.     for(spCurrNode = sDestList.spHead;
  453. spCurrNode != NULL;
  454. spCurrNode = spCurrNode->spNext)
  455.       {
  456. spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  457. SetSource(spCurrDest); // gives us the correct source addr & port
  458. sprintf(cpOutString, 
  459. "time: %-8.5f  "
  460. "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d "
  461. "rcdCount: %dn",
  462. dCurrTime, 
  463. addr(), port(), 
  464. spCurrDest->iNsAddr, spCurrDest->iNsPort,
  465. spCurrDest->iRcdCount);
  466. if(channel_)
  467.   (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  468.       }
  469.     }
  470.   else
  471.     {
  472.       sprintf(cpOutString,
  473.       "time: %-8.5f  "
  474.       "saddr: %-2d sport: %-2d daddr: %-2d dport: %-2d %s: %sn",
  475.       dCurrTime, addr(), port(), daddr(), dport(),
  476.       cpVar, "ERROR (unepected trace variable)"); 
  477.       if(channel_)
  478. (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  479.     }
  480.   sprintf(cpOutString, "n");
  481.   if(channel_)
  482.     (void)Tcl_Write(channel_, cpOutString, strlen(cpOutString));
  483. }
  484. void SctpAgent::trace(TracedVar* v) 
  485. {
  486.   if(eTraceAll == TRUE)
  487.     TraceAll();
  488.   else 
  489.     TraceVar(v->name());
  490. }
  491. /* Reset() is called to refresh the current association settings. It is used
  492.  * for the first association. It can also be used to abruptly terminate the
  493.  * existing association (so that a new one can begin), but this usage has NOT
  494.  * been tested extensively.
  495.  */
  496. void SctpAgent::Reset()
  497. {
  498.   /* Just in case the user uses the standard ns-2 way of turning on
  499.    * debugging, we turn on all debugging. However, if the uiDebugMask is
  500.    * used, then the user knows about SCTP's fine-level debugging control
  501.    * and the debug_ flag is ignored.
  502.    */
  503.   if(debug_ == TRUE && uiDebugMask == 0)
  504.     uiDebugMask = 0xffffffff;
  505.   /* No debugging output will appear until this is called. Why do we do it
  506.    * here?  This is the earliest point at which we have the necessary
  507.    * debugging variables bound from TCL.  
  508.    */
  509.   DBG_FOPEN(); // internal check is done to ensure we only open once!
  510.   DBG_I(Reset);
  511.   if(eState != SCTP_STATE_UNINITIALIZED && eState != SCTP_STATE_CLOSED)
  512.     Close();  // abruptly close the connection
  513.   DBG_PL(Reset, "uiDebugMask=%u"), uiDebugMask DBG_PR;
  514.   DBG_PL(Reset, "iDebugFileIndex=%d"), iDebugFileIndex DBG_PR;
  515.   DBG_PL(Reset, "uiAssociationMaxRetrans=%ld"), uiAssociationMaxRetrans DBG_PR;
  516.   DBG_PL(Reset, "uiPathMaxRetrans=%ld"), uiPathMaxRetrans DBG_PR;
  517.   DBG_PL(Reset, "uiChangePrimaryThresh=%d"), uiChangePrimaryThresh DBG_PR;
  518.   DBG_PL(Reset, "uiHeartbeatInterval=%ld"), uiHeartbeatInterval DBG_PR;
  519.   DBG_PL(Reset, "uiMtu=%ld"), uiMtu DBG_PR;
  520.   DBG_PL(Reset, "uiInitialRwnd=%ld"), uiInitialRwnd DBG_PR;
  521.   DBG_PL(Reset, "iInitialSsthresh=%ld"), iInitialSsthresh DBG_PR;
  522.   DBG_PL(Reset, "uiIpHeaderSize=%ld"), uiIpHeaderSize DBG_PR;
  523.   DBG_PL(Reset, "uiDataChunkSize=%ld"), uiDataChunkSize DBG_PR;
  524.   DBG_PL(Reset, "uiNumOutStreams=%ld"), uiNumOutStreams DBG_PR;
  525.   DBG_PL(Reset, "eUseDelayedSacks=%s"), 
  526.     eUseDelayedSacks ? "TRUE" : "FALSE" DBG_PR;
  527.   DBG_PL(Reset, "dSackDelay=%f"), dSackDelay DBG_PR;
  528.   DBG_PL(Reset, "eUseMaxBurst=%s"), eUseMaxBurst ? "TRUE" : "FALSE" DBG_PR;
  529.   DBG_PL(Reset, "iInitialCwnd=%ld"), iInitialCwnd DBG_PR;
  530.   DBG_PL(Reset, "dInitialRto=%f"), dInitialRto DBG_PR;
  531.   DBG_PL(Reset, "dMinRto=%f"), dMinRto DBG_PR;
  532.   DBG_PL(Reset, "dMaxRto=%f"), dMaxRto DBG_PR;
  533.   DBG_PL(Reset, "iFastRtxTrigger=%ld"), iFastRtxTrigger DBG_PR;
  534.   DBG_PL(Reset, "uiNumUnrelStreams=%ld"), uiNumUnrelStreams DBG_PR;
  535.   DBG_PL(Reset, "uiReliability=%ld"), uiReliability DBG_PR;
  536.   DBG_PL(Reset, "eUnordered=%s"), eUnordered ? "TRUE" : "FALSE" DBG_PR;
  537.   switch(eRtxToAlt)
  538.     {
  539.     case RTX_TO_ALT_OFF:
  540.       DBG_PL(Reset, "eRtxToAlt=RTX_TO_ALT_OFF") DBG_PR;
  541.       break;
  542.     case RTX_TO_ALT_ON:
  543.       DBG_PL(Reset, "eRtxToAlt=RTX_TO_ALT_ON") DBG_PR;
  544.       break;
  545.     case RTX_TO_ALT_TIMEOUTS_ONLY:
  546.       DBG_PL(Reset, "eRtxToAlt=RTX_TO_ALT_TIMEOUTS_ONLY") DBG_PR;
  547.       break;
  548.     }
  549.   switch(eDormantAction)
  550.     {
  551.     case DORMANT_HOP:
  552.       DBG_PL(Reset, "eDormantAction=DORMANT_HOP") DBG_PR;
  553.       break;
  554.     case DORMANT_PRIMARY:
  555.       DBG_PL(Reset, "eDormantAction=DORMANT_PRIMARY") DBG_PR;
  556.       break;
  557.     case DORMANT_LASTDEST:
  558.       DBG_PL(Reset, "eDormantAction=DORMANT_LASTDEST") DBG_PR;
  559.       break;
  560.     }
  561.   DBG_PL(Reset, "eTraceAll=%s"), eTraceAll ? "TRUE" : "FALSE" DBG_PR;
  562.   Node_S *spCurrNode = NULL;
  563.   SctpDest_S *spCurrDest = NULL;
  564.   int i;
  565.   if(uiInitialRwnd > MAX_RWND_SIZE)
  566.     {
  567.       fprintf(stderr, "SCTP ERROR: initial rwnd (%d) > max (%d)n",
  568.       uiInitialRwnd, MAX_RWND_SIZE);
  569.       DBG_PL(Reset, "ERROR: initial rwnd (%d) > max (%d)"), 
  570. uiInitialRwnd, MAX_RWND_SIZE DBG_PR;
  571.       DBG_PL(Reset, "exiting...") DBG_PR;
  572.       exit(-1);
  573.     }
  574.   if(uiNumOutStreams > MAX_NUM_STREAMS)
  575.     {
  576.       fprintf(stderr, "%s number of streams (%d) > max (%d)n",
  577.       "SCTP ERROR:",
  578.       uiNumOutStreams, MAX_NUM_STREAMS);
  579.       DBG_PL(Reset, "ERROR: number of streams (%d) > max (%d)"), 
  580. uiNumOutStreams, MAX_NUM_STREAMS DBG_PR;
  581.       DBG_PL(Reset, "exiting...") DBG_PR;
  582.       exit(-1);
  583.     }
  584.   else if(uiNumUnrelStreams > uiNumOutStreams)
  585.     {
  586.       fprintf(stderr, "%s number of unreliable streams (%d) > total (%d)n",
  587.       "SCTP ERROR:",
  588.       uiNumUnrelStreams, uiNumOutStreams);
  589.       DBG_PL(Reset, "ERROR: number of unreliable streams (%d) > total (%d)"), 
  590. uiNumUnrelStreams, uiNumOutStreams DBG_PR;
  591.       DBG_PL(Reset, "exiting...") DBG_PR;
  592.       exit(-1);
  593.     }
  594.   uiMaxPayloadSize = uiMtu - SCTP_HDR_SIZE - uiIpHeaderSize;
  595.   uiMaxDataSize = uiMaxPayloadSize - ControlChunkReservation();
  596.   if(uiDataChunkSize > MAX_DATA_CHUNK_SIZE)
  597.     {
  598.       fprintf(stderr, "%s data chunk size (%d) > max (%d)n",
  599.       "SCTP ERROR:",
  600.       uiDataChunkSize, MAX_DATA_CHUNK_SIZE);
  601.       DBG_PL(Reset, "ERROR: data chunk size (%d) > max (%d)"), 
  602. uiDataChunkSize, MAX_DATA_CHUNK_SIZE DBG_PR;
  603.       DBG_PL(Reset, "exiting...") DBG_PR;
  604.       exit(-1);
  605.     }
  606.   else if(uiDataChunkSize > uiMaxDataSize)
  607.     {
  608.       fprintf(stderr, "SCTP ERROR: DATA chunk size (%d) too big!n",
  609.       uiDataChunkSize);
  610.       fprintf(stderr, "            SCTP/IP header = %dn",
  611.       SCTP_HDR_SIZE + uiIpHeaderSize);
  612.       fprintf(stderr, "            Control chunk reservation = %dn",
  613.       ControlChunkReservation());
  614.       fprintf(stderr, "            MTU = %dn", uiMtu);
  615.       fprintf(stderr, "n");
  616.       DBG_PL(Reset, 
  617.      "ERROR: data chunk size (%d) + SCTP/IP header(%d) + Reserved (%d) > MTU (%d)"), 
  618. uiDataChunkSize, SCTP_HDR_SIZE + uiIpHeaderSize, 
  619. ControlChunkReservation(), uiMtu DBG_PR;
  620.       DBG_PL(Reset, "exiting...") DBG_PR;
  621.       exit(-1);
  622.     }
  623.   else if(uiDataChunkSize < MIN_DATA_CHUNK_SIZE)
  624.     {
  625.       fprintf(stderr, "%s data chunk size (%d) < min (%d)n",
  626.       "SCTP ERROR:",
  627.       uiDataChunkSize, MIN_DATA_CHUNK_SIZE);
  628.       DBG_PL(Reset, "ERROR: data chunk size (%d) < min (%d)"), 
  629. uiDataChunkSize, MIN_DATA_CHUNK_SIZE DBG_PR;
  630.       DBG_PL(Reset, "exiting...") DBG_PR;
  631.       exit(-1);
  632.     }
  633.   /* size_ is an Agent variable which is normally the packet size, but
  634.    * SCTP uses size_ to dictate to non-sctp aware applications the max
  635.    * data size of an application write. If size_ isn't set by SCTP, some
  636.    * non-sctp aware apps (such as Telnet) will call sendmsg() with 0
  637.    * bytes.
  638.    */
  639.   size_ = uiMtu - SCTP_HDR_SIZE - uiIpHeaderSize - sizeof(SctpDataChunkHdr_S);
  640.   eState = SCTP_STATE_CLOSED;
  641.   eForceSource = FALSE;
  642.   iAssocErrorCount = 0;
  643.   if(uiHeartbeatInterval != 0)
  644.     {
  645.       opHeartbeatGenTimer->force_cancel();
  646.     }
  647.   opT1InitTimer->force_cancel();
  648.   opT1CookieTimer->force_cancel();
  649.   iInitTryCount = 0;
  650.   uiNextTsn = 0;
  651.   usNextStreamId = 0;
  652.   /* if it's already allocated, let's delete and reallocate just in case user
  653.    * has changed TCL bindable variables
  654.    */
  655.   if(spOutStreams != NULL)
  656.     delete spOutStreams;
  657.   spOutStreams = new SctpOutStream_S [uiNumOutStreams];
  658.   memset(spOutStreams, 0, (uiNumOutStreams * sizeof(SctpOutStream_S)) );
  659.   for(i = 0; i < (int) uiNumUnrelStreams; i++)
  660.     {
  661.       DBG_PL(Reset, "setting outStream %d to UNRELIABLE"), i DBG_PR;
  662.       spOutStreams[i].eMode = SCTP_STREAM_UNRELIABLE;
  663.     }
  664.   for(; i < (int) uiNumOutStreams; i++)
  665.     {
  666.       DBG_PL(Reset, "setting outStream %d to RELIABLE"), i DBG_PR;
  667.       spOutStreams[i].eMode = SCTP_STREAM_RELIABLE;
  668.     }
  669.   uiPeerRwnd = 0;
  670.   uiCumAckPoint = 0;
  671.   uiAdvancedPeerAckPoint = 0;
  672.   uiHighestTsnNewlyAcked = 0;
  673.   uiRecover = 0;
  674.   memset(&sAppLayerBuffer, 0, sizeof(List_S) );
  675.   memset(&sSendBuffer, 0, sizeof(List_S) );
  676.   if(uiAssociationMaxRetrans > (sDestList.uiLength * uiPathMaxRetrans))
  677.     {
  678.       DBG_PL(Reset, 
  679.      "WARNING: Association.Max.Retrans > "
  680.      "summation of all destinations' Path.Max.Retrans "
  681.      "(rfc2960 section 8.1)") DBG_PR;
  682.     }
  683.   for(spCurrNode = sDestList.spHead;
  684.       spCurrNode != NULL;
  685.       spCurrNode = spCurrNode->spNext)
  686.     {
  687.       spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  688.       spCurrDest->iCwnd = iInitialCwnd * uiMaxDataSize; 
  689.       spCurrDest->iSsthresh = iInitialSsthresh;
  690.       spCurrDest->eFirstRttMeasurement = TRUE;
  691.       spCurrDest->dRto = dInitialRto;
  692.       if(spCurrDest->opT3RtxTimer == NULL)
  693. spCurrDest->opT3RtxTimer = new T3RtxTimer(this, spCurrDest);
  694.       else 
  695. spCurrDest->opT3RtxTimer->force_cancel();
  696.       spCurrDest->iOutstandingBytes = 0;
  697.       spCurrDest->iPartialBytesAcked = 0;
  698.       spCurrDest->iErrorCount = 0;
  699.       spCurrDest->iTimeoutCount = 0;
  700.       spCurrDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
  701.       if(spCurrDest->opCwndDegradeTimer == NULL)
  702. {
  703.   spCurrDest->opCwndDegradeTimer =
  704.     new CwndDegradeTimer(this, spCurrDest);
  705. }
  706.       else
  707. {
  708.   spCurrDest->opCwndDegradeTimer->force_cancel();
  709. }
  710.       
  711.       spCurrDest->dIdleSince = 0;
  712.             
  713.       if(spCurrDest->opHeartbeatTimeoutTimer == NULL)
  714. {
  715.   spCurrDest->opHeartbeatTimeoutTimer =
  716.     new HeartbeatTimeoutTimer(this, spCurrDest);
  717. }
  718.       else
  719. {
  720.   spCurrDest->opHeartbeatTimeoutTimer->force_cancel();
  721. }
  722.       
  723.       spCurrDest->eCcApplied = FALSE;
  724.       spCurrDest->spFirstOutstanding = NULL;
  725.       
  726.       /* per destination vars for CMT
  727.        */
  728.       spCurrDest->uiBurstLength = 0;
  729.       spCurrDest->eMarkedChunksPending = FALSE;
  730.       
  731.       spCurrDest->iRcdCount = 0;      
  732.       spCurrDest->eRouteCached = FALSE;
  733.       
  734.       if(spCurrDest->opRouteCacheFlushTimer == NULL)
  735. {
  736.   spCurrDest->opRouteCacheFlushTimer =
  737.     new RouteCacheFlushTimer(this, spCurrDest);
  738. }
  739.       else
  740. {
  741.   spCurrDest->opRouteCacheFlushTimer->force_cancel();
  742. }
  743.       if(spCurrDest->opRouteCalcDelayTimer == NULL)
  744. {
  745.   spCurrDest->opRouteCalcDelayTimer =
  746.     new RouteCalcDelayTimer(this, spCurrDest);
  747. }
  748.       else
  749. {
  750.   spCurrDest->opRouteCalcDelayTimer->force_cancel();
  751. }
  752.       memset(&spCurrDest->sBufferedPackets, 0, sizeof(List_S) );
  753.     }
  754.   eForwardTsnNeeded = FALSE;
  755.   eSendNewDataChunks = FALSE;
  756.   eMarkedChunksPending = FALSE;
  757.   eApplyMaxBurst = FALSE; // Why is MaxBurst init'd to FALSE?? (JRI)
  758.   eDataSource = DATA_SOURCE_APPLICATION;
  759.   uiBurstLength = 0;
  760.   uiMyRwnd = uiInitialRwnd;
  761.   uiCumAck = 0; 
  762.   uiHighestRecvTsn = 0;
  763.   memset(&sRecvTsnBlockList, 0, sizeof(List_S) );
  764.   memset(&sDupTsnList, 0, sizeof(List_S) );
  765.   eStartOfPacket = FALSE;
  766.   iDataPktCountSinceLastSack = 0;
  767.   eSackChunkNeeded = FALSE;
  768.   opSackGenTimer->force_cancel();
  769.   /* if it's already allocated, let's delete and reallocate just in case user
  770.    * has changed TCL bindable variables
  771.    */
  772.   if(spSctpTrace != NULL)
  773.     delete spSctpTrace;
  774.   
  775.   /* We don't know how many chunks will be in a packet, so we assume the 
  776.    * theoretical maximum... a packet full of only chunk headers.
  777.    */
  778.   spSctpTrace = new SctpTrace_S[uiMaxPayloadSize / sizeof(SctpChunkHdr_S)];
  779.   uiNumChunks = 0;
  780.   /* Trigger changes for trace to pick up (we want to know the initial values)
  781.    */
  782.   tiCwnd++;
  783.   tiRwnd++;
  784.   tdRto++;
  785.   tiErrorCount++;
  786.   tiFrCount = 0;
  787.   tiTimeoutCount++;
  788.   tiRcdCount++;
  789.   OptionReset();
  790.   DBG_PL(Reset, "spSctpTrace=%p"), spSctpTrace DBG_PR;
  791.   DBG_X(Reset);
  792. }
  793. /* This function serves as a hook for optional extensions to reset additional
  794.  * state variables.
  795.  */
  796. void SctpAgent::OptionReset()
  797. {
  798.   return;
  799. }
  800. /* This function returns a size based on how much space is needed for
  801.  * bundled chunks. Real implementations, such as the KAME stack, reserve
  802.  * space for ECN, etc. We are using it for experimental extensions such as
  803.  * the Timestamp chunk (sctp-timestamp.cc). Such a function avoids having
  804.  * to maintain nearly identical copies of the Reset() function for each
  805.  * extension. For the base sctp, we don't reserve any space... so return 0.
  806.  */
  807. u_int SctpAgent::ControlChunkReservation()
  808. {
  809.   DBG_I(ControlChunkReservation);
  810.   DBG_PL(ControlChunkReservation, "returning 0") DBG_PR;
  811.   DBG_X(ControlChunkReservation);
  812.   return 0;
  813. }
  814. int SctpAgent::command(int argc, const char*const* argv)
  815. {
  816.   DBG_I(command);// internal check is done to avoid printing if file is unopen!
  817.   double dCurrTime = Scheduler::instance().clock();
  818.   DBG_PL(command, "<time:%f> argc=%d argv[1]=%s"),
  819.     dCurrTime, argc, argv[1] DBG_PR;
  820.   Tcl& oTcl = Tcl::instance();
  821.   Node *opNode = NULL;
  822.   int iNsAddr;
  823.   int iNsPort;
  824.   NsObject *opTarget = NULL;
  825.   NsObject *opLink = NULL;
  826.   int iRetVal;
  827.   if(argc == 2)   
  828.     {
  829.       if (strcmp(argv[1], "reset") == 0) 
  830. {
  831.   Reset();
  832.   DBG_X(command);
  833.   return (TCL_OK);
  834. }
  835.       else if (strcmp(argv[1], "close") == 0) 
  836. {
  837.   Close();
  838.   DBG_X(command);
  839.   return (TCL_OK);
  840. }
  841.     }
  842.   else if(argc == 3) 
  843.     {
  844.       if (strcmp(argv[1], "advance") == 0) 
  845. {
  846.   DBG_X(command);
  847.   return (TCL_OK);
  848. }
  849.       else if (strcmp(argv[1], "set-multihome-core") == 0) 
  850.   opCoreTarget = (Classifier *) TclObject::lookup(argv[2]);
  851.   if(opCoreTarget == NULL) 
  852.     {
  853.       oTcl.resultf("no such object %s", argv[4]);
  854.       return (TCL_ERROR);
  855.     }
  856.   DBG_X(command);
  857.   return (TCL_OK);
  858. }
  859.       else if (strcmp(argv[1], "set-primary-destination") == 0)
  860. {
  861.   opNode = (Node *) TclObject::lookup(argv[2]);
  862.   if(opNode == NULL) 
  863.     {
  864.       oTcl.resultf("no such object %s", argv[2]);
  865.       return (TCL_ERROR);
  866.     }
  867.   iRetVal = SetPrimary( opNode->address() );
  868.   if(iRetVal == TCL_ERROR)
  869.     {
  870.       fprintf(stderr, "[SctpAgent::command] ERROR:"
  871.       "%s is not a valid destinationn", argv[2]);
  872.       DBG_X(command);
  873.       return (TCL_ERROR);
  874.     }
  875.   DBG_X(command);
  876.   return (TCL_OK);
  877. }
  878.       else if (strcmp(argv[1], "force-source") == 0)
  879. {
  880.   opNode = (Node *) TclObject::lookup(argv[2]);
  881.   if(opNode == NULL) 
  882.     {
  883.       oTcl.resultf("no such object %s", argv[2]);
  884.       return (TCL_ERROR);
  885.     }
  886.   iRetVal = ForceSource( opNode->address() );
  887.   if(iRetVal == TCL_ERROR)
  888.     {
  889.       fprintf(stderr, "[SctpAgent::command] ERROR:"
  890.       "%s is not a valid sourcen", argv[2]);
  891.       DBG_X(command);
  892.       return (TCL_ERROR);
  893.     }
  894.   DBG_X(command);
  895.   return (TCL_OK);
  896. }
  897.       else if (strcmp(argv[1], "print") == 0) 
  898. {
  899.   if(eTraceAll == TRUE)
  900.     TraceAll();
  901.   else 
  902.     TraceVar(argv[2]);
  903.   DBG_X(command);
  904.   return (TCL_OK);
  905. }
  906.     }
  907.   else if(argc == 4)
  908.     {
  909.       if (strcmp(argv[1], "add-multihome-destination") == 0) 
  910.   iNsAddr = atoi(argv[2]);
  911.   iNsPort = atoi(argv[3]);
  912.   AddDestination(iNsAddr, iNsPort);
  913.   DBG_X(command);
  914.   return (TCL_OK);
  915. }
  916.       else if (strcmp(argv[1], "set-destination-lossrate") == 0)
  917. {
  918.   opNode = (Node *) TclObject::lookup(argv[2]);
  919.   if(opNode == NULL) 
  920.     {
  921.       oTcl.resultf("no such object %s", argv[2]);
  922.       return (TCL_ERROR);
  923.     }
  924.   iRetVal = SetLossrate( opNode->address(), atof(argv[3]) );
  925.   if(iRetVal == TCL_ERROR)
  926.     {
  927.       fprintf(stderr, "[SctpAgent::command] ERROR:"
  928.       "%s is not a valid destinationn", argv[2]);
  929.       DBG_X(command);
  930.       return (TCL_ERROR);
  931.     }
  932.   DBG_X(command);
  933.   return (TCL_OK);
  934. }
  935.     }
  936.   else if(argc == 6)
  937.     {
  938.       if (strcmp(argv[1], "add-multihome-interface") == 0) 
  939.   iNsAddr = atoi(argv[2]);
  940.   iNsPort = atoi(argv[3]);
  941.   opTarget = (NsObject *) TclObject::lookup(argv[4]);
  942.   if(opTarget == NULL) 
  943.     {
  944.       oTcl.resultf("no such object %s", argv[4]);
  945.       return (TCL_ERROR);
  946.     }
  947.   opLink = (NsObject *) TclObject::lookup(argv[5]);
  948.   if(opLink == NULL) 
  949.     {
  950.       oTcl.resultf("no such object %s", argv[5]);
  951.       return (TCL_ERROR);
  952.     }
  953.   AddInterface(iNsAddr, iNsPort, opTarget, opLink);
  954.   DBG_X(command);
  955.   return (TCL_OK);
  956. }
  957.     }
  958.   DBG_X(command);
  959.   return (Agent::command(argc, argv));
  960. }
  961. /* Given params: sList, spPrevNode, spNextNode, spNewNode... insert spNewNode
  962.  * into sList between spPrevNode and spNextNode.
  963.  */
  964. void SctpAgent::InsertNode(List_S *spList, Node_S *spPrevNode, 
  965.   Node_S *spNewNode,  Node_S *spNextNode)
  966. {
  967.   if(spPrevNode == NULL)
  968.     spList->spHead = spNewNode;
  969.   else
  970.     spPrevNode->spNext = spNewNode;
  971.   spNewNode->spPrev = spPrevNode;
  972.   spNewNode->spNext = spNextNode;
  973.   if(spNextNode == NULL)
  974.     spList->spTail = spNewNode;
  975.   else
  976.     spNextNode->spPrev = spNewNode;
  977.   spList->uiLength++;
  978. }
  979. void SctpAgent::DeleteNode(List_S *spList, Node_S *spNode)
  980. {
  981.   if(spNode->spPrev == NULL)
  982.     spList->spHead = spNode->spNext;
  983.   else
  984.     spNode->spPrev->spNext = spNode->spNext;
  985.   
  986.   if(spNode->spNext == NULL)
  987.     spList->spTail = spNode->spPrev;
  988.   else
  989.     spNode->spNext->spPrev = spNode->spPrev;
  990.   /* now let's free the internal structures
  991.    */
  992.   switch(spNode->eType)
  993.     {
  994.     case NODE_TYPE_STREAM_BUFFER:
  995.       delete[] (u_char *) ((SctpStreamBufferNode_S *) spNode->vpData)->spChunk;
  996.       ((SctpStreamBufferNode_S *) spNode->vpData)->spChunk = NULL;
  997.       delete (SctpStreamBufferNode_S *) spNode->vpData;
  998.       spNode->vpData = NULL;
  999.       break;
  1000.     case NODE_TYPE_RECV_TSN_BLOCK:
  1001.       delete (SctpRecvTsnBlock_S *) spNode->vpData;
  1002.       spNode->vpData = NULL;
  1003.       break;
  1004.     case NODE_TYPE_DUP_TSN:
  1005.       delete (SctpDupTsn_S *) spNode->vpData;
  1006.       spNode->vpData = NULL;
  1007.       break;
  1008.     case NODE_TYPE_SEND_BUFFER:
  1009.       delete[] (u_char *) ((SctpSendBufferNode_S *) spNode->vpData)->spChunk;
  1010.       ((SctpSendBufferNode_S *) spNode->vpData)->spChunk = NULL;
  1011.       delete (SctpSendBufferNode_S *) spNode->vpData;
  1012.       spNode->vpData = NULL;
  1013.       break;
  1014.     case NODE_TYPE_APP_LAYER_BUFFER:
  1015.       delete (AppData_S *) spNode->vpData;
  1016.       spNode->vpData = NULL;
  1017.       break;
  1018.     case NODE_TYPE_INTERFACE_LIST:
  1019.       delete (SctpInterface_S *) spNode->vpData;
  1020.       spNode->vpData = NULL;
  1021.       break;
  1022.     case NODE_TYPE_DESTINATION_LIST:
  1023.       delete (SctpDest_S *) spNode->vpData;
  1024.       spNode->vpData = NULL;
  1025.       break;
  1026.     case NODE_TYPE_PACKET_BUFFER:
  1027.       /* no need to free data, because SctpAgent hands over responsibility to
  1028.        * the send() function
  1029.        */
  1030.       spNode->vpData = NULL;
  1031.       break;
  1032.     }
  1033.   delete spNode;
  1034.   spList->uiLength--;
  1035. }
  1036. void SctpAgent::ClearList(List_S *spList)
  1037. {
  1038.   Node_S *spCurrNode = spList->spHead;
  1039.   Node_S *spDeleteNode = NULL;
  1040.   while(spCurrNode != NULL)
  1041.     {
  1042.       spDeleteNode = spCurrNode;
  1043.       spCurrNode = spCurrNode->spNext;
  1044.       DeleteNode(spList, spDeleteNode);
  1045.     }
  1046. }
  1047. void SctpAgent::AddInterface(int iNsAddr, int iNsPort, 
  1048.      NsObject *opTarget, NsObject *opLink)
  1049. {
  1050.   DBG_I(AddInterface);
  1051.   Node_S *spNewNode = new Node_S;
  1052.   spNewNode->eType = NODE_TYPE_INTERFACE_LIST;
  1053.   spNewNode->vpData = new SctpInterface_S;
  1054.   SctpInterface_S *spNewInterface = (SctpInterface_S *) spNewNode->vpData;
  1055.   spNewInterface->iNsAddr = iNsAddr;
  1056.   spNewInterface->iNsPort = iNsPort;
  1057.   spNewInterface->opTarget = opTarget;
  1058.   spNewInterface->opLink = opLink;
  1059.   
  1060.   InsertNode(&sInterfaceList, sInterfaceList.spTail, spNewNode, NULL);
  1061.   DBG_X(AddInterface);
  1062. }
  1063. void SctpAgent::AddDestination(int iNsAddr, int iNsPort)
  1064. {
  1065.   DBG_I(AddDestination);
  1066.   Node_S *spNewNode = new Node_S;
  1067.   spNewNode->eType = NODE_TYPE_DESTINATION_LIST;
  1068.   spNewNode->vpData = new SctpDest_S;
  1069.   SctpDest_S *spNewDest = (SctpDest_S *) spNewNode->vpData;
  1070.   memset(spNewDest, 0, sizeof(SctpDest_S));
  1071.   spNewDest->iNsAddr = iNsAddr;
  1072.   spNewDest->iNsPort = iNsPort;
  1073.   /* set the primary to the last destination added just in case the user does
  1074.    * not set a primary
  1075.    */
  1076.   spPrimaryDest = spNewDest;
  1077.   spNewTxDest = spPrimaryDest;
  1078.   /* allocate packet with the dest addr. to be used later for setting src dest
  1079.    */
  1080.   daddr() = spNewDest->iNsAddr;
  1081.   dport() = spNewDest->iNsPort;
  1082.   spNewDest->opRoutingAssistPacket = allocpkt();
  1083.   InsertNode(&sDestList, sDestList.spTail, spNewNode, NULL);
  1084.   DBG_X(AddDestination);
  1085. }
  1086. int SctpAgent::SetPrimary(int iNsAddr)
  1087. {
  1088.   DBG_I(SetPrimary);
  1089.   Node_S *spCurrNode = NULL;
  1090.   SctpDest_S *spCurrDest = NULL;
  1091.   for(spCurrNode = sDestList.spHead;
  1092.       spCurrNode != NULL;
  1093.       spCurrNode = spCurrNode->spNext)
  1094.     {
  1095.       spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  1096.       
  1097.       if(spCurrDest->iNsAddr == iNsAddr)
  1098. {
  1099.   spPrimaryDest = spCurrDest;
  1100.   spNewTxDest = spPrimaryDest;
  1101.   DBG_PL(SetPrimary, "returning TCL_OK") DBG_PR;
  1102.   DBG_X(SetPrimary);
  1103.   return (TCL_OK);
  1104. }
  1105.     }
  1106.   DBG_PL(SetPrimary, "returning TCL_ERROR") DBG_PR;
  1107.   DBG_X(SetPrimary);
  1108.   return (TCL_ERROR);
  1109. }
  1110. /* Helps maintain information passed down from the TCL script by an oracle
  1111.  * about path lossrates.  Used in RTX-LOSSRATE rtx policy for
  1112.  * CMT. Lossrate for a path is set in the dest node's datastructure.
  1113.  */
  1114. int SctpAgent::SetLossrate(int iNsAddr, float fLossrate)
  1115. {
  1116.   Node_S *spCurrNode = NULL;
  1117.   SctpDest_S *spCurrDest = NULL;
  1118.   for(spCurrNode = sDestList.spHead;
  1119.       spCurrNode != NULL;
  1120.       spCurrNode = spCurrNode->spNext)
  1121.     {
  1122.       spCurrDest = (SctpDest_S *) spCurrNode->vpData;
  1123.       if(spCurrDest->iNsAddr == iNsAddr)
  1124. {
  1125.   spCurrDest->fLossrate = fLossrate;
  1126.   return (TCL_OK);
  1127. }
  1128.     }
  1129.   return (TCL_ERROR);
  1130. }
  1131. int SctpAgent::ForceSource(int iNsAddr)
  1132. {
  1133.   DBG_I(ForceSource);
  1134.   Node_S *spCurrNode = sInterfaceList.spHead;
  1135.   SctpInterface_S *spCurrInterface = NULL;
  1136.   while(spCurrNode != NULL)
  1137.     {
  1138.       spCurrInterface = (SctpInterface_S *) spCurrNode->vpData;
  1139.       if(spCurrInterface->iNsAddr == iNsAddr)
  1140. {
  1141.   addr() = spCurrInterface->iNsAddr;
  1142.   port() = spCurrInterface->iNsPort;
  1143.   target_ = spCurrInterface->opTarget;
  1144.   eForceSource = TRUE;
  1145.   DBG_PL(ForceSource, "returning TCL_OK") DBG_PR;
  1146.   DBG_X(ForceSource);
  1147.   return (TCL_OK);
  1148. }
  1149.       else
  1150. spCurrNode = spCurrNode->spNext;
  1151.     }
  1152.   DBG_PL(ForceSource, "returning TCL_ERROR") DBG_PR;
  1153.   DBG_X(ForceSource);
  1154.   return (TCL_ERROR);
  1155. }
  1156. /* returns the size of the chunk
  1157.  */
  1158. int SctpAgent::GenChunk(SctpChunkType_E eType, u_char *ucpChunk)
  1159. {
  1160.   DBG_I(GenChunk);
  1161.   double dCurrTime = Scheduler::instance().clock();
  1162.   AppData_S *spAppMessage = NULL;
  1163.   int iSize = 0;
  1164.   DBG_PL(GenChunk, "spSctpTrace=%p"), spSctpTrace DBG_PR;
  1165.   switch(eType)
  1166.     {
  1167.     case SCTP_CHUNK_INIT:
  1168.       iSize = sizeof(SctpInitChunk_S);
  1169.       ((SctpInitChunk_S *) ucpChunk)->sHdr.ucType = eType;
  1170.       ((SctpInitChunk_S *) ucpChunk)->uiArwnd = uiInitialRwnd; 
  1171.       ((SctpInitChunk_S *) ucpChunk)->usNumOutboundStreams = uiNumOutStreams;
  1172.       ((SctpInitChunk_S *) ucpChunk)->uiInitialTsn = 0; 
  1173.       ((SctpInitChunk_S *) ucpChunk)->sUnrelStream.usType 
  1174. = SCTP_INIT_PARAM_UNREL;
  1175.       ((SctpInitChunk_S *) ucpChunk)->sUnrelStream.usLength
  1176. = sizeof(SctpUnrelStreamsParam_S);
  1177.       
  1178.       if(uiNumUnrelStreams > 0)
  1179. {
  1180.   ((SctpInitChunk_S *) ucpChunk)->sUnrelStream.usLength 
  1181.     += sizeof(SctpUnrelStreamPair_S);
  1182.   SctpUnrelStreamPair_S *spUnrelStreamPair 
  1183.             = (SctpUnrelStreamPair_S *) (ucpChunk+iSize);
  1184.           spUnrelStreamPair->usStart = 0;
  1185.           spUnrelStreamPair->usEnd = uiNumUnrelStreams - 1;
  1186.   iSize += sizeof(SctpUnrelStreamPair_S);
  1187.   }
  1188.       ((SctpInitChunk_S *) ucpChunk)->sHdr.usLength = iSize;
  1189.       /* fill in tracing fields too
  1190.        */
  1191.       spSctpTrace[uiNumChunks].eType = eType;
  1192.       spSctpTrace[uiNumChunks].uiTsn = (u_int) -1;
  1193.       spSctpTrace[uiNumChunks].usStreamId = (u_short) -1;
  1194.       spSctpTrace[uiNumChunks].usStreamSeqNum = (u_short) -1;
  1195.       break;
  1196.     case SCTP_CHUNK_INIT_ACK:
  1197.       iSize = sizeof(SctpInitAckChunk_S);
  1198.       ((SctpInitAckChunk_S *) ucpChunk)->sHdr.ucType = eType;
  1199.       ((SctpInitAckChunk_S *) ucpChunk)->uiArwnd = uiInitialRwnd; 
  1200.       ((SctpInitChunk_S *) ucpChunk)->usNumOutboundStreams = uiNumOutStreams;
  1201.       ((SctpInitAckChunk_S *) ucpChunk)->uiInitialTsn = 0; 
  1202.       ((SctpInitAckChunk_S *) ucpChunk)->sUnrelStream.usType 
  1203. = SCTP_INIT_PARAM_UNREL;
  1204.       ((SctpInitAckChunk_S *) ucpChunk)->sUnrelStream.usLength
  1205. = sizeof(SctpUnrelStreamsParam_S);
  1206.       if(uiNumUnrelStreams > 0)
  1207. {
  1208.   ((SctpInitAckChunk_S *) ucpChunk)->sUnrelStream.usLength 
  1209.     += sizeof(SctpUnrelStreamPair_S);
  1210.   SctpUnrelStreamPair_S *spUnrelStreamPair 
  1211.             = (SctpUnrelStreamPair_S *) (ucpChunk+iSize);
  1212.           spUnrelStreamPair->usStart = 0;
  1213.           spUnrelStreamPair->usEnd = uiNumUnrelStreams - 1;
  1214.   iSize += sizeof(SctpUnrelStreamPair_S);
  1215. }
  1216.       ((SctpInitAckChunk_S *) ucpChunk)->sHdr.usLength = iSize;
  1217.       /* fill in tracing fields too
  1218.        */
  1219.       spSctpTrace[uiNumChunks].eType = eType;
  1220.       spSctpTrace[uiNumChunks].uiTsn = (u_int) -1;
  1221.       spSctpTrace[uiNumChunks].usStreamId = (u_short) -1;
  1222.       spSctpTrace[uiNumChunks].usStreamSeqNum = (u_short) -1;
  1223.       break;
  1224.     case SCTP_CHUNK_COOKIE_ECHO:
  1225.       iSize = sizeof(SctpCookieEchoChunk_S);
  1226.       ((SctpCookieEchoChunk_S *) ucpChunk)->sHdr.ucType = eType;
  1227.       ((SctpCookieEchoChunk_S *) ucpChunk)->sHdr.usLength = iSize;
  1228.       /* fill in tracing fields too
  1229.        */
  1230.       spSctpTrace[uiNumChunks].eType = eType;
  1231.       spSctpTrace[uiNumChunks].uiTsn = (u_int) -1;
  1232.       spSctpTrace[uiNumChunks].usStreamId = (u_short) -1;
  1233.       spSctpTrace[uiNumChunks].usStreamSeqNum = (u_short) -1;
  1234.       break;
  1235.       
  1236.     case SCTP_CHUNK_COOKIE_ACK:
  1237.       iSize = sizeof(SctpCookieAckChunk_S);
  1238.       ((SctpCookieAckChunk_S *) ucpChunk)->sHdr.ucType = eType;
  1239.       ((SctpCookieAckChunk_S *) ucpChunk)->sHdr.usLength = iSize;
  1240.       /* fill in tracing fields too
  1241.        */
  1242.       spSctpTrace[uiNumChunks].eType = eType;
  1243.       spSctpTrace[uiNumChunks].uiTsn = (u_int) -1;
  1244.       spSctpTrace[uiNumChunks].usStreamId = (u_short) -1;
  1245.       spSctpTrace[uiNumChunks].usStreamSeqNum = (u_short) -1;
  1246.       break;
  1247.     case SCTP_CHUNK_DATA:
  1248.       /* Depending on eDataSource, we either use chunk parameters 
  1249.        * from the app layer buffer, or use the defaults for infinite 
  1250.        * data generation.
  1251.        */
  1252.       if(eDataSource == DATA_SOURCE_APPLICATION)
  1253. {
  1254.   /* If DATA_SOURCE_APPLICATION, we have to get chunk parameters
  1255.    * from the app layer buffer 
  1256.    */
  1257.   DBG_PL (GenChunk, "eDataSource=DATA_SOURCE_APPLICATION") DBG_PR; 
  1258.   spAppMessage = (AppData_S *) (sAppLayerBuffer.spHead->vpData);
  1259.   DBG_PL (GenChunk, "App Message ---------------->") DBG_PR;
  1260.   DBG_PL (GenChunk, "usNumStreams: %d"), 
  1261.     spAppMessage->usNumStreams DBG_PR;
  1262.   DBG_PL (GenChunk, "usNumUnreliable: %d"), 
  1263.     spAppMessage->usNumUnreliable DBG_PR;
  1264.   DBG_PL (GenChunk, "uiNumBytes: %d"),
  1265.     spAppMessage->uiNumBytes DBG_PR;
  1266.   DBG_PL (GenChunk, "usStreamId: %d"), 
  1267.     spAppMessage->usStreamId DBG_PR;
  1268.   DBG_PL (GenChunk, "eUnordered: %s"), 
  1269.     spAppMessage->eUnordered ? "TRUE" : "FALSE" DBG_PR;
  1270.   DBG_PL (GenChunk, "usReliability: %d"), 
  1271.     spAppMessage->usReliability DBG_PR;
  1272.   DBG_PL (GenChunk, "App Message <----------------") DBG_PR;
  1273.   iSize = spAppMessage->uiNumBytes + sizeof(SctpDataChunkHdr_S);
  1274.   ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.ucType = SCTP_CHUNK_DATA;
  1275.   ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.usLength = iSize;
  1276.   /* DATA chunks must be padded to a 4 byte boundary (section 3.3.1)
  1277.    * ...but the adjustment should happen after usLength field is set,
  1278.    * because the field should represent the size before padding.
  1279.    */
  1280.   if( (iSize % 4) != 0)
  1281.     iSize += 4 - (iSize % 4);
  1282.   ((SctpDataChunkHdr_S *) ucpChunk)->uiTsn = ++uiNextTsn;
  1283.   
  1284.   ((SctpDataChunkHdr_S *) ucpChunk)->usStreamId 
  1285.     = spAppMessage->usStreamId; 
  1286.   if(spAppMessage->eUnordered == TRUE)
  1287.     {
  1288.       ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.ucFlags 
  1289. |= SCTP_DATA_FLAG_UNORDERED;
  1290.       /* no stream seq num on unordered chunks!
  1291.        */
  1292.     }
  1293.   else
  1294.     {
  1295.       ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.ucFlags = 0;
  1296.       ((SctpDataChunkHdr_S *) ucpChunk)->usStreamSeqNum 
  1297. = spOutStreams[spAppMessage->usStreamId].usNextStreamSeqNum++;
  1298.     }
  1299. }
  1300.       else
  1301. {
  1302.   DBG_PL (GenChunk, "eDataSource=DATA_SOURCE_INFINITE") DBG_PR; 
  1303.   iSize = uiDataChunkSize;
  1304.   ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.ucType = SCTP_CHUNK_DATA;
  1305.   if(eUnordered == TRUE)
  1306.     {
  1307.       ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.ucFlags 
  1308. |= SCTP_DATA_FLAG_UNORDERED;
  1309.     }
  1310.   else
  1311.     {
  1312.       ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.ucFlags = 0;
  1313.     }
  1314.   ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.usLength = iSize;
  1315.   /* DATA chunks must be padded to a 4 byte boundary (section 3.3.1)
  1316.    * ...but the adjustment should happen after usLength field is set,
  1317.    * because the field should represent the size before padding.
  1318.    */
  1319.   if( (uiDataChunkSize % 4) != 0)
  1320.     iSize += 4 - (uiDataChunkSize % 4);
  1321.   ((SctpDataChunkHdr_S *) ucpChunk)->uiTsn = ++uiNextTsn;
  1322.   
  1323.   ((SctpDataChunkHdr_S *) ucpChunk)->usStreamId 
  1324.     = (usNextStreamId % uiNumOutStreams); 
  1325.   if(eUnordered == TRUE)
  1326.     {
  1327.       ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.ucFlags 
  1328. |= SCTP_DATA_FLAG_UNORDERED;
  1329.       /* no stream seq num on unordered chunks!
  1330.        */
  1331.     }
  1332.   else
  1333.     {
  1334.       ((SctpDataChunkHdr_S *) ucpChunk)->sHdr.ucFlags = 0;
  1335.       ((SctpDataChunkHdr_S *) ucpChunk)->usStreamSeqNum 
  1336. = spOutStreams[usNextStreamId%uiNumOutStreams].usNextStreamSeqNum++;
  1337.     }
  1338.   
  1339.   usNextStreamId++; // round-robin stream feeding
  1340. }
  1341.       /* fill in tracing fields too
  1342.        */
  1343.       spSctpTrace[uiNumChunks].eType = eType;
  1344.       spSctpTrace[uiNumChunks].uiTsn 
  1345. = ((SctpDataChunkHdr_S *) ucpChunk)->uiTsn;
  1346.       spSctpTrace[uiNumChunks].usStreamId 
  1347. = ((SctpDataChunkHdr_S *) ucpChunk)->usStreamId;
  1348.       spSctpTrace[uiNumChunks].usStreamSeqNum 
  1349. = ((SctpDataChunkHdr_S *) ucpChunk)->usStreamSeqNum;
  1350.       DBG_PL(GenChunk, "DataTsn=%d at dCurrTime=%f"), 
  1351. uiNextTsn, dCurrTime DBG_PR;
  1352.       break;
  1353.     case SCTP_CHUNK_SACK:
  1354.       iSize = sizeof(SctpSackChunk_S);
  1355.       ((SctpSackChunk_S *) ucpChunk)->sHdr.ucType = eType;
  1356.       ((SctpSackChunk_S *) ucpChunk)->uiCumAck = uiCumAck;
  1357.       ((SctpSackChunk_S *) ucpChunk)->uiArwnd = uiMyRwnd;
  1358.       ((SctpSackChunk_S *) ucpChunk)->usNumGapAckBlocks 
  1359. = sRecvTsnBlockList.uiLength;
  1360.       ((SctpSackChunk_S *) ucpChunk)->usNumDupTsns = sDupTsnList.uiLength;
  1361.       DBG_PL(GenChunk, "SACK CumAck=%d arwnd=%d"), uiCumAck, uiMyRwnd DBG_PR;
  1362.       /* Append all the Gap Ack Blocks
  1363.        */
  1364.       for(Node_S *spCurrFrag = sRecvTsnBlockList.spHead;
  1365.   (spCurrFrag != NULL) &&
  1366.     (iSize + sizeof(SctpGapAckBlock_S) < uiMaxDataSize); 
  1367.   spCurrFrag = spCurrFrag->spNext, iSize += sizeof(SctpGapAckBlock_S) )
  1368. {
  1369.   SctpGapAckBlock_S *spGapAckBlock 
  1370.     = (SctpGapAckBlock_S *) (ucpChunk+iSize);
  1371.   spGapAckBlock->usStartOffset 
  1372.     = ((SctpRecvTsnBlock_S *)spCurrFrag->vpData)->uiStartTsn -uiCumAck;
  1373.   spGapAckBlock->usEndOffset
  1374.     = ((SctpRecvTsnBlock_S *)spCurrFrag->vpData)->uiEndTsn - uiCumAck;
  1375.   DBG_PL(GenChunk, "GapAckBlock StartOffset=%d EndOffset=%d"), 
  1376.     spGapAckBlock->usStartOffset, spGapAckBlock->usEndOffset DBG_PR;
  1377. }
  1378.       /* Append all the Duplicate TSNs
  1379.        */
  1380.       for(Node_S *spPrevDup = NULL, *spCurrDup = sDupTsnList.spHead;
  1381.   (spCurrDup != NULL) &&
  1382.     (iSize + sizeof(SctpDupTsn_S) < uiMaxDataSize); 
  1383.   spPrevDup = spCurrDup, spCurrDup = spCurrDup->spNext, 
  1384.     DeleteNode(&sDupTsnList, spPrevDup), iSize += sizeof(SctpDupTsn_S))
  1385. {
  1386.   SctpDupTsn_S *spDupTsn = (SctpDupTsn_S *) (ucpChunk+iSize);
  1387.   spDupTsn->uiTsn = ((SctpDupTsn_S *) spCurrDup->vpData)->uiTsn;
  1388.   DBG_PL(GenChunk, "DupTsn=%d"), spDupTsn->uiTsn DBG_PR;
  1389. }
  1390.       /* After all the dynamic appending, we can NOW fill in the chunk size!
  1391.        */
  1392.       ((SctpSackChunk_S *) ucpChunk)->sHdr.usLength = iSize;
  1393.       /* fill in tracing fields too
  1394.        */
  1395.       spSctpTrace[uiNumChunks].eType = eType;
  1396.       spSctpTrace[uiNumChunks].uiTsn = ((SctpSackChunk_S *)ucpChunk)->uiCumAck;
  1397.       spSctpTrace[uiNumChunks].usStreamId = (u_short) -1;
  1398.       spSctpTrace[uiNumChunks].usStreamSeqNum = (u_short) -1;
  1399.       break;
  1400.     case SCTP_CHUNK_FORWARD_TSN:
  1401.       iSize = SCTP_CHUNK_FORWARD_TSN_LENGTH;
  1402.       ((SctpForwardTsnChunk_S *) ucpChunk)->sHdr.ucType = eType;
  1403.       ((SctpForwardTsnChunk_S *) ucpChunk)->sHdr.ucFlags = 0;// flags not used?
  1404.       ((SctpForwardTsnChunk_S *) ucpChunk)->sHdr.usLength = iSize;
  1405.       ((SctpForwardTsnChunk_S *) ucpChunk)->uiNewCum = uiAdvancedPeerAckPoint;
  1406.       /* fill in tracing fields too
  1407.        */
  1408.       spSctpTrace[uiNumChunks].eType = eType;
  1409.       spSctpTrace[uiNumChunks].uiTsn = uiAdvancedPeerAckPoint;
  1410.       spSctpTrace[uiNumChunks].usStreamId = (u_short) -1;
  1411.       spSctpTrace[uiNumChunks].usStreamSeqNum = (u_short) -1;
  1412.       break;
  1413.     case SCTP_CHUNK_HB:     
  1414.     case SCTP_CHUNK_HB_ACK:
  1415.       iSize = SCTP_CHUNK_HEARTBEAT_LENGTH;
  1416.       ((SctpHeartbeatChunk_S *) ucpChunk)->sHdr.ucType = eType;
  1417.       ((SctpHeartbeatChunk_S *) ucpChunk)->sHdr.ucFlags = 0;
  1418.       ((SctpHeartbeatChunk_S *) ucpChunk)->sHdr.usLength = iSize;
  1419.       ((SctpHeartbeatChunk_S *) ucpChunk)->usInfoType = 1;
  1420.       ((SctpHeartbeatChunk_S *) ucpChunk)->usInfoLength 
  1421. = iSize - sizeof(SctpChunkHdr_S);
  1422.       ((SctpHeartbeatChunk_S *) ucpChunk)->dTimestamp = dCurrTime;
  1423.       ((SctpHeartbeatChunk_S *) ucpChunk)->spDest = NULL; // caller sets dest
  1424.       /* fill in tracing fields too
  1425.        */
  1426.       spSctpTrace[uiNumChunks].eType = eType;
  1427.       spSctpTrace[uiNumChunks].uiTsn = (u_int) -1;
  1428.       spSctpTrace[uiNumChunks].usStreamId = (u_short) -1;
  1429.       spSctpTrace[uiNumChunks].usStreamSeqNum = (u_short) -1;
  1430.       break;
  1431.     case SCTP_CHUNK_SHUTDOWN:
  1432.       break;
  1433.     case SCTP_CHUNK_SHUTDOWN_ACK:
  1434.       break;
  1435.     case SCTP_CHUNK_SHUTDOWN_COMPLETE:
  1436.       break;
  1437.     default:
  1438.       fprintf(stderr, "[GenChunk] ERROR: bad chunk type!n");
  1439.       DBG_PL(GenChunk, "ERROR: bad chunk type!") DBG_PR;
  1440.       DBG_PL(GenChunk, "exiting...") DBG_PR;
  1441.       exit(-1);
  1442.     }
  1443.   uiNumChunks++;
  1444.   DBG_X(GenChunk);
  1445.   return iSize;
  1446. }
  1447. u_int SctpAgent::GetNextDataChunkSize()
  1448. {
  1449.   DBG_I(GetNextDataChunkSize);
  1450.   AppData_S *spAppMessage = NULL;
  1451.   u_int uiChunkSize = 0;
  1452.   if(eDataSource == DATA_SOURCE_APPLICATION)
  1453.     {
  1454.       if(sAppLayerBuffer.uiLength == 0)
  1455. {
  1456.   uiChunkSize = 0;
  1457. }
  1458.       else
  1459. {
  1460.   spAppMessage = (AppData_S *) (sAppLayerBuffer.spHead->vpData);
  1461.   uiChunkSize = spAppMessage->uiNumBytes + sizeof(SctpDataChunkHdr_S);
  1462. }
  1463.     }
  1464.   else
  1465.     {
  1466.       uiChunkSize = uiDataChunkSize;
  1467.     }
  1468.   /* DATA chunks must be padded to a 4 byte boundary (section 3.3.1)
  1469.    */
  1470.   if( (uiChunkSize % 4) != 0)
  1471.     uiChunkSize += 4 - (uiChunkSize % 4);
  1472.   DBG_PL(GetNextDataChunkSize, "returning %d"), uiChunkSize DBG_PR;
  1473.   DBG_X(GetNextDataChunkSize);
  1474.   return uiChunkSize;
  1475. }
  1476. /* This function generates ONE data chunk.Since we could call GenChunk directly
  1477.  * with only one extra parameter, it may seem pointless to have this function.
  1478.  * However, it isn't! All variable adjustments that go with generating a new
  1479.  * data chunk should be isolated in one place to avoid bugs.
  1480.  */
  1481. int SctpAgent::GenOneDataChunk(u_char *ucpOutData)
  1482. {
  1483.   DBG_I(GenOneDataChunk);
  1484.   AppData_S *spAppData = NULL;
  1485.   int iChunkSize = GenChunk(SCTP_CHUNK_DATA, ucpOutData);
  1486.   if(eDataSource == DATA_SOURCE_APPLICATION)
  1487.     {
  1488.       spAppData = (AppData_S *) sAppLayerBuffer.spHead->vpData;
  1489.       AddToSendBuffer( (SctpDataChunkHdr_S *) ucpOutData, iChunkSize, 
  1490.        spAppData->usReliability, spNewTxDest);
  1491.       DeleteNode(&sAppLayerBuffer, sAppLayerBuffer.spHead);
  1492.     }
  1493.   else
  1494.     {
  1495.       AddToSendBuffer( (SctpDataChunkHdr_S *) ucpOutData, iChunkSize, 
  1496.        uiReliability, spNewTxDest);
  1497.     }
  1498.   
  1499.   DBG_PL(GenOneDataChunk, "dest=%p chunk length=%d"), 
  1500.     spNewTxDest, ((SctpDataChunkHdr_S *) ucpOutData)->sHdr.usLength DBG_PR;
  1501.   spNewTxDest->iOutstandingBytes 
  1502.     += ((SctpDataChunkHdr_S *) ucpOutData)->sHdr.usLength;
  1503.   DBG_PL(GenOneDataChunk,"After adding chunk, out=%d"), 
  1504.     spNewTxDest->iOutstandingBytes DBG_PR;
  1505.   /* rfc2960 section 6.2.1.B
  1506.    */
  1507.   if(iChunkSize <= (int) uiPeerRwnd)
  1508.     uiPeerRwnd -= iChunkSize; 
  1509.   else
  1510.     uiPeerRwnd = 0;
  1511.   if(spNewTxDest->eRtxTimerIsRunning == FALSE)
  1512.     StartT3RtxTimer(spNewTxDest); //section 6.3.2.R1
  1513.   DBG_X(GenOneDataChunk);
  1514.   return iChunkSize;
  1515. }
  1516. /* This function fills a packet with as many chunks that can fit into the PMTU 
  1517.  * and the peer's rwnd.
  1518.  *
  1519.  * Since, this function is called the first time a chunk(s) is sent, all chunks
  1520.  * generated here are added to the sSendBuffer.
  1521.  *
  1522.  * returns the resulting size of the packet
  1523.  */
  1524. int SctpAgent::GenMultipleDataChunks(u_char *ucpOutData, int iTotalOutDataSize)
  1525. {
  1526.   DBG_I(GenMultipleDataChunks);
  1527.   
  1528.   int iChunkSize = 0;
  1529.   int iStartingTotalSize = iTotalOutDataSize;
  1530.   while((iTotalOutDataSize + GetNextDataChunkSize()  <= uiMaxDataSize) &&
  1531. (GetNextDataChunkSize()                      <= uiPeerRwnd) &&
  1532. (eDataSource == DATA_SOURCE_INFINITE || sAppLayerBuffer.uiLength != 0))
  1533.     {
  1534.       iChunkSize = GenOneDataChunk(ucpOutData);
  1535.       ucpOutData += iChunkSize;
  1536.       iTotalOutDataSize += iChunkSize;
  1537.     }
  1538.   
  1539.   DBG_X(GenMultipleDataChunks);
  1540.   return iTotalOutDataSize - iStartingTotalSize;
  1541. }
  1542. /* This function serves as a hook for extensions (such as Timestamp) which
  1543.  * need to bundle extra control chunks. However, it can later be used to
  1544.  * actually bundle SACKs, FOWARD_TSN, DATA w/ COOKIE and
  1545.  * COOKIE_ECHO. Since we don't currently bundle any control chunks in the
  1546.  * base SCTP, this function just returns 0 (ie, no bundled chunks).
  1547.  *
  1548.  * returns the aggregate size of the control chunk(s)
  1549.  */
  1550. int SctpAgent::BundleControlChunks(u_char *ucpOutData)
  1551. {
  1552.   DBG_I(BundleControlChunks);
  1553.   DBG_PL(BundleControlChunks, "None... returning 0") DBG_PR;
  1554.   DBG_X(BundleControlChunks);
  1555.   return 0;
  1556. }
  1557. void SctpAgent::StartT3RtxTimer(SctpDest_S *spDest)
  1558. {
  1559.   DBG_I(StartT3RtxTimer);
  1560.   double dCurrTime = Scheduler::instance().clock();
  1561.   DBG_PL(StartT3RtxTimer, "spDest=%p dCurrTime=%f expires at %f "), 
  1562.     spDest, dCurrTime, dCurrTime+spDest->dRto DBG_PR;
  1563.   spDest->opT3RtxTimer->resched(spDest->dRto);
  1564.   spDest->eRtxTimerIsRunning = TRUE;
  1565.   DBG_X(StartT3RtxTimer);
  1566. }
  1567. void SctpAgent::StopT3RtxTimer(SctpDest_S *spDest)
  1568. {
  1569.   DBG_I(StopT3RtxTimer);
  1570.   double dCurrTime = Scheduler::instance().clock();
  1571.   DBG_PL(StopT3RtxTimer, "spDest=%p dCurrTime=%f"), spDest, dCurrTime DBG_PR;
  1572.   spDest->opT3RtxTimer->force_cancel();
  1573.   spDest->eRtxTimerIsRunning = FALSE;
  1574.   DBG_X(StopT3RtxTimer);
  1575. }
  1576. void SctpAgent::AddToSendBuffer(SctpDataChunkHdr_S *spChunk, 
  1577. int iChunkSize,
  1578. u_int uiReliability,
  1579. SctpDest_S *spDest)
  1580. {
  1581.   DBG_I(AddToSendBuffer);
  1582.   DBG_PL(AddToSendBuffer, "spDest=%p  iChunkSize=%d"), 
  1583.     spDest, iChunkSize DBG_PR;
  1584.   Node_S *spNewNode = new Node_S;
  1585.   spNewNode->eType = NODE_TYPE_SEND_BUFFER;
  1586.   spNewNode->vpData = new SctpSendBufferNode_S;
  1587.   SctpSendBufferNode_S * spNewNodeData 
  1588.     = (SctpSendBufferNode_S *) spNewNode->vpData;
  1589.   /* This can NOT simply be a 'new SctpDataChunkHdr_S', because we need to
  1590.    * allocate the space for the ENTIRE data chunk and not just the data
  1591.    * chunk header.  
  1592.    */
  1593.   spNewNodeData->spChunk = (SctpDataChunkHdr_S *) new u_char[iChunkSize];
  1594.   memcpy(spNewNodeData->spChunk, spChunk, iChunkSize);
  1595.   spNewNodeData->eAdvancedAcked = FALSE;
  1596.   spNewNodeData->eGapAcked = FALSE;
  1597.   spNewNodeData->eAddedToPartialBytesAcked = FALSE;
  1598.   spNewNodeData->iNumMissingReports = 0;
  1599.   spNewNodeData->iUnrelRtxLimit = uiReliability;
  1600.   spNewNodeData->eMarkedForRtx = NO_RTX;
  1601.   spNewNodeData->eIneligibleForFastRtx = FALSE;
  1602.   spNewNodeData->iNumTxs = 1;
  1603.   spNewNodeData->spDest = spDest;
  1604.   /* Is there already a DATA chunk in flight measuring an RTT? 
  1605.    * (6.3.1.C4 RTT measured once per round trip)
  1606.    */
  1607.   if(spDest->eRtoPending == FALSE)  // NO?
  1608.     {
  1609.       spNewNodeData->dTxTimestamp = Scheduler::instance().clock();
  1610.       spDest->eRtoPending = TRUE;   // ...well now there is :-)
  1611.     }
  1612.   else
  1613.     spNewNodeData->dTxTimestamp = 0; // don't use this check for RTT estimate
  1614.   InsertNode(&sSendBuffer, sSendBuffer.spTail, spNewNode, NULL);
  1615.   DBG_X(AddToSendBuffer);
  1616. }
  1617. void SctpAgent::RttUpdate(double dTxTime, SctpDest_S *spDest)
  1618. {
  1619.   DBG_I(RttUpdate);
  1620.   double dNewRtt;
  1621.   double dCurrTime = Scheduler::instance().clock();
  1622.   dNewRtt = dCurrTime - dTxTime;
  1623.       
  1624.   if(spDest->eFirstRttMeasurement == TRUE) // section 6.3.1.C2
  1625.     {
  1626.       /* Bug Fix. eFirstRttMeasurement should be set to FALSE here.
  1627.        * 06/11/2001 - PDA and JRI
  1628.        */
  1629.       spDest->eFirstRttMeasurement = FALSE; 
  1630.       spDest->dSrtt = dNewRtt;
  1631.       spDest->dRttVar = dNewRtt/2;
  1632.       spDest->dRto = spDest->dSrtt + 4 * spDest->dRttVar;
  1633.     }
  1634.   else //section 6.3.1.C3
  1635.     {
  1636.       spDest->dRttVar 
  1637. = ( (1 - RTO_BETA) * spDest->dRttVar 
  1638.     + RTO_BETA * abs(spDest->dSrtt - dNewRtt) );
  1639.       spDest->dSrtt 
  1640. = (1 - RTO_ALPHA) * spDest->dSrtt + RTO_ALPHA * dNewRtt;
  1641.     
  1642.       spDest->dRto = spDest->dSrtt + 4 * spDest->dRttVar;
  1643.     }
  1644.   if(spDest->dRto < dMinRto)  // section 6.3.1.C6
  1645.     spDest->dRto = dMinRto;
  1646.   else if(spDest->dRto > dMaxRto)  // section 6.3.1.C7
  1647.     spDest->dRto = dMaxRto;
  1648.   tdRto++; // trigger changes for trace to pick up
  1649.   DBG_PL(RttUpdate, "spDest->dRto=%f"), spDest->dRto DBG_PR;
  1650.   DBG_X(RttUpdate);
  1651. }
  1652. /* Go thru the send buffer deleting all chunks which have a tsn <= the 
  1653.  * tsn parameter passed in. We assume the chunks in the rtx list are ordered by
  1654.  * their tsn value. In addtion, for each chunk deleted:
  1655.  *   1. we add the chunk length to # newly acked bytes and partial bytes acked
  1656.  *   2. we update round trip time if appropriate
  1657.  *   3. stop the timer if the chunk's destination timer is running
  1658.  */
  1659. void SctpAgent::SendBufferDequeueUpTo(u_int uiTsn)
  1660. {
  1661.   DBG_I(SendBufferDequeueUpTo);
  1662.   Node_S *spDeleteNode = NULL;
  1663.   Node_S *spCurrNode = sSendBuffer.spHead;
  1664.   SctpSendBufferNode_S *spCurrNodeData = NULL;
  1665.   iAssocErrorCount = 0;
  1666.   while(spCurrNode != NULL &&
  1667. ((SctpSendBufferNode_S*)spCurrNode->vpData)->spChunk->uiTsn <= uiTsn)
  1668.     {
  1669.       spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
  1670.       /* Only count this chunk as newly acked and towards partial bytes
  1671.        * acked if it hasn't been gap acked or marked as ack'd due to rtx
  1672.        * limit.  
  1673.        */
  1674.       if((spCurrNodeData->eGapAcked == FALSE) &&
  1675.  (spCurrNodeData->eAdvancedAcked == FALSE) )
  1676. {
  1677.   uiHighestTsnNewlyAcked = spCurrNodeData->spChunk->uiTsn;
  1678.   spCurrNodeData->spDest->iNumNewlyAckedBytes 
  1679.     += spCurrNodeData->spChunk->sHdr.usLength;
  1680.   /* only add to partial bytes acked if we are in congestion
  1681.    * avoidance mode and if there was cwnd amount of data
  1682.    * outstanding on the destination (implementor's guide) 
  1683.    */
  1684.   if(spCurrNodeData->spDest->iCwnd >spCurrNodeData->spDest->iSsthresh 
  1685.      &&
  1686.      ( spCurrNodeData->spDest->iOutstandingBytes 
  1687.        >= spCurrNodeData->spDest->iCwnd) )
  1688.     {
  1689.       spCurrNodeData->spDest->iPartialBytesAcked 
  1690. += spCurrNodeData->spChunk->sHdr.usLength;
  1691.     }
  1692. }
  1693.       /* This is to ensure that Max.Burst is applied when a SACK
  1694.        * acknowledges a chunk which has been fast retransmitted. If it is
  1695.        * ineligible for fast rtx, that can only be because it was fast
  1696.        * rtxed or it timed out. If it timed out, a burst shouldn't be
  1697.        * possible, but shouldn't hurt either. The fast rtx case is what we
  1698.        * are really after. This is a proposed change to RFC2960 section
  1699.        * 7.2.4
  1700.        */
  1701.       if(spCurrNodeData->eIneligibleForFastRtx == TRUE)
  1702. eApplyMaxBurst = TRUE;
  1703.     
  1704.       /* We update the RTT estimate if the following hold true:
  1705.        *   1. RTO pending flag is set (6.3.1.C4 measured once per round trip)
  1706.        *   2. Timestamp is set for this chunk(ie, we were measuring this chunk)
  1707.        *   3. This chunk has not been retransmitted
  1708.        *   4. This chunk has not been gap acked already 
  1709.        *   5. This chunk has not been advanced acked (pr-sctp: exhausted rtxs)
  1710.        */
  1711.       if(spCurrNodeData->spDest->eRtoPending == TRUE &&
  1712.  spCurrNodeData->dTxTimestamp > 0 &&
  1713.  spCurrNodeData->iNumTxs == 1 &&
  1714.  spCurrNodeData->eGapAcked == FALSE &&
  1715.  spCurrNodeData->eAdvancedAcked == FALSE) 
  1716. {
  1717.   /* If the chunk is marked for timeout rtx, then the sender is an 
  1718.    * ambigious state. Were the sacks lost or was there a failure? 
  1719.    * (See below, where we talk about error count resetting)
  1720.    * Since we don't clear the error counter below, we also don't
  1721.    * update the RTT. This could be a problem for late arriving SACKs.
  1722.    */
  1723.   if(spCurrNodeData->eMarkedForRtx != TIMEOUT_RTX)
  1724.     RttUpdate(spCurrNodeData->dTxTimestamp, spCurrNodeData->spDest);
  1725.   spCurrNodeData->spDest->eRtoPending = FALSE;
  1726. }
  1727.       /* if there is a timer running on the chunk's destination, then stop it
  1728.        */
  1729.       if(spCurrNodeData->spDest->eRtxTimerIsRunning == TRUE)
  1730. StopT3RtxTimer(spCurrNodeData->spDest);
  1731.       /* We don't want to clear the error counter if it's cleared already;
  1732.        * otherwise, we'll unnecessarily trigger a trace event.
  1733.        *
  1734.        * Also, the error counter is cleared by SACKed data ONLY if the
  1735.        * TSNs are not marked for timeout retransmission and has not been
  1736.        * gap acked before. Without this condition, we can run into a
  1737.        * problem for failure detection. When a failure occurs, some data
  1738.        * may have made it through before the failure, but the sacks got
  1739.        * lost. When the sender retransmits the first outstanding, the
  1740.        * receiver will sack all the data whose sacks got lost. We don't
  1741.        * want these sacks to clear the error counter, or else failover
  1742.        * would take longer.
  1743.        */
  1744.       if(spCurrNodeData->spDest->iErrorCount != 0 &&
  1745.  spCurrNodeData->eMarkedForRtx != TIMEOUT_RTX &&
  1746.  spCurrNodeData->eGapAcked == FALSE)
  1747. {
  1748.   DBG_PL(SendBufferDequeueUpTo, 
  1749.  "clearing error counter for %p with tsn=%lu"), 
  1750.     spCurrNodeData->spDest, spCurrNodeData->spChunk->uiTsn DBG_PR;
  1751.   spCurrNodeData->spDest->iErrorCount = 0; // clear error counter
  1752.   tiErrorCount++;                          // ... and trace it too!
  1753.   spCurrNodeData->spDest->eStatus = SCTP_DEST_STATUS_ACTIVE;
  1754.   if(spCurrNodeData->spDest == spPrimaryDest &&
  1755.      spNewTxDest != spPrimaryDest) 
  1756.     {
  1757.       DBG_PL(SendBufferDequeueUpTo,
  1758.      "primary recovered... migrating back from %p to %p"),
  1759. spNewTxDest, spPrimaryDest DBG_PR;
  1760.       spNewTxDest = spPrimaryDest; // return to primary
  1761.     }
  1762. }
  1763.       spDeleteNode = spCurrNode;
  1764.       spCurrNode = spCurrNode->spNext;
  1765.       DeleteNode(&sSendBuffer, spDeleteNode);
  1766.       spDeleteNode = NULL;
  1767.     }
  1768.   DBG_X(SendBufferDequeueUpTo);
  1769. }
  1770. /* This function uses the iOutstandingBytes variable and assumes that it has 
  1771.  * NOT been updated yet to reflect the newly received SACK. Hence, it is the 
  1772.  * previously outstanding DATA bytes.
  1773.  */
  1774. void SctpAgent::AdjustCwnd(SctpDest_S *spDest)
  1775. {
  1776.   DBG_I(AdjustCwnd);
  1777.   if(spDest->iCwnd <= spDest->iSsthresh) //in slow-start mode?
  1778.     {
  1779.       DBG_PL(AdjustCwnd, "slow start mode") DBG_PR;
  1780.       DBG_PL(AdjustCwnd, "iSsthresh=%d"), spDest->iSsthresh DBG_PR;
  1781.       /* section 7.2.1 (w/ implementor's guide)
  1782.        */
  1783.       if(spDest->iOutstandingBytes >= spDest->iCwnd)
  1784. {
  1785.   spDest->iCwnd += MIN(spDest->iNumNewlyAckedBytes,(int)uiMaxDataSize);
  1786.   tiCwnd++; // trigger changes for trace to pick up
  1787. }
  1788.     }
  1789.   else // congestion avoidance mode
  1790.     {
  1791.       DBG_PL(AdjustCwnd,"congestion avoidance mode") DBG_PR;
  1792.       DBG_PL(AdjustCwnd,"iPartialBytesAcked=%d iCwnd=%d iOutStandingBytes=%d"),
  1793. spDest->iPartialBytesAcked, 
  1794. spDest->iCwnd, 
  1795. spDest->iOutstandingBytes
  1796. DBG_PR;
  1797.       /* section 7.2.2
  1798.        */
  1799.       if(spDest->iPartialBytesAcked >= spDest->iCwnd &&
  1800.  spDest->iOutstandingBytes >= spDest->iCwnd )
  1801. {
  1802.   DBG_PL(AdjustCwnd, "adjusting cwnd") DBG_PR;
  1803.   if(spDest->iCwnd <= spDest->iPartialBytesAcked)
  1804.       spDest->iPartialBytesAcked -= spDest->iCwnd;
  1805.   else
  1806.     spDest->iPartialBytesAcked = 0;
  1807.   spDest->iCwnd += uiMaxDataSize;
  1808.   tiCwnd++; // trigger changes for trace to pick up
  1809. }
  1810.     }
  1811.   DBG_PL(AdjustCwnd, "pba=%d cwnd=%d out=%d PeerRwnd=%d"),
  1812.     spDest->iPartialBytesAcked, 
  1813.     spDest->iCwnd, 
  1814.     spDest->iOutstandingBytes,
  1815.     uiPeerRwnd
  1816.     DBG_PR;
  1817.   DBG_X(AdjustCwnd);
  1818. }
  1819. void SctpAgent::AdvancePeerAckPoint()
  1820. {
  1821.   DBG_I(AdvancePeerAckPoint);
  1822.   Node_S *spCurrNode = NULL;
  1823.   SctpSendBufferNode_S *spCurrNodeData = NULL;
  1824.   if(uiAdvancedPeerAckPoint < uiCumAckPoint)
  1825.     uiAdvancedPeerAckPoint = uiCumAckPoint;
  1826.   for(spCurrNode = sSendBuffer.spHead;
  1827.       spCurrNode != NULL;
  1828.       spCurrNode = spCurrNode->spNext)
  1829.     {
  1830.       spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
  1831.       
  1832.       /* If we haven't marked the chunk as ack'd either via an u-stream's
  1833.        * rtx exhaustion or a gap ack, then jump out of the loop. ...we've
  1834.        * advanced as far as we can!
  1835.        */
  1836.       if(spCurrNodeData->eAdvancedAcked == FALSE &&
  1837.  spCurrNodeData->eGapAcked == FALSE)
  1838. break;
  1839.       uiAdvancedPeerAckPoint = spCurrNodeData->spChunk->uiTsn;
  1840.     }
  1841.   DBG_PL(AdvancePeerAckPoint, "uiAdvancedPeerAckPoint=%d"), 
  1842.     uiAdvancedPeerAckPoint DBG_PR;
  1843.   DBG_X(AdvancePeerAckPoint);
  1844. }
  1845. u_int SctpAgent::GetHighestOutstandingTsn()
  1846. {
  1847.   DBG_I(GetHighestOutstandingTsn);
  1848.   u_int uiHighestOutstandingTsn = 0;
  1849.   Node_S *spCurrBuffNode = NULL;
  1850.   SctpSendBufferNode_S *spCurrBuffData = NULL;
  1851.   /* start from the tailof the send buffer and search towards the head for the
  1852.    * first tsn oustanding... that's the highest outstanding tsn.
  1853.    */
  1854.   for(spCurrBuffNode = sSendBuffer.spTail;
  1855.       spCurrBuffNode != NULL;
  1856.       spCurrBuffNode = spCurrBuffNode->spPrev)
  1857.     {
  1858.       spCurrBuffData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
  1859.       
  1860.       if(spCurrBuffData->eMarkedForRtx == NO_RTX)  // is it oustanding?
  1861. {
  1862.   uiHighestOutstandingTsn = spCurrBuffData->spChunk->uiTsn;// found it!
  1863.   break;
  1864. }
  1865.     }
  1866.   DBG_PL(GetHighestOutstandingTsn, "uiHighestOutstandingTsn=%d"), 
  1867.     uiHighestOutstandingTsn DBG_PR;
  1868.   DBG_X(GetHighestOutstandingTsn);
  1869.   return uiHighestOutstandingTsn;
  1870. }
  1871. /* This function is called as soon as we are done processing a SACK which 
  1872.  * notifies the need of a fast rtx. Following RFC2960, we pack as many chunks
  1873.  * as possible into one packet (PTMU restriction). The remaining marked packets
  1874.  * are sent as soon as cwnd allows.
  1875.  */
  1876. void SctpAgent::FastRtx()
  1877. {
  1878.   DBG_I(FastRtx);
  1879.   
  1880.   Node_S *spCurrDestNode = NULL;
  1881.   SctpDest_S *spCurrDestData = NULL;
  1882.   Node_S *spCurrBuffNode = NULL;
  1883.   SctpSendBufferNode_S *spCurrBuffData = NULL;
  1884.   /* be sure we clear all the eCcApplied flags before using them!
  1885.    */
  1886.   for(spCurrDestNode = sDestList.spHead;
  1887.       spCurrDestNode != NULL;
  1888.       spCurrDestNode = spCurrDestNode->spNext)
  1889.     {
  1890.       spCurrDestData = (SctpDest_S *) spCurrDestNode->vpData;
  1891.       spCurrDestData->eCcApplied = FALSE;
  1892.     }
  1893.   
  1894.   /* go thru chunks marked for rtx and cut back their ssthresh, cwnd, and
  1895.    * partial bytes acked. make sure we only apply congestion control once
  1896.    * per destination and once per window (ie, round-trip).
  1897.    */
  1898.   for(spCurrBuffNode = sSendBuffer.spHead;
  1899.       spCurrBuffNode != NULL;
  1900.       spCurrBuffNode = spCurrBuffNode->spNext)
  1901.     {
  1902.       spCurrBuffData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
  1903.       /* If the chunk has been either marked for rtx or advanced ack, we want
  1904.        * to apply congestion control (assuming we didn't already).
  1905.        *
  1906.        * Why do we do it for advanced ack chunks? Well they were advanced ack'd
  1907.        * because they were lost. The ONLY reason we are not fast rtxing them is
  1908.        * because the chunk has run out of retransmissions (u-sctp). So we need
  1909.        * to still account for the fact they were lost... so apply congestion
  1910.        * control!
  1911.        */
  1912.       if( (spCurrBuffData->eMarkedForRtx != NO_RTX ||
  1913.   spCurrBuffData->eAdvancedAcked == TRUE) &&
  1914.  spCurrBuffData->spDest->eCcApplied == FALSE &&
  1915.  spCurrBuffData->spChunk->uiTsn > uiRecover)
  1916.  
  1917.   /* section 7.2.3 of rfc2960 (w/ implementor's guide) 
  1918.    */
  1919.   spCurrBuffData->spDest->iSsthresh 
  1920.     = MAX(spCurrBuffData->spDest->iCwnd/2, 
  1921.   iInitialCwnd * (int) uiMaxDataSize);
  1922.   spCurrBuffData->spDest->iCwnd = spCurrBuffData->spDest->iSsthresh;
  1923.   spCurrBuffData->spDest->iPartialBytesAcked = 0; //reset
  1924.   tiCwnd++; // trigger changes for trace to pick up
  1925.   spCurrBuffData->spDest->eCcApplied = TRUE;
  1926.   /* Cancel any pending RTT measurement on this
  1927.    * destination. Stephan Baucke (2004-04-27) suggested this
  1928.    * action as a fix for the following simple scenario:
  1929.    *
  1930.    * - Host A sends packets 1, 2 and 3 to host B, and choses 3 for
  1931.    *   an RTT measurement
  1932.    *
  1933.    * - Host B receives all packets correctly and sends ACK1, ACK2,
  1934.    *   and ACK3.
  1935.    *
  1936.    * - ACK2 and ACK3 are lost on the return path
  1937.    *
  1938.    * - Eventually a timeout fires for packet 2, and A retransmits 2
  1939.    *
  1940.    * - Upon receipt of 2, B sends a cumulative ACK3 (since it has
  1941.    *   received 2 & 3 before)
  1942.    *
  1943.    * - Since packet 3 has never been retransmitted, the SCTP code
  1944.    *   actually accepts the ACK for an RTT measurement, although it
  1945.    *   was sent in reply to the retransmission of 2, which results
  1946.    *   in a much too high RTT estimate. Since this case tends to
  1947.    *   happen in case of longer link interruptions, the error is
  1948.    *   often amplified by subsequent timer backoffs.
  1949.    */
  1950.   spCurrBuffData->spDest->eRtoPending = FALSE; 
  1951.   /* Set the recover variable to avoid multiple cwnd cuts for losses
  1952.    * in the same window (ie, round-trip).
  1953.    */
  1954.   uiRecover = GetHighestOutstandingTsn();
  1955. }
  1956.     }
  1957.   /* possible that no chunks are pending retransmission since they could be 
  1958.    * advanced ack'd 
  1959.    */
  1960.   if(eMarkedChunksPending == TRUE)  
  1961.     RtxMarkedChunks(RTX_LIMIT_ONE_PACKET);
  1962.   DBG_X(FastRtx);
  1963. }
  1964. void SctpAgent::TimeoutRtx(SctpDest_S *spDest)
  1965. {
  1966.   DBG_I(TimeoutRtx);
  1967.   Node_S *spCurrNode = NULL;
  1968.   SctpSendBufferNode_S *spCurrNodeData = NULL;
  1969.   
  1970.   DBG_PL(TimeoutRtx, "spDest=%p"), spDest DBG_PR;
  1971.   for(spCurrNode = sSendBuffer.spHead;
  1972.       spCurrNode != NULL;
  1973.       spCurrNode = spCurrNode->spNext)
  1974.     {
  1975.       spCurrNodeData = (SctpSendBufferNode_S *) spCurrNode->vpData;
  1976.       /* Mark chunks that were sent to the destination which had a timeout and
  1977.        * have NOT been gap ack'd or advanced.
  1978.        */
  1979.       if(spCurrNodeData->spDest == spDest &&
  1980.  spCurrNodeData->eGapAcked == FALSE &&
  1981.  spCurrNodeData->eAdvancedAcked == FALSE)
  1982. {
  1983.   MarkChunkForRtx(spCurrNodeData, TIMEOUT_RTX);
  1984.   spCurrNodeData->iNumMissingReports = 0;
  1985. }
  1986.     }
  1987.   if(eMarkedChunksPending == TRUE)  
  1988.     RtxMarkedChunks(RTX_LIMIT_ONE_PACKET);
  1989.   DBG_X(TimeoutRtx);
  1990. }
  1991. void SctpAgent::MarkChunkForRtx(SctpSendBufferNode_S *spNodeData,
  1992. MarkedForRtx_E eMarkedForRtx)
  1993. {
  1994.   DBG_I(MarkChunkForRtx);
  1995.   SctpDataChunkHdr_S  *spChunk = spNodeData->spChunk;
  1996.   SctpOutStream_S *spStream = &(spOutStreams[spChunk->usStreamId]);
  1997.   DBG_PL(MarkChunkForRtx, "tsn=%lu eMarkedForRtx=%s"), 
  1998.     spChunk->uiTsn,
  1999.     !eMarkedForRtx ? "NO_RTX" 
  2000.     : (eMarkedForRtx==FAST_RTX ? "FAST_RTX": "TIMEOUT_RTX") DBG_PR;
  2001.   spNodeData->eMarkedForRtx = eMarkedForRtx;
  2002.   uiPeerRwnd += spChunk->sHdr.usLength; // 6.2.1.C1 
  2003.   /* let's see if this chunk is on an unreliable stream. if so and the chunk 
  2004.    * has run out of retransmissions, mark it as advanced acked and unmark it 
  2005.    * for rtx
  2006.    */
  2007.   if(spStream->eMode == SCTP_STREAM_UNRELIABLE)
  2008.     {
  2009.       /* have we run out of retransmissions??
  2010.        */
  2011.       if(spNodeData->iNumTxs > spNodeData->iUnrelRtxLimit)
  2012. {
  2013.   DBG_PL(MarkChunkForRtx, "giving up on tsn %lu..."),
  2014.     spChunk->uiTsn DBG_PR;
  2015.   spNodeData->eAdvancedAcked = TRUE;
  2016.   spNodeData->eMarkedForRtx = NO_RTX;
  2017.   spNodeData->spDest->iOutstandingBytes -= spChunk->sHdr.usLength;
  2018. }
  2019.     }
  2020.   
  2021.   if(spNodeData->eMarkedForRtx != NO_RTX)
  2022.     eMarkedChunksPending = TRUE;
  2023.   DBG_PL(MarkChunkForRtx, "uiPeerRwnd=%lu"), uiPeerRwnd DBG_PR;
  2024.   DBG_X(MarkChunkForRtx);
  2025. }
  2026. Boolean_E SctpAgent::AnyMarkedChunks()
  2027. {
  2028.   DBG_I(AnyMarkedChunks);
  2029.   Node_S *spCurrBuffNode = NULL;
  2030.   SctpSendBufferNode_S *spCurrBuffNodeData = NULL;
  2031.   for(spCurrBuffNode = sSendBuffer.spHead;
  2032.       spCurrBuffNode != NULL; 
  2033.       spCurrBuffNode = spCurrBuffNode->spNext)
  2034.     {
  2035.       spCurrBuffNodeData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
  2036.       if(spCurrBuffNodeData->eMarkedForRtx != NO_RTX)
  2037. {
  2038.   DBG_PL(AnyMarkedChunks, "TRUE") DBG_PR;
  2039.   DBG_X(AnyMarkedChunks);
  2040.   return TRUE;
  2041. }
  2042.     }
  2043.   DBG_PL(AnyMarkedChunks, "FALSE") DBG_PR;
  2044.   DBG_X(AnyMarkedChunks);
  2045.   return FALSE;
  2046. }
  2047. /* This function goes through the entire send buffer filling a packet with 
  2048.  * chunks marked for retransmission. Once a packet is full (according to MTU)
  2049.  * it is transmittted. If the eLimit is one packet, than that is all that is
  2050.  * done. If the eLimit is cwnd, then packets full of marked tsns are sent until
  2051.  * cwnd is full.
  2052.  */
  2053. void SctpAgent::RtxMarkedChunks(SctpRtxLimit_E eLimit)
  2054. {
  2055.   DBG_I(RtxMarkedChunks);
  2056.   u_char *ucpOutData = new u_char[uiMaxPayloadSize];
  2057.   u_char *ucpCurrOutData = ucpOutData;
  2058.   int iBundledControlChunkSize = 0;
  2059.   int iCurrSize = 0;
  2060.   int iOutDataSize = 0;
  2061.   Node_S *spCurrBuffNode = NULL;
  2062.   SctpSendBufferNode_S *spCurrBuffNodeData = NULL;
  2063.   SctpDataChunkHdr_S  *spCurrChunk;
  2064.   SctpDest_S *spRtxDest = NULL;
  2065.   Node_S *spCurrDestNode = NULL;
  2066.   SctpDest_S *spCurrDestNodeData = NULL;
  2067.   Boolean_E eControlChunkBundled = FALSE;
  2068.   int iNumPacketsSent = 0;
  2069.   memset(ucpOutData, 0, uiMaxPayloadSize);
  2070.   uiBurstLength = 0;
  2071.   /* make sure we clear all the spFirstOutstanding pointers before using them!
  2072.    */
  2073.   for(spCurrDestNode = sDestList.spHead;
  2074.       spCurrDestNode != NULL;
  2075.       spCurrDestNode = spCurrDestNode->spNext)
  2076.     {
  2077.       spCurrDestNodeData = (SctpDest_S *) spCurrDestNode->vpData;
  2078.       spCurrDestNodeData->spFirstOutstanding = NULL;  // reset
  2079.     }
  2080.   /* We need to set the destination address for the retransmission(s).We assume
  2081.    * that on a given call to this function, all should all be sent to the same
  2082.    * address (should be a reasonable assumption). So, to determine the address,
  2083.    * we find the first marked chunk and determine the destination it was last 
  2084.    * sent to. 
  2085.    *
  2086.    * Also, we temporarily count all marked chunks as not outstanding.Why? Well,
  2087.    * if we try retransmitting on the same dest as used previously, the cwnd may
  2088.    * never let us retransmit because the outstanding is counting marked chunks
  2089.    * too. At the end of this function, we'll count all marked chunks as 
  2090.    * outstanding again. (ugh... there has to be a better way!)
  2091.    */
  2092.   for(spCurrBuffNode = sSendBuffer.spHead; 
  2093.       spCurrBuffNode != NULL;
  2094.       spCurrBuffNode = spCurrBuffNode->spNext)
  2095.     {
  2096.       spCurrBuffNodeData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
  2097.   
  2098.       if(spCurrBuffNodeData->eMarkedForRtx != NO_RTX)
  2099. {
  2100.   spCurrChunk = spCurrBuffNodeData->spChunk;
  2101.   if(spRtxDest == NULL)
  2102.     {
  2103.       /* RFC2960 says that retransmissions should go to an
  2104.        * alternate destination when available, which is the
  2105.        * default behavior characterized by
  2106.        * eRtxToAlt=RTX_TO_ALT_ON. 
  2107.        *
  2108.        * We add two experimental options:
  2109.        *    1. rtx all data to same destination (RTX_TO_ALT_OFF)
  2110.        *    2. rtx only timeouts to alt dest (RTX_TO_ALT_TIMEOUTS_ONLY)
  2111.        *
  2112.        * Note: Even with these options, if the same dest is inactive,
  2113.        * then alt dest is used.
  2114.        */
  2115.       switch(eRtxToAlt)
  2116. {
  2117. case RTX_TO_ALT_OFF:
  2118.   if(spCurrBuffNodeData->spDest->eStatus 
  2119.      == SCTP_DEST_STATUS_ACTIVE)
  2120.     {
  2121.       spRtxDest = spCurrBuffNodeData->spDest;
  2122.     }
  2123.   else
  2124.     {
  2125.       spRtxDest = GetNextDest(spCurrBuffNodeData->spDest);
  2126.     }
  2127.   break;
  2128.   
  2129. case RTX_TO_ALT_ON:
  2130.   spRtxDest = GetNextDest(spCurrBuffNodeData->spDest);
  2131.   break;
  2132. case RTX_TO_ALT_TIMEOUTS_ONLY:
  2133.   if(spCurrBuffNodeData->eMarkedForRtx == FAST_RTX &&
  2134.      spCurrBuffNodeData->spDest->eStatus 
  2135.      == SCTP_DEST_STATUS_ACTIVE)
  2136.     {
  2137.       spRtxDest = spCurrBuffNodeData->spDest; 
  2138.     }
  2139.   else
  2140.     {
  2141.       spRtxDest = GetNextDest(spCurrBuffNodeData->spDest);
  2142.     }
  2143.   break;
  2144. }
  2145.     }
  2146.   spCurrBuffNodeData->spDest->iOutstandingBytes
  2147.     -= spCurrChunk->sHdr.usLength;
  2148. }
  2149.     }
  2150.   spCurrBuffNode = sSendBuffer.spHead;
  2151.   while( (eLimit == RTX_LIMIT_ONE_PACKET && 
  2152.   iNumPacketsSent < 1 && 
  2153.   spCurrBuffNode != NULL) ||
  2154.  (eLimit == RTX_LIMIT_CWND &&
  2155.   spRtxDest->iOutstandingBytes < spRtxDest->iCwnd &&
  2156.   spCurrBuffNode != NULL) )
  2157.     {
  2158.       DBG_PL(RtxMarkedChunks, 
  2159.      "eLimit=%s pktsSent=%d out=%d cwnd=%d spCurrBuffNode=%p"),
  2160. (eLimit == RTX_LIMIT_ONE_PACKET) ? "ONE_PACKET" : "CWND",
  2161. iNumPacketsSent, spRtxDest->iOutstandingBytes, spRtxDest->iCwnd,
  2162. spCurrBuffNode
  2163. DBG_PR;
  2164.       
  2165.       /* section 7.2.4.3
  2166.        *
  2167.        * continue filling up the packet with chunks which are marked for
  2168.        * rtx. exit loop when we have either run out of chunks or the
  2169.        * packet is full.
  2170.        *
  2171.        * note: we assume at least one data chunk fits in the packet.  
  2172.        */
  2173.       for(eControlChunkBundled = FALSE; 
  2174.   spCurrBuffNode != NULL; 
  2175.   spCurrBuffNode = spCurrBuffNode->spNext)
  2176. {
  2177.   spCurrBuffNodeData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
  2178.   
  2179.   /* is this chunk the first outstanding on its destination?
  2180.    */
  2181.     if(spCurrBuffNodeData->spDest->spFirstOutstanding == NULL &&
  2182.      spCurrBuffNodeData->eGapAcked == FALSE &&
  2183.      spCurrBuffNodeData->eAdvancedAcked == FALSE)
  2184.     {
  2185.       /* yes, it is the first!
  2186.        */
  2187.       spCurrBuffNodeData->spDest->spFirstOutstanding 
  2188. = spCurrBuffNodeData;
  2189.     }
  2190.   /* Only retransmit the chunks which have been marked for rtx.
  2191.    */
  2192.   if(spCurrBuffNodeData->eMarkedForRtx != NO_RTX)
  2193.     {
  2194.       spCurrChunk = spCurrBuffNodeData->spChunk;
  2195.       /* bundle the control chunk before any data chunks and only
  2196.        * once per packet
  2197.        */
  2198.       if(eControlChunkBundled == FALSE)
  2199. {
  2200.   eControlChunkBundled = TRUE;
  2201.   iBundledControlChunkSize=BundleControlChunks(ucpCurrOutData);
  2202.   ucpCurrOutData += iBundledControlChunkSize;
  2203.   iOutDataSize += iBundledControlChunkSize;
  2204. }
  2205.       /* can we fit this chunk into the packet without exceeding MTU?? 
  2206.        */
  2207.          if((iOutDataSize + spCurrChunk->sHdr.usLength) 
  2208.  > (int) uiMaxPayloadSize)
  2209. break;  // doesn't fit in packet... jump out of the for loop
  2210.       /* If this chunk was being used to measure the RTT,stop using it.
  2211.        */
  2212.       if(spCurrBuffNodeData->spDest->eRtoPending == TRUE &&
  2213.  spCurrBuffNodeData->dTxTimestamp > 0)
  2214. {
  2215.   spCurrBuffNodeData->dTxTimestamp = 0;
  2216.   spCurrBuffNodeData->spDest->eRtoPending = FALSE;
  2217. }
  2218.       /* section 7.2.4.4 (condition 2) - is this the first
  2219.        * outstanding for the destination and are there still
  2220.        * outstanding bytes on the destination? if so, restart
  2221.        * timer.  
  2222.        */
  2223.       if(spCurrBuffNodeData->spDest->spFirstOutstanding 
  2224.  == spCurrBuffNodeData)
  2225. {
  2226.   if(spCurrBuffNodeData->spDest->iOutstandingBytes > 0)
  2227.     StartT3RtxTimer(spCurrBuffNodeData->spDest);
  2228. }
  2229.       
  2230.       /* section 6.1 - Whenever a transmission or retransmission is 
  2231.        * made to any address, if the T3-rtx timer of that address 
  2232.        * is not currently running, the sender MUST start that timer.
  2233.        * If the timer for that address is already running, the sender 
  2234.        * MUST restart the timer if the earliest (i.e., lowest TSN)
  2235.        * outstanding DATA chunk sent to that address is being
  2236.        * retransmitted.  Otherwise, the data sender MUST NOT
  2237.        * restart the timer.  
  2238.        */
  2239.       if(spRtxDest->spFirstOutstanding == NULL ||
  2240.  spCurrChunk->uiTsn <
  2241.  spRtxDest->spFirstOutstanding->spChunk->uiTsn)
  2242. {
  2243.   /* This chunk is now the first outstanding on spRtxDest.
  2244.    */
  2245.   spRtxDest->spFirstOutstanding = spCurrBuffNodeData;
  2246.   StartT3RtxTimer(spRtxDest);
  2247. }
  2248.       
  2249.       memcpy(ucpCurrOutData, spCurrChunk, spCurrChunk->sHdr.usLength);
  2250.       iCurrSize = spCurrChunk->sHdr.usLength;
  2251.       
  2252.       /* the chunk length field does not include the padded bytes,
  2253.        * so we need to account for these extra bytes.
  2254.        */
  2255.       if( (iCurrSize % 4) != 0 ) 
  2256. iCurrSize += 4 - (iCurrSize % 4);
  2257.       ucpCurrOutData += iCurrSize;
  2258.       iOutDataSize += iCurrSize;
  2259.       spCurrBuffNodeData->spDest = spRtxDest;
  2260.       spCurrBuffNodeData->iNumTxs++;
  2261.       spCurrBuffNodeData->eMarkedForRtx = NO_RTX;
  2262.       /* fill in tracing fields too
  2263.        */
  2264.       spSctpTrace[uiNumChunks].eType = SCTP_CHUNK_DATA;
  2265.       spSctpTrace[uiNumChunks].uiTsn = spCurrChunk->uiTsn;
  2266.       spSctpTrace[uiNumChunks].usStreamId = spCurrChunk->usStreamId;
  2267.       spSctpTrace[uiNumChunks].usStreamSeqNum 
  2268. = spCurrChunk->usStreamSeqNum;
  2269.       uiNumChunks++;
  2270.       /* the chunk is now outstanding on the alternate destination
  2271.        */
  2272.       spCurrBuffNodeData->spDest->iOutstandingBytes
  2273. += spCurrChunk->sHdr.usLength;
  2274.       uiPeerRwnd -= spCurrChunk->sHdr.usLength; // 6.2.1.B
  2275.       DBG_PL(RtxMarkedChunks, "spDest->iOutstandingBytes=%d"), 
  2276. spCurrBuffNodeData->spDest->iOutstandingBytes DBG_PR;
  2277.       DBG_PL(RtxMarkedChunks, "TSN=%d"), spCurrChunk->uiTsn DBG_PR;
  2278.     }
  2279.   else if(spCurrBuffNodeData->eAdvancedAcked == TRUE)
  2280.     {
  2281.       if(spCurrBuffNodeData->spDest->spFirstOutstanding 
  2282.  == spCurrBuffNodeData)
  2283. {
  2284.   /* This WAS considered the first outstanding chunk for
  2285.    * the destination, then stop the timer if there are no
  2286.    * outstanding chunks waiting behind this one in the
  2287.    * send buffer.  However, if there ARE more outstanding
  2288.    * chunks on this destination, we need to restart timer
  2289.    * for those.
  2290.    */
  2291.   if(spCurrBuffNodeData->spDest->iOutstandingBytes > 0)
  2292.     StartT3RtxTimer(spCurrBuffNodeData->spDest);
  2293.   else
  2294.     StopT3RtxTimer(spCurrBuffNodeData->spDest);
  2295. }
  2296.     }
  2297. }
  2298.       /* Transmit the packet now...
  2299.        */
  2300.       if(iOutDataSize > 0)
  2301. {
  2302.   SendPacket(ucpOutData, iOutDataSize, spRtxDest);
  2303.   if(spRtxDest->eRtxTimerIsRunning == FALSE)
  2304.     StartT3RtxTimer(spRtxDest);
  2305.   iNumPacketsSent++;   
  2306.   iOutDataSize = 0; // reset
  2307.   ucpCurrOutData = ucpOutData; // reset
  2308.   memset(ucpOutData, 0, uiMaxPayloadSize); // reset
  2309.   spRtxDest->opCwndDegradeTimer->resched(spRtxDest->dRto);
  2310.   /* This addresses the proposed change to RFC2960 section 7.2.4,
  2311.    * regarding using of Max.Burst. We have an option which allows
  2312.    * to control if Max.Burst is applied.
  2313.    */
  2314.   if(eUseMaxBurst == MAX_BURST_USAGE_ON)
  2315.     if( (eApplyMaxBurst == TRUE) && (uiBurstLength++ >= MAX_BURST) )
  2316.       {
  2317. /* we've reached Max.Burst limit, so jump out of loop
  2318.  */
  2319. eApplyMaxBurst = FALSE; // reset before jumping out of loop
  2320. break;
  2321.       }
  2322. }
  2323.     }
  2324.   /* Ok, let's count all marked chunks as outstanding again. (ugh... there
  2325.    * has to be a better way!)  
  2326.    */
  2327.   for(spCurrBuffNode = sSendBuffer.spHead; 
  2328.       spCurrBuffNode != NULL;
  2329.       spCurrBuffNode = spCurrBuffNode->spNext)
  2330.     {
  2331.       spCurrBuffNodeData = (SctpSendBufferNode_S *) spCurrBuffNode->vpData;
  2332.   
  2333.       if(spCurrBuffNodeData->eMarkedForRtx != NO_RTX)
  2334. {
  2335.   spCurrChunk = spCurrBuffNodeData->spChunk;
  2336.   spCurrBuffNodeData->spDest->iOutstandingBytes
  2337.     += spCurrChunk->sHdr.usLength;
  2338. }
  2339.     }
  2340.     
  2341.   /* If we made it here, either our limit was only one packet worth of
  2342.    * retransmissions or we hit the end of the list and there are no more
  2343.    * marked chunks. If we didn't hit the end, let's see if there are more
  2344.    * marked chunks.
  2345.    */
  2346.   eMarkedChunksPending = AnyMarkedChunks();
  2347.   DBG_X(RtxMarkedChunks);
  2348.   delete [] ucpOutData;
  2349. }
  2350. /* Updates uiHighestRecvTsn
  2351.  */
  2352. Boolean_E SctpAgent::UpdateHighestTsn(u_int uiTsn)
  2353. {
  2354.   DBG_I(UpdateHighestTsn);
  2355.   if(uiTsn > uiHighestRecvTsn)
  2356.     {
  2357.       uiHighestRecvTsn = uiTsn;
  2358.       DBG_PL(UpdateHighestTsn, "returning TRUE") DBG_PR;
  2359.       DBG_X(UpdateHighestTsn);
  2360.       return TRUE;
  2361.     } 
  2362.   else