SCTPAssociationRcvMessage.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005-2010 Irene Ruengeler
00003 // Copyright (C) 2009-2010 Thomas Dreibholz
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 #include <string.h>
00020 #include <assert.h>
00021 #include "SCTP.h"
00022 #include "SCTPAssociation.h"
00023 #include "SCTPCommand_m.h"
00024 #include "SCTPMessage_m.h"
00025 #include "SCTPQueue.h"
00026 #include "SCTPAlgorithm.h"
00027 #include "IPv4InterfaceData.h"
00028 #include "IPv6InterfaceData.h"
00029 #include "IPControlInfo_m.h"
00030 
00031 
00032 void SCTPAssociation::decreaseOutstandingBytes(SCTPDataVariables* chunk)
00033 {
00034     SCTPPathVariables* lastPath = chunk->getLastDestinationPath();
00035 
00036     assert(lastPath->outstandingBytes >= chunk->booksize);
00037     lastPath->outstandingBytes -= chunk->booksize;
00038     state->outstandingBytes -= chunk->booksize;
00039     assert((int64)state->outstandingBytes >= 0);
00040 
00041     chunk->countsAsOutstanding = false;
00042 
00043     CounterMap::iterator iterator = qCounter.roomRetransQ.find(lastPath->remoteAddress);
00044         iterator->second -= ADD_PADDING(chunk->booksize + SCTP_DATA_CHUNK_LENGTH);
00045 
00046 }
00047 
00048 
00049 bool SCTPAssociation::process_RCV_Message(SCTPMessage*       sctpmsg,
00050                                                         const IPvXAddress& src,
00051                                                         const IPvXAddress& dest)
00052 {
00053     // ====== Header checks ==================================================
00054     sctpEV3 << getFullPath()  << " SCTPAssociationRcvMessage:process_RCV_Message"
00055               << " localAddr="  << localAddr
00056               << " remoteAddr=" << remoteAddr << endl;
00057     if ((sctpmsg->hasBitError() || !sctpmsg->getChecksumOk()))
00058     {
00059         if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType() == INIT_ACK) {
00060             stopTimer(T1_InitTimer);
00061             sctpEV3 << "InitAck with bit-error. Retransmit Init" << endl;
00062             retransmitInit();
00063             startTimer(T1_InitTimer,state->initRexmitTimeout);
00064         }
00065         if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType() == COOKIE_ACK) {
00066             stopTimer(T1_InitTimer);
00067             sctpEV3 << "CookieAck with bit-error. Retransmit CookieEcho" << endl;
00068             retransmitCookieEcho();
00069             startTimer(T1_InitTimer,state->initRexmitTimeout);
00070         }
00071     }
00072 
00073     SCTPPathVariables* path      = getPath(src);
00074     const uint16 srcPort         = sctpmsg->getDestPort();
00075     const uint16 destPort        = sctpmsg->getSrcPort();
00076     const uint32 numberOfChunks = sctpmsg->getChunksArraySize();
00077     sctpEV3 << "numberOfChunks=" <<numberOfChunks << endl;
00078 
00079     state->sctpmsg = (SCTPMessage*)sctpmsg->dup();
00080 
00081     // ====== Handle chunks ==================================================
00082     bool trans              = true;
00083     bool sendAllowed        = false;
00084     bool dupReceived        = false;
00085     bool dataChunkReceived  = false;
00086     bool dataChunkDelivered = false;
00087     bool shutdownCalled     = false;
00088     for (uint32 i = 0; i < numberOfChunks; i++) {
00089         const SCTPChunk* header = (const SCTPChunk*)(sctpmsg->removeChunk());
00090         const uint8       type  = header->getChunkType();
00091 
00092         if ((type != INIT) &&
00093              (type != ABORT) &&
00094              (type != ERRORTYPE) &&
00095              (sctpmsg->getTag() != peerVTag)) {
00096             sctpEV3 << " VTag "<< sctpmsg->getTag() << " incorrect. Should be "
00097                       << peerVTag << " localVTag=" << localVTag << endl;
00098             return true;
00099         }
00100 
00101         switch (type) {
00102         case INIT:
00103             sctpEV3 << "SCTPAssociationRcvMessage: INIT received" << endl;
00104             SCTPInitChunk* initChunk;
00105             initChunk = check_and_cast<SCTPInitChunk*>(header);
00106             if ((initChunk->getNoInStreams() != 0) &&
00107                  (initChunk->getNoOutStreams() != 0) &&
00108                  (initChunk->getInitTag() != 0)) {
00109                 trans = processInitArrived(initChunk, srcPort, destPort);
00110             }
00111             i = numberOfChunks-1;
00112             delete initChunk;
00113             break;
00114         case INIT_ACK:
00115             sctpEV3 << "SCTPAssociationRcvMessage: INIT_ACK received" << endl;
00116             if (fsm->getState() == SCTP_S_COOKIE_WAIT) {
00117                 SCTPInitAckChunk* initAckChunk;
00118                 initAckChunk = check_and_cast<SCTPInitAckChunk*>(header);
00119                 if ((initAckChunk->getNoInStreams() != 0) &&
00120                     (initAckChunk->getNoOutStreams() != 0) &&
00121                     (initAckChunk->getInitTag() != 0)) {
00122                     trans = processInitAckArrived(initAckChunk);
00123                 }
00124                 else if (initAckChunk->getInitTag() == 0) {
00125                     sendAbort();
00126                     sctpMain->removeAssociation(this);
00127                 }
00128                 i = numberOfChunks-1;
00129                 delete initAckChunk;
00130             }
00131             else {
00132                 sctpEV3 << "INIT_ACK will be ignored" << endl;
00133             }
00134             break;
00135         case COOKIE_ECHO:
00136             sctpEV3 << "SCTPAssociationRcvMessage: COOKIE_ECHO received" << endl;
00137             SCTPCookieEchoChunk* cookieEchoChunk;
00138             cookieEchoChunk = check_and_cast<SCTPCookieEchoChunk*>(header);
00139             trans = processCookieEchoArrived(cookieEchoChunk,src);
00140             delete cookieEchoChunk;
00141             break;
00142         case COOKIE_ACK:
00143             sctpEV3 << "SCTPAssociationRcvMessage: COOKIE_ACK received" << endl;
00144             if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
00145                 SCTPCookieAckChunk* cookieAckChunk;
00146                 cookieAckChunk = check_and_cast<SCTPCookieAckChunk*>(header);
00147                 trans = processCookieAckArrived();
00148                 delete cookieAckChunk;
00149             }
00150             break;
00151         case DATA:
00152             sctpEV3 << "SCTPAssociationRcvMessage: DATA received" << endl;
00153             if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
00154                 trans = performStateTransition(SCTP_E_RCV_COOKIE_ACK);
00155             }
00156             if (!(fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED || fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) {
00157                 SCTPDataChunk* dataChunk;
00158                 dataChunk = check_and_cast<SCTPDataChunk*>(header);
00159                 if ((dataChunk->getByteLength()- 16) > 0) {
00160                     const SCTPEventCode event = processDataArrived(dataChunk);
00161                     if (event == SCTP_E_DELIVERED) {
00162                         dataChunkReceived    = true;
00163                         dataChunkDelivered = true;
00164                         state->sackAllowed = true;
00165                     }
00166                     else if (event==SCTP_E_SEND || event==SCTP_E_IGNORE) {
00167                         dataChunkReceived    = true;
00168                         state->sackAllowed = true;
00169                     }
00170                     else if (event==SCTP_E_DUP_RECEIVED) {
00171                         dupReceived = true;
00172                     }
00173                 }
00174                 else {
00175                     sendAbort();
00176                     sctpMain->removeAssociation(this);
00177                 }
00178                 delete dataChunk;
00179             }
00180             trans = true;
00181             break;
00182         case SACK:
00183         {
00184             sctpEV3 << "SCTPAssociationRcvMessage: SACK received" << endl;
00185             const int32 scount = qCounter.roomSumSendStreams;
00186             SCTPSackChunk* sackChunk;
00187             sackChunk = check_and_cast<SCTPSackChunk*>(header);
00188             processSackArrived(sackChunk);
00189             trans           = true;
00190             sendAllowed = true;
00191             delete sackChunk;
00192             if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && scount==0) {
00193                 if (fsm->getState() == SCTP_S_SHUTDOWN_PENDING) {
00194                     sctpEV3 << "No more packets: send SHUTDOWN" << endl;
00195                     sendShutdown();
00196                     trans               = performStateTransition(SCTP_E_NO_MORE_OUTSTANDING);
00197                     shutdownCalled = true;
00198                 }
00199                 else if (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED) {
00200                     sctpEV3 << "No more outstanding" << endl;
00201                     sendShutdownAck(remoteAddr);
00202                 }
00203             }
00204             break;
00205         }
00206         case ABORT:
00207             SCTPAbortChunk* abortChunk;
00208             abortChunk = check_and_cast<SCTPAbortChunk*>(header);
00209             sctpEV3 << "SCTPAssociationRcvMessage: ABORT with T-Bit "
00210                       << abortChunk->getT_Bit() << " received" << endl;
00211             if (sctpmsg->getTag() == localVTag || sctpmsg->getTag() == peerVTag) {
00212                 sendIndicationToApp(SCTP_I_ABORT);
00213                 trans = performStateTransition(SCTP_E_ABORT);
00214             }
00215             delete abortChunk;
00216             break;
00217         case HEARTBEAT:
00218             sctpEV3 << "SCTPAssociationRcvMessage: HEARTBEAT received" << endl;
00219             SCTPHeartbeatChunk* heartbeatChunk;
00220             heartbeatChunk = check_and_cast<SCTPHeartbeatChunk*>(header);
00221             if (!(fsm->getState() == SCTP_S_CLOSED)) {
00222                 sendHeartbeatAck(heartbeatChunk, dest, src);
00223             }
00224             trans = true;
00225             delete heartbeatChunk;
00226             if (path) {
00227                 path->numberOfHeartbeatsRcvd++;
00228                 path->pathRcvdHb->record(path->numberOfHeartbeatsRcvd);
00229             }
00230             break;
00231         case HEARTBEAT_ACK:
00232             sctpEV3 << "SCTPAssociationRcvMessage: HEARTBEAT_ACK received" << endl;
00233             if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
00234                 trans = performStateTransition(SCTP_E_RCV_COOKIE_ACK);
00235             }
00236             SCTPHeartbeatAckChunk* heartbeatAckChunk;
00237             heartbeatAckChunk = check_and_cast<SCTPHeartbeatAckChunk*>(header);
00238             if (path) {
00239                 processHeartbeatAckArrived(heartbeatAckChunk, path);
00240             }
00241             trans = true;
00242             delete heartbeatAckChunk;
00243             break;
00244         case SHUTDOWN:
00245             sctpEV3 << "SCTPAssociationRcvMessage: SHUTDOWN received" << endl;
00246             SCTPShutdownChunk* shutdownChunk;
00247             shutdownChunk = check_and_cast<SCTPShutdownChunk*>(header);
00248             if (shutdownChunk->getCumTsnAck()>state->lastTsnAck) {
00249                 simtime_t rttEstimation = MAXTIME;
00250                 dequeueAckedChunks(shutdownChunk->getCumTsnAck(),
00251                                          getPath(remoteAddr), rttEstimation);
00252                 state->lastTsnAck = shutdownChunk->getCumTsnAck();
00253             }
00254             trans = performStateTransition(SCTP_E_RCV_SHUTDOWN);
00255             sendIndicationToApp(SCTP_I_SHUTDOWN_RECEIVED);
00256             trans = true;
00257             delete shutdownChunk;
00258             break;
00259         case SHUTDOWN_ACK:
00260             sctpEV3 << "SCTPAssociationRcvMessage: SHUTDOWN_ACK received" << endl;
00261             if (fsm->getState()!=SCTP_S_ESTABLISHED) {
00262                 SCTPShutdownAckChunk* shutdownAckChunk;
00263                 shutdownAckChunk = check_and_cast<SCTPShutdownAckChunk*>(header);
00264                 sendShutdownComplete();
00265                 stopTimers();
00266                 stopTimer(T2_ShutdownTimer);
00267                 stopTimer(T5_ShutdownGuardTimer);
00268                 sctpEV3 << "state=" << stateName(fsm->getState()) << endl;
00269                 if ((fsm->getState() == SCTP_S_SHUTDOWN_SENT) ||
00270                      (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) {
00271                     trans = performStateTransition(SCTP_E_RCV_SHUTDOWN_ACK);
00272                     sendIndicationToApp(SCTP_I_CLOSED);
00273                     delete state->shutdownChunk;
00274                 }
00275                 delete shutdownAckChunk;
00276             }
00277             break;
00278         case SHUTDOWN_COMPLETE:
00279             sctpEV3<<"Shutdown Complete arrived" << endl;
00280             SCTPShutdownCompleteChunk* shutdownCompleteChunk;
00281             shutdownCompleteChunk = check_and_cast<SCTPShutdownCompleteChunk*>(header);
00282             trans = performStateTransition(SCTP_E_RCV_SHUTDOWN_COMPLETE);
00283             sendIndicationToApp(SCTP_I_PEER_CLOSED);     // necessary for NAT-Rendezvous
00284             if (trans == true) {
00285                 stopTimers();
00286             }
00287             stopTimer(T2_ShutdownTimer);
00288             stopTimer(T5_ShutdownGuardTimer);
00289             delete state->shutdownAckChunk;
00290             delete shutdownCompleteChunk;
00291             break;
00292         default: sctpEV3<<"different type" << endl;
00293             break;
00294         }
00295 
00296         if (i==numberOfChunks-1 && (dataChunkReceived || dupReceived)) {
00297             sendAllowed=true;
00298             sctpEV3 << "i=" << i << " sendAllowed=true; scheduleSack" << endl;
00299             scheduleSack();
00300             if (fsm->getState() == SCTP_S_SHUTDOWN_SENT && state->ackState>=sackFrequency) {
00301                 sendSack();
00302             }
00303         }
00304 
00305         // Send any new DATA chunks, SACK chunks, HEARTBEAT chunks etc.
00306         sctpEV3 << "SCTPAssociationRcvMessage: send new data? state=" << stateName(fsm->getState())
00307                   << " sendAllowed="        << sendAllowed
00308                   << " shutdownCalled=" << shutdownCalled << endl;
00309         if (((fsm->getState() == SCTP_S_ESTABLISHED) ||
00310               (fsm->getState() == SCTP_S_SHUTDOWN_PENDING) ||
00311               (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED)) &&
00312              (sendAllowed) &&
00313              (!shutdownCalled)) {
00314             sendOnAllPaths(state->getPrimaryPath());
00315         }
00316     }
00317 
00318     // ====== Clean-up =======================================================
00319     disposeOf(state->sctpmsg);
00320     return trans;
00321 }
00322 
00323 bool SCTPAssociation::processInitArrived(SCTPInitChunk* initchunk, int32 srcPort, int32 destPort)
00324 {
00325     SCTPAssociation* assoc;
00326     char timerName[128];
00327     bool trans = false;
00328     InterfaceTableAccess interfaceTableAccess;
00329     AddressVector adv;
00330     sctpEV3<<"processInitArrived\n";
00331     if (fsm->getState() == SCTP_S_CLOSED)
00332     {
00333         sctpEV3<<"fork="<<state->fork<<" initReceived="<<state->initReceived<<"\n";
00334         if (state->fork && !state->initReceived)
00335         {
00336             sctpEV3<<"cloneAssociation\n";
00337             assoc = cloneAssociation();
00338             sctpEV3<<"addForkedAssociation\n";
00339             sctpMain->addForkedAssociation(this, assoc, localAddr, remoteAddr, srcPort, destPort);
00340 
00341             sctpEV3 << "Connection forked: this connection got new assocId=" << assocId << ", "
00342                 "spinoff keeps LISTENing with assocId=" << assoc->assocId << "\n";
00343             snprintf(timerName, sizeof(timerName), "T2_SHUTDOWN of assoc %d", assocId);
00344             T2_ShutdownTimer->setName(timerName);
00345             snprintf(timerName, sizeof(timerName), "T5_SHUTDOWN_GUARD of assoc %d", assocId);
00346             T5_ShutdownGuardTimer->setName(timerName);
00347             snprintf(timerName, sizeof(timerName), "SACK_TIMER of assoc %d", assocId);
00348             SackTimer->setName(timerName);
00349             snprintf(timerName, sizeof(timerName), "T1_INIT of assoc %d", assocId);
00350             T1_InitTimer->setName(timerName);
00351         }
00352         else
00353         {
00354             sctpMain->updateSockPair(this, localAddr, remoteAddr, srcPort, destPort);
00355 
00356         }
00357         if (!state->initReceived)
00358         {
00359             state->initReceived = true;
00360             state->initialPrimaryPath = remoteAddr;
00361             state->setPrimaryPath(getPath(remoteAddr));
00362             if (initchunk->getAddressesArraySize()==0)
00363             {
00364                 sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<"\n";
00365                 SCTPPathVariables* rPath = new SCTPPathVariables(remoteAddr, this);
00366                 sctpPathMap[rPath->remoteAddress] = rPath;
00367                 qCounter.roomTransQ[rPath->remoteAddress]     = 0;
00368                 qCounter.bookedTransQ[rPath->remoteAddress] = 0;
00369                 qCounter.roomRetransQ[rPath->remoteAddress] = 0;
00370             }
00371             initPeerTsn=initchunk->getInitTSN();
00372             state->cTsnAck = initPeerTsn - 1;
00373             state->initialPeerRwnd = initchunk->getA_rwnd();
00374             state->peerRwnd = state->initialPeerRwnd;
00375             localVTag= initchunk->getInitTag();
00376             numberOfRemoteAddresses =initchunk->getAddressesArraySize();
00377             IInterfaceTable *ift = interfaceTableAccess.get();
00378             state->localAddresses.clear();
00379             if (localAddressList.front() == IPvXAddress("0.0.0.0"))
00380             {
00381                 for (int32 i=0; i<ift->getNumInterfaces(); ++i)
00382                 {
00383                     if (ift->getInterface(i)->ipv4Data()!=NULL)
00384                     {
00385                         adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress());
00386                     }
00387                     else if (ift->getInterface(i)->ipv6Data()!=NULL)
00388                     {
00389                         adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(0));
00390                     }
00391                 }
00392             }
00393             else
00394             {
00395                 adv = localAddressList;
00396             }
00397             uint32 rlevel = getLevel(remoteAddr);
00398             if (rlevel>0)
00399                 for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i)
00400                 {
00401                     if (getLevel((*i))>=rlevel)
00402                     {
00403                         sctpMain->addLocalAddress(this, (*i));
00404                         state->localAddresses.push_back((*i));
00405                     }
00406                 }
00407             for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++)
00408             {
00409                 // skip IPv6 because we can't send to them yet
00410                 if (initchunk->getAddresses(j).isIPv6())
00411                     continue;
00412                 // set path variables for this pathlocalAddresses
00413                 if (!getPath(initchunk->getAddresses(j)))
00414                 {
00415                     SCTPPathVariables* path = new SCTPPathVariables(initchunk->getAddresses(j), this);
00416                     sctpEV3<<__LINE__<<" get new path for "<<initchunk->getAddresses(j)<<" ptr="<<path<<"\n";
00417                     for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k)
00418                     {
00419                         sctpMain->addRemoteAddress(this,(*k), initchunk->getAddresses(j));
00420                         this->remoteAddressList.push_back(initchunk->getAddresses(j));
00421                     }
00422                     sctpPathMap[path->remoteAddress] = path;
00423                     qCounter.roomTransQ[path->remoteAddress]     = 0;
00424                     qCounter.bookedTransQ[path->remoteAddress] = 0;
00425                     qCounter.roomRetransQ[path->remoteAddress] = 0;
00426                 }
00427             }
00428             SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr);
00429             if (ite==sctpPathMap.end())
00430             {
00431                 SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this);
00432                 sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<" ptr="<<path<<"\n";
00433                 sctpPathMap[remoteAddr] = path;
00434                 qCounter.roomTransQ[remoteAddr]  = 0;
00435                 qCounter.bookedTransQ[remoteAddr] = 0;
00436                 qCounter.roomRetransQ[remoteAddr] = 0;
00437             }
00438             trans = performStateTransition(SCTP_E_RCV_INIT);
00439             if (trans) {
00440                 sendInitAck(initchunk);
00441             }
00442         }
00443         else if (fsm->getState() == SCTP_S_CLOSED)
00444         {
00445             trans=performStateTransition(SCTP_E_RCV_INIT);
00446             if (trans) {
00447                 sendInitAck(initchunk);
00448             }
00449         }
00450         else {
00451             trans = true;
00452         }
00453     }
00454     else if (fsm->getState() == SCTP_S_COOKIE_WAIT) //INIT-Collision
00455     {
00456         sctpEV3<<"INIT collision: send Init-Ack\n";
00457         sendInitAck(initchunk);
00458         trans=true;
00459     }
00460     else if (fsm->getState() == SCTP_S_COOKIE_ECHOED || fsm->getState() == SCTP_S_ESTABLISHED)
00461     {
00462         // check, whether a new address has been added
00463         bool addressPresent = false;
00464         for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++)
00465         {
00466             if (initchunk->getAddresses(j).isIPv6())
00467                 continue;
00468             for (AddressVector::iterator k=remoteAddressList.begin(); k!=remoteAddressList.end(); ++k)
00469             {
00470                 if ((*k)==(initchunk->getAddresses(j)))
00471                 {
00472                     addressPresent = true;
00473                     break;
00474                 }
00475             }
00476             if (!addressPresent)
00477             {
00478                 sendAbort();
00479                 return true;
00480             }
00481         }
00482         sendInitAck(initchunk);
00483         trans=true;
00484     }
00485     else if (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)
00486         trans = true;
00487     printSctpPathMap();
00488     return trans;
00489 }
00490 
00491 
00492 bool SCTPAssociation::processInitAckArrived(SCTPInitAckChunk* initAckChunk)
00493 {
00494     bool trans = false;
00495     if (fsm->getState() == SCTP_S_COOKIE_WAIT)
00496     {
00497         sctpEV3<<"State is COOKIE_WAIT, Cookie_Echo has to be sent\n";
00498         stopTimer(T1_InitTimer);
00499         state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT;
00500         trans=performStateTransition(SCTP_E_RCV_INIT_ACK);
00501         //delete state->initChunk; will be deleted when state ESTABLISHED is entered
00502         if (trans)
00503         {
00504             state->initialPrimaryPath = remoteAddr;
00505             state->setPrimaryPath(getPath(remoteAddr));
00506             initPeerTsn=initAckChunk->getInitTSN();
00507             localVTag= initAckChunk->getInitTag();
00508             state->cTsnAck = initPeerTsn - 1;
00509             state->initialPeerRwnd = initAckChunk->getA_rwnd();
00510             state->peerRwnd = state->initialPeerRwnd;
00511             remoteAddressList.clear();
00512             numberOfRemoteAddresses =initAckChunk->getAddressesArraySize();
00513             sctpEV3<<"number of remote addresses in initAck="<<numberOfRemoteAddresses<<"\n";
00514             for (uint32 j=0; j<numberOfRemoteAddresses; j++)
00515             {
00516                 if (initAckChunk->getAddresses(j).isIPv6())
00517                     continue;
00518                 for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k)
00519                 {
00520                     if (!((*k).isUnspecified()))
00521                     {
00522                         sctpEV3<<"addPath "<<initAckChunk->getAddresses(j)<<"\n";
00523                         sctpMain->addRemoteAddress(this,(*k), initAckChunk->getAddresses(j));
00524                         this->remoteAddressList.push_back(initAckChunk->getAddresses(j));
00525                         addPath(initAckChunk->getAddresses(j));
00526                     }
00527                 }
00528             }
00529             SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr);
00530             if (ite==sctpPathMap.end())
00531             {
00532                 sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<"\n";
00533                 SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this);
00534                 sctpPathMap[remoteAddr] = path;
00535                 qCounter.roomTransQ[remoteAddr]  = 0;
00536                 qCounter.roomRetransQ[remoteAddr] = 0;
00537                 qCounter.bookedTransQ[remoteAddr] = 0;
00538             }
00539             inboundStreams   = ((initAckChunk->getNoOutStreams()<inboundStreams)?initAckChunk->getNoOutStreams():inboundStreams);
00540             outboundStreams = ((initAckChunk->getNoInStreams()<outboundStreams)?initAckChunk->getNoInStreams():outboundStreams);
00541             (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams);
00542             sendCookieEcho(initAckChunk);
00543         }
00544         startTimer(T1_InitTimer, state->initRexmitTimeout);
00545     }
00546     else
00547         sctpEV3<<"State="<<fsm->getState()<<"\n";
00548     printSctpPathMap();
00549     return trans;
00550 }
00551 
00552 
00553 
00554 bool SCTPAssociation::processCookieEchoArrived(SCTPCookieEchoChunk* cookieEcho, IPvXAddress addr)
00555 {
00556     bool trans = false;
00557     SCTPCookie* cookie = check_and_cast<SCTPCookie*>(cookieEcho->getStateCookie());
00558     if (cookie->getCreationTime()+(int32)sctpMain->par("validCookieLifetime")<simTime())
00559     {
00560         sctpEV3<<"stale Cookie: sendAbort\n";
00561         sendAbort();
00562         delete cookie;
00563         return trans;
00564     }
00565     if (fsm->getState() == SCTP_S_CLOSED)
00566     {
00567         if (cookie->getLocalTag()!=localVTag || cookie->getPeerTag() != peerVTag)
00568         {
00569             bool same=true;
00570             for (int32 i=0; i<32; i++)
00571             {
00572                 if (cookie->getLocalTieTag(i)!=state->localTieTag[i])
00573                 {
00574                     same = false;
00575                     break;
00576                 }
00577                 if (cookie->getPeerTieTag(i)!=state->peerTieTag[i])
00578                 {
00579                     same = false;
00580                     break;
00581                 }
00582             }
00583             if (!same)
00584             {
00585                 sendAbort();
00586                 delete cookie;
00587                 return trans;
00588             }
00589         }
00590         sctpEV3<<"State is CLOSED, Cookie_Ack has to be sent\n";
00591         trans=performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO);
00592         if (trans)
00593             sendCookieAck(addr);//send to address
00594     }
00595     else if (fsm->getState() == SCTP_S_ESTABLISHED || fsm->getState() == SCTP_S_COOKIE_WAIT || fsm->getState() == SCTP_S_COOKIE_ECHOED)
00596     {
00597         sctpEV3<<"State is not CLOSED, but COOKIE_ECHO received. Compare the Tags\n";
00598         // case A: Peer restarted, retrieve information from cookie
00599         if (cookie->getLocalTag()!=localVTag && cookie->getPeerTag() != peerVTag )
00600         {
00601             bool same=true;
00602             for (int32 i=0; i<32; i++)
00603             {
00604                 if (cookie->getLocalTieTag(i)!=state->localTieTag[i])
00605                 {
00606                     same = false;
00607                     break;
00608                 }
00609                 if (cookie->getPeerTieTag(i)!=state->peerTieTag[i])
00610                 {
00611                     same = false;
00612                     break;
00613                 }
00614             }
00615             if (same)
00616             {
00617                 localVTag = cookie->getLocalTag();
00618                 peerVTag = cookie->getPeerTag();
00619                 sendCookieAck(addr);
00620             }
00621         }
00622         // case B: Setup collision, retrieve information from cookie
00623         else if (cookie->getPeerTag()==peerVTag && (cookie->getLocalTag()!=localVTag || cookie->getLocalTag()==0))
00624         {
00625             localVTag = cookie->getLocalTag();
00626             peerVTag = cookie->getPeerTag();
00627             performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO);
00628             sendCookieAck(addr);
00629         }
00630         else if (cookie->getPeerTag()==peerVTag && cookie->getLocalTag()==localVTag)
00631         {
00632             sendCookieAck(addr); //send to address src
00633         }
00634         trans=true;
00635     }
00636     else
00637     {
00638         sctpEV3<<"State="<<fsm->getState()<<"\n";
00639         trans = true;
00640     }
00641     delete cookie;
00642     return trans;
00643 }
00644 
00645 bool SCTPAssociation::processCookieAckArrived()
00646 {
00647     bool trans=false;
00648 
00649     if (fsm->getState() == SCTP_S_COOKIE_ECHOED)
00650     {
00651         stopTimer(T1_InitTimer);
00652         trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK);
00653         if (state->cookieChunk->getCookieArraySize()==0)
00654         {
00655                 delete state->cookieChunk->getStateCookie();
00656         }
00657         delete state->cookieChunk;
00658         return trans;
00659     }
00660     else
00661         sctpEV3<<"State="<<fsm->getState()<<"\n";
00662 
00663     return trans;
00664 }
00665 
00666 void SCTPAssociation::tsnWasReneged(SCTPDataVariables*       chunk,
00667                                                 const int                    type)
00668 {
00669 
00670 #ifdef PKT
00671     if (transmissionQ->getQueueSize() > 0) {
00672         for (SCTPQueue::PayloadQueue::iterator tq = transmissionQ->payloadQueue.begin();
00673               tq != transmissionQ->payloadQueue.end(); tq++) {
00674             if (tq->second->tsn > chunk->tsn) {
00675                 if (!transmissionQ->checkAndInsertChunk(chunk->tsn, chunk)) {
00676                     sctpEV3 << "tsnWasReneged: cannot add message/chunk (TSN="
00677                               << chunk->tsn <<") to the transmissionQ" << endl;
00678                 }
00679                 else {
00680                     chunk->enqueuedInTransmissionQ = true;
00681                     chunk->setNextDestination(chunk->getLastDestinationPath());
00682                     CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination());
00683                     q->second+=ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
00684                     CounterMap::iterator qb=qCounter.bookedTransQ.find(chunk->getNextDestination());
00685                     qb->second+=chunk->booksize;
00686                     return;
00687                 }
00688             }
00689         }
00690     }
00691 #endif
00692     sctpEV3 << "TSN " << chunk->tsn << " has been reneged (type "
00693               << type << ")" << endl;
00694     unackChunk(chunk);
00695     if (chunk->countsAsOutstanding) {
00696         decreaseOutstandingBytes(chunk);
00697     }
00698     chunk->hasBeenReneged = true;
00699     chunk->gapReports        = 1;
00700     if (!chunk->getLastDestinationPath()->T3_RtxTimer->isScheduled()) {
00701         startTimer(chunk->getLastDestinationPath()->T3_RtxTimer,
00702                       chunk->getLastDestinationPath()->pathRto);
00703     }
00704 }
00705 
00706 
00707 
00708 
00709 SCTPEventCode SCTPAssociation::processSackArrived(SCTPSackChunk* sackChunk)
00710 {
00711     simtime_t            rttEstimation            = MAXTIME;
00712     bool                     ctsnaAdvanced            = false;
00713     SCTPPathVariables* path                       = getPath(remoteAddr);    // Path for *this* SACK!
00714     const uint64         arwnd                    = sackChunk->getA_rwnd();
00715     const uint32         tsna                         = sackChunk->getCumTsnAck();
00716     uint32               highestNewAck            = tsna;   // Highest newly acked TSN
00717     const uint16         numGaps                      = sackChunk->getNumGaps();
00718     bool                     getChunkFastFirstTime = true;
00719 
00720     // ====== Print some information =========================================
00721     sctpEV3 << "##### SACK Processing: TSNa=" << tsna << " #####" << endl;
00722     for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
00723         SCTPPathVariables* myPath = piter->second;
00724         sctpEV3 << "Path " << myPath->remoteAddress << ":\t"
00725                   << "outstanding="          << path->outstandingBytes << "\t"
00726                   << "T3scheduled="          << path->T3_RtxTimer->getArrivalTime() << " "
00727                   << (path->T3_RtxTimer->isScheduled() ? "[ok]" : "[NOT SCHEDULED]") << "\t"
00728                   << endl;
00729     }
00730 
00731 
00732 
00733     // ====== Initialize some variables ======================================
00734     for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
00735         SCTPPathVariables* myPath = piter->second;
00736         // T.D. 26.03.09: Remember outstanding bytes before this update
00737         // Values are necessary for updating the congestion window!
00738         myPath->outstandingBytesBeforeUpdate = myPath->outstandingBytes;     // T.D. 14.11.09: Bugfix - copy from myPath, not from path!
00739         myPath->requiresRtx                      = false;
00740         myPath->lowestTSNRetransmitted       = false;
00741         myPath->findLowestTSN                    = true;
00742         myPath->gapAcksInLastSACK                = 0;
00743         myPath->gapNAcksInLastSACK               = 0;
00744         myPath->newlyAckedBytes                  = 0;
00745         if (myPath == path) {
00746             myPath->lastAckTime = simTime();
00747         }
00748     }
00749 
00750 
00751     // ====== Zero Window Probing ============================================
00752     if ( (state->zeroWindowProbing) && (arwnd > 0) ) {
00753         state->zeroWindowProbing = false;
00754     }
00755 
00756 
00757     // #######################################################################
00758     // #### Processing of CumAck                                                         ####
00759     // #######################################################################
00760 
00761     if (tsnGt(tsna, state->lastTsnAck)) {    // Handle new CumAck
00762         sctpEV3 << "===== Handling new CumAck for TSN " << tsna << " =====" << endl;
00763 
00764 
00765         // We have got new chunks acked, and our cum ack point is advanced ...
00766         // Depending on the parameter osbWithHeader ackedBytes are with or without the header bytes.
00767         // T.D. 23.03.09: path->newlyAckedBytes is updated in dequeueAckedChunks()!
00768         dequeueAckedChunks(tsna, path, rttEstimation); // chunks with tsn between lastTsnAck and tsna are removed from the transmissionQ and the retransmissionQ; outstandingBytes are decreased
00769 
00770         state->lastTsnAck = tsna;
00771         ctsnaAdvanced = true;
00772     }
00773     else if (tsnLt(tsna, state->lastTsnAck)) {
00774         sctpEV3 << "Stale CumAck (" << tsna << " < " << state->lastTsnAck << ")"
00775                   << endl;
00776         return SCTP_E_IGNORE;
00777     }
00778 
00779 
00780     // ====== Handle reneging ================================================
00781     if ((numGaps == 0) && (tsnLt(tsna, state->highestTsnAcked))) {
00782         // Reneging, type 0:
00783         // In a previous SACK, chunks up to highestTsnAcked have been acked.
00784         // This SACK contains a CumAck < highestTsnAcked
00785         //      => rereg TSNs from CumAck+1 to highestTsnAcked
00786         //      => new highestTsnAcked = CumAck
00787         sctpEV3 << "numGaps=0 && tsna " << tsna
00788                   << " < highestTsnAcked " << state->highestTsnAcked << endl;
00789         uint32 i = state->highestTsnAcked;
00790         while (i >= tsna + 1) {
00791             SCTPDataVariables* myChunk = retransmissionQ->getChunk(i);
00792             if(myChunk) {
00793                 if(chunkHasBeenAcked(myChunk)) {
00794                     tsnWasReneged(myChunk,
00795                                       0);
00796                 }
00797             }
00798             i--;
00799         }
00800         state->highestTsnAcked = tsna;
00801     }
00802 
00803 
00804     // #######################################################################
00805     // #### Processing of GapAcks                                                        ####
00806     // #######################################################################
00807 
00808     if ((numGaps > 0) && (!retransmissionQ->payloadQueue.empty()) ) {
00809         sctpEV3 << "===== Handling GapAcks after CumTSNAck " << tsna << " =====" << endl;
00810         sctpEV3 << "We got " << numGaps << " gap reports" << endl;
00811 
00812         // We got fragment reports... check for newly acked chunks.
00813         const uint32 queuedChunks = retransmissionQ->payloadQueue.size();
00814         sctpEV3 << "Number of chunks in retransmissionQ: " << queuedChunks
00815                   <<" highestGapStop: "  << sackChunk->getGapStop(numGaps-1)
00816                   <<" highestTsnAcked: " << state->highestTsnAcked << endl;
00817 
00818         // ====== Handle reneging =============================================
00819         // highest gapStop smaller than highestTsnAcked: there might have been reneging
00820         if (tsnLt(sackChunk->getGapStop(numGaps-1), state->highestTsnAcked)) {
00821             // Reneging, type 2:
00822             // In a previous SACK, chunks up to highestTsnAcked have been acked.
00823             // This SACK contains a last gap ack < highestTsnAcked
00824             //      => rereg TSNs from last gap ack to highestTsnAcked
00825             //      => new highestTsnAcked = last gap ack
00826             uint32 i = state->highestTsnAcked;
00827             while (i >= sackChunk->getGapStop(numGaps - 1) + 1) {
00828                 // ====== Looking up TSN in retransmission queue ================
00829                 SCTPDataVariables* myChunk = retransmissionQ->getChunk(i);
00830                 if(myChunk) {
00831                     if (chunkHasBeenAcked(myChunk)) {
00832                         sctpEV3 << "TSN " << i << " was found. It has been un-acked." << endl;
00833                         tsnWasReneged(myChunk,
00834                                           2);
00835                         sctpEV3 << "highestTsnAcked now " << state->highestTsnAcked << endl;
00836                     }
00837                 }
00838                 else {
00839                     sctpEV3 << "TSN " << i << " not found in retransmissionQ" << endl;
00840                 }
00841                 i--;
00842             }
00843             state->highestTsnAcked = sackChunk->getGapStop(numGaps - 1);
00844         }
00845 
00846         // ====== Looking for changes in the gap reports ======================
00847         sctpEV3 << "Looking for changes in gap reports" << endl;
00848         for (int32 key = 0;key < numGaps; key++) {
00849             const uint32 lo = sackChunk->getGapStart(key);
00850             const uint32 hi = sackChunk->getGapStop(key);
00851 
00852 
00853             // ====== Iterate over TSNs in gap reports =========================
00854             sctpEV3 << "Examine TSNs between " << lo << " and " << hi << endl;
00855             for (uint32 pos = lo; pos <= hi; pos++) {
00856                 SCTPDataVariables* myChunk = retransmissionQ->getChunkFast(pos, getChunkFastFirstTime);
00857                 if (myChunk) {
00858                     if(chunkHasBeenAcked(myChunk) == false) {
00859                         SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath();
00860                         assert(myChunkLastPath != NULL);
00861                         // T.D. 02.02.2010: This chunk has been acked newly.
00862                         //                        Let's process this new acknowledgement!
00863                         handleChunkReportedAsAcked(highestNewAck, rttEstimation, myChunk,
00864                                                             path /* i.e. the SACK path for RTT measurement! */);
00865                     }
00866                 }
00867             }
00868         }
00869         state->highestTsnAcked = sackChunk->getGapStop(numGaps-1);
00870 
00871         // ====== Examine chunks between the gap reports ======================
00872         // They might have to be retransmitted or they could have been removed
00873         uint32 lo = tsna;
00874         for (int32 key = 0; key < numGaps; key++) {
00875             const uint32 hi = sackChunk->getGapStart(key);
00876             for (uint32 pos = lo+1; pos <= hi - 1; pos++) {
00877                 SCTPDataVariables* myChunk = retransmissionQ->getChunkFast(pos, getChunkFastFirstTime);
00878                 if(myChunk) {
00879                     handleChunkReportedAsMissing(sackChunk, highestNewAck, myChunk,
00880                                                           path /* i.e. the SACK path for RTT measurement! */);
00881                 }
00882                 else {
00883                     sctpEV3 << "TSN " << pos << " not found in retransmissionQ" << endl;
00884                 }
00885             }
00886             lo = sackChunk->getGapStop(key);
00887         }
00888 
00889 
00890         // ====== Validity checks =============================================
00891     }
00892 
00893 
00894     // ====== Update Fast Recovery status, according to SACK =================
00895     updateFastRecoveryStatus(state->lastTsnAck);
00896 
00897     // ====== Update RTT measurement for newly acked data chunks =============
00898     sctpEV3 << simTime() << ": SACK: rtt=" << rttEstimation
00899               << ", path=" << path->remoteAddress << endl;
00900     pmRttMeasurement(path, rttEstimation);
00901 
00902 
00903 
00904     // #######################################################################
00905     // #### Receiver Window Management                                               ####
00906     // #######################################################################
00907 
00908     const uint32 osb = getOutstandingBytes();
00909     state->peerRwnd = arwnd - osb;
00910 
00911     // position of statement changed 20.07.05 I.R.
00912     if ((int32)(state->peerRwnd) < 0) {
00913         state->peerRwnd = 0;
00914     }
00915     if (state->peerRwnd > state->initialPeerRwnd) {
00916         state->peerRwnd = state->initialPeerRwnd;
00917     }
00918     if (arwnd == 1 || state->peerRwnd < state->swsLimit || arwnd == 0) {
00919         sctpEV3 << "processSackArrived: arwnd=" << arwnd
00920                   << " state->peerRwnd=" << state->peerRwnd
00921                   << " set peerWindowFull" << endl;
00922         state->peerWindowFull = true;
00923     }
00924     else
00925     {
00926         state->peerWindowFull    = false;
00927         state->zeroWindowProbing = false;
00928     }
00929 #ifdef PVIATE
00930     advancePeerTsn();
00931 #endif
00932 
00933     // ====== Need for zero-window probing? ==================================
00934     if(osb == 0) {
00935         if (arwnd == 0)
00936             state->zeroWindowProbing = true;
00937     }
00938 
00939 
00940     // #######################################################################
00941     // #### Congestion Window Management                                             ####
00942     // #######################################################################
00943 
00944     sctpEV3 << "Before ccUpdateBytesAcked: ";
00945     for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
00946         SCTPPathVariables* myPath    = piter->second;
00947         const IPvXAddress& myPathId = myPath->remoteAddress;
00948 
00949 
00950         if(myPath->newlyAckedBytes > 0) {
00951             // T.D. 07.10.2009: Only call ccUpdateBytesAcked() when there are
00952             //                        acked bytes on this path!
00953             const bool advanceWindow = myPath->newCumAck;
00954 
00955             sctpEV3 << simTime() << ":\tCC " << myPath->newlyAckedBytes
00956                       << " newly acked on path " << myPathId << ";"
00957                       << "\t->\tadvanceWindow="       << advanceWindow << endl;
00958 
00959             (this->*ccFunctions.ccUpdateBytesAcked)(myPath, myPath->newlyAckedBytes, advanceWindow);
00960         }
00961     }
00962 
00963     // ====== Update congestion windows on paths (handling decreases) ========
00964     sctpEV3 << "Before ccUpdateAfterSack with tsna=" << tsna << endl;
00965     // ccUpdateAfterSack() will iterate over all paths.
00966     (this->*ccFunctions.ccUpdateAfterSack)();
00967 
00968 
00969     // #######################################################################
00970     // #### Path Management                                                              ####
00971     // #######################################################################
00972 
00973     // ====== Need to stop or restart T3 timer? ==============================
00974     for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
00975         SCTPPathVariables* myPath    = piter->second;
00976         const IPvXAddress& myPathId = myPath->remoteAddress;
00977 
00978         if (myPath->outstandingBytes == 0) {
00979             // T.D. 07.01.2010: Only stop T3 timer when there is nothing more to send on this path!
00980             if(qCounter.roomTransQ.find(myPath->remoteAddress)->second == 0) {
00981                 // Stop T3 timer, if there are no more outstanding bytes.
00982                 stopTimer(myPath->T3_RtxTimer);
00983             }
00984         }
00985         else if (myPath->newCumAck) {
00986             stopTimer(myPath->T3_RtxTimer);
00987             startTimer(myPath->T3_RtxTimer, myPath->pathRto);
00988         }
00989         else {
00990             /* Also restart T3 timer, when lowest TSN is rtx'ed */
00991             if(myPath->lowestTSNRetransmitted == true) {
00992                 sctpEV3 << "Lowest TSN retransmitted => restart of T3 timer for path "
00993                             << myPathId << endl;
00994                 stopTimer(myPath->T3_RtxTimer);
00995                 startTimer(myPath->T3_RtxTimer, myPath->pathRto);
00996             }
00997         }
00998 
00999         // ====== Clear error counter if TSNs on path have been acked =========
01000         if (myPath->newlyAckedBytes > 0) {
01001             pmClearPathCounter(myPath);
01002         }
01003     }
01004 
01005 
01006 
01007     return SCTP_E_IGNORE;
01008 }
01009 
01010 
01011 void SCTPAssociation::handleChunkReportedAsAcked(uint32&                  highestNewAck,
01012                                                                  simtime_t&           rttEstimation,
01013                                                                  SCTPDataVariables* myChunk,
01014                                                                  SCTPPathVariables* sackPath)
01015 {
01016     SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath();
01017     if ( (myChunk->numberOfTransmissions == 1) &&
01018           (myChunk->hasBeenReneged == false) ) {
01019         if (myChunkLastPath == sackPath) {
01020             const simtime_t timeDifference = simTime() - myChunk->sendTime;
01021             if((timeDifference < rttEstimation) || (rttEstimation == -1.0)) {
01022                 rttEstimation = timeDifference;
01023             }
01024             sctpEV3 << simTime()          << " processSackArrived: computed rtt time diff == "
01025                       << timeDifference << " for TSN "<< myChunk->tsn << endl;
01026         }
01027     }
01028     if ( (myChunk->hasBeenAbandoned == false)    &&
01029           (myChunk->hasBeenReneged == false) ) {
01030         myChunkLastPath->newlyAckedBytes += (myChunk->booksize);
01031 
01032         sctpEV3 << simTime() << ": GapAcked TSN " << myChunk->tsn
01033                   << " on path " << myChunkLastPath->remoteAddress << endl;
01034 
01035         if (myChunk->tsn > highestNewAck) {
01036             highestNewAck = myChunk->tsn;
01037         }
01038         ackChunk(myChunk);
01039         if (myChunk->countsAsOutstanding) {
01040             decreaseOutstandingBytes(myChunk);
01041         }
01042         if (transmissionQ->getChunk(myChunk->tsn)) {      // I.R. 02.01.07
01043             sctpEV3 << "Found TSN " << myChunk->tsn << " in transmissionQ -> remote it" << endl;
01044             transmissionQ->removeMsg(myChunk->tsn);
01045             myChunk->enqueuedInTransmissionQ = false;
01046             CounterMap::iterator q = qCounter.roomTransQ.find(myChunk->getNextDestination());
01047             q->second -= ADD_PADDING(myChunk->len/8+SCTP_DATA_CHUNK_LENGTH);
01048             CounterMap::iterator qb = qCounter.bookedTransQ.find(myChunk->getNextDestination());
01049             qb->second -= myChunk->booksize;
01050         }
01051         myChunk->gapReports = 0;
01052     }
01053 }
01054 
01055 
01056 void SCTPAssociation::handleChunkReportedAsMissing(const SCTPSackChunk*      sackChunk,
01057                                                                     const uint32                 highestNewAck,
01058                                                                     SCTPDataVariables*       myChunk,
01059                                                                     const SCTPPathVariables* sackPath)
01060 {
01061     SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath();
01062     sctpEV3 << "TSN " << myChunk->tsn << " is missing in gap reports (last "
01063               << myChunkLastPath->remoteAddress << ") ";
01064     if (!chunkHasBeenAcked(myChunk)) {
01065         sctpEV3 << "has not been acked, highestNewAck=" << highestNewAck
01066                   << " countsAsOutstanding=" << myChunk->countsAsOutstanding << endl;
01067         const uint32 chunkReportedAsMissing = (highestNewAck > myChunk->tsn) ? 1 : 0;
01068         if (chunkReportedAsMissing > 0) {
01069             // T.D. 15.04.09: Increase gapReports by chunkReportedAsMissing.
01070             // Fixed bug here: gapReports += chunkReportedAsMissing instead of gapReports = chunkReportedAsMissing.
01071             /*
01072             printf("GapReports for TSN %u [ret=%d,fast=%s] at t=%s:  %d --> %d by %d\n",
01073                         myChunk->tsn,
01074                         myChunk->numberOfRetransmissions,
01075                         (myChunk->hasBeenFastRetransmitted == true) ? "YES" : "no",
01076                         simTime().str().c_str(),
01077                         myChunk->gapReports,
01078                         myChunk->gapReports + chunkReportedAsMissing,
01079                         chunkReportedAsMissing);
01080             */
01081             myChunk->gapReports += chunkReportedAsMissing;
01082 
01083             myChunkLastPath->gapNAcksInLastSACK++;
01084 
01085             if (myChunk->gapReports >= state->numGapReports) {
01086                 bool fastRtx = false;
01087                 fastRtx = ((myChunk->hasBeenFastRetransmitted == false) &&
01088                               (myChunk->numberOfRetransmissions == 0));
01089                 if (fastRtx) {
01090 
01091                     // ====== Add chunk to transmission queue ========
01092                     SCTPQueue::PayloadQueue::iterator it = transmissionQ->payloadQueue.find(myChunk->tsn);
01093                     if (transmissionQ->getChunk(myChunk->tsn) == NULL) {
01094                         SCTP::AssocStat* assocStat = sctpMain->getAssocStat(assocId);
01095                         if(assocStat) {
01096                             assocStat->numFastRtx++;
01097                         }
01098                         myChunk->hasBeenFastRetransmitted = true;
01099 
01100                         sctpEV3 << simTime() << ": Fast RTX for TSN "
01101                                   << myChunk->tsn << " on path " << myChunk->getLastDestination() << endl;
01102                         myChunkLastPath->numberOfFastRetransmissions++;
01103 
01104                         myChunk->setNextDestination(getNextDestination(myChunk));
01105                         SCTPPathVariables* myChunkNextPath = myChunk->getNextDestinationPath();
01106                         assert(myChunkNextPath != NULL);
01107 
01108                         if (myChunk->countsAsOutstanding) {
01109                             decreaseOutstandingBytes(myChunk);
01110                         }
01111                         if (!transmissionQ->checkAndInsertChunk(myChunk->tsn, myChunk)) {
01112                             sctpEV3 << "Fast RTX: cannot add message/chunk (TSN="
01113                                       << myChunk->tsn << ") to the transmissionQ" << endl;
01114                         }
01115                         else    {
01116                             myChunk->enqueuedInTransmissionQ = true;
01117                             CounterMap::iterator q = qCounter.roomTransQ.find(myChunk->getNextDestination());
01118                             q->second += ADD_PADDING(myChunk->len/8+SCTP_DATA_CHUNK_LENGTH);
01119                             CounterMap::iterator qb = qCounter.bookedTransQ.find(myChunk->getNextDestination());
01120                             qb->second += myChunk->booksize;
01121                         }
01122                         myChunkNextPath->requiresRtx = true;
01123                         if(myChunkNextPath->findLowestTSN == true) {
01124                             // TD 08.12.09: fixed detection of lowest TSN retransmitted
01125                             myChunkNextPath->lowestTSNRetransmitted = true;
01126                         }
01127                     }
01128                 }
01129             }
01130         }
01131         else {
01132             myChunk->hasBeenFastRetransmitted = false;
01133             sctpEV3 << "TSN " << myChunk->tsn << " countsAsOutstanding="
01134                         << myChunk->countsAsOutstanding << endl;
01135             if (highestNewAck > myChunk->tsn) {
01136                 myChunk->gapReports++;
01137             }
01138             myChunkLastPath->gapAcksInLastSACK++;
01139         }
01140         myChunkLastPath->findLowestTSN = false;
01141     }
01142     else {
01143         // Reneging, type 1:
01144         // A chunk in the gap blocks has been un-acked => reneg it.
01145                     tsnWasReneged(myChunk,
01146                                       1);
01147     }
01148 }
01149 
01150 
01151 uint32 SCTPAssociation::dequeueAckedChunks(const uint32       tsna,
01152                                                          SCTPPathVariables* sackPath,
01153                                                          simtime_t&           rttEstimation)
01154 {
01155     SCTP::AssocStat* assocStat                   = sctpMain->getAssocStat(assocId);
01156     uint32            newlyAckedBytes            = 0;
01157     uint64            sendBufferBeforeUpdate = state->sendBuffer;
01158 
01159     // Set it ridiculously high
01160     rttEstimation = MAXTIME;
01161 
01162     // Are there chunks in the retransmission queue ? If Yes -> check for dequeue.
01163     SCTPQueue::PayloadQueue::iterator iterator = retransmissionQ->payloadQueue.begin();
01164     while (iterator != retransmissionQ->payloadQueue.end()) {
01165         SCTPDataVariables* chunk = iterator->second;
01166         if (tsnGe(tsna, chunk->tsn)) {
01167             // Dequeue chunk, cause it has been acked
01168             if (transmissionQ->getChunk(chunk->tsn)) {
01169                 transmissionQ->removeMsg(chunk->tsn);
01170                 chunk->enqueuedInTransmissionQ = false;
01171                 CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination());
01172                 q->second -= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
01173                 CounterMap::iterator qb = qCounter.bookedTransQ.find(chunk->getNextDestination());
01174                 qb->second -= chunk->booksize;
01175             }
01176 
01177             chunk = retransmissionQ->getAndExtractChunk(chunk->tsn);
01178             state->sendBuffer -= chunk->len/8;
01179 
01180             SCTPPathVariables* lastPath = chunk->getLastDestinationPath();
01181             assert(lastPath != NULL);
01182 
01183             if (!chunkHasBeenAcked(chunk)) {
01184                 newlyAckedBytes += (chunk->booksize);
01185 
01186                 sctpEV3 << simTime() << ": CumAcked TSN " << chunk->tsn
01187                           << " on path " << chunk->getLastDestination() << endl;
01188 
01189                 lastPath->newlyAckedBytes += (chunk->booksize);
01190 
01191                 // T.D. 05.12.09: CumAck affects lastPath -> reset its T3 timer later.
01192                 lastPath->newCumAck = true;
01193             }
01194 
01195 
01196             if(assocStat) {
01197                 assocStat->ackedBytes += chunk->len/8;
01198             }
01199 
01200             if ((chunkHasBeenAcked(chunk) == false) && (chunk->countsAsOutstanding)) {
01201                 ackChunk(chunk);
01202                 if ((chunk->numberOfTransmissions == 1) && (chunk->getLastDestinationPath() == sackPath)) {
01203                     const simtime_t timeDifference = simTime() - chunk->sendTime;
01204                     if ((timeDifference < rttEstimation) || (rttEstimation == MAXTIME)) {
01205                         rttEstimation = timeDifference;
01206                     }
01207                 }
01208                 decreaseOutstandingBytes(chunk);
01209             }
01210             if (chunk->userData != NULL) {
01211                 delete chunk->userData;
01212             }
01213             delete chunk;
01214         }
01215         else {
01216             break;
01217         }
01218         iterator = retransmissionQ->payloadQueue.begin();
01219     }
01220 
01221     if(sendBufferBeforeUpdate != state->sendBuffer && state->sendBuffer < state->sendQueueLimit) {
01222         // T.D. 06.02.2010: Just send SCTP_I_SENDQUEUE_ABATED once, after all newly acked
01223         //                        chunks have been dequeued.
01224         // I.R. only send indication if the sendBuffer size has dropped below the sendQueueLimit
01225         assert(state->lastSendQueueAbated < simTime());
01226         state->appSendAllowed = true;
01227         sctpEV3 << simTime() << ":\tSCTP_I_SENDQUEUE_ABATED("
01228                   << sendBufferBeforeUpdate - state->sendBuffer << ") to refill buffer "
01229                   << state->sendBuffer << "/" << state->sendQueueLimit << endl;
01230         sendIndicationToApp(SCTP_I_SENDQUEUE_ABATED, sendBufferBeforeUpdate - state->sendBuffer);
01231         state->lastSendQueueAbated = simTime();
01232     }
01233 
01234     sctpEV3 << "dequeueAckedChunks(): newlyAckedBytes=" << newlyAckedBytes
01235               << ", rttEstimation=" << rttEstimation << endl;
01236 
01237     return (newlyAckedBytes);
01238 }
01239 
01240 
01241 
01242 SCTPEventCode SCTPAssociation::processDataArrived(SCTPDataChunk* dataChunk)
01243 {
01244     bool                     checkCtsnaChange = false;
01245     const uint32         tsn                    = dataChunk->getTsn();
01246     SCTPPathVariables* path                 = getPath(remoteAddr);
01247 
01248     state->newChunkReceived       = false;
01249     state->lastTsnReceived        = tsn;
01250     state->lastDataSourceAddress = remoteAddr;
01251 
01252     sctpEV3 << simTime() << " SCTPAssociation::processDataArrived TSN=" << tsn << endl;
01253     path->pathRcvdTSN->record(tsn);
01254 
01255     SCTPSimpleMessage* smsg = check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
01256     dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8);
01257     dataChunk->encapsulate(smsg);
01258     const uint32 payloadLength = dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH;
01259     sctpEV3 << "state->bytesRcvd=" << state->bytesRcvd << endl;
01260     state->bytesRcvd+=payloadLength;
01261     sctpEV3 << "state->bytesRcvd now=" << state->bytesRcvd << endl;
01262     SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
01263     iter->second.rcvdBytes+=dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH;
01264 
01265     if (state->numGaps == 0) {
01266         state->highestTsnReceived = state->cTsnAck;
01267     }
01268     else {
01269         state->highestTsnReceived = state->gapStopList[state->numGaps-1];
01270     }
01271     if (state->stopReceiving) {
01272         return SCTP_E_IGNORE;
01273     }
01274 
01275     if (tsnLe(tsn, state->cTsnAck)) {
01276             sctpEV3 << "Duplicate TSN " << tsn << " (smaller than CumAck)" << endl;
01277             state->dupList.push_back(tsn);
01278             state->dupList.unique();
01279             delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
01280             return SCTP_E_DUP_RECEIVED;
01281     }
01282 
01283 
01284     if ((int32)(state->localRwnd-state->queuedReceivedBytes) <= 0) {
01285         if (tsnGt(tsn, state->highestTsnReceived)) {
01286             return SCTP_E_IGNORE;
01287         }
01288         // changed 06.07.05 I.R.
01289         else if ((!tsnIsDuplicate(tsn)) &&
01290                     (tsn < state->highestTsnStored)) {
01291             if (!makeRoomForTsn(tsn, dataChunk->getBitLength()-SCTP_DATA_CHUNK_LENGTH*8, dataChunk->getUBit())) {
01292                 delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
01293                 return SCTP_E_IGNORE;
01294             }
01295         }
01296     }
01297     if (tsnGt(tsn, state->highestTsnReceived)) {
01298         sctpEV3 << "highestTsnReceived=" << state->highestTsnReceived
01299                   << " tsn=" << tsn << endl;
01300         state->highestTsnReceived = state->highestTsnStored = tsn;
01301         if (tsn == initPeerTsn) {
01302             state->cTsnAck = tsn;
01303         }
01304         else {
01305             sctpEV3 << "Update fragment list" << endl;
01306             checkCtsnaChange = updateGapList(tsn);
01307         }
01308         state->newChunkReceived = true;
01309     }
01310     else if (tsnIsDuplicate(tsn)) {
01311         // TSN value is duplicate within a fragment
01312         sctpEV3 << "Duplicate TSN " << tsn << " (copy)" << endl;
01313         state->dupList.push_back(tsn);
01314         state->dupList.unique();
01315         return SCTP_E_IGNORE;
01316     }
01317     else {
01318         checkCtsnaChange = updateGapList(tsn);
01319     }
01320     if (state->swsAvoidanceInvoked) {
01321         // swsAvoidanceInvoked => schedule a SACK to be sent at once in this case
01322         sctpEV3 << "swsAvoidanceInvoked" << endl;
01323         state->ackState = sackFrequency;
01324     }
01325 
01326     if (checkCtsnaChange) {
01327         advanceCtsna();
01328     }
01329     sctpEV3 << "cTsnAck=" << state->cTsnAck
01330               << " highestTsnReceived=" << state->highestTsnReceived << endl;
01331 
01332     SCTPEventCode event = SCTP_E_SEND;
01333     if (state->newChunkReceived) {
01334         SCTPReceiveStreamMap::iterator iter = receiveStreams.find(dataChunk->getSid());
01335         const int ret = iter->second->enqueueNewDataChunk(makeVarFromMsg(dataChunk));
01336         if (ret > 0) {
01337             state->queuedReceivedBytes+=payloadLength;
01338 
01339             event = SCTP_E_DELIVERED;
01340             if (ret < 3) {
01341                 sendDataArrivedNotification(dataChunk->getSid());
01342                 putInDeliveryQ(dataChunk->getSid());
01343             }
01344         }
01345         state->newChunkReceived = false;
01346     }
01347 
01348     return(event);
01349 }
01350 
01351 
01352 SCTPEventCode SCTPAssociation::processHeartbeatAckArrived(SCTPHeartbeatAckChunk* hback,
01353                                                                              SCTPPathVariables*     path)
01354 {
01355     path->numberOfHeartbeatAcksRcvd++;
01356     path->pathRcvdHbAck->record(path->numberOfHeartbeatAcksRcvd);
01357     /* hb-ack goes to pathmanagement, reset error counters, stop timeout timer */
01358     const IPvXAddress addr          = hback->getRemoteAddr();
01359     const simtime_t hbTimeField = hback->getTimeField();
01360     stopTimer(path->HeartbeatTimer);
01361     /* assume a valid RTT measurement on this path */
01362     simtime_t rttEstimation = simTime() - hbTimeField;
01363     pmRttMeasurement(path, rttEstimation);
01364     pmClearPathCounter(path);
01365     path->confirmed = true;
01366     path->lastAckTime = simTime();
01367     if (path->primaryPathCandidate == true) {
01368         state->setPrimaryPath(getPath(addr));
01369         path->primaryPathCandidate = false;
01370         if (path->pmtu < state->assocPmtu) {
01371             state->assocPmtu = path->pmtu;
01372         }
01373         path->ssthresh = state->peerRwnd;
01374         recordCwndUpdate(path);
01375         path->heartbeatTimeout = (double)sctpMain->par("hbInterval") + path->pathRto;
01376     }
01377 
01378     if (path->activePath == false) {
01379         sctpEV3 << "HB ACK arrived activePath=false. remoteAddress=" <<path->remoteAddress
01380                   << " initialPP=" << state->initialPrimaryPath << endl;
01381         path->activePath = true;
01382         if (state->reactivatePrimaryPath && path->remoteAddress == state->initialPrimaryPath) {
01383             state->setPrimaryPath(path);
01384         }
01385         sctpEV3 << "primaryPath now " << state->getPrimaryPathIndex() << endl;
01386     }
01387     sctpEV3 << "Received HB ACK chunk...resetting error counters on path " << addr
01388               <<", rttEstimation=" << rttEstimation << endl;
01389     path->pathErrorCount = 0;
01390     return SCTP_E_IGNORE;
01391 }
01392 
01393 
01394 
01395 void SCTPAssociation::process_TIMEOUT_INIT_REXMIT(SCTPEventCode& event)
01396 {
01397     if (++state->initRetransCounter > (int32)sctpMain->par("maxInitRetrans"))
01398     {
01399         sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("maxInitRetrans") << ", giving up\n";
01400         sendIndicationToApp(SCTP_I_CLOSED);
01401         sendAbort();
01402         sctpMain->removeAssociation(this);
01403         return;
01404     }
01405     sctpEV3<< "Performing retransmission #" << state->initRetransCounter << "\n";
01406     switch(fsm->getState())
01407     {
01408         case SCTP_S_COOKIE_WAIT: retransmitInit(); break;
01409         case SCTP_S_COOKIE_ECHOED: retransmitCookieEcho(); break;
01410         default:     opp_error("Internal error: INIT-REXMIT timer expired while in state %s", stateName(fsm->getState()));
01411     }
01412     state->initRexmitTimeout *= 2;
01413     if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX)
01414         state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX;
01415     startTimer(T1_InitTimer,state->initRexmitTimeout);
01416 }
01417 
01418 void SCTPAssociation::process_TIMEOUT_SHUTDOWN(SCTPEventCode& event)
01419 {
01420 
01421     if (++state->errorCount > (uint32)sctpMain->par("assocMaxRetrans"))
01422     {
01423         sendIndicationToApp(SCTP_I_CONN_LOST);
01424         sendAbort();
01425         sctpMain->removeAssociation(this);
01426         return;
01427     }
01428 
01429     sctpEV3 << "Performing shutdown retransmission. Assoc error count now "<<state->errorCount<<" \n";
01430     if(fsm->getState() == SCTP_S_SHUTDOWN_SENT)
01431     {
01432         retransmitShutdown();
01433     }
01434     else if (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)
01435         retransmitShutdownAck();
01436 
01437     state->initRexmitTimeout *= 2;
01438     if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX)
01439         state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX;
01440     startTimer(T2_ShutdownTimer,state->initRexmitTimeout);
01441 }
01442 
01443 
01444 void SCTPAssociation::process_TIMEOUT_HEARTBEAT_INTERVAL(SCTPPathVariables* path, bool force)
01445 {
01446 
01447     sctpEV3<<"HB Interval timer expired -- sending new HB REQ on path "<<path->remoteAddress<<"\n";
01448     /* restart hb_send_timer on this path */
01449     stopTimer(path->HeartbeatIntervalTimer);
01450     stopTimer(path->HeartbeatTimer);
01451     path->heartbeatIntervalTimeout = (double)sctpMain->par("hbInterval") +  path->pathRto;
01452     path->heartbeatTimeout = path->pathRto;
01453     startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout);
01454     if ((simTime() - path->lastAckTime > path->heartbeatIntervalTimeout/2) || path->forceHb)
01455     {
01456         sendHeartbeat(path);
01457         startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
01458 
01459         path->forceHb = false;
01460     }
01461 }
01462 
01463 
01464 void SCTPAssociation::process_TIMEOUT_HEARTBEAT(SCTPPathVariables* path)
01465 {
01466     bool oldState;
01467 
01468     /* check if error counters must be increased */
01469       if (path->activePath)
01470       {
01471              state->errorCount++;
01472              path->pathErrorCount++;
01473 
01474              sctpEV3<<"HB timeout timer expired for path "<<path->remoteAddress<<" --> Increase Error Counters (Assoc: "<<state->errorCount<<", Path: "<<path->pathErrorCount<<")\n";
01475       }
01476 
01477     /* RTO must be doubled for this path ! */
01478     path->pathRto = (simtime_t)min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax"));
01479     path->statisticsPathRTO->record(path->pathRto);
01480     /* check if any thresholds are exceeded, and if so, check if ULP must be notified */
01481     if (state->errorCount > (uint32)sctpMain->par("assocMaxRetrans"))
01482     {
01483         sendIndicationToApp(SCTP_I_CONN_LOST);
01484         sendAbort();
01485         sctpMain->removeAssociation(this);
01486         return;
01487     }
01488     else
01489     {
01490         /* set path state to INACTIVE, if the path error counter is exceeded */
01491         if (path->pathErrorCount >   (uint32)sctpMain->par("pathMaxRetrans"))
01492         {
01493             oldState = path->activePath;
01494             path->activePath = false;
01495             if (path == state->getPrimaryPath()) {
01496                 state->setPrimaryPath(getNextPath(path));
01497             }
01498             sctpEV3 << "pathErrorCount now "<< path->pathErrorCount
01499                       << "; PP now " << state->getPrimaryPathIndex() << endl;
01500         }
01501         /* then: we can check, if all paths are INACTIVE ! */
01502         if (allPathsInactive())
01503         {
01504             sctpEV3<<"sctp_do_hb_to_timer() : ALL PATHS INACTIVE --> closing ASSOC\n";
01505             sendIndicationToApp(SCTP_I_CONN_LOST);
01506             return;
01507 
01508         } else if (path->activePath == false && oldState == true)
01509         {
01510             /* notify the application, in case the PATH STATE has changed from ACTIVE to INACTIVE */
01511             pathStatusIndication(path, false);
01512         }
01513 
01514     }
01515 }
01516 
01517 void SCTPAssociation::stopTimers()
01518 {
01519     for (SCTPPathMap::iterator j = sctpPathMap.begin(); j != sctpPathMap.end(); j++) {
01520         stopTimer(j->second->HeartbeatTimer);
01521         stopTimer(j->second->HeartbeatIntervalTimer);
01522     }
01523 }
01524 
01525 void SCTPAssociation::stopTimer(cMessage* timer)
01526 {
01527 
01528     ev << "stopTimer " << timer->getName() << endl;
01529     if (timer->isScheduled()) {
01530         cancelEvent(timer);
01531     }
01532 }
01533 
01534 void SCTPAssociation::startTimer(cMessage* timer, const simtime_t& timeout)
01535 {
01536     sctpEV3 << "startTimer " << timer->getName() << " with timeout "
01537               << timeout << " to expire at " << simTime() + timeout << endl;
01538     scheduleTimeout(timer, timeout);
01539 }
01540 
01541 
01542 
01543 int32 SCTPAssociation::updateCounters(SCTPPathVariables* path)
01544 {
01545     bool notifyUlp = false;
01546     if (++state->errorCount >=   (uint32)sctpMain->par("assocMaxRetrans"))
01547     {
01548         sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("assocMaxRetrans") << ", giving up\n";
01549         sendIndicationToApp(SCTP_I_CLOSED);
01550         sendAbort();
01551         sctpMain->removeAssociation(this);
01552         return 0;
01553     }
01554     else if (++path->pathErrorCount >=  (uint32)sctpMain->par("pathMaxRetrans"))
01555     {
01556         if (path->activePath)
01557         {
01558             /* tell the source */
01559             notifyUlp = true;
01560         }
01561 
01562         path->activePath = false;
01563         if (path == state->getPrimaryPath()) {
01564             state->setPrimaryPath(getNextPath(path));
01565         }
01566         sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE\n";
01567         if (allPathsInactive())
01568         {
01569             sctpEV3<<"process_TIMEOUT_RESET : ALL PATHS INACTIVE --> closing ASSOC\n";
01570             sendIndicationToApp(SCTP_I_CONN_LOST);
01571             sendAbort();
01572             sctpMain->removeAssociation(this);
01573             return 0;
01574         }
01575         else if (notifyUlp)
01576         {
01577             /* notify the application */
01578             pathStatusIndication(path, false);
01579         }
01580         sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER now "<<path->pathErrorCount<<"\n";
01581         return 2;
01582     }
01583     return 1;
01584 }
01585 
01586 
01587 
01588 int32 SCTPAssociation::process_TIMEOUT_RTX(SCTPPathVariables* path)
01589 {
01590     sctpEV3 << "Processing retransmission timeout ..." << endl;
01591 
01592     // ====== Increase the RTO (by doubling it) ==============================
01593     path->pathRto = min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax"));
01594     path->statisticsPathRTO->record(path->pathRto);
01595     sctpEV3 << "Schedule T3 based retransmission for path "<< path->remoteAddress << endl;
01596 
01597     // ====== Update congestion window =======================================
01598     (this->*ccFunctions.ccUpdateAfterRtxTimeout)(path);
01599 
01600 
01601     // ====== Error Counter Handling =========================================
01602     if (!state->zeroWindowProbing) {
01603         state->errorCount++;
01604         path->pathErrorCount++;
01605         sctpEV3 << "RTX-Timeout: errorCount increased to "<<path->pathErrorCount<<"  state->errorCount="<<state->errorCount<<"\n";
01606     }
01607     if (state->errorCount >= (uint32)sctpMain->par("assocMaxRetrans")) {
01608         /* error counter exceeded terminate the association -- create an SCTPC_EV_CLOSE event and send it to myself */
01609 
01610         sctpEV3 << "process_TIMEOUT_RTX : ASSOC ERROR COUNTER EXCEEDED, closing ASSOC" << endl;
01611         sendIndicationToApp(SCTP_I_CONN_LOST);
01612         sendAbort();
01613         sctpMain->removeAssociation(this);
01614         return 0;
01615 
01616     }
01617     else {
01618         if (path->pathErrorCount > (uint32)sctpMain->par("pathMaxRetrans")) {
01619             bool notifyUlp = false;
01620 
01621             sctpEV3 << "pathErrorCount exceeded\n";
01622             if (path->activePath) {
01623                 /* tell the source */
01624                 notifyUlp = true;
01625             }
01626             path->activePath = false;
01627             if (path->remoteAddress == state->getPrimaryPathIndex()) {
01628                 SCTPPathVariables* nextPath = getNextPath(path);
01629                 if (nextPath != NULL) {
01630                     state->setPrimaryPath(nextPath);
01631                 }
01632             }
01633             sctpEV3 << "process_TIMEOUT_RTX(" << path->remoteAddress
01634                       << ") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE" << endl;
01635             if (allPathsInactive()) {
01636                 sctpEV3 << "process_TIMEOUT_RTX: ALL PATHS INACTIVE --> connection LOST!" << endl;
01637                 sendIndicationToApp(SCTP_I_CONN_LOST);
01638                 sendAbort();
01639                 sctpMain->removeAssociation(this);
01640                 return 0;
01641             }
01642             else if (notifyUlp) {
01643                 // Send notification to the application
01644                 pathStatusIndication(path, false);
01645             }
01646         }
01647         sctpEV3 << "process_TIMEOUT_RTX(" << path->remoteAddress
01648                   << ") : PATH ERROR COUNTER now " << path->pathErrorCount << endl;
01649     }
01650 
01651 
01652     // ====== Do Retransmission ==============================================
01653     // dequeue all chunks not acked so far and put them in the TransmissionQ
01654     if (!retransmissionQ->payloadQueue.empty()) {
01655         sctpEV3 << "Still " << retransmissionQ->payloadQueue.size()
01656                   << " chunks in retransmissionQ" << endl;
01657 
01658         for (SCTPQueue::PayloadQueue::iterator iterator = retransmissionQ->payloadQueue.begin();
01659             iterator != retransmissionQ->payloadQueue.end(); iterator++) {
01660             SCTPDataVariables* chunk = iterator->second;
01661             assert(chunk != NULL);
01662 
01663             // ====== Insert chunks into TransmissionQ ============================
01664             // Only insert chunks that were sent to the path that has timed out
01665             if ( ((chunkHasBeenAcked(chunk) == false && chunk->countsAsOutstanding) || chunk->hasBeenReneged) &&
01666                   (chunk->getLastDestinationPath() == path) ) {
01667                 sctpEV3 << simTime() << ": Timer-Based RTX for TSN "
01668                           << chunk->tsn << " on path " << chunk->getLastDestination() << endl;
01669                 chunk->getLastDestinationPath()->numberOfTimerBasedRetransmissions++;
01670                 SCTP::AssocStatMap::iterator iter = sctpMain->assocStatMap.find(assocId);
01671                 iter->second.numT3Rtx++;
01672 
01673                 moveChunkToOtherPath(chunk, getNextDestination(chunk));
01674             }
01675         }
01676     }
01677 
01678 
01679     SCTPPathVariables* nextPath = getNextPath(path);
01680     sctpEV3 << "TimeoutRTX: sendOnAllPaths()" << endl;
01681     sendOnAllPaths(nextPath);
01682 
01683     return 0;
01684 }
01685 
01686 
01687 void SCTPAssociation::moveChunkToOtherPath(SCTPDataVariables* chunk,
01688                                                          SCTPPathVariables* newPath)
01689 {
01690     // ====== Prepare next destination =======================================
01691     SCTPPathVariables* lastPath = chunk->getLastDestinationPath();
01692     chunk->hasBeenFastRetransmitted = false;
01693     chunk->gapReports                     = 0;
01694     chunk->setNextDestination(newPath);
01695     sctpEV3 << simTime() << ": Timer-Based RTX for TSN " << chunk->tsn
01696               << ": lastDestination=" << chunk->getLastDestination()
01697               << " nextDestination="  << chunk->getNextDestination() << endl;
01698 
01699     // ======= Remove chunk's booksize from outstanding bytes ================
01700     // T.D. 12.02.2010: This case may happen when using sender queue control!
01701     if(chunk->countsAsOutstanding) {
01702         assert(lastPath->outstandingBytes >= chunk->booksize);
01703         lastPath->outstandingBytes -= chunk->booksize;
01704         assert((int32)lastPath->outstandingBytes >= 0);
01705         state->outstandingBytes -= chunk->booksize;
01706         assert((int64)state->outstandingBytes >= 0);
01707         chunk->countsAsOutstanding = false;
01708         // T.D. 12.02.2010: No Timer-Based RTX is necessary any more when there
01709         //                        are no outstanding bytes!
01710         if(lastPath->outstandingBytes == 0) {
01711             stopTimer(lastPath->T3_RtxTimer);
01712         }
01713     }
01714 
01715 
01716     // ====== Perform bookkeeping ============================================
01717     // Check, if chunk_ptr->tsn is already in transmission queue.
01718     // This can happen in case multiple timeouts occur in succession.
01719     if (!transmissionQ->checkAndInsertChunk(chunk->tsn, chunk)) {
01720         sctpEV3 << "TSN " << chunk->tsn << " already in transmissionQ" << endl;
01721         return;
01722     }
01723     else {
01724         chunk->enqueuedInTransmissionQ = true;
01725         sctpEV3 << "Inserting TSN " << chunk->tsn << " into transmissionQ" << endl;
01726         CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination());
01727         q->second += ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
01728         CounterMap::iterator qb = qCounter.bookedTransQ.find(chunk->getNextDestination());
01729         qb->second += chunk->booksize;
01730 
01731         if (chunk->countsAsOutstanding) {
01732             decreaseOutstandingBytes(chunk);
01733         }
01734         state->peerRwnd += (chunk->booksize);
01735     }
01736     if (state->peerRwnd > state->initialPeerRwnd) {
01737         state->peerRwnd = state->initialPeerRwnd;
01738     }
01739     sctpEV3 << "T3 Timeout: Chunk (TSN=" << chunk->tsn
01740                 << ") has been requeued in transmissionQ, rwnd was set to "
01741                 << state->peerRwnd << endl;
01742 }