00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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);
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
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
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
00410 if (initchunk->getAddresses(j).isIPv6())
00411 continue;
00412
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)
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
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
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);
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
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
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);
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);
00714 const uint64 arwnd = sackChunk->getA_rwnd();
00715 const uint32 tsna = sackChunk->getCumTsnAck();
00716 uint32 highestNewAck = tsna;
00717 const uint16 numGaps = sackChunk->getNumGaps();
00718 bool getChunkFastFirstTime = true;
00719
00720
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
00734 for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
00735 SCTPPathVariables* myPath = piter->second;
00736
00737
00738 myPath->outstandingBytesBeforeUpdate = myPath->outstandingBytes;
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
00752 if ( (state->zeroWindowProbing) && (arwnd > 0) ) {
00753 state->zeroWindowProbing = false;
00754 }
00755
00756
00757
00758
00759
00760
00761 if (tsnGt(tsna, state->lastTsnAck)) {
00762 sctpEV3 << "===== Handling new CumAck for TSN " << tsna << " =====" << endl;
00763
00764
00765
00766
00767
00768 dequeueAckedChunks(tsna, path, rttEstimation);
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
00781 if ((numGaps == 0) && (tsnLt(tsna, state->highestTsnAcked))) {
00782
00783
00784
00785
00786
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
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
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
00819
00820 if (tsnLt(sackChunk->getGapStop(numGaps-1), state->highestTsnAcked)) {
00821
00822
00823
00824
00825
00826 uint32 i = state->highestTsnAcked;
00827 while (i >= sackChunk->getGapStop(numGaps - 1) + 1) {
00828
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
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
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
00862
00863 handleChunkReportedAsAcked(highestNewAck, rttEstimation, myChunk,
00864 path );
00865 }
00866 }
00867 }
00868 }
00869 state->highestTsnAcked = sackChunk->getGapStop(numGaps-1);
00870
00871
00872
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 );
00881 }
00882 else {
00883 sctpEV3 << "TSN " << pos << " not found in retransmissionQ" << endl;
00884 }
00885 }
00886 lo = sackChunk->getGapStop(key);
00887 }
00888
00889
00890
00891 }
00892
00893
00894
00895 updateFastRecoveryStatus(state->lastTsnAck);
00896
00897
00898 sctpEV3 << simTime() << ": SACK: rtt=" << rttEstimation
00899 << ", path=" << path->remoteAddress << endl;
00900 pmRttMeasurement(path, rttEstimation);
00901
00902
00903
00904
00905
00906
00907
00908 const uint32 osb = getOutstandingBytes();
00909 state->peerRwnd = arwnd - osb;
00910
00911
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
00934 if(osb == 0) {
00935 if (arwnd == 0)
00936 state->zeroWindowProbing = true;
00937 }
00938
00939
00940
00941
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
00952
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
00964 sctpEV3 << "Before ccUpdateAfterSack with tsna=" << tsna << endl;
00965
00966 (this->*ccFunctions.ccUpdateAfterSack)();
00967
00968
00969
00970
00971
00972
00973
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
00980 if(qCounter.roomTransQ.find(myPath->remoteAddress)->second == 0) {
00981
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
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
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)) {
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
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
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
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
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
01144
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
01160 rttEstimation = MAXTIME;
01161
01162
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
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
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
01223
01224
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
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
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
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
01358 const IPvXAddress addr = hback->getRemoteAddr();
01359 const simtime_t hbTimeField = hback->getTimeField();
01360 stopTimer(path->HeartbeatTimer);
01361
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
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
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
01478 path->pathRto = (simtime_t)min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax"));
01479 path->statisticsPathRTO->record(path->pathRto);
01480
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
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
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
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
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
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
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
01598 (this->*ccFunctions.ccUpdateAfterRtxTimeout)(path);
01599
01600
01601
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
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
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
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
01653
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
01664
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
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
01700
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
01709
01710 if(lastPath->outstandingBytes == 0) {
01711 stopTimer(lastPath->T3_RtxTimer);
01712 }
01713 }
01714
01715
01716
01717
01718
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 }