INET Framework for OMNeT++/OMNEST
inet::sctp::SctpAssociation Class Reference

#include <SctpAssociation.h>

Inheritance diagram for inet::sctp::SctpAssociation:

Classes

struct  BytesToBeSent
 
struct  CCFunctions
 
struct  QueueCounter
 
struct  SSFunctions
 

Public Member Functions

 SctpAssociation (Sctp *mod, int32_t appGateIndex, int32_t assocId, IRoutingTable *rt, IInterfaceTable *ift)
 Constructor. More...
 
 ~SctpAssociation ()
 Destructor. More...
 
void sendOnPath (SctpPathVariables *pathId, const bool firstPass=true)
 Utility: Send data from sendQueue. More...
 
void sendOnAllPaths (SctpPathVariables *firstPath)
 
int32_t getFsmState () const
 
SctpStateVariablesgetState () const
 
SctpQueuegetTransmissionQueue () const
 
SctpQueuegetRetransmissionQueue () const
 
SctpAlgorithmgetSctpAlgorithm () const
 
SctpgetSctpMain () const
 
cFSM * getFsm () const
 
cMessage * getInitTimer () const
 
cMessage * getShutdownTimer () const
 
cMessage * getSackTimer () const
 
bool processTimer (cMessage *msg)
 
bool processSctpMessage (SctpHeader *sctpmsg, const L3Address &srcAddr, const L3Address &destAddr)
 Process incoming SCTP segment. More...
 
bool processAppCommand (cMessage *msg, SctpCommandReq *sctpCommand)
 Process commands from the application. More...
 
void removePath ()
 
void removePath (const L3Address &addr)
 
void deleteStreams ()
 
void stopTimer (cMessage *timer)
 
void stopTimers ()
 
SctpPathVariablesgetPath (const L3Address &pathId) const
 
void printSctpPathMap () const
 

Static Public Member Functions

static const char * indicationName (int32_t code)
 Utility: returns name of SCTP_I_xxx constants. More...
 
static int getAddressLevel (const L3Address &addr)
 Utility: return IPv4 or IPv6 address level. More...
 
static const char * stateName (int32_t state)
 Utility: returns name of SCTP_S_xxx constants. More...
 
static uint16_t chunkToInt (const char *type)
 
static bool SCTP_UINT16_GT (uint16_t a, uint16_t b)
 Compare TSNs. More...
 
static bool SCTP_UINT16_GE (uint16_t a, uint16_t b)
 
static bool SCTP_UINT32_GT (uint32_t a, uint32_t b)
 
static bool SCTP_UINT32_GE (uint32_t a, uint32_t b)
 
static bool tsnGe (const uint32_t tsn1, const uint32_t tsn2)
 
static bool tsnGt (const uint32_t tsn1, const uint32_t tsn2)
 
static bool tsnLe (const uint32_t tsn1, const uint32_t tsn2)
 
static bool tsnLt (const uint32_t tsn1, const uint32_t tsn2)
 
static bool tsnBetween (const uint32_t tsn1, const uint32_t midtsn, const uint32_t tsn2)
 
static bool ssnGt (const uint16_t ssn1, const uint16_t ssn2)
 
static bool midGt (const uint32_t mid1, const uint32_t mid2)
 

Public Attributes

int32_t appGateIndex
 
int32_t assocId
 
int32_t listeningAssocId
 
int32_t fd
 
bool listening
 
L3Address remoteAddr
 
L3Address localAddr
 
uint16_t localPort
 
uint16_t remotePort
 
uint32_t localVTag
 
uint32_t peerVTag
 
cMessage * T1_InitTimer
 
cMessage * T2_ShutdownTimer
 
cMessage * T5_ShutdownGuardTimer
 
cMessage * SackTimer
 
cMessage * StartTesting
 
cMessage * StartAddIP
 
cOutVector * advMsgRwnd
 
cOutVector * EndToEndDelay
 
bool fairTimer
 
std::map< uint16_t, cOutVector * > streamThroughputVectors
 
cOutVector * assocThroughputVector
 
cMessage * FairStartTimer
 
cMessage * FairStopTimer
 
uint8_t dacPacketsRcvd
 

Protected Member Functions

FSM transitions: analysing events and executing state transitions
SctpEventCode preanalyseAppCommandEvent (int32_t commandCode)
 Maps app command codes (msg kind of app command msgs) to SCTP_E_xxx event codes. More...
 
bool performStateTransition (const SctpEventCode &event)
 Implemements the pure SCTP state machine. More...
 
void stateEntered (int32_t state)
 
Processing app commands. Invoked from processAppCommand().
void process_ASSOCIATE (SctpEventCode &event, SctpCommandReq *sctpCommand, cMessage *msg)
 
void process_OPEN_PASSIVE (SctpEventCode &event, SctpCommandReq *sctpCommand, cMessage *msg)
 
void process_SEND (SctpEventCode &event, SctpCommandReq *sctpCommand, cMessage *msg)
 
void process_CLOSE (SctpEventCode &event)
 
void process_ABORT (SctpEventCode &event)
 
void process_STATUS (SctpEventCode &event, SctpCommandReq *sctpCommand, cMessage *msg)
 
void process_RECEIVE_REQUEST (SctpEventCode &event, SctpCommandReq *sctpCommand)
 
void process_PRIMARY (SctpEventCode &event, SctpCommandReq *sctpCommand)
 
void process_STREAM_RESET (SctpCommandReq *sctpCommand)
 
Processing Sctp message arrivals. Invoked from processSctpHeader().
bool process_RCV_Message (SctpHeader *sctpmsg, const L3Address &src, const L3Address &dest)
 
bool processInitArrived (SctpInitChunk *initChunk, int32_t sport, int32_t dport)
 Process incoming SCTP packets. More...
 
bool processInitAckArrived (SctpInitAckChunk *initAckChunk)
 
bool processCookieEchoArrived (SctpCookieEchoChunk *cookieEcho, L3Address addr)
 
bool processCookieAckArrived ()
 
SctpEventCode processDataArrived (SctpDataChunk *dataChunk)
 
SctpEventCode processSackArrived (SctpSackChunk *sackChunk)
 
SctpEventCode processHeartbeatAckArrived (SctpHeartbeatAckChunk *heartbeatack, SctpPathVariables *path)
 
SctpEventCode processForwardTsnArrived (SctpForwardTsnChunk *forChunk)
 
bool processPacketDropArrived (SctpPacketDropChunk *pktdrop)
 
void processErrorArrived (SctpErrorChunk *error)
 

Protected Attributes

IRoutingTablert
 
IInterfaceTableift
 
AddressVector localAddressList
 
AddressVector remoteAddressList
 
uint32_t numberOfRemoteAddresses
 
uint32_t inboundStreams
 
uint32_t outboundStreams
 
uint32_t initInboundStreams
 
int32_t status
 
uint32_t initTsn
 
uint32_t initPeerTsn
 
uint32_t sackFrequency
 
double sackPeriod
 
CCFunctions ccFunctions
 
uint16_t ccModule
 
cOutVector * advRwnd
 
cOutVector * cumTsnAck
 
cOutVector * sendQueue
 
cOutVector * numGapBlocks
 
SctpStateVariablesstate
 
BytesToBeSent bytes
 
SctpsctpMain
 
cFSM * fsm
 
SctpPathMap sctpPathMap
 
QueueCounter qCounter
 
SctpQueuetransmissionQ
 
SctpQueueretransmissionQ
 
SctpSendStreamMap sendStreams
 
SctpReceiveStreamMap receiveStreams
 
SctpAlgorithmsctpAlgorithm
 
cOutVector * statisticsOutstandingBytes
 
cOutVector * statisticsQueuedReceivedBytes
 
cOutVector * statisticsQueuedSentBytes
 
cOutVector * statisticsTotalSSthresh
 
cOutVector * statisticsTotalCwnd
 
cOutVector * statisticsTotalBandwidth
 
cOutVector * statisticsRevokableGapBlocksInLastSACK
 
cOutVector * statisticsNonRevokableGapBlocksInLastSACK
 
cOutVector * statisticsArwndInLastSACK
 
cOutVector * statisticsPeerRwnd
 
cOutVector * statisticsNumTotalGapBlocksStored
 
cOutVector * statisticsNumRevokableGapBlocksStored
 
cOutVector * statisticsNumNonRevokableGapBlocksStored
 
cOutVector * statisticsNumDuplicatesStored
 
cOutVector * statisticsNumRevokableGapBlocksSent
 
cOutVector * statisticsNumNonRevokableGapBlocksSent
 
cOutVector * statisticsNumDuplicatesSent
 
cOutVector * statisticsSACKLengthSent
 

Private Types

typedef std::map< L3Address, SctpPathVariables * > SctpPathMap
 
typedef std::map< L3Address, uint32_t > CounterMap
 
typedef std::map< uint32_t, SctpSendStream * > SctpSendStreamMap
 
typedef std::map< uint32_t, SctpReceiveStream * > SctpReceiveStreamMap
 
typedef std::map< uint32_t, SctpPathVariables * > SctpPathCollection
 

Private Attributes

SctpPathCollection assocBestPaths
 
SctpPathCollection assocMaxWndPaths
 
SctpPathCollection assocCollectedPaths
 

Friends

class Sctp
 
class SctpPathVariables
 

Processing timeouts. Invoked from processTimer().

SSFunctions ssFunctions
 
uint16_t ssModule
 
void process_TIMEOUT_RTX (SctpPathVariables *path)
 
void process_TIMEOUT_BLOCKING (SctpPathVariables *path)
 
void process_TIMEOUT_HEARTBEAT (SctpPathVariables *path)
 
void process_TIMEOUT_HEARTBEAT_INTERVAL (SctpPathVariables *path, bool force)
 
void process_TIMEOUT_INIT_REXMIT (SctpEventCode &event)
 
void process_TIMEOUT_PROBING ()
 
void process_TIMEOUT_SHUTDOWN (SctpEventCode &event)
 
int32_t updateCounters (SctpPathVariables *path)
 
void process_TIMEOUT_RESET (SctpPathVariables *path)
 
void process_TIMEOUT_ASCONF (SctpPathVariables *path)
 
void startTimer (cMessage *timer, const simtime_t &timeout)
 
SctpAssociationcloneAssociation ()
 Utility: clone a listening association. More...
 
void initAssociation (SctpOpenReq *openCmd)
 Utility: creates send/receive queues and sctpAlgorithm. More...
 
bool tsnIsDuplicate (const uint32_t tsn) const
 Methods dealing with the handling of TSNs
More...
 
bool makeRoomForTsn (const uint32_t tsn, const uint32_t length, const bool uBit)
 
void sendInit ()
 Methods for creating and sending chunks. More...
 
void sendInitAck (SctpInitChunk *initchunk)
 
void sendCookieEcho (SctpInitAckChunk *initackchunk)
 
void sendCookieAck (const L3Address &dest)
 
void sendAbort (uint16_t tBit=0)
 
void sendHeartbeat (const SctpPathVariables *path)
 
void sendHeartbeatAck (const SctpHeartbeatChunk *heartbeatChunk, const L3Address &src, const L3Address &dest)
 
void sendSack ()
 
void sendShutdown ()
 
void sendShutdownAck (const L3Address &dest)
 
void sendShutdownComplete ()
 
SctpSackChunkcreateSack ()
 
void retransmitInit ()
 Retransmitting chunks. More...
 
void retransmitCookieEcho ()
 
void retransmitReset ()
 
void retransmitShutdown ()
 
void retransmitShutdownAck ()
 
void sendToIP (Packet *pkt, const Ptr< SctpHeader > &sctpmsg, L3Address dest)
 Utility: adds control info to message and sends it to IP. More...
 
void sendToIP (Packet *pkt, const Ptr< SctpHeader > &sctpmsg)
 
void scheduleSack ()
 
void signalConnectionTimeout ()
 Utility: signal to user that connection timed out. More...
 
void scheduleTimeout (cMessage *msg, const simtime_t &timeout)
 Utility: start a timer. More...
 
cMessage * cancelEvent (cMessage *msg)
 Utility: cancel a timer. More...
 
void sendToApp (cMessage *msg)
 Utility: sends packet to application. More...
 
void sendIndicationToApp (int32_t code, int32_t value=0)
 Utility: sends status indication (SCTP_I_xxx) to application. More...
 
void sendEstabIndicationToApp ()
 Utility: sends SCTP_I_ESTABLISHED indication with SctpConnectInfo to application. More...
 
void sendAvailableIndicationToApp ()
 
bool isToBeAccepted () const
 
void pushUlp ()
 
void sendDataArrivedNotification (uint16_t sid)
 
void putInDeliveryQ (uint16_t sid)
 
void printAssocBrief ()
 Utility: prints local/remote addr/port and app gate index/assocId. More...
 
void addPath (const L3Address &addr)
 
SctpPathVariablesgetNextPath (const SctpPathVariables *oldPath) const
 
const L3AddressgetNextAddress (const SctpPathVariables *oldPath) const
 
SctpPathVariablesgetNextDestination (SctpDataVariables *chunk) const
 
void bytesAllowedToSend (SctpPathVariables *path, bool firstPass)
 
void pathStatusIndication (const SctpPathVariables *path, bool status)
 
bool allPathsInactive () const
 
void sendStreamResetRequest (SctpResetReq *info)
 
void sendStreamResetResponse (uint32_t srrsn, int result)
 
void sendStreamResetResponse (SctpSsnTsnResetRequestParameter *requestParam, int result, bool options)
 
void sendOutgoingResetRequest (SctpIncomingSsnResetRequestParameter *requestParam)
 
void sendAddOutgoingStreamsRequest (uint16_t numStreams)
 
void sendBundledOutgoingResetAndResponse (SctpIncomingSsnResetRequestParameter *requestParam)
 
void sendAddInAndOutStreamsRequest (SctpResetReq *info)
 
void sendDoubleStreamResetResponse (uint32_t insrrsn, uint16_t inresult, uint32_t outsrrsn, uint16_t outresult)
 
void checkStreamsToReset ()
 
bool streamIsPending (int32_t sid)
 
void sendPacketDrop (const bool flag)
 
void sendHMacError (const uint16_t id)
 
void sendInvalidStreamError (uint16_t sid)
 
void resetGapLists ()
 
SctpForwardTsnChunkcreateForwardTsnChunk (const L3Address &pid)
 
bool msgMustBeAbandoned (SctpDataMsg *msg, int32_t stream, bool ordered)
 
bool chunkMustBeAbandoned (SctpDataVariables *chunk, SctpPathVariables *sackPath)
 
void advancePeerTsn ()
 
void cucProcessGapReports (const SctpDataVariables *chunk, SctpPathVariables *path, const bool isAcked)
 
SctpDataChunktransformDataChunk (SctpDataVariables *chunk)
 Manipulating chunks. More...
 
SctpDataVariablesmakeVarFromMsg (SctpDataChunk *datachunk)
 
int32_t streamScheduler (SctpPathVariables *path, bool peek)
 Dealing with streams. More...
 
void initStreams (uint32_t inStreams, uint32_t outStreams)
 
void addInStreams (uint32_t inStreams)
 
void addOutStreams (uint32_t outStreams)
 
int32_t numUsableStreams ()
 
int32_t streamSchedulerRoundRobinPacket (SctpPathVariables *path, bool peek)
 
int32_t streamSchedulerRandom (SctpPathVariables *path, bool peek)
 
int32_t streamSchedulerRandomPacket (SctpPathVariables *path, bool peek)
 
int32_t streamSchedulerFairBandwidth (SctpPathVariables *path, bool peek)
 
int32_t streamSchedulerFairBandwidthPacket (SctpPathVariables *path, bool peek)
 
int32_t streamSchedulerPriority (SctpPathVariables *path, bool peek)
 
int32_t streamSchedulerFCFS (SctpPathVariables *path, bool peek)
 
int32_t pathStreamSchedulerManual (SctpPathVariables *path, bool peek)
 
int32_t pathStreamSchedulerMapToPath (SctpPathVariables *path, bool peek)
 
void process_QUEUE_MSGS_LIMIT (const SctpCommandReq *sctpCommand)
 Queue Management. More...
 
void process_QUEUE_BYTES_LIMIT (const SctpCommandReq *sctpCommand)
 
int32_t getOutstandingBytes () const
 
void dequeueAckedChunks (const uint32_t tsna, SctpPathVariables *path, simtime_t &rttEstimation)
 
SctpDataMsgpeekOutboundDataMsg ()
 
SctpDataVariablespeekAbandonedChunk (const SctpPathVariables *path)
 
SctpDataVariablesgetOutboundDataChunk (const SctpPathVariables *path, int32_t availableSpace, int32_t availableCwnd)
 
void fragmentOutboundDataMsgs ()
 
SctpDataMsgdequeueOutboundDataMsg (SctpPathVariables *path, int32_t availableSpace, int32_t availableCwnd)
 
bool nextChunkFitsIntoPacket (SctpPathVariables *path, int32_t bytes)
 
void putInTransmissionQ (uint32_t tsn, SctpDataVariables *chunk)
 
uint32_t getAllTransQ ()
 
void pmStartPathManagement ()
 Flow control. More...
 
void pmDataIsSentOn (SctpPathVariables *path)
 
void pmClearPathCounter (SctpPathVariables *path)
 
void pmRttMeasurement (SctpPathVariables *path, const simtime_t &rttEstimation)
 
void disposeOf (SctpHeader *sctpmsg)
 
void removeFirstChunk (SctpHeader *sctpmsg)
 
void resetSsns ()
 Methods for Stream Reset. More...
 
void resetExpectedSsns ()
 
bool sendStreamPresent (uint32_t sid)
 
bool receiveStreamPresent (uint32_t sid)
 
void resetSsn (uint16_t id)
 
void resetExpectedSsn (uint16_t id)
 
uint32_t getExpectedSsnOfStream (uint16_t id)
 
uint32_t getSsnOfStream (uint16_t id)
 
SctpParametermakeOutgoingStreamResetParameter (uint32_t srsn, SctpResetReq *info)
 
SctpParametermakeIncomingStreamResetParameter (uint32_t srsn, SctpResetReq *info)
 
SctpParametermakeSsnTsnResetParameter (uint32_t srsn)
 
SctpParametermakeAddStreamsRequestParameter (uint32_t srsn, SctpResetReq *info)
 
void sendOutgoingRequestAndResponse (uint32_t inRequestSn, uint32_t outRequestSn)
 
void sendOutgoingRequestAndResponse (SctpIncomingSsnResetRequestParameter *inRequestParam, SctpOutgoingSsnResetRequestParameter *outRequestParam)
 
SctpEventCode processInAndOutResetRequestArrived (SctpIncomingSsnResetRequestParameter *inRequestParam, SctpOutgoingSsnResetRequestParameter *outRequestParam)
 
SctpEventCode processOutAndResponseArrived (SctpOutgoingSsnResetRequestParameter *outRequestParam, SctpStreamResetResponseParameter *responseParam)
 
SctpEventCode processStreamResetArrived (SctpStreamResetChunk *strResChunk)
 
void processOutgoingResetRequestArrived (SctpOutgoingSsnResetRequestParameter *requestParam)
 
void processIncomingResetRequestArrived (SctpIncomingSsnResetRequestParameter *requestParam)
 
void processSsnTsnResetRequestArrived (SctpSsnTsnResetRequestParameter *requestParam)
 
void processResetResponseArrived (SctpStreamResetResponseParameter *responseParam)
 
void processAddInAndOutResetRequestArrived (const SctpAddStreamsRequestParameter *addInRequestParam, SctpAddStreamsRequestParameter *addOutRequestParam)
 
uint32_t getBytesInFlightOfStream (uint16_t sid)
 
bool getFragInProgressOfStream (uint16_t sid)
 
void setFragInProgressOfStream (uint16_t sid, bool frag)
 
bool orderedQueueEmptyOfStream (uint16_t sid)
 
bool unorderedQueueEmptyOfStream (uint16_t sid)
 
void sendAsconf (const char *type, bool remote=false)
 Methods for Add-IP and AUTH. More...
 
void sendAsconfAck (uint32_t serialNumber)
 
SctpEventCode processAsconfArrived (SctpAsconfChunk *asconfChunk)
 
SctpEventCode processAsconfAckArrived (SctpAsconfAckChunk *asconfAckChunk)
 
void retransmitAsconf ()
 
bool typeInChunkList (uint16_t type)
 
bool typeInOwnChunkList (uint16_t type)
 
SctpAsconfAckChunkcreateAsconfAckChunk (uint32_t serialNumber)
 
SctpAuthenticationChunkcreateAuthChunk ()
 
SctpSuccessIndicationcreateSuccessIndication (uint32_t correlationId)
 
void calculateAssocSharedKey ()
 
bool compareRandom ()
 
void calculateRcvBuffer ()
 
void listOrderedQ ()
 
void tsnWasReneged (SctpDataVariables *chunk, const SctpPathVariables *sackPath, const int type)
 
void printOutstandingTsns ()
 
void initCcParameters (SctpPathVariables *path)
 SctpCcFunctions. More...
 
void updateFastRecoveryStatus (uint32_t lastTsnAck)
 
void cwndUpdateBeforeSack ()
 
void cwndUpdateAfterSack ()
 
void cwndUpdateAfterCwndTimeout (SctpPathVariables *path)
 
void cwndUpdateAfterRtxTimeout (SctpPathVariables *path)
 
void cwndUpdateMaxBurst (SctpPathVariables *path)
 
void cwndUpdateBytesAcked (SctpPathVariables *path, uint32_t ackedBytes, bool ctsnaAdvanced)
 
int32_t rpPathBlockingControl (SctpPathVariables *path, double reduction)
 
static void printSegmentBrief (SctpHeader *sctpmsg)
 Utility: prints important header fields. More...
 
static const char * eventName (int32_t event)
 Utility: returns name of SCTP_E_xxx constants. More...
 
SctpDataVariablesmakeDataVarFromDataMsg (SctpDataMsg *datMsg, SctpPathVariables *path)
 
SctpPathVariableschoosePathForRetransmission ()
 
void timeForSack (bool &sackOnly, bool &sackWithData)
 
void recordCwndUpdate (SctpPathVariables *path)
 
void sendSACKviaSelectedPath (const Ptr< SctpHeader > &sctpMsg)
 
void checkOutstandingBytes ()
 
void updateHighSpeedCCThresholdIdx (SctpPathVariables *path)
 
uint32_t getInitialCwnd (const SctpPathVariables *path) const
 
void generateSendQueueAbatedIndication (uint64_t bytes)
 
void renegablyAckChunk (SctpDataVariables *chunk, SctpPathVariables *sackPath)
 
void nonRenegablyAckChunk (SctpDataVariables *chunk, SctpPathVariables *sackPath, simtime_t &rttEstimation, Sctp::AssocStat *assocStat)
 
void handleChunkReportedAsAcked (uint32_t &highestNewAck, simtime_t &rttEstimation, SctpDataVariables *myChunk, SctpPathVariables *sackPath, const bool sackIsNonRevokable)
 
void handleChunkReportedAsMissing (const SctpSackChunk *sackChunk, const uint32_t highestNewAck, SctpDataVariables *myChunk, SctpPathVariables *sackPath)
 
void moveChunkToOtherPath (SctpDataVariables *chunk, SctpPathVariables *newPath)
 
void decreaseOutstandingBytes (SctpDataVariables *chunk)
 
void increaseOutstandingBytes (SctpDataVariables *chunk, SctpPathVariables *path)
 
int32_t calculateBytesToSendOnPath (const SctpPathVariables *pathVar)
 
void storePacket (SctpPathVariables *pathVar, const Ptr< SctpHeader > &sctpMsg, uint16_t chunksAdded, uint16_t dataChunksAdded, bool authAdded)
 
void loadPacket (SctpPathVariables *pathVar, Ptr< SctpHeader > *sctpMsg, uint16_t *chunksAdded, uint16_t *dataChunksAdded, bool *authAdded)
 
void ackChunk (SctpDataVariables *chunk, SctpPathVariables *sackPath)
 
void unackChunk (SctpDataVariables *chunk)
 
bool chunkHasBeenAcked (const SctpDataVariables *chunk) const
 
bool chunkHasBeenAcked (uint32_t tsn) const
 
void checkPseudoCumAck (const SctpPathVariables *path)
 
std::vector< SctpPathVariables * > getSortedPathMap ()
 
void chunkReschedulingControl (SctpPathVariables *path)
 
void recalculateOLIABasis ()
 
uint32_t updateOLIA (uint32_t w, uint32_t s, uint32_t totalW, double a, uint32_t mtu, uint32_t ackedBytes, SctpPathVariables *path)
 w: cwnd of the path s: ssthresh of the path totalW: Sum of all cwnds of the association a: factor alpha of olia calculation - see https://tools.ietf.org/html/draft-khalili-mptcp-congestion-control-05 mtu: mtu of the path ackedBytes: ackednowlged bytes path: path variable (for further investigation, debug, etc) More...
 
bool addAuthChunkIfNecessary (Ptr< SctpHeader > sctpMsg, uint16_t chunkType, bool authAdded)
 
static bool pathMapLargestSSThreshold (const SctpPathVariables *left, const SctpPathVariables *right)
 
static bool pathMapLargestSpace (const SctpPathVariables *left, const SctpPathVariables *right)
 
static bool pathMapLargestSpaceAndSSThreshold (const SctpPathVariables *left, const SctpPathVariables *right)
 
static bool pathMapSmallestLastTransmission (const SctpPathVariables *left, const SctpPathVariables *right)
 
static bool pathMapRandomized (const SctpPathVariables *left, const SctpPathVariables *right)
 

Member Typedef Documentation

◆ CounterMap

typedef std::map<L3Address, uint32_t> inet::sctp::SctpAssociation::CounterMap
private

◆ SctpPathCollection

◆ SctpPathMap

◆ SctpReceiveStreamMap

◆ SctpSendStreamMap

typedef std::map<uint32_t, SctpSendStream *> inet::sctp::SctpAssociation::SctpSendStreamMap
private

Constructor & Destructor Documentation

◆ SctpAssociation()

inet::sctp::SctpAssociation::SctpAssociation ( Sctp mod,
int32_t  appGateIndex,
int32_t  assocId,
IRoutingTable rt,
IInterfaceTable ift 
)

Constructor.

556 {
557  // ====== Initialize variables ===========================================
558  rt = _rt;
559  ift = _ift;
560  sctpMain = _module;
561  appGateIndex = _appGateIndex;
562  assocId = _assocId;
563  listeningAssocId = -1;
564  fd = -1;
565  listening = false;
566  localPort = 0;
567  remotePort = 0;
568  localVTag = 0;
569  peerVTag = 0;
573  initInboundStreams = 0;
574  // queues and algorithm will be created on active or passive open
575  transmissionQ = nullptr;
576  retransmissionQ = nullptr;
577  sctpAlgorithm = nullptr;
578  state = nullptr;
580 
581  cumTsnAck = nullptr;
582  sendQueue = nullptr;
583  numGapBlocks = nullptr;
584 
588  bytes.chunk = false;
589  bytes.packet = false;
590  bytes.bytesToSend = 0;
591 
592  fairTimer = false;
594  initTsn = 0;
595  initPeerTsn = 0;
596  sackFrequency = 2;
597  ccFunctions.ccInitParams = nullptr;
599  ccFunctions.ccUpdateAfterSack = nullptr;
602  ccFunctions.ccUpdateMaxBurst = nullptr;
604  ccModule = 0;
605  ssFunctions.ssInitStreams = nullptr;
606  ssFunctions.ssAddInStreams = nullptr;
607  ssFunctions.ssAddOutStreams = nullptr;
608  ssFunctions.ssGetNextSid = nullptr;
609  ssFunctions.ssUsableStreams = nullptr;
610 
611  EV_INFO << "SctpAssociationBase::SctpAssociation(): new assocId="
612  << assocId << endl;
613 
614  // ====== FSM ============================================================
615  char fsmName[64];
616  snprintf(fsmName, sizeof(fsmName), "fsm-%d", assocId);
617  fsm = new cFSM();
618  fsm->setName(fsmName);
619  fsm->setState(SCTP_S_CLOSED);
620 
621  // ====== Path Info ======================================================
622  SctpPathInfo *pinfo = new SctpPathInfo("pathInfo");
623  pinfo->setRemoteAddress(L3Address());
624 
625  // ====== Timers =========================================================
626  char timerName[128];
627  snprintf(timerName, sizeof(timerName), "T1_INIT of Association %d", assocId);
628  T1_InitTimer = new cMessage(timerName);
629  snprintf(timerName, sizeof(timerName), "T2_SHUTDOWN of Association %d", assocId);
630  T2_ShutdownTimer = new cMessage(timerName);
631  snprintf(timerName, sizeof(timerName), "T5_SHUTDOWN_GUARD of Association %d", assocId);
632  T5_ShutdownGuardTimer = new cMessage(timerName);
633  snprintf(timerName, sizeof(timerName), "SACK_TIMER of Association %d", assocId);
634  SackTimer = new cMessage(timerName);
635 
636  StartTesting = nullptr;
637  if (sctpMain->testTimeout > 0) {
638  StartTesting = new cMessage("StartTesting");
639  StartTesting->setContextPointer(this);
640  StartTesting->setControlInfo(pinfo->dup());
642  }
643 
644  T1_InitTimer->setContextPointer(this);
645  T2_ShutdownTimer->setContextPointer(this);
646  SackTimer->setContextPointer(this);
647  T5_ShutdownGuardTimer->setContextPointer(this);
648 
649  T1_InitTimer->setControlInfo(pinfo);
650  T2_ShutdownTimer->setControlInfo(pinfo->dup());
651  SackTimer->setControlInfo(pinfo->dup());
652  T5_ShutdownGuardTimer->setControlInfo(pinfo->dup());
653 
654  // ====== Output vectors =================================================
655  char vectorName[128];
656  snprintf(vectorName, sizeof(vectorName), "Advertised Receiver Window %d", assocId);
657  advRwnd = new cOutVector(vectorName);
658 
659  snprintf(vectorName, sizeof(vectorName), "Slow Start Threshold %d:Total", assocId);
660  statisticsTotalSSthresh = new cOutVector(vectorName);
661  snprintf(vectorName, sizeof(vectorName), "Congestion Window %d:Total", assocId);
662  statisticsTotalCwnd = new cOutVector(vectorName);
663  snprintf(vectorName, sizeof(vectorName), "Bandwidth %d:Total", assocId);
664  statisticsTotalBandwidth = new cOutVector(vectorName);
665  snprintf(vectorName, sizeof(vectorName), "Queued Received Bytes %d:Total", assocId);
666  statisticsQueuedReceivedBytes = new cOutVector(vectorName);
667  snprintf(vectorName, sizeof(vectorName), "Queued Sent Bytes %d:Total", assocId);
668  statisticsQueuedSentBytes = new cOutVector(vectorName);
669  snprintf(vectorName, sizeof(vectorName), "Outstanding Bytes %d:Total", assocId);
670  statisticsOutstandingBytes = new cOutVector(vectorName);
671 
672  snprintf(vectorName, sizeof(vectorName), "Number of Revokable Gap Blocks in SACK %d", assocId);
673  statisticsRevokableGapBlocksInLastSACK = new cOutVector(vectorName);
674  snprintf(vectorName, sizeof(vectorName), "Number of Non-Revokable Gap Blocks in SACK %d", assocId);
675  statisticsNonRevokableGapBlocksInLastSACK = new cOutVector(vectorName);
676 
677  snprintf(vectorName, sizeof(vectorName), "Number of Total Gap Blocks Stored %d", assocId);
678  statisticsNumTotalGapBlocksStored = new cOutVector(vectorName);
679  snprintf(vectorName, sizeof(vectorName), "Number of Revokable Gap Blocks Stored %d", assocId);
680  statisticsNumRevokableGapBlocksStored = new cOutVector(vectorName);
681  snprintf(vectorName, sizeof(vectorName), "Number of Non-Revokable Gap Blocks Stored %d", assocId);
682  statisticsNumNonRevokableGapBlocksStored = new cOutVector(vectorName);
683  snprintf(vectorName, sizeof(vectorName), "Number of Duplicate TSNs Stored %d", assocId);
684  statisticsNumDuplicatesStored = new cOutVector(vectorName);
685 
686  snprintf(vectorName, sizeof(vectorName), "Number of Revokable Gap Blocks Sent %d", assocId);
687  statisticsNumRevokableGapBlocksSent = new cOutVector(vectorName);
688  snprintf(vectorName, sizeof(vectorName), "Number of Non-Revokable Gap Blocks Sent %d", assocId);
689  statisticsNumNonRevokableGapBlocksSent = new cOutVector(vectorName);
690  snprintf(vectorName, sizeof(vectorName), "Number of Duplicate TSNs Sent %d", assocId);
691  statisticsNumDuplicatesSent = new cOutVector(vectorName);
692  snprintf(vectorName, sizeof(vectorName), "Length of SACK Sent %d", assocId);
693  statisticsSACKLengthSent = new cOutVector(vectorName);
694 
695  snprintf(vectorName, sizeof(vectorName), "Arwnd in Last SACK %d", assocId);
696  statisticsArwndInLastSACK = new cOutVector(vectorName);
697  snprintf(vectorName, sizeof(vectorName), "Peer Rwnd %d", assocId);
698  statisticsPeerRwnd = new cOutVector(vectorName);
699 
700  // ====== Extensions =====================================================
701  StartAddIP = new cMessage("addIP");
702  StartAddIP->setContextPointer(this);
703  StartAddIP->setControlInfo(pinfo->dup());
704  FairStartTimer = new cMessage("fairStart");
705  FairStartTimer->setContextPointer(this);
706  FairStartTimer->setControlInfo(pinfo->dup());
707  FairStopTimer = new cMessage("fairStop");
708  FairStopTimer->setContextPointer(this);
709  FairStopTimer->setControlInfo(pinfo->dup());
710  snprintf(vectorName, sizeof(vectorName), "Advertised Message Receiver Window of Association %d", assocId);
711  advMsgRwnd = new cOutVector(vectorName);
712  snprintf(vectorName, sizeof(vectorName), "End to End Delay of Association %d", assocId);
713  EndToEndDelay = new cOutVector(vectorName);
714 
715  // ====== Assoc throughput ===============================================
716  snprintf(vectorName, sizeof(vectorName), "Throughput of Association %d", assocId);
717  assocThroughputVector = new cOutVector(vectorName);
718  assocThroughputVector->record(0.0);
719 
720  // ====== CMT Delayed Ack ================================================
721  dacPacketsRcvd = 0;
722 
723  // ====== Stream scheduling ==============================================
724  ssModule = sctpMain->par("ssModule");
725 
726  switch (ssModule) {
727  case ROUND_ROBIN:
733  EV_DETAIL << "Setting Stream Scheduler: ROUND_ROBIN" << endl;
734  break;
735 
736  case ROUND_ROBIN_PACKET:
742  EV_DETAIL << "Setting Stream Scheduler: ROUND_ROBIN_PACKET" << endl;
743  break;
744 
745  case RANDOM_SCHEDULE:
751  EV_DETAIL << "Setting Stream Scheduler: RANDOM_SCHEDULE" << endl;
752  break;
753 
760  EV_DETAIL << "Setting Stream Scheduler: RANDOM_SCHEDULE_PACKET" << endl;
761  break;
762 
763  case FAIR_BANDWITH:
769  EV_DETAIL << "Setting Stream Scheduler: FAIR_BANDWITH" << endl;
770  break;
771 
778  EV_DETAIL << "Setting Stream Scheduler: FAIR_BANDWITH_PACKET" << endl;
779  break;
780 
781  case PRIORITY:
787  EV_DETAIL << "Setting Stream Scheduler: PRIORITY" << endl;
788  break;
789 
790  case FCFS:
794  EV_DETAIL << "Setting Stream Scheduler: FCFS" << endl;
795  break;
796 
797  case PATH_MANUAL:
803  EV_DETAIL << "Setting Stream Scheduler: PATH_MANUAL" << endl;
804  break;
805 
806  case PATH_MAP_TO_PATH:
812  EV_DETAIL << "Setting Stream Scheduler: PATH_MAP_TO_PATH" << endl;
813  break;
814  }
815 }

Referenced by cloneAssociation().

◆ ~SctpAssociation()

inet::sctp::SctpAssociation::~SctpAssociation ( )

Destructor.

818 {
819  EV_TRACE << "Destructor SctpAssociation " << assocId << endl;
820 
821  delete T1_InitTimer;
822  delete T2_ShutdownTimer;
823  delete T5_ShutdownGuardTimer;
824  delete SackTimer;
825 
826  delete advRwnd;
827  delete cumTsnAck;
828  delete numGapBlocks;
829  delete sendQueue;
830 
835  delete statisticsTotalCwnd;
837 
848 
850  delete statisticsPeerRwnd;
851 
852  delete StartAddIP;
853  delete advMsgRwnd;
854  delete EndToEndDelay;
855 
856  int i = 0;
857  while (streamThroughputVectors[i] != nullptr) {
858  delete streamThroughputVectors[i++];
859  }
860  if (assocThroughputVector != nullptr)
861  delete assocThroughputVector;
862  if (FairStartTimer)
863  delete cancelEvent(FairStartTimer);
864  if (FairStopTimer)
865  delete cancelEvent(FairStopTimer);
866 
868  delete state->asconfChunk;
869 
870  delete fsm;
871  delete state;
872  delete sctpAlgorithm;
873 }

Member Function Documentation

◆ ackChunk()

void inet::sctp::SctpAssociation::ackChunk ( SctpDataVariables chunk,
SctpPathVariables sackPath 
)
inlineprivate
1440  {
1441  chunk->hasBeenAcked = true;
1442  chunk->ackedOnPath = sackPath;
1443  }

Referenced by nonRenegablyAckChunk(), and renegablyAckChunk().

◆ addAuthChunkIfNecessary()

bool inet::sctp::SctpAssociation::addAuthChunkIfNecessary ( Ptr< SctpHeader sctpMsg,
uint16_t  chunkType,
bool  authAdded 
)
inlineprivate
1486  {
1487  if ((state->auth) && (state->peerAuth) && (typeInChunkList(chunkType)) && (authAdded == false)) {
1488  SctpAuthenticationChunk *authChunk = createAuthChunk();
1489  sctpMsg->appendSctpChunks(authChunk);
1490  auto it = sctpMain->assocStatMap.find(assocId);
1491  it->second.numAuthChunksSent++;
1492  return true;
1493  }
1494  return false;
1495  }

Referenced by sendOnPath().

◆ addInStreams()

void inet::sctp::SctpAssociation::addInStreams ( uint32_t  inStreams)
protected
82 {
83  for (auto& elem : sendStreams) {
84  delete elem.second;
85  }
86  for (auto& elem : receiveStreams) {
87  delete elem.second;
88  }
89 }
90 
91 int32_t SctpAssociation::streamScheduler(SctpPathVariables *path, bool peek) // peek indicates that no data is sent, but we just want to peek
92 {

Referenced by SctpAssociation(), and sendAddInAndOutStreamsRequest().

◆ addOutStreams()

void inet::sctp::SctpAssociation::addOutStreams ( uint32_t  outStreams)
protected
95  : RoundRobin\n";
96 
97  sid = -1;
98 
99  if ((state->ssLastDataChunkSizeSet == false || state->ssNextStream == false) &&
100  (sendStreams.find(state->lastStreamScheduled)->second->getUnorderedStreamQ()->getLength() > 0 ||
101  sendStreams.find(state->lastStreamScheduled)->second->getStreamQ()->getLength() > 0))
102  {
103  sid = state->lastStreamScheduled;

Referenced by SctpAssociation(), and sendAddInAndOutStreamsRequest().

◆ addPath()

void inet::sctp::SctpAssociation::addPath ( const L3Address addr)
protected
2114 {
2115  EV_INFO << "Add Path remote address: " << addr << "\n";
2116 
2117  if (!containsKey(sctpPathMap, addr)) {
2118  EV_DEBUG << " get new path for " << addr << " at line " << __LINE__ << "\n";
2119  SctpPathVariables *path = new SctpPathVariables(addr, this, rt);
2120  sctpPathMap[addr] = path;
2121  qCounter.roomTransQ[addr] = 0;
2122  qCounter.bookedTransQ[addr] = 0;
2123  qCounter.roomRetransQ[addr] = 0;
2124  }
2125  EV_INFO << "path added\n";
2126 }

Referenced by processAsconfArrived(), and processInitAckArrived().

◆ advancePeerTsn()

void inet::sctp::SctpAssociation::advancePeerTsn ( )
protected
2280 {
2281  // Rewrote code for efficiency, it consomed >40% of total CPU time before!
2282  // Find the highest TSN to advance to, not just the first one.
2283  auto iterator = retransmissionQ->payloadQueue.find(state->advancedPeerAckPoint + 1);
2284  while (iterator != retransmissionQ->payloadQueue.end()) {
2285  if (iterator->second->hasBeenAbandoned) {
2286  state->advancedPeerAckPoint = iterator->second->tsn;
2287  state->ackPointAdvanced = true;
2288  iterator++;
2289  }
2290  else {
2291  if (iterator->second->hasBeenAcked == true)
2292  iterator++;
2293  else
2294  break;
2295  }
2296  }
2297 
2298  EV_INFO << "advancedPeerTsnAck now=" << state->advancedPeerAckPoint << endl;
2299 }

Referenced by createForwardTsnChunk(), and processSackArrived().

◆ allPathsInactive()

bool inet::sctp::SctpAssociation::allPathsInactive ( ) const
protected
2865 {
2866  for (const auto& elem : sctpPathMap) {
2867  if (elem.second->activePath) {
2868  return false;
2869  }
2870  }
2871  return true;
2872 }

Referenced by process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().

◆ bytesAllowedToSend()

void inet::sctp::SctpAssociation::bytesAllowedToSend ( SctpPathVariables path,
bool  firstPass 
)
protected
549 {
550  assert(path != nullptr);
551 
552  bytes.chunk = false;
553  bytes.packet = false;
554  bytes.bytesToSend = 0;
555 
556  EV_INFO << "bytesAllowedToSend(" << path->remoteAddress << "):"
557  << " osb=" << path->outstandingBytes << " cwnd=" << path->cwnd << endl;
558 
559  // ====== First transmission =============================================
560  if (!state->firstDataSent) {
561  bytes.chunk = true;
562  }
563  // ====== Transmission allowed by peer's receiver window? ================
564  else if ((state->peerWindowFull || (state->peerAllowsChunks && state->peerMsgRwnd <= 0)) && (path->outstandingBytes == 0)) {
565  // Zero Window Probing
566  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): zeroWindowProbing" << endl;
567  state->zeroWindowProbing = true;
568  bytes.chunk = true;
569  }
570  // ====== Retransmissions ================================================
571  else {
572  CounterMap::const_iterator it = qCounter.roomTransQ.find(path->remoteAddress);
573  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): bytes in transQ=" << it->second << endl;
574  if (it->second > 0) {
575  const int32_t allowance = path->cwnd - path->outstandingBytes;
576  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd-osb=" << allowance << endl;
577  if (state->peerRwnd < path->pmtu) {
578  bytes.bytesToSend = 0;
579  bytes.chunk = true;
580  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): one chunk" << endl;
581  // RFC4960: When a Fast Retransmit is being performed, the sender SHOULD ignore the value
582  // of cwnd and SHOULD NOT delay retransmission for this single packet.
583  return;
584  }
585  else if (allowance > 0) {
586  CounterMap::const_iterator bit = qCounter.bookedTransQ.find(path->remoteAddress);
587  if (bit->second > (uint32_t)allowance) {
588  bytes.bytesToSend = allowance;
589  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd does not allow all RTX" << endl;
590  return; // More bytes available than allowed -> just return what is allowed.
591  }
592  else {
593  bytes.bytesToSend = bit->second;
594  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd allows more than those "
595  << bytes.bytesToSend << " bytes for retransmission" << endl;
596  }
597  }
598  else { // You may retransmit one packet
599  bytes.packet = true;
600  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): allowance<=0: retransmit one packet" << endl;
601  }
602  }
603 
604  // ====== New transmissions ===========================================
605  if (!bytes.chunk && !bytes.packet) {
606  (this->*ccFunctions.ccUpdateMaxBurst)(path);
607 
608  // ====== Get cwnd value to use, according to maxBurstVariant ======
609  uint32_t myCwnd = path->cwnd;
612  {
613  myCwnd = path->tempCwnd;
614  }
615  // ====== Obtain byte allowance ====================================
616  if ((((state->peerAllowsChunks) &&
617  (path->outstandingBytes < myCwnd) &&
618  (!state->peerWindowFull) &&
619  (state->peerMsgRwnd > 0))
620  ||
621  ((!state->peerAllowsChunks) &&
622  (path->outstandingBytes < myCwnd) &&
623  (!state->peerWindowFull)))
624  &&
625  ((path->blockingTimeout < 0.0) || /* Chunk Rescheduling: no new transmission when blocking is active! */
626  (simTime() >= path->blockingTimeout)))
627  {
628  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "):"
629  << " bookedSumSendStreams=" << qCounter.bookedSumSendStreams
630  << " bytes.bytesToSend=" << bytes.bytesToSend << endl;
631  const int32_t allowance = myCwnd - path->outstandingBytes - bytes.bytesToSend;
632  if (allowance > 0) {
633  if (qCounter.bookedSumSendStreams > (uint32_t)allowance) {
634  bytes.bytesToSend = myCwnd - path->outstandingBytes;
635  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): bytesToSend are limited by cwnd: "
636  << bytes.bytesToSend << endl;
637  }
638  else {
640  EV_DETAIL << "bytesAllowedToSend(" << path->remoteAddress << "): send all stored bytes: "
641  << bytes.bytesToSend << endl;
642  }
643  }
644  // Do not send more than the peer's arwnd allows
646  }
647  }
648  }
649 
650  EV_INFO << "bytesAllowedToSend(" << path->remoteAddress << "):"
651  << " osb=" << path->outstandingBytes
652  << " cwnd=" << path->cwnd
653  << " tempCwnd=" << path->tempCwnd
654  << " bytes.packet=" << (bytes.packet ? "YES!" : "no")
655  << " bytes.chunk=" << (bytes.chunk ? "YES!" : "no")
656  << " bytes.bytesToSend=" << bytes.bytesToSend << endl;
657 }

Referenced by sendOnPath().

◆ calculateAssocSharedKey()

void inet::sctp::SctpAssociation::calculateAssocSharedKey ( )
protected
261 {
262  const bool peerFirst = compareRandom();
263  if (peerFirst == true) {
264  for (uint32_t i = 0; i < state->sizeKeyVector; i++)
265  state->sharedKey[i] = state->keyVector[i];
266  for (uint32_t i = 0; i < state->sizePeerKeyVector; i++)
268  }
269  else {
270  for (uint32_t i = 0; i < state->sizePeerKeyVector; i++)
272  for (uint32_t i = 0; i < state->sizeKeyVector; i++)
274  }
275 }

◆ calculateBytesToSendOnPath()

int32_t inet::sctp::SctpAssociation::calculateBytesToSendOnPath ( const SctpPathVariables pathVar)
private

◆ calculateRcvBuffer()

void inet::sctp::SctpAssociation::calculateRcvBuffer ( )
protected
48 {
49  uint32_t sumDelivery = 0;
50  uint32_t sumOrdered = 0;
51  uint32_t sumUnOrdered = 0;
52  for (SctpReceiveStreamMap::const_iterator iterator = receiveStreams.begin();
53  iterator != receiveStreams.end(); iterator++)
54  {
55  const SctpReceiveStream *stream = iterator->second;
56  sumDelivery += stream->getDeliveryQ()->getQueueSize();
57  sumOrdered += stream->getOrderedQ()->getQueueSize();
58  sumUnOrdered += stream->getUnorderedQ()->getQueueSize();
59  }
60  EV_DEBUG << "DeliveryQ= " << sumDelivery
61  << ", OrderedQ=" << sumOrdered
62  << ", UnorderedQ=" << sumUnOrdered
63  << ", bufferedMessages=" << state->bufferedMessages
64  << endl;
65 }

Referenced by createSack(), makeRoomForTsn(), makeVarFromMsg(), processDataArrived(), and processForwardTsnArrived().

◆ cancelEvent()

cMessage* inet::sctp::SctpAssociation::cancelEvent ( cMessage *  msg)
inlineprotected

Utility: cancel a timer.

1192  {
1193  return sctpMain->cancelEvent(msg);
1194  }

Referenced by stopTimer(), and ~SctpAssociation().

◆ checkOutstandingBytes()

void inet::sctp::SctpAssociation::checkOutstandingBytes ( )
private

◆ checkPseudoCumAck()

void inet::sctp::SctpAssociation::checkPseudoCumAck ( const SctpPathVariables path)
private
112 {
113  uint32_t earliestOutstandingTsn = path->pseudoCumAck;
114  uint32_t rtxEarliestOutstandingTsn = path->rtxPseudoCumAck;
115 
117  path->remoteAddress,
118  earliestOutstandingTsn, rtxEarliestOutstandingTsn);
119 
120  if (tsnGt(path->pseudoCumAck, earliestOutstandingTsn) ||
121  tsnGt(path->rtxPseudoCumAck, rtxEarliestOutstandingTsn))
122  {
123  EV_WARN << "WRONG PSEUDO CUM-ACK!" << endl
124  << "pseudoCumAck=" << path->pseudoCumAck << ", earliestOutstandingTsn=" << earliestOutstandingTsn << endl
125  << "rtxPseudoCumAck=" << path->rtxPseudoCumAck << ", rtxEarliestOutstandingTsn=" << rtxEarliestOutstandingTsn << endl;
126  }
127 }

◆ checkStreamsToReset()

void inet::sctp::SctpAssociation::checkStreamsToReset ( )
protected
54 {
55  if (!state->resetPending && !state->fragInProgress && (state->resetRequested || state->incomingRequest != nullptr) && (state->outstandingBytes == 0 || state->streamsPending.size() > 0)) {
57  state->streamsToReset.clear();
58  std::list<uint16_t>::iterator it;
59  for (it = state->streamsPending.begin(); it != state->streamsPending.end();) {
60  if (getBytesInFlightOfStream(*it) == 0) {
61  state->streamsToReset.push_back(*it);
62  it = state->streamsPending.erase(it);
63  }
64  else
65  ++it;
66  }
67  }
72  {
74  state->resetPending = true;
75  }
76  if (state->resetDeferred && (state->streamsToReset.size() > 0 || state->peerRequestType == SSN_TSN)) {
77  switch (state->peerRequestType) {
78  case SSN_TSN: {
79  SctpSsnTsnResetRequestParameter *ssnParam = check_and_cast<SctpSsnTsnResetRequestParameter *>(state->incomingRequest);
83  state->sendResponse = 0;
84  sendStreamResetResponse(ssnParam, PERFORMED, true);
85  }
86  delete ssnParam;
87  break;
88  }
89  case RESET_INCOMING: {
90  SctpIncomingSsnResetRequestParameter *inParam = check_and_cast<SctpIncomingSsnResetRequestParameter *>(state->incomingRequest->dup());
91 // state->incomingRequest->setName("StateSackIncoming");
92 // inParam->setName("checkInParam");
94  if (state->incomingRequestSet && state->incomingRequest != nullptr) {
95  delete state->incomingRequest;
96  state->incomingRequest = nullptr;
97  state->incomingRequestSet = false;
98  }
99  delete inParam;
100  break;
101  }
102  }
103  state->resetDeferred = false;
104  }
106  (state->streamsToReset.size() > 0))
107  {
111  state->resetPending = true;
112  }
113  }
114 }

Referenced by process_RCV_Message().

◆ choosePathForRetransmission()

SctpPathVariables * inet::sctp::SctpAssociation::choosePathForRetransmission ( )
private
232 {
233  uint32_t max = 0;
234  SctpPathVariables *temp = nullptr;
235 
236  for (auto& elem : sctpPathMap) {
237  SctpPathVariables *path = elem.second;
238  CounterMap::const_iterator tq = qCounter.roomTransQ.find(path->remoteAddress);
239  if ((tq != qCounter.roomTransQ.end()) && (tq->second > max)) {
240  max = tq->second;
241  temp = path;
242  }
243  }
244  return temp;
245 }

Referenced by sendOnPath().

◆ chunkHasBeenAcked() [1/2]

bool inet::sctp::SctpAssociation::chunkHasBeenAcked ( const SctpDataVariables chunk) const
inlineprivate

◆ chunkHasBeenAcked() [2/2]

bool inet::sctp::SctpAssociation::chunkHasBeenAcked ( uint32_t  tsn) const
inlineprivate
1456  {
1457  const SctpDataVariables *chunk = retransmissionQ->getChunk(tsn);
1458  if (chunk) {
1459  return chunkHasBeenAcked(chunk);
1460  }
1461  return false;
1462  }

◆ chunkMustBeAbandoned()

bool inet::sctp::SctpAssociation::chunkMustBeAbandoned ( SctpDataVariables chunk,
SctpPathVariables sackPath 
)
protected
2344 {
2345  switch (chunk->prMethod) {
2346  case PR_TTL:
2347  if (chunk->expiryTime > 0 && chunk->expiryTime <= simTime()) {
2348  if (!chunk->hasBeenAbandoned) {
2349  EV_INFO << "TSN " << chunk->tsn << " will be abandoned"
2350  << " (expiryTime=" << chunk->expiryTime
2351  << " sendTime=" << chunk->sendTime << ")" << endl;
2352  chunk->hasBeenAbandoned = true;
2353  chunk->sendForwardIfAbandoned = true;
2355  }
2356  }
2357  break;
2358 
2359  case PR_RTX:
2360  if (chunk->numberOfRetransmissions >= chunk->allowedNoRetransmissions) {
2361  if (!chunk->hasBeenAbandoned) {
2362  EV_INFO << "chunkMustBeAbandoned: TSN " << chunk->tsn << " will be abandoned"
2363  << " (maxRetransmissions=" << chunk->allowedNoRetransmissions << ")" << endl;
2364  chunk->hasBeenAbandoned = true;
2365  chunk->sendForwardIfAbandoned = true;
2366  decreaseOutstandingBytes(chunk);
2367  chunk->countsAsOutstanding = false;
2369  }
2370  }
2371  break;
2372  }
2373 
2374  if (chunk->hasBeenAbandoned) {
2375  return true;
2376  }
2377  return false;
2378 }

Referenced by handleChunkReportedAsMissing(), and process_TIMEOUT_RTX().

◆ chunkReschedulingControl()

void inet::sctp::SctpAssociation::chunkReschedulingControl ( SctpPathVariables path)
private
331 {
332  EV << simTime() << ": chunkReschedulingControl:"
333  << "\tqueueFillLevel=" << (100.0 * (double)state->queuedSentBytes) / (double)state->sendQueueLimit << "%"
334  << "\tpeerRwnd=" << state->peerRwnd
335  << endl;
336 
337  double totalBandwidth = 0.0;
338  unsigned int totalOutstandingBytes = 0;
339  unsigned int totalQueuedBytes = 0;
340  for (auto& elem : sctpPathMap) {
341  const SctpPathVariables *myPath = elem.second;
342  totalQueuedBytes += myPath->queuedBytes;
343  totalOutstandingBytes += myPath->outstandingBytes;
344  totalBandwidth += (double)myPath->cwnd / myPath->srtt.dbl();
345  }
346  assert(totalOutstandingBytes == state->outstandingBytes);
347 
348  const unsigned int queuedBytes = path->queuedBytes;
349  const unsigned int outstandingBytes = path->outstandingBytes;
350 
351  /* senderLimit is just the size of the send queue! */
352  uint32_t senderLimit = ((state->sendQueueLimit != 0) ? state->sendQueueLimit : 0xffffffff);
356  {
357  senderLimit = senderLimit / sctpPathMap.size();
358  }
359 
360  /* receiverLimit is the peerRwnd + all bytes queued
361  (i.e. waiting or being outstanding)! */
362  uint32_t receiverLimit = state->peerRwnd + totalQueuedBytes;
366  {
367  receiverLimit = receiverLimit / sctpPathMap.size();
368  }
369 
370  const double senderBlockingFraction = (queuedBytes - outstandingBytes) / (double)senderLimit;
371  const double receiverBlockingFraction = (queuedBytes - outstandingBytes) / (double)receiverLimit;
372 
373  EV << " - " << path->remoteAddress
374  << "\tt3=" << (path->T3_RtxTimer->isScheduled() ? path->T3_RtxTimer->getArrivalTime().dbl() : -1.0)
375  << "\tssthresh=" << path->ssthresh
376  << "\tcwnd=" << path->cwnd
377  << "\tsrtt=" << path->srtt
378  << "\tbw=" << (8.0 * (double)path->cwnd) / (1000000.0 * path->srtt) << " Mbit/s"
379  << "\tosb=" << path->outstandingBytes
380  << "\tqueued=" << path->queuedBytes
381  << "\tslimit=" << senderLimit
382  << "\trlimit=" << receiverLimit
383  << "\tsblocking=" << 100.0 * senderBlockingFraction << " %"
384  << "\trblocking=" << 100.0 * receiverBlockingFraction << " %"
385  << endl;
386 
387  path->statisticsPathSenderBlockingFraction->record(senderBlockingFraction);
388  path->statisticsPathReceiverBlockingFraction->record(receiverBlockingFraction);
389 
390  // ====== Chunk Rescheduling =============================================
394  {
397  (senderBlockingFraction >= state->cmtChunkReschedulingThreshold)) ||
400  (receiverBlockingFraction >= state->cmtChunkReschedulingThreshold)))
401  {
402  if ((!path->fastRecoveryActive) && // Only apply when path is not yet in Fast Recovery!
403  ((path->blockingTimeout < 0.0) || // Do not move chunks to an already-blocked path!
404  (simTime() >= path->blockingTimeout)))
405  {
406  // ====== Rescheduling of chunk from other path to current path ====
407  auto iterator = retransmissionQ->payloadQueue.begin();
408  if (iterator != retransmissionQ->payloadQueue.end()) {
409  SctpDataVariables *chunk = iterator->second;
410  SctpPathVariables *lastPath = chunk->getLastDestinationPath();
411 
412  if ((chunk->countsAsOutstanding == true) && // T.D. 04.08.2011: Chunk must be outstanding, i.e. in the network!
413  (chunk->hasBeenMoved == false) && // T.D. 08.07.2011: Check, whether this chunk has already been moved!
414  ((lastPath != path) ||
415  (chunk->sendTime + (2 * path->srtt) < simTime())))
416  {
417  assert(chunk->numberOfTransmissions > 0); // It has been transmitted as least once
418  assert(chunk->hasBeenAcked == false); // It has not been acked (since it is outstanding)
419 
420  EV << simTime() << ": RESCHEDULING TSN " << chunk->tsn << " on "
421  << lastPath->remoteAddress << " to "
422  << path->remoteAddress << endl;
423 
424  // ====== Move chunk ======================================
425  lastPath->vectorPathBlockingTsnsMoved->record(chunk->tsn);
426  moveChunkToOtherPath(chunk, path);
427 
428  // This chunk is important, since it is blocking others ...
429  // If SackNow is supported, ensure that it is SACK'ed quickly!
430  chunk->ibit = sctpMain->sackNow;
431 
433  chunk->hasBeenMoved = (lastPath != path);
434 
435  // Restart T3 timer on its old path, if it is scheduled
436  if (lastPath->T3_RtxTimer->isScheduled()) {
437  // Stop timer, if path is empty now.
438  // Else, keep it running, without reset!
439  if (lastPath->queuedBytes == 0) {
440  stopTimer(lastPath->T3_RtxTimer);
441  }
442  }
443 
444  // ====== Handle Congestion Control =======================
445  if (state->cmtMovedChunksReduceCwnd == true) {
446  if (lastPath != path) {
447  if ((lastPath->blockingTimeout >= 0.0) &&
448  (simTime() < lastPath->blockingTimeout))
449  {
450  // Path is already blocked
451  EV << simTime() << "\tCR-3 on path "
452  << lastPath->remoteAddress << " (blocked until "
453  << lastPath->blockingTimeout << ")" << endl;
454  }
455  else if (lastPath->fastRecoveryActive) {
456  // A further problem during Fast Recovery -> block path
457  const simtime_t pause = lastPath->srtt;
458  lastPath->blockingTimeout = simTime() + pause;
459  assert(!lastPath->BlockingTimer->isScheduled());
460  startTimer(lastPath->BlockingTimer, pause);
461  EV << simTime() << "\tCR-2 on path "
462  << lastPath->remoteAddress << " (pause="
463  << pause << "; blocked until "
464  << lastPath->blockingTimeout << ")" << endl;
465  }
466  else {
467  // Go into Fast Recovery mode ...
468  lastPath->requiresRtx = true;
469  (this->*ccFunctions.ccUpdateBeforeSack)();
470  (this->*ccFunctions.ccUpdateAfterSack)();
471  lastPath->requiresRtx = false;
472  EV << simTime() << "\tCR-1 on path "
473  << lastPath->remoteAddress << endl;
474  }
475  }
476  else {
477  EV << simTime() << "\tCR-4 on path "
478  << path->remoteAddress << " (lastTX="
479  << simTime() - chunk->sendTime
480  << ", TSN " << chunk->tsn << ")" << endl;
481 
482  lastPath->requiresRtx = true;
483  (this->*ccFunctions.ccUpdateBeforeSack)();
484  (this->*ccFunctions.ccUpdateAfterSack)();
485  lastPath->requiresRtx = false;
486  }
487  }
488  }
489  }
490  }
491  }
492  }
493  // ====== Test ===========================================================
495  abort();
496  }
497 }

Referenced by sendOnPath().

◆ chunkToInt()

uint16_t inet::sctp::SctpAssociation::chunkToInt ( const char *  type)
static
238 {
239  EV_STATICCONTEXT;
240 
241  if (strcmp(type, "DATA") == 0)
242  return DATA;
243  if (strcmp(type, "INIT") == 0)
244  return INIT;
245  if (strcmp(type, "INIT_ACK") == 0)
246  return INIT_ACK;
247  if (strcmp(type, "SACK") == 0)
248  return SACK;
249  if (strcmp(type, "HEARTBEAT") == 0)
250  return HEARTBEAT;
251  if (strcmp(type, "HEARTBEAT_ACK") == 0)
252  return HEARTBEAT_ACK;
253  if (strcmp(type, "ABORT") == 0)
254  return ABORT;
255  if (strcmp(type, "SHUTDOWN") == 0)
256  return SHUTDOWN;
257  if (strcmp(type, "SHUTDOWN_ACK") == 0)
258  return SHUTDOWN_ACK;
259  if (strcmp(type, "ERRORTYPE") == 0)
260  return ERRORTYPE;
261  if (strcmp(type, "COOKIE_ECHO") == 0)
262  return COOKIE_ECHO;
263  if (strcmp(type, "COOKIE_ACK") == 0)
264  return COOKIE_ACK;
265  if (strcmp(type, "SHUTDOWN_COMPLETE") == 0)
266  return SHUTDOWN_COMPLETE;
267  if (strcmp(type, "AUTH") == 0)
268  return AUTH;
269  if (strcmp(type, "NR-SACK") == 0)
270  return NR_SACK;
271  if (strcmp(type, "ASCONF_ACK") == 0)
272  return ASCONF_ACK;
273  if (strcmp(type, "PKTDROP") == 0)
274  return PKTDROP;
275  if (strcmp(type, "RE_CONFIG") == 0)
276  return RE_CONFIG;
277  if (strcmp(type, "FORWARD_TSN") == 0)
278  return FORWARD_TSN;
279  if (strcmp(type, "ASCONF") == 0)
280  return ASCONF;
281  if (strcmp(type, "IFORWARD_TSN") == 0)
282  return IFORWARD_TSN;
283  EV_WARN << "ChunkConversion not successful\n";
284  return 0xffff;
285 }

Referenced by cloneAssociation(), and initAssociation().

◆ cloneAssociation()

SctpAssociation * inet::sctp::SctpAssociation::cloneAssociation ( )
protected

Utility: clone a listening association.

Used for forking.

305 {
307  const char *queueClass = transmissionQ->getClassName();
308  assoc->transmissionQ = check_and_cast<SctpQueue *>(inet::utils::createOne(queueClass));
309  assoc->retransmissionQ = check_and_cast<SctpQueue *>(inet::utils::createOne(queueClass));
310 
311  const char *sctpAlgorithmClass = sctpAlgorithm->getClassName();
312  assoc->sctpAlgorithm = check_and_cast<SctpAlgorithm *>(inet::utils::createOne(sctpAlgorithmClass));
313  assoc->sctpAlgorithm->setAssociation(assoc);
314  assoc->sctpAlgorithm->initialize();
315  assoc->state = assoc->sctpAlgorithm->createStateVariables();
316 
317  if (sctpMain->par("auth").boolValue()) {
318  const char *chunks = sctpMain->par("chunks");
319  bool asc = false;
320  bool asca = false;
321  char *chunkscopy = (char *)malloc(strlen(chunks) + 1);
322  strcpy(chunkscopy, chunks);
323  char *token;
324  token = strtok(chunkscopy, ",");
325  while (token != nullptr) {
326  if (chunkToInt(token) == ASCONF)
327  asc = true;
328  if (chunkToInt(token) == ASCONF_ACK)
329  asca = true;
330  if (!typeInOwnChunkList(chunkToInt(token))) {
331  this->state->chunkList.push_back(chunkToInt(token));
332  }
333  token = strtok(nullptr, ",");
334  }
335  if (sctpMain->par("addIP").boolValue()) {
336  if (!asc && !typeInOwnChunkList(ASCONF))
337  state->chunkList.push_back(ASCONF);
338  if (!asca && !typeInOwnChunkList(ASCONF_ACK))
339  state->chunkList.push_back(ASCONF_ACK);
340  }
341  free(chunkscopy);
342  }
343 
344  assoc->state->active = false;
345  assoc->state->fork = true;
346  assoc->localAddr = localAddr;
347  assoc->localPort = localPort;
348  assoc->localAddressList = localAddressList;
349  assoc->listening = true;
350 
351  assoc->outboundStreams = outboundStreams;
352  assoc->inboundStreams = inboundStreams;
353  assoc->fd = fd;
354 
355  FSM_Goto((*assoc->fsm), SCTP_S_CLOSED);
357  return assoc;
358 }

Referenced by processInitArrived().

◆ compareRandom()

bool inet::sctp::SctpAssociation::compareRandom ( )
protected
227 {
228  int32_t i, sizeKeyVector, sizePeerKeyVector, size = 0;
229 
230  sizeKeyVector = state->sizeKeyVector;
231  sizePeerKeyVector = state->sizePeerKeyVector;
232 
233  if (sizeKeyVector != sizePeerKeyVector) {
234  if (sizePeerKeyVector > sizeKeyVector) {
235  size = sizeKeyVector;
236  for (i = sizePeerKeyVector - 1; i > sizeKeyVector; i--) {
237  if (state->peerKeyVector[i] != 0)
238  return false;
239  }
240  }
241  else {
242  size = sizePeerKeyVector;
243  for (i = sizeKeyVector - 1; i > sizePeerKeyVector; i--) {
244  if (state->keyVector[i] != 0)
245  return true;
246  }
247  }
248  }
249  else
250  size = sizeKeyVector;
251  for (i = size - 1; i > 0; i--) {
252  if (state->keyVector[i] < state->peerKeyVector[i])
253  return false;
254  if (state->keyVector[i] > state->peerKeyVector[i])
255  return true;
256  }
257  return true;
258 }

Referenced by calculateAssocSharedKey().

◆ createAsconfAckChunk()

SctpAsconfAckChunk * inet::sctp::SctpAssociation::createAsconfAckChunk ( uint32_t  serialNumber)
protected
202 {
203  SctpAsconfAckChunk *asconfAckChunk = new SctpAsconfAckChunk();
204  asconfAckChunk->setSctpChunkType(ASCONF_ACK);
205  asconfAckChunk->setSerialNumber(serialNumber);
206  asconfAckChunk->setByteLength(SCTP_ADD_IP_CHUNK_LENGTH);
207  return asconfAckChunk;
208 }

Referenced by processAsconfArrived().

◆ createAuthChunk()

SctpAuthenticationChunk * inet::sctp::SctpAssociation::createAuthChunk ( )
protected
211 {
212  SctpAuthenticationChunk *authChunk = new SctpAuthenticationChunk();
213 
214  authChunk->setSctpChunkType(AUTH);
215  authChunk->setSharedKey(0);
216  authChunk->setHMacIdentifier(1);
217  authChunk->setHMacOk(true);
218  authChunk->setHMACArraySize(SHA_LENGTH);
219  for (int32_t i = 0; i < SHA_LENGTH; i++) {
220  authChunk->setHMAC(i, 0);
221  }
222  authChunk->setByteLength(SCTP_AUTH_CHUNK_LENGTH + SHA_LENGTH);
223  return authChunk;
224 }

Referenced by processAsconfArrived(), processPacketDropArrived(), retransmitAsconf(), retransmitCookieEcho(), sendAbort(), sendAsconf(), sendAsconfAck(), sendCookieAck(), sendCookieEcho(), sendHeartbeat(), sendHeartbeatAck(), sendInvalidStreamError(), sendSack(), and sendShutdown().

◆ createForwardTsnChunk()

SctpForwardTsnChunk * inet::sctp::SctpAssociation::createForwardTsnChunk ( const L3Address pid)
protected
1350 {
1351  uint16_t chunkLength = SCTP_FORWARD_TSN_CHUNK_LENGTH;
1352  SctpDataVariables *chunk;
1353  typedef std::map<uint16_t, int16_t> SidMap;
1354  SidMap sidMap;
1355 
1356  EV_INFO << "Create forwardTsnChunk for " << pid << "\n";
1357  SctpForwardTsnChunk *forwChunk = new SctpForwardTsnChunk();
1358  forwChunk->setSctpChunkType(FORWARD_TSN);
1359  advancePeerTsn();
1360  forwChunk->setNewCumTsn(state->advancedPeerAckPoint);
1361  for (auto& elem : retransmissionQ->payloadQueue) {
1362  chunk = elem.second;
1363  EV_DETAIL << "tsn=" << chunk->tsn << " lastDestination=" << chunk->getLastDestination() << " abandoned=" << chunk->hasBeenAbandoned << "\n";
1364  if (chunk->getLastDestination() == pid && chunk->hasBeenAbandoned && chunk->tsn <= forwChunk->getNewCumTsn()) {
1365  if (chunk->ordered) {
1366  sidMap[chunk->sid] = chunk->ssn;
1367  }
1368  else {
1369  sidMap[chunk->sid] = -1;
1370  }
1371  /* Fake chunk retransmission */
1372  if (chunk->sendForwardIfAbandoned) {
1373  chunk->gapReports = 0;
1374  chunk->hasBeenFastRetransmitted = false;
1375  chunk->sendTime = simTime();
1376  chunk->numberOfRetransmissions++;
1377  chunk->sendForwardIfAbandoned = false;
1378 
1379  auto itt = transmissionQ->payloadQueue.find(chunk->tsn);
1380  if (itt != transmissionQ->payloadQueue.end()) {
1381  transmissionQ->payloadQueue.erase(itt);
1382  chunk->enqueuedInTransmissionQ = false;
1383  auto i = qCounter.roomTransQ.find(pid);
1384  i->second -= ADD_PADDING(chunk->len / 8 + SCTP_DATA_CHUNK_LENGTH);
1385  auto ib = qCounter.bookedTransQ.find(pid);
1386  ib->second -= chunk->booksize;
1387  }
1388  }
1389  }
1390  }
1391  forwChunk->setSidArraySize(sidMap.size());
1392  forwChunk->setSsnArraySize(sidMap.size());
1393  int32_t i = 0;
1394  for (auto& elem : sidMap) {
1395  forwChunk->setSid(i, elem.first);
1396  forwChunk->setSsn(i, elem.second);
1397  chunkLength += 4;
1398  i++;
1399  }
1400  forwChunk->setByteLength(chunkLength);
1401  auto iter = sctpMain->assocStatMap.find(assocId);
1402  iter->second.numForwardTsn++;
1403  return forwChunk;
1404 }

Referenced by processPacketDropArrived(), and sendOnPath().

◆ createSack()

SctpSackChunk * inet::sctp::SctpAssociation::createSack ( )
protected
1538 {
1539  EV_INFO << simTime() << "SctpAssociationUtil:createSACK localAddress=" << localAddr << " remoteAddress=" << remoteAddr << "\n";
1540 
1541  EV_INFO << " localRwnd=" << state->localRwnd << " queuedBytes=" << state->queuedReceivedBytes << "\n";
1542 
1543  // ====== Get receiver window size to be advertised ======================
1544  uint32_t arwnd = 0;
1545  uint32_t msgRwnd = 0;
1547  if ((state->messageAcceptLimit > 0 && (int32_t)(state->localMsgRwnd - state->bufferedMessages) <= 0)
1549  {
1550  msgRwnd = 0;
1551  }
1552  else if ((state->messageAcceptLimit > 0 && (int32_t)(state->localMsgRwnd - state->bufferedMessages) < 3)
1554  {
1555  msgRwnd = 1;
1556  state->swsMsgInvoked = true;
1557  }
1558  else {
1559  if (state->messageAcceptLimit > 0) {
1560  msgRwnd = state->localMsgRwnd - state->bufferedMessages;
1561  }
1562  else {
1563  msgRwnd = state->localRwnd
1566  }
1567  }
1568  if (state->tellArwnd) {
1569  arwnd = msgRwnd;
1570  }
1571  else {
1572  // ====== Receiver buffer is full =====================================
1573  if ((int32_t)(state->localRwnd - state->queuedReceivedBytes) <= 0) {
1574  arwnd = 0;
1575  if (state->swsLimit > 0) {
1576  state->swsAvoidanceInvoked = true;
1577  }
1578  }
1579  // ====== Silly window syndrome avoidance =============================
1580  else if ((state->localRwnd - state->queuedReceivedBytes < state->swsLimit) ||
1581  (state->swsAvoidanceInvoked == true))
1582  {
1583  arwnd = 1;
1584  if (state->swsLimit > 0)
1585  state->swsAvoidanceInvoked = true;
1586  EV_DETAIL << "arwnd=1; createSack : SWS Avoidance ACTIVE !!!\n";
1587  }
1588  // ====== There is space in the receiver buffer =======================
1589  else {
1591  EV_DETAIL << simTime() << " arwnd = " << state->localRwnd << " - " << state->queuedReceivedBytes << " = " << arwnd << "\n";
1592  }
1593  }
1594 
1595  // ====== Record statistics ==============================================
1596  if (state->messageAcceptLimit > 0) {
1597  advMsgRwnd->record(msgRwnd);
1598  }
1600  advRwnd->record(arwnd);
1601 
1602  // ====== Create SACK chunk ==============================================
1603  SctpSackChunk *sackChunk = new SctpSackChunk();
1604  if (state->nrSack == true) {
1605  sackChunk->setSctpChunkType(NR_SACK);
1606 // sackChunk->setName("NR_SACK");
1607  }
1608  else {
1609  sackChunk->setSctpChunkType(SACK);
1610  }
1611  sackChunk->setCumTsnAck(state->gapList.getCumAckTsn());
1612  EV_DEBUG << "SACK: set cumTsnAck to " << sackChunk->getCumTsnAck() << endl;
1613  sackChunk->setA_rwnd(arwnd);
1614  sackChunk->setIsNrSack(state->nrSack);
1615  sackChunk->setSackSeqNum(++state->outgoingSackSeqNum);
1616  if (state->messageAcceptLimit > 0) {
1617  sackChunk->setMsg_rwnd(state->messageAcceptLimit - state->bufferedMessages);
1618  }
1619  else {
1620  sackChunk->setMsg_rwnd(0);
1621  }
1622 
1623  // ====== What has to be stored in the SACK? =============================
1624  const uint32_t mtu = getPath(remoteAddr)->pmtu;
1625 
1626  uint32_t hdrSize;
1628  hdrSize = 40;
1629  else if (remoteAddr.getType() == L3Address::IPv4)
1630  hdrSize = 20;
1631  else
1632  throw cRuntimeError("Unknown address type");
1633 
1634  const uint32_t allowedLength = mtu
1635  - hdrSize
1638  uint32_t numDups = state->dupList.size();
1639  uint32_t numRevokableGaps = state->gapList.getNumGaps(SctpGapList::GT_Revokable);
1640  uint32_t numNonRevokableGaps = state->gapList.getNumGaps(SctpGapList::GT_NonRevokable);
1641  size_t revokableGapsSpace = ~0;
1642  size_t nonRevokableGapsSpace = ~0;
1643  size_t sackHeaderLength = ~0;
1644  const uint32_t totalGaps = state->gapList.getNumGaps(SctpGapList::GT_Any);
1645  bool compression = false;
1646 
1647  // ====== Record statistics ==============================================
1648  statisticsNumTotalGapBlocksStored->record(totalGaps);
1649  statisticsNumRevokableGapBlocksStored->record(numRevokableGaps);
1650  statisticsNumNonRevokableGapBlocksStored->record(numNonRevokableGaps);
1651  statisticsNumDuplicatesStored->record(numDups);
1652 
1653  // ====== Optimization ===================================================
1654  const int optR = (int)numRevokableGaps - (int)totalGaps;
1655  const int optNR = (int)numNonRevokableGaps - (int)totalGaps;
1656 
1658  ((numRevokableGaps > 0) || (numNonRevokableGaps > 0)))
1659  {
1660  compression = true;
1661  }
1662 
1663  // ------ Optimization 1: R=ANY, NR=non-revokable ------
1664  if ((state->nrSack == true) &&
1666  ((optR > 0) && (optR >= optNR) && (state->gapListOptimizationVariant >= SctpStateVariables::GLOV_Optimized2))))
1667  {
1668  assert(totalGaps < numRevokableGaps);
1669  sackHeaderLength = (compression == true) ? SCTP_COMPRESSED_NRSACK_CHUNK_LENGTH : SCTP_NRSACK_CHUNK_LENGTH;
1670  numRevokableGaps = copyToRGaps(sackChunk, &state->gapList, SctpGapList::GT_Any, compression, revokableGapsSpace); // Add ALL
1671  numNonRevokableGaps = copyToNRGaps(sackChunk, &state->gapList, SctpGapList::GT_NonRevokable, compression, nonRevokableGapsSpace); // Add NR-acks only
1672  assert(numRevokableGaps == totalGaps);
1673 // opt += optR;
1674  }
1675  // ------ Optimization 2: NR=ANY, R=difference ---------
1676  else if ((state->nrSack == true) &&
1678  {
1679  assert(totalGaps < numNonRevokableGaps);
1680  sackChunk->setNrSubtractRGaps(true);
1681  sackHeaderLength = (compression == true) ? SCTP_COMPRESSED_NRSACK_CHUNK_LENGTH : SCTP_NRSACK_CHUNK_LENGTH;
1682  numRevokableGaps = copyToRGaps(sackChunk, &state->gapList, SctpGapList::GT_Revokable, compression, revokableGapsSpace); // Add R-acks only
1683  numNonRevokableGaps = copyToNRGaps(sackChunk, &state->gapList, SctpGapList::GT_Any, compression, nonRevokableGapsSpace); // Add ALL
1684  assert(numNonRevokableGaps == totalGaps);
1685 // opt += optNR;
1686  }
1687  else {
1688  // ------ Regular NR-SACK ---------------------------
1689  if (state->nrSack == true) {
1690  sackHeaderLength = SCTP_NRSACK_CHUNK_LENGTH;
1691  if (compression == true) {
1692  sackHeaderLength = SCTP_COMPRESSED_NRSACK_CHUNK_LENGTH;
1693  }
1694  numRevokableGaps = copyToRGaps(sackChunk, &state->gapList, SctpGapList::GT_Revokable, compression, revokableGapsSpace); // Add R-acks only
1695  numNonRevokableGaps = copyToNRGaps(sackChunk, &state->gapList, SctpGapList::GT_NonRevokable, compression, nonRevokableGapsSpace); // Add NR-acks only
1696  }
1697  // ------ Regular SACK ------------------------------
1698  else {
1699  sackHeaderLength = SCTP_SACK_CHUNK_LENGTH;
1700  numRevokableGaps = copyToRGaps(sackChunk, &state->gapList, SctpGapList::GT_Any, false, revokableGapsSpace); // Add ALL
1701  numNonRevokableGaps = 0;
1702  nonRevokableGapsSpace = 0;
1703  }
1704  }
1705 
1706  // ====== SACK has to be shortened to fit in MTU ===========================
1707  uint32_t sackLength = sackHeaderLength + revokableGapsSpace + nonRevokableGapsSpace + numDups * 4;
1708  if (sackLength > allowedLength) {
1709  // Strategy to reduce the SACK size:
1710  // - Report no duplicates (they are not used for congestion control)
1711  // - Split the remaining space equally between
1712  // revokable and non-revokable GapAcks
1713 
1714  // ====== Drop duplicates list ========================================
1715  numDups = 0;
1716  sackLength -= 4 * numDups;
1717 
1718  if (sackLength > allowedLength) {
1719  // Unfortunately, dropping the duplicates has not solved the problem.
1720  // => Now, the gap lists have to be shortened!
1721 
1722  auto iter = sctpMain->assocStatMap.find(assocId);
1723  iter->second.numOverfullSACKs++;
1724  // ====== Undo NR optimization ====================================
1725  if (sackChunk->getNrSubtractRGaps() == true) {
1726  sackChunk->setNrSubtractRGaps(false); // Unset SubtractRGaps!
1727  // This optimization cannot work when lists have to be shortened.
1728  // Just use regular NR list.
1729  }
1730  revokableGapsSpace = allowedLength - sackHeaderLength;
1731  if (totalGaps < (state->gapList.getNumGaps(SctpGapList::GT_Revokable))) {
1732  numRevokableGaps = copyToRGaps(sackChunk, &state->gapList, SctpGapList::GT_Any, compression, revokableGapsSpace); // Add ALL
1733  }
1734  else {
1735  numRevokableGaps = copyToRGaps(sackChunk, &state->gapList, SctpGapList::GT_Revokable, compression, revokableGapsSpace); // Add R-acks only
1736  }
1737  sackLength = sackHeaderLength + revokableGapsSpace + nonRevokableGapsSpace + numDups * 4;
1738 
1739  // ====== Shorten gap lists ========================================
1741  if (sackHeaderLength + revokableGapsSpace < allowedLength) {
1742  // Fill NR-acks up to allowed size
1743  nonRevokableGapsSpace = allowedLength - sackHeaderLength - revokableGapsSpace;
1744  numNonRevokableGaps = copyToNRGaps(sackChunk, &state->gapList, SctpGapList::GT_NonRevokable, compression, nonRevokableGapsSpace); // Add NR-acks only
1745  sackLength = sackHeaderLength + revokableGapsSpace + nonRevokableGapsSpace + numDups * 4;
1746  }
1747  else {
1748  // Not even space to set R-acks => cut R-acks, no NR-acks!
1749  nonRevokableGapsSpace = allowedLength - sackHeaderLength;
1750  numRevokableGaps = copyToRGaps(sackChunk, &state->gapList, SctpGapList::GT_Any, compression, revokableGapsSpace); // Add ALL
1751  }
1752  }
1753  else {
1754  if (sackLength > allowedLength) {
1755  double revokableFraction = 1.0;
1756  const uint32_t blocksBeRemoved = (sackLength - allowedLength) / 4;
1757  if (numRevokableGaps + numNonRevokableGaps > 0) {
1758  revokableFraction = numRevokableGaps / (double)(numRevokableGaps + numNonRevokableGaps);
1759  }
1760  const uint32_t removeRevokable = (uint32_t)ceil(blocksBeRemoved * revokableFraction);
1761  const uint32_t removeNonRevokable = (uint32_t)ceil(blocksBeRemoved * (1.0 - revokableFraction));
1762  numRevokableGaps -= std::min(removeRevokable, numRevokableGaps);
1763  numNonRevokableGaps -= std::min(removeNonRevokable, numNonRevokableGaps);
1764  revokableGapsSpace = 4 * numRevokableGaps;
1765  nonRevokableGapsSpace = 4 * numNonRevokableGaps;
1766  numRevokableGaps = copyToRGaps(sackChunk, &state->gapList, SctpGapList::GT_Revokable, compression, revokableGapsSpace); // Add R-acks only
1767  numNonRevokableGaps = copyToNRGaps(sackChunk, &state->gapList, SctpGapList::GT_NonRevokable, compression, nonRevokableGapsSpace); // Add NR-acks only
1768  sackLength = sackHeaderLength + revokableGapsSpace + nonRevokableGapsSpace + numDups * 4;
1769  }
1770  }
1771 
1772  assert(sackLength <= allowedLength);
1773 
1774  // Update values in SACK chunk ...
1775  sackChunk->setNumGaps(numRevokableGaps);
1776  sackChunk->setNumNrGaps(numNonRevokableGaps);
1777  }
1778  }
1779  sackChunk->setNumDupTsns(numDups);
1780  sackChunk->setByteLength(sackLength);
1781 
1782  // ====== Apply limit ====================================================
1783  if (state->gapReportLimit < 1000000) {
1784  if (!compression) {
1785  numRevokableGaps = std::min(numRevokableGaps, state->gapReportLimit);
1786  numNonRevokableGaps = std::min(numNonRevokableGaps, state->gapReportLimit);
1787  // Update values in SACK chunk ...
1788  sackChunk->setNumGaps(numRevokableGaps);
1789  sackChunk->setNumNrGaps(numNonRevokableGaps);
1790  sackLength = sackHeaderLength + revokableGapsSpace + nonRevokableGapsSpace + numDups * 4;
1791  }
1792  else {
1793  assert(false); // NOTE: IMPLEMENT ME!
1794  }
1795  }
1796 
1797  // ====== Add duplicates =================================================
1798  if (numDups > 0) {
1799  sackChunk->setDupTsnsArraySize(numDups);
1800  uint32_t key = 0;
1801  for (auto& elem : state->dupList) {
1802  sackChunk->setDupTsns(key, elem);
1803  key++;
1804  if (key == numDups)
1805  break;
1806  }
1807  state->dupList.clear();
1808  }
1809 
1810  // ====== Record statistics ==============================================
1811  statisticsSACKLengthSent->record(sackLength);
1812  statisticsNumRevokableGapBlocksSent->record(numRevokableGaps);
1813  statisticsNumNonRevokableGapBlocksSent->record(numNonRevokableGaps);
1814  statisticsNumDuplicatesSent->record(numDups);
1815 
1816  // ====== Print information ==============================================
1817  EV_DEBUG << "createSack:"
1818  << " bufferedMessages=" << state->bufferedMessages
1819  << " msgRwnd=" << msgRwnd
1820  << " arwnd=" << sackChunk->getA_rwnd()
1821  << " cumAck=" << state->gapList.getCumAckTsn()
1822  << " numRGaps=" << numRevokableGaps
1823  << " numNRGaps=" << numNonRevokableGaps
1824  << " numDups=" << numDups
1825  << " gapList={" << state->gapList << "}"
1826  << endl;
1827  return sackChunk;
1828 }

Referenced by sendInvalidStreamError(), sendOnPath(), sendSack(), and sendStreamResetResponse().

◆ createSuccessIndication()

SctpSuccessIndication * inet::sctp::SctpAssociation::createSuccessIndication ( uint32_t  correlationId)
protected
298 {
299  SctpSuccessIndication *success = new SctpSuccessIndication();
300 
301  success->setParameterType(SUCCESS_INDICATION);
302  success->setResponseCorrelationId(correlationId);
303  success->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH);
304  return success;
305 }

Referenced by processAsconfArrived().

◆ cucProcessGapReports()

void inet::sctp::SctpAssociation::cucProcessGapReports ( const SctpDataVariables chunk,
SctpPathVariables path,
const bool  isAcked 
)
protected
938 {
939  // We only care for newly acked chunks.
940  // Therefore, the previous state must be "unacked".
941  if (chunkHasBeenAcked(chunk) == false) {
942  // For CUCv2, it has to be checked whether it is the first transmission.
943  // Otherwise, the behaviour will be like CUCv1 -> decreasing PseudoCumAck on T3 RTX!
944  if ((path->findPseudoCumAck == true) &&
945  ((chunk->numberOfRetransmissions == 0) ||
947  {
948  path->pseudoCumAck = chunk->tsn;
949  path->findPseudoCumAck = false;
950  }
951  if ((isAcked) && /* Not acked before and acked now => ack for the first time */
952  (path->pseudoCumAck == chunk->tsn))
953  {
954  path->newPseudoCumAck = true;
955  path->findPseudoCumAck = true;
956  }
957 
958  // CUCv2
959  if ((path->findRTXPseudoCumAck == true) &&
960  (chunk->numberOfRetransmissions > 0))
961  {
962  path->rtxPseudoCumAck = chunk->tsn;
963  path->findRTXPseudoCumAck = false;
964  }
965  if ((isAcked) && /* Not acked before and acked now => ack for the first time */
966  (path->rtxPseudoCumAck == chunk->tsn))
967  {
968  path->newRTXPseudoCumAck = true;
969  path->findRTXPseudoCumAck = true;
970  }
971  }
972 }

Referenced by processSackArrived().

◆ cwndUpdateAfterCwndTimeout()

void inet::sctp::SctpAssociation::cwndUpdateAfterCwndTimeout ( SctpPathVariables path)
protected
979 {
980  // When the association does not transmit data on a given transport address
981  // within an RTO, the cwnd of the transport address SHOULD be adjusted to 2*MTU.
982  EV_INFO << assocId << ": " << simTime() << ":\tCC [cwndUpdateAfterCwndTimeout]\t" << path->remoteAddress
983  << " (cmtCCGroup=" << path->cmtCCGroup << ")"
984  << "\tsst=" << path->ssthresh
985  << "\tcwnd=" << path->cwnd;
986  path->cwnd = getInitialCwnd(path);
987  EV_INFO << "\t=>\tsst=" << path->ssthresh
988  << "\tcwnd=" << path->cwnd << endl;
989  recordCwndUpdate(path);
990 }

Referenced by stateEntered().

◆ cwndUpdateAfterRtxTimeout()

void inet::sctp::SctpAssociation::cwndUpdateAfterRtxTimeout ( SctpPathVariables path)
protected
831 {
832  double decreaseFactor = 0.5;
833  path->oliaSentBytes = 0;
834  EV << assocId << ": " << simTime() << ":\tCC [cwndUpdateAfterRtxTimeout]\t" << path->remoteAddress
835  << " (cmtCCGroup=" << path->cmtCCGroup << ")"
836  << "\tsst=" << path->ssthresh
837  << "\tcwnd=" << path->cwnd
838  << "\tSST=" << path->cmtGroupTotalSsthresh
839  << "\tCWND=" << path->cmtGroupTotalCwnd
840  << "\tBW.CWND=" << path->cmtGroupTotalCwndBandwidth;
841  if (state->highSpeedCC == true) {
842  decreaseFactor = HighSpeedCwndAdjustmentTable[path->highSpeedCCThresholdIdx].decreaseFactor;
843  EV << "\tHighSpeedDecreaseFactor=" << decreaseFactor;
844  }
845 
846  // ====== SCTP or CMT-SCTP (independent congestion control) ==============
847  if ((state->allowCMT == false) || (state->cmtCCVariant == SctpStateVariables::CCCV_CMT)) {
848  path->ssthresh = max((int32_t)path->cwnd - (int32_t)rint(decreaseFactor * (double)path->cwnd),
849  4 * (int32_t)path->pmtu);
850  path->cwnd = path->pmtu;
851  }
852  // ====== Resource Pooling RTX Timeout ===================================
853  else {
854  // ====== CMT/RPv1-SCTP RTX Timeout ===================================
856  const double sstRatio = (double)path->ssthresh / (double)path->cmtGroupTotalSsthresh;
857  const int32_t decreasedWindow = (int32_t)path->cwnd - (int32_t)rint(path->cmtGroupTotalCwnd * decreaseFactor);
858  path->ssthresh = max(decreasedWindow,
859  max((int32_t)path->pmtu,
860  (int32_t)ceil((double)state->rpMinCwnd * (double)path->pmtu * sstRatio)));
861  path->cwnd = max((int32_t)path->pmtu,
862  (int32_t)ceil((double)path->pmtu * sstRatio));
863  }
864  // ====== CMT/RPv2-SCTP RTX Timeout ===================================
866  const double pathBandwidth = path->cwnd / GET_SRTT(path->srtt.dbl());
867  const double bandwidthToGive = path->cmtGroupTotalCwndBandwidth / 2.0;
868  const double reductionFactor = max(0.5, bandwidthToGive / pathBandwidth);
869 
870  path->ssthresh = (int32_t)max((int32_t)state->rpMinCwnd * (int32_t)path->pmtu,
871  (int32_t)ceil(path->cwnd - reductionFactor * path->cwnd));
872  path->cwnd = path->pmtu;
873  }
874  // ====== Like MPTCP RTX Timeout ======================================
876  path->ssthresh = max((int32_t)path->cwnd - (int32_t)rint(decreaseFactor * (double)path->cwnd),
877  (int32_t)state->rpMinCwnd * (int32_t)path->pmtu);
878  path->cwnd = path->pmtu;
879  }
881  // like draft
882  path->ssthresh = max((int32_t)path->cwnd - (int32_t)rint(decreaseFactor * (double)path->cwnd),
883  4 * (int32_t)path->pmtu);
884  path->cwnd = path->pmtu;
885  }
886  // ====== TEST RTX Timeout ============================================
888  const double pathBandwidth = path->cwnd / GET_SRTT(path->srtt.dbl());
889  const double bandwidthToGive = path->cmtGroupTotalCwndBandwidth / 2.0;
890  const double reductionFactor = max(0.5, bandwidthToGive / pathBandwidth);
891 
892  path->ssthresh = (int32_t)max((int32_t)state->rpMinCwnd * (int32_t)path->pmtu,
893  (int32_t)ceil(path->cwnd - reductionFactor * path->cwnd));
894  path->cwnd = path->pmtu;
895  }
896  // ====== Like MPTCP RTX Timeout ======================================
898  path->ssthresh = max((int32_t)path->cwnd - (int32_t)rint(decreaseFactor * (double)path->cwnd),
899  (int32_t)state->rpMinCwnd * (int32_t)path->pmtu);
900  path->cwnd = path->pmtu;
901  }
902  // ====== Other -> error ==============================================
903  else {
904  throw cRuntimeError("Implementation for this cmtCCVariant is missing!");
905  }
906  }
907  path->highSpeedCCThresholdIdx = 0;
908  path->partialBytesAcked = 0;
909  path->vectorPathPbAcked->record(path->partialBytesAcked);
910  EV_INFO << "\t=>\tsst=" << path->ssthresh
911  << "\tcwnd=" << path->cwnd << endl;
912  recordCwndUpdate(path);
913 
914  // Leave Fast Recovery mode
915  if (path->fastRecoveryActive == true) {
916  path->fastRecoveryActive = false;
917  path->fastRecoveryExitPoint = 0;
918  path->vectorPathFastRecoveryState->record(0);
919  }
920 }

Referenced by stateEntered().

◆ cwndUpdateAfterSack()

void inet::sctp::SctpAssociation::cwndUpdateAfterSack ( )
protected
434 {
435  for (auto iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) {
436  SctpPathVariables *path = iter->second;
437  if (path->fastRecoveryActive == false) {
438  // ====== Retransmission required -> reduce congestion window ======
439  if (path->requiresRtx) {
440  double decreaseFactor = 0.5;
441  EV << assocId << ": " << simTime() << ":\tCC [cwndUpdateAfterSack]\t" << path->remoteAddress
442  << " (cmtCCGroup=" << path->cmtCCGroup << ")"
443  << "\tsst=" << path->ssthresh
444  << "\tcwnd=" << path->cwnd
445  << "\tSST=" << path->cmtGroupTotalSsthresh
446  << "\tCWND=" << path->cmtGroupTotalCwnd
447  << "\tBW.CWND=" << path->cmtGroupTotalCwndBandwidth;
448  if (state->highSpeedCC == true) {
449  decreaseFactor = HighSpeedCwndAdjustmentTable[path->highSpeedCCThresholdIdx].decreaseFactor;
450  EV << "\tHighSpeedDecreaseFactor=" << decreaseFactor;
451  }
452 
453  // ====== SCTP or CMT-SCTP (independent congestion control) =====
454  if ((state->allowCMT == false) ||
456  {
457  EV_INFO << simTime() << ":\tCC [cwndUpdateAfterSack]\t" << path->remoteAddress
458  << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd;
459 
460  path->ssthresh = max((int32_t)path->cwnd - (int32_t)rint(decreaseFactor * (double)path->cwnd),
461  4 * (int32_t)path->pmtu);
462  path->cwnd = path->ssthresh;
463  }
464  // ====== Resource Pooling ======================================
465  else {
466  // ====== CMT/RP-SCTPv1 Fast Retransmit ======================
468  const double sstRatio = (double)path->ssthresh / (double)path->cmtGroupTotalSsthresh;
469  const int32_t reducedCwnd = rpPathBlockingControl(path, rint(path->cmtGroupTotalCwnd * decreaseFactor));
470  path->ssthresh = max(reducedCwnd,
471  max((int32_t)path->pmtu,
472  (int32_t)ceil((double)state->rpMinCwnd * (double)path->pmtu * sstRatio)));
473  path->cwnd = path->ssthresh;
474  }
475  // ====== CMT/RPv2-SCTP Fast Retransmit ======================
477  // Bandwidth is based on cwnd, *not* ssthresh!
478  const double pathBandwidth = path->cwnd / GET_SRTT(path->srtt.dbl());
479  const double bandwidthToGive = path->cmtGroupTotalCwndBandwidth / 2.0;
480  const double reductionFactor = max(0.5, bandwidthToGive / pathBandwidth);
481  const int32_t reducedCwnd = rpPathBlockingControl(path, reductionFactor * path->cwnd);
482  path->ssthresh = (int32_t)max(reducedCwnd, (int32_t)state->rpMinCwnd * (int32_t)path->pmtu);
483  path->cwnd = path->ssthresh;
484  }
485  // ====== Like MPTCP Fast Retransmit =========================
487  // Just like plain CMT-SCTP ...
488  const int32_t reducedCwnd = rpPathBlockingControl(path, rint(decreaseFactor * (double)path->cwnd));
489  path->ssthresh = max(reducedCwnd, (int32_t)state->rpMinCwnd * (int32_t)path->pmtu);
490  path->cwnd = path->ssthresh;
491  }
493  // like draft
494  path->ssthresh = max((int32_t)path->cwnd - (int32_t)rint(decreaseFactor * (double)path->cwnd),
495  4 * (int32_t)path->pmtu);
496  path->cwnd = path->ssthresh;
497  }
498  // ====== TEST Fast Retransmit ===============================
500  // Bandwidth is based on cwnd, *not* ssthresh!
501  const double pathBandwidth = path->cwnd / GET_SRTT(path->srtt.dbl());
502  const double bandwidthToGive = path->cmtGroupTotalCwndBandwidth / 2.0;
503  const double reductionFactor = max(0.5, bandwidthToGive / pathBandwidth);
504  const int32_t reducedCwnd = rpPathBlockingControl(path, reductionFactor * path->cwnd);
505  path->ssthresh = (int32_t)max(reducedCwnd, (int32_t)state->rpMinCwnd * (int32_t)path->pmtu);
506  path->cwnd = path->ssthresh;
507  }
508  // ====== TEST Fast Retransmit ===============================
510  // Just like CMT-SCTP ...
511  const int32_t reducedCwnd = rpPathBlockingControl(path, rint(decreaseFactor * (double)path->cwnd));
512  path->ssthresh = max(reducedCwnd, (int32_t)state->rpMinCwnd * (int32_t)path->pmtu);
513  path->cwnd = path->ssthresh;
514  }
515  // ====== Other -> error =====================================
516  else {
517  throw cRuntimeError("Implementation for this cmtCCVariant is missing!");
518  }
519  }
520 
521  EV_INFO << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
522  recordCwndUpdate(path);
523  path->partialBytesAcked = 0;
524  path->vectorPathPbAcked->record(path->partialBytesAcked);
525  if (state->highSpeedCC == true) {
527  }
528 
529  // ====== Fast Recovery ========================================
531  uint32_t highestAckOnPath = state->lastTsnAck;
532  uint32_t highestOutstanding = state->lastTsnAck;
533  for (SctpQueue::PayloadQueue::const_iterator chunkIterator = retransmissionQ->payloadQueue.begin();
534  chunkIterator != retransmissionQ->payloadQueue.end(); chunkIterator++)
535  {
536  const SctpDataVariables *chunk = chunkIterator->second;
537  if (chunk->getLastDestinationPath() == path) {
538  if (chunkHasBeenAcked(chunk)) {
539  if (tsnGt(chunk->tsn, highestAckOnPath)) {
540  highestAckOnPath = chunk->tsn;
541  }
542  }
543  else {
544  if (tsnGt(chunk->tsn, highestOutstanding)) {
545  highestOutstanding = chunk->tsn;
546  }
547  }
548  }
549  }
550  path->oliaSentBytes = 0;
551  /* this can ONLY become TRUE, when Fast Recovery IS supported */
552  path->fastRecoveryActive = true;
553  path->fastRecoveryExitPoint = highestOutstanding;
554  path->fastRecoveryEnteringTime = simTime();
555  path->vectorPathFastRecoveryState->record(path->cwnd);
556 
557  EV_INFO << simTime() << ":\tCC [cwndUpdateAfterSack] Entering Fast Recovery on path "
558  << path->remoteAddress
559  << ", exit point is " << path->fastRecoveryExitPoint
560  << ", pseudoCumAck=" << path->pseudoCumAck
561  << ", rtxPseudoCumAck=" << path->rtxPseudoCumAck << endl;
562  }
563  }
564  }
565  else {
566  for (auto& elem : sctpPathMap) {
567  SctpPathVariables *path = elem.second;
568  if (path->fastRecoveryActive) {
569  EV_INFO << assocId << ": " << simTime() << ":\tCC [cwndUpdateAfterSack] Still in Fast Recovery on path "
570  << path->remoteAddress
571  << ", exit point is " << path->fastRecoveryExitPoint << endl;
572  }
573  }
574  }
575  }
576 }

Referenced by stateEntered().

◆ cwndUpdateBeforeSack()

void inet::sctp::SctpAssociation::cwndUpdateBeforeSack ( )
protected
134 {
135  // First, calculate per-path values.
136  for (auto& elem : sctpPathMap) {
137  SctpPathVariables *otherPath = elem.second;
138  otherPath->utilizedCwnd = otherPath->outstandingBytesBeforeUpdate;
139  }
140 
141  // Calculate per-path-group values.
142  for (auto currentPathIterator = sctpPathMap.begin();
143  currentPathIterator != sctpPathMap.end(); currentPathIterator++)
144  {
145  SctpPathVariables *currentPath = currentPathIterator->second;
146 
147  currentPath->cmtGroupPaths = 0;
148  currentPath->cmtGroupTotalCwnd = 0;
149  currentPath->cmtGroupTotalSsthresh = 0;
150  currentPath->cmtGroupTotalUtilizedCwnd = 0;
151  currentPath->cmtGroupTotalCwndBandwidth = 0.0;
152  currentPath->cmtGroupTotalUtilizedCwndBandwidth = 0.0;
153 
154  double qNumerator = 0.0;
155  double qDenominator = 0.0;
156  for (SctpPathMap::const_iterator otherPathIterator = sctpPathMap.begin();
157  otherPathIterator != sctpPathMap.end(); otherPathIterator++)
158  {
159  const SctpPathVariables *otherPath = otherPathIterator->second;
160  if (otherPath->cmtCCGroup == currentPath->cmtCCGroup) {
161  currentPath->cmtGroupPaths++;
162 
163  currentPath->cmtGroupTotalCwnd += otherPath->cwnd;
164  currentPath->cmtGroupTotalSsthresh += otherPath->ssthresh;
165  currentPath->cmtGroupTotalCwndBandwidth += otherPath->cwnd / GET_SRTT(otherPath->srtt.dbl());
166 
167  if ((otherPath->blockingTimeout < 0.0) || (otherPath->blockingTimeout < simTime())) {
168  currentPath->cmtGroupTotalUtilizedCwnd += otherPath->utilizedCwnd;
169  currentPath->cmtGroupTotalUtilizedCwndBandwidth += otherPath->utilizedCwnd / GET_SRTT(otherPath->srtt.dbl());
170  }
171 
172  qNumerator = max(qNumerator, otherPath->cwnd / (pow(GET_SRTT(otherPath->srtt.dbl()), 2.0)));
173  qDenominator = qDenominator + (otherPath->cwnd / GET_SRTT(otherPath->srtt.dbl()));
174  }
175  }
176  currentPath->cmtGroupAlpha = currentPath->cmtGroupTotalCwnd * (qNumerator / pow(qDenominator, 2.0));
177  }
178 }

Referenced by stateEntered().

◆ cwndUpdateBytesAcked()

void inet::sctp::SctpAssociation::cwndUpdateBytesAcked ( SctpPathVariables path,
uint32_t  ackedBytes,
bool  ctsnaAdvanced 
)
protected
608 {
609  EV_INFO << simTime() << "====> cwndUpdateBytesAcked:"
610  << " path=" << path->remoteAddress
611  << " ackedBytes=" << ackedBytes
612  << " ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no")
613  << " cwnd=" << path->cwnd
614  << " ssthresh=" << path->ssthresh
615  << " ackedBytes=" << ackedBytes
616  << " pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate
617  << " pathOsb=" << path->outstandingBytes
618  << endl;
619 
620  if (path->fastRecoveryActive == false) {
621  // T.D. 21.11.09: Increasing cwnd is only allowed when not being in
622  // Fast Recovery mode!
623 
624  // ====== Slow Start ==================================================
625  if (path->cwnd <= path->ssthresh) {
626  // ------ Clear PartialBytesAcked counter --------------------------
627  path->partialBytesAcked = 0;
628 
629  // ------ Increase Congestion Window -------------------------------
630  if ((ctsnaAdvanced == true) &&
631  ((path->outstandingBytesBeforeUpdate >= path->cwnd) ||
632  ((state->strictCwndBooking) && (path->outstandingBytesBeforeUpdate + path->pmtu > path->cwnd))))
633  {
634  EV_INFO << assocId << ": " << simTime() << ":\tCC [cwndUpdateBytesAcked-SlowStart]\t" << path->remoteAddress
635  << " (cmtCCGroup=" << path->cmtCCGroup << ")"
636  << "\tacked=" << ackedBytes
637  << "\tsst=" << path->ssthresh
638  << "\tcwnd=" << path->cwnd
639  << "\tSST=" << path->cmtGroupTotalSsthresh
640  << "\tCWND=" << path->cmtGroupTotalCwnd
641  << "\tBW.CWND=" << path->cmtGroupTotalCwndBandwidth;
642 
643  // ====== SCTP or CMT-SCTP (independent congestion control) =====
644  if ((state->allowCMT == false) || (state->cmtCCVariant == SctpStateVariables::CCCV_CMT)) {
645  path->cwnd += (int32_t)min(path->pmtu, ackedBytes);
646  }
647  // ====== Resource Pooling Slow Start ===========================
648  else {
649  // ====== CMT/RPv1-SCTP Slow Start ===========================
651  const double sstRatio = (double)path->ssthresh / (double)path->cmtGroupTotalSsthresh;
652  path->cwnd += (int32_t)ceil(min(path->pmtu, ackedBytes) * sstRatio);
653  }
654  // ====== CMT/RPv2-SCTP Slow Start ===========================
656  // Increase ratio based on cwnd bandwidth share!
657  const double increaseRatio = ((double)path->cwnd / GET_SRTT(path->srtt.dbl()))
658  / (double)path->cmtGroupTotalCwndBandwidth;
659  path->cwnd += (int32_t)ceil(min(path->pmtu, ackedBytes) * increaseRatio);
660  }
661  // ====== Like MPTCP Slow Start ==============================
663  // T.D. 14.08.2011: Rewrote MPTCP-Like CC code
664  path->cwnd = updateMPTCP(path->cwnd, path->cmtGroupTotalCwnd,
665  path->cmtGroupAlpha, path->pmtu, ackedBytes);
666  }
668  // OLIA see draft
669  path->cwnd = updateOLIA(path->cwnd, path->ssthresh,
670  path->cmtGroupTotalCwnd, path->cmtGroupAlpha,
671  path->pmtu, ackedBytes, path);
672  }
673  // ====== TEST Slow Start ====================================
675  // Increase ratio based on cwnd bandwidth share!
676  const double increaseRatio = ((double)path->utilizedCwnd / GET_SRTT(path->srtt.dbl()))
677  / (double)path->cmtGroupTotalUtilizedCwndBandwidth;
678  path->cwnd += (int32_t)ceil(min(path->pmtu, ackedBytes) * increaseRatio);
679  }
680  // ====== Like MPTCP Slow Start ==============================
682  path->cwnd = updateMPTCP(path->cwnd, path->cmtGroupTotalCwnd,
683  path->cmtGroupAlpha, path->pmtu, ackedBytes);
684  }
685  // ====== Other -> error =====================================
686  else {
687  throw cRuntimeError("Implementation for this cmtCCVariant is missing!");
688  }
689  }
690  path->vectorPathPbAcked->record(path->partialBytesAcked);
691  EV << "\t=>\tsst=" << path->ssthresh
692  << "\tcwnd=" << path->cwnd << endl;
693 
694  recordCwndUpdate(path);
695  }
696  // ------ No need to increase Congestion Window --------------------
697  else {
698  EV_INFO << assocId << ": " << simTime() << ":\tCC "
699  << "Not increasing cwnd of path " << path->remoteAddress << " in slow start:\t"
700  << "ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no") << "\t"
701  << "cwnd=" << path->cwnd << "\t"
702  << "ssthresh=" << path->ssthresh << "\t"
703  << "ackedBytes=" << ackedBytes << "\t"
704  << "pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << "\t"
705  << "pathOsb=" << path->outstandingBytes << "\t"
706  << "(pathOsbBeforeUpdate >= path->cwnd)="
707  << (path->outstandingBytesBeforeUpdate >= path->cwnd) << endl;
708  }
709  }
710  // ====== Congestion Avoidance ========================================
711  else {
712  // ------ Increase PartialBytesAcked counter -----------------------
713  path->partialBytesAcked += ackedBytes;
714 
715  // ------ Increase Congestion Window -------------------------------
716  double increaseFactor = 1.0;
717  if (state->highSpeedCC == true) {
719  increaseFactor = HighSpeedCwndAdjustmentTable[path->highSpeedCCThresholdIdx].increaseFactor;
720  EV << "HighSpeedCC Increase: factor=" << increaseFactor << endl;
721  }
722 
723  const bool avancedAndEnoughOutstanding =
724  (ctsnaAdvanced == true) &&
725  ((path->outstandingBytesBeforeUpdate >= path->cwnd) ||
726  ((state->strictCwndBooking) &&
727  (path->outstandingBytesBeforeUpdate + path->pmtu > path->cwnd)));
728  const bool enoughPartiallyAcked =
729  (path->partialBytesAcked >= path->cwnd) ||
730  ((state->strictCwndBooking) &&
731  (path->partialBytesAcked >= path->pmtu) &&
732  (path->partialBytesAcked + path->pmtu > path->cwnd));
733 
734  if (avancedAndEnoughOutstanding && enoughPartiallyAcked) {
735  EV << assocId << ": " << simTime() << ":\tCC [cwndUpdateBytesAcked-CgAvoidance]\t" << path->remoteAddress
736  << " (cmtCCGroup=" << path->cmtCCGroup << ")"
737  << "\tacked=" << ackedBytes
738  << "\tsst=" << path->ssthresh
739  << "\tcwnd=" << path->cwnd
740  << "\tSST=" << path->cmtGroupTotalSsthresh
741  << "\tCWND=" << path->cmtGroupTotalCwnd
742  << "\tBW.CWND=" << path->cmtGroupTotalCwndBandwidth;
743 
744  // ====== SCTP or CMT-SCTP (independent congestion control) =====
745  if ((state->allowCMT == false) || (state->cmtCCVariant == SctpStateVariables::CCCV_CMT)) {
746  path->cwnd += (int32_t)rint(increaseFactor * path->pmtu);
747  }
748  // ====== Resource Pooling Congestion Avoidance =================
749  else {
750  // ====== CMT/RP-SCTP Congestion Avoidance ===================
752  const double sstRatio = (double)path->ssthresh / (double)path->cmtGroupTotalSsthresh;
753  path->cwnd += (int32_t)ceil(increaseFactor * path->pmtu * sstRatio);
754  }
755  // ====== CMT/RPv2-SCTP Congestion Avoidance =================
757  // Increase ratio based on cwnd bandwidth share!
758  const double increaseRatio = ((double)path->cwnd / GET_SRTT(path->srtt.dbl()))
759  / (double)path->cmtGroupTotalCwndBandwidth;
760  path->cwnd += (int32_t)ceil(increaseFactor * path->pmtu * increaseRatio);
761  }
762  // ====== Like MPTCP Congestion Avoidance ====================
764  // T.D. 14.08.2011: Rewrote MPTCP-Like CC code
765  path->cwnd = updateMPTCP(path->cwnd, path->cmtGroupTotalCwnd,
766  path->cmtGroupAlpha, path->pmtu, path->pmtu);
767  }
769  // like draft
770  path->cwnd = updateOLIA(path->cwnd, path->ssthresh,
771  path->cmtGroupTotalCwnd, path->cmtGroupAlpha,
772  path->pmtu, path->pmtu, path);
773  }
774  // ====== TEST Congestion Avoidance ==========================
776  // Increase ratio based on cwnd bandwidth share!
777  const double increaseRatio = ((double)path->utilizedCwnd / GET_SRTT(path->srtt.dbl()))
778  / (double)path->cmtGroupTotalUtilizedCwndBandwidth;
779  path->cwnd += (int32_t)ceil(increaseFactor * path->pmtu * increaseRatio);
780  }
781  // ====== TEST Congestion Avoidance ==========================
783  path->cwnd = updateMPTCP(path->cwnd, path->cmtGroupTotalCwnd,
784  path->cmtGroupAlpha, path->pmtu, path->pmtu);
785  }
786  // ====== Other -> error =====================================
787  else {
788  throw cRuntimeError("Implementation for this cmtCCVariant is missing!");
789  }
790  }
791  EV << "\t=>\tsst=" << path->ssthresh
792  << "\tcwnd=" << path->cwnd << endl;
793 
794  recordCwndUpdate(path);
795  path->partialBytesAcked =
796  ((path->cwnd < path->partialBytesAcked) ?
797  (path->partialBytesAcked - path->cwnd) : 0);
798  }
799  // ------ No need to increase Congestion Window -------------------
800  else {
801  EV_INFO << assocId << ": " << simTime() << ":\tCC "
802  << "Not increasing cwnd of path " << path->remoteAddress << " in congestion avoidance: "
803  << "ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no") << "\t"
804  << "cwnd=" << path->cwnd << "\t"
805  << "ssthresh=" << path->ssthresh << "\t"
806  << "ackedBytes=" << ackedBytes << "\t"
807  << "pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << "\t"
808  << "pathOsb=" << path->outstandingBytes << "\t"
809  << "(pathOsbBeforeUpdate >= path->cwnd)="
810  << (path->outstandingBytesBeforeUpdate >= path->cwnd) << "\t"
811  << "partialBytesAcked=" << path->partialBytesAcked << "\t"
812  << "(path->partialBytesAcked >= path->cwnd)="
813  << (path->partialBytesAcked >= path->cwnd) << endl;
814  }
815  }
816 
817  // ====== Reset PartialBytesAcked counter if no more outstanding bytes
818  if (path->outstandingBytes == 0) {
819  path->partialBytesAcked = 0;
820  }
821  path->vectorPathPbAcked->record(path->partialBytesAcked);
822  }
823  else {
824  EV_INFO << assocId << ": " << simTime() << ":\tCC "
825  << "Not increasing cwnd of path " << path->remoteAddress
826  << " during Fast Recovery" << endl;
827  }
828 }

Referenced by stateEntered().

◆ cwndUpdateMaxBurst()

void inet::sctp::SctpAssociation::cwndUpdateMaxBurst ( SctpPathVariables path)
protected
923 {
928  {
929  if (path->cwnd > ((path->outstandingBytes + state->maxBurst * path->pmtu))) {
930  EV_INFO << assocId << ": " << simTime() << ":\tCC [cwndUpdateMaxBurst]\t"
931  << path->remoteAddress
932  << "\tsst=" << path->ssthresh
933  << "\tcwnd=" << path->cwnd
934  << "\ttempCwnd=" << path->tempCwnd
935  << "\tosb=" << path->outstandingBytes
936  << "\tmaxBurst=" << state->maxBurst * path->pmtu;
937 
938  // ====== Update cwnd or tempCwnd, according to MaxBurst variant ===
941  {
942  path->cwnd = path->outstandingBytes + (state->maxBurst * path->pmtu);
943  }
946  {
947  path->tempCwnd = path->outstandingBytes + (state->maxBurst * path->pmtu);
948  }
949  else {
950  assert(false);
951  }
952 
954  if (path->ssthresh < path->cwnd) {
955  path->ssthresh = path->cwnd;
956  }
957  }
959  if (path->ssthresh < path->tempCwnd) {
960  path->ssthresh = path->tempCwnd;
961  }
962  }
963  recordCwndUpdate(path);
964 
965  EV_INFO << "\t=>\tsst=" << path->ssthresh
966  << "\tcwnd=" << path->cwnd
967  << "\ttempCwnd=" << path->tempCwnd
968  << endl;
969  }
970  // ====== Possible transmission will not exceed burst size ============
971  else {
972  // Just store current cwnd to tempCwnd
973  path->tempCwnd = path->cwnd;
974  }
975  }
976 }

Referenced by stateEntered().

◆ decreaseOutstandingBytes()

void inet::sctp::SctpAssociation::decreaseOutstandingBytes ( SctpDataVariables chunk)
private
35 {
36  SctpPathVariables *lastPath = chunk->getLastDestinationPath();
37 
38  if (chunk->countsAsOutstanding) {
39  assert(lastPath->outstandingBytes >= chunk->booksize);
40  lastPath->outstandingBytes -= chunk->booksize;
41  lastPath->statisticsPathOutstandingBytes->record(lastPath->outstandingBytes);
42  state->outstandingBytes -= chunk->booksize;
43  SctpSendStream *stream = nullptr;
44  auto associter = sendStreams.find(chunk->sid);
45  if (associter != sendStreams.end()) {
46  stream = associter->second;
47  }
48  else {
49  throw cRuntimeError("Stream with id %d not found", chunk->sid);
50  }
51  stream->setBytesInFlight(stream->getBytesInFlight() - chunk->booksize);
52  assert((int64_t)state->outstandingBytes >= 0);
54 
55  chunk->countsAsOutstanding = false;
56 
57  auto iterator = qCounter.roomRetransQ.find(lastPath->remoteAddress);
59  if (state->osbWithHeader)
60  iterator->second -= ADD_PADDING(chunk->booksize);
61  else
62  iterator->second -= ADD_PADDING(chunk->booksize + SCTP_DATA_CHUNK_LENGTH);
63  }
64 }

Referenced by chunkMustBeAbandoned(), handleChunkReportedAsMissing(), moveChunkToOtherPath(), nonRenegablyAckChunk(), putInTransmissionQ(), renegablyAckChunk(), storePacket(), and tsnWasReneged().

◆ deleteStreams()

void inet::sctp::SctpAssociation::deleteStreams ( )
107  {
108  testsid = state->lastStreamScheduled;
109 
110  do {
111  testsid = (testsid + 1) % outboundStreams;
112 
113  if (streamIsPending(testsid)) {

Referenced by inet::sctp::Sctp::removeAssociation().

◆ dequeueAckedChunks()

void inet::sctp::SctpAssociation::dequeueAckedChunks ( const uint32_t  tsna,
SctpPathVariables path,
simtime_t &  rttEstimation 
)
protected
2031 {
2032  Sctp::AssocStat *assocStat = sctpMain->getAssocStat(assocId);
2033 
2034  // Set it ridiculously high
2035  rttEstimation = SIMTIME_MAX;
2036 
2037  // Are there chunks in the retransmission queue ? If Yes -> check for dequeue.
2038  auto iterator = retransmissionQ->payloadQueue.begin();
2039  while (iterator != retransmissionQ->payloadQueue.end()) {
2040  SctpDataVariables *chunk = iterator->second;
2041  if (tsnGe(tsna, chunk->tsn)) {
2042  EV_DETAIL << simTime() << ": CumAcked TSN " << chunk->tsn
2043  << " on path " << chunk->getLastDestination() << endl;
2044 
2045  if (!chunkHasBeenAcked(chunk)) {
2046  SctpPathVariables *lastPath = chunk->getLastDestinationPath();
2047  // CumAck affects lastPath -> reset its T3 timer later.
2048  lastPath->newCumAck = true;
2049  // CumAck of SACK has acknowledged this chunk. Handle Pseudo CumAck.
2050  lastPath->findPseudoCumAck = true;
2051  lastPath->newPseudoCumAck = true;
2052  // T.D. 22.11.09: CUCv2
2053  lastPath->findRTXPseudoCumAck = true;
2054  lastPath->newRTXPseudoCumAck = true;
2055  }
2056 
2057  nonRenegablyAckChunk(chunk, sackPath, rttEstimation, assocStat);
2058  }
2059  else {
2060  break;
2061  }
2062  iterator = retransmissionQ->payloadQueue.begin();
2063  }
2064 
2065  EV_INFO << "dequeueAckedChunks(): rttEstimation=" << rttEstimation << endl;
2066 }

Referenced by process_RCV_Message(), and processSackArrived().

◆ dequeueOutboundDataMsg()

SctpDataMsg * inet::sctp::SctpAssociation::dequeueOutboundDataMsg ( SctpPathVariables path,
int32_t  availableSpace,
int32_t  availableCwnd 
)
protected
2560 {
2561  SctpDataMsg *datMsg = nullptr;
2562  cPacketQueue *streamQ = nullptr;
2563  int32_t nextStream = -1;
2564 
2565  EV_INFO << "dequeueOutboundDataMsg: " << availableSpace << " bytes left to be sent" << endl;
2566 
2568 
2569  /* Only change stream if we don't have to finish a fragmented message */
2571  nextStream = state->lastStreamScheduled;
2572  else
2573  nextStream = (this->*ssFunctions.ssGetNextSid)(path, false);
2574 
2575  if (nextStream == -1)
2576  return nullptr;
2577 
2578  EV_INFO << "dequeueOutboundDataMsg: now stream " << nextStream << endl;
2579 
2580  SctpSendStream *stream = sendStreams.find(nextStream)->second;
2581  streamQ = nullptr;
2582 
2583  if (!stream->getUnorderedStreamQ()->isEmpty()) {
2584  streamQ = stream->getUnorderedStreamQ();
2585  EV_DETAIL << "DequeueOutboundDataMsg() found chunks in stream " << nextStream << " unordered queue, queue size=" << stream->getUnorderedStreamQ()->getLength() << "\n";
2586  }
2587  else if (!stream->getStreamQ()->isEmpty()) {
2588  streamQ = stream->getStreamQ();
2589  EV_DETAIL << "DequeueOutboundDataMsg() found chunks in stream " << nextStream << " ordered queue, queue size=" << stream->getStreamQ()->getLength() << "\n";
2590  }
2591 
2592  if (streamQ) {
2593  int32_t b = ADD_PADDING(check_and_cast<SctpDataMsg *>(streamQ->front())->getEncapsulatedPacket()->getByteLength() + SCTP_DATA_CHUNK_LENGTH);
2594 
2595  if ((b <= availableSpace) &&
2596  ((int32_t)check_and_cast<SctpDataMsg *>(streamQ->front())->getBooksize() <= availableCwnd))
2597  {
2598  datMsg = check_and_cast<SctpDataMsg *>(streamQ->pop());
2599  sendQueue->record(streamQ->getLength());
2600 
2601  if (!datMsg->getFragment()) {
2602  datMsg->setBBit(true);
2603  datMsg->setEBit(true);
2604  state->lastMsgWasFragment = false;
2605  }
2606  else {
2607  if (datMsg->getEBit())
2608  state->lastMsgWasFragment = false;
2609  else
2610  state->lastMsgWasFragment = true;
2611  }
2612 
2613  EV_DETAIL << "DequeueOutboundDataMsg() found chunk (" << datMsg->str() << ") in the stream queue " << nextStream << "(" << streamQ << ") queue size=" << streamQ->getLength() << endl;
2614  }
2615  }
2616 
2617  if (datMsg != nullptr) {
2618  qCounter.roomSumSendStreams -= ADD_PADDING(datMsg->getEncapsulatedPacket()->getByteLength() + SCTP_DATA_CHUNK_LENGTH);
2619  qCounter.bookedSumSendStreams -= datMsg->getBooksize();
2620  }
2621  return datMsg;
2622 }

Referenced by sendOnPath().

◆ disposeOf()

void inet::sctp::SctpAssociation::disposeOf ( SctpHeader sctpmsg)
protected
2881 {
2882  SctpChunk *chunk;
2883  uint32_t numberOfChunks = sctpmsg->getSctpChunksArraySize();
2884  if (numberOfChunks > 0)
2885  for (uint32_t i = 0; i < numberOfChunks; i++) {
2886  chunk = sctpmsg->removeFirstChunk();
2887  /* if (chunk->getSctpChunkType() == DATA) {
2888  delete chunk->Chunk::peek<SctpSimpleMessage>(Chunk::BackwardIterator(B(0)));
2889  }*/
2890  delete chunk;
2891  }
2892  delete sctpmsg;
2893 }

Referenced by processPacketDropArrived(), and sendPacketDrop().

◆ eventName()

const char * inet::sctp::SctpAssociation::eventName ( int32_t  event)
staticprotected

Utility: returns name of SCTP_E_xxx constants.

Referenced by performStateTransition(), and processAppCommand().

◆ fragmentOutboundDataMsgs()

void inet::sctp::SctpAssociation::fragmentOutboundDataMsgs ( )
protected
2428  {
2429  cPacketQueue *streamQ = nullptr;
2430  for (auto iter = sendStreams.begin(); iter != sendStreams.end(); ++iter) {
2431  SctpSendStream *stream = iter->second;
2432  streamQ = nullptr;
2433 
2434  if (!stream->getUnorderedStreamQ()->isEmpty()) {
2435  streamQ = stream->getUnorderedStreamQ();
2436  EV_DETAIL << "fragmentOutboundDataMsgs() found chunks in stream " << iter->first << " unordered queue, queue size=" << stream->getUnorderedStreamQ()->getLength() << "\n";
2437  }
2438  else if (!stream->getStreamQ()->isEmpty()) {
2439  streamQ = stream->getStreamQ();
2440  EV_DETAIL << "fragmentOutboundDataMsgs() found chunks in stream " << iter->first << " ordered queue, queue size=" << stream->getStreamQ()->getLength() << "\n";
2441  }
2442 
2443  if (streamQ) {
2444  int32_t b = ADD_PADDING(check_and_cast<SctpDataMsg *>(streamQ->front())->getEncapsulatedPacket()->getByteLength() + SCTP_DATA_CHUNK_LENGTH);
2445 
2446  /* check if chunk found in queue has to be fragmented */
2447  if (b > (int32_t)state->fragPoint + (int32_t)SCTP_DATA_CHUNK_LENGTH) {
2448  /* START FRAGMENTATION */
2449  SctpDataMsg *datMsgQueued = check_and_cast<SctpDataMsg *>(streamQ->pop());
2450  cPacket *datMsgQueuedEncMsg = datMsgQueued->getEncapsulatedPacket();
2451  SctpDataMsg *datMsgLastFragment = nullptr;
2452  uint32_t offset = 0;
2453  uint32_t msgbytes = state->fragPoint;
2454  const uint16_t fullSizedPackets = (uint16_t)(datMsgQueued->getByteLength() / msgbytes);
2455  EV_DETAIL << "Fragmentation: chunk " << &datMsgQueued << " - size = " << datMsgQueued->getByteLength() << endl;
2456  EV_DETAIL << assocId << ": number of fullSizedPackets: " << fullSizedPackets << endl;
2457  uint16_t pcounter = 0;
2458 
2459  while (datMsgQueued) {
2460  /* detemine size of fragment, either max payload or what's left */
2461  if (msgbytes > datMsgQueuedEncMsg->getByteLength() - offset)
2462  msgbytes = datMsgQueuedEncMsg->getByteLength() - offset;
2463 
2464  /* new DATA msg */
2465  SctpDataMsg *datMsgFragment = new SctpDataMsg();
2466  datMsgFragment->setSid(datMsgQueued->getSid());
2467  datMsgFragment->setPpid(datMsgQueued->getPpid());
2468  if (++pcounter == fullSizedPackets && sctpMain->sackNow)
2469  datMsgFragment->setSackNow(true);
2470  else
2471  datMsgFragment->setSackNow(datMsgQueued->getSackNow());
2472  datMsgFragment->setInitialDestination(datMsgQueued->getInitialDestination());
2473  datMsgFragment->setEnqueuingTime(datMsgQueued->getEnqueuingTime());
2474  datMsgFragment->setPrMethod(datMsgQueued->getPrMethod());
2475  datMsgFragment->setPriority(datMsgQueued->getPriority());
2476 // EV_DETAIL << "felix: " << datMsgQueued->getPriority() << endl;
2477  datMsgFragment->setStrReset(datMsgQueued->getStrReset());
2478  datMsgFragment->setMsgNum(datMsgQueued->getMsgNum());
2479  datMsgFragment->setOrdered(datMsgQueued->getOrdered());
2480  datMsgFragment->setExpiryTime(datMsgQueued->getExpiryTime());
2481  datMsgFragment->setRtx(datMsgQueued->getRtx());
2482  datMsgFragment->setFragment(true);
2483 
2484  if (state->padding)
2485  datMsgFragment->setBooksize(ADD_PADDING(msgbytes + state->header));
2486  else
2487  datMsgFragment->setBooksize(msgbytes + state->header);
2488 
2489  /* is this the first fragment? */
2490  if (offset == 0)
2491  datMsgFragment->setBBit(true);
2492 
2493  /* new msg */
2494  cPacket *datMsgFragmentEncMsg = datMsgQueuedEncMsg->dup();
2495 
2496  datMsgFragmentEncMsg->setByteLength(msgbytes);
2497 
2498  SctpSimpleMessage *datMsgQueuedSimple = dynamic_cast<SctpSimpleMessage *>(datMsgQueuedEncMsg);
2499  SctpSimpleMessage *datMsgFragmentSimple = dynamic_cast<SctpSimpleMessage *>(datMsgFragmentEncMsg);
2500  if ((datMsgQueuedSimple != nullptr) &&
2501  (datMsgFragmentSimple != nullptr) &&
2502  (datMsgQueuedSimple->getDataArraySize() >= msgbytes + offset))
2503  {
2504  datMsgFragmentSimple->setDataArraySize(msgbytes);
2505  datMsgFragmentSimple->setDataLen(msgbytes);
2506  /* copy data */
2507  for (uint32_t i = offset; i < offset + msgbytes; i++) {
2508  datMsgFragmentSimple->setData(i - offset, datMsgQueuedSimple->getData(i));
2509  }
2510  }
2511 
2512  offset += msgbytes;
2513 // datMsgFragment->insertAtBack(datMsgFragmentEncMsg);
2514  datMsgFragment->encapsulate(datMsgFragmentEncMsg);
2515 
2516  /* insert fragment into queue */
2517  if (!streamQ->isEmpty()) {
2518  if (!datMsgLastFragment) {
2519  /* insert first fragment at the begining of the queue*/
2520  streamQ->insertBefore(check_and_cast<SctpDataMsg *>(streamQ->front()), datMsgFragment);
2521  }
2522  else {
2523  /* insert fragment after last inserted */
2524  streamQ->insertAfter(datMsgLastFragment, datMsgFragment);
2525  }
2526  }
2527  else
2528  streamQ->insert(datMsgFragment);
2529 
2530  state->queuedMessages++;
2531  qCounter.roomSumSendStreams += ADD_PADDING(datMsgFragment->getByteLength() + SCTP_DATA_CHUNK_LENGTH);
2532  qCounter.bookedSumSendStreams += datMsgFragment->getBooksize();
2533  EV_DETAIL << "Fragmentation: fragment " << &datMsgFragment << " created, length = " << datMsgFragmentEncMsg->getByteLength() << ", queue size = " << streamQ->getLength() << endl;
2534 
2535  datMsgLastFragment = datMsgFragment;
2536 
2537  /* all fragments done? */
2538  if (datMsgQueuedEncMsg->getByteLength() == offset) {
2539  datMsgFragment->setEBit(true);
2540  if (sctpMain->sackNow)
2541  datMsgFragment->setSackNow(true);
2542  /* remove original element */
2543  EV_DETAIL << "Fragmentation: delete " << &datMsgQueued << endl;
2544 // streamQ->pop();
2545  qCounter.roomSumSendStreams -= ADD_PADDING(datMsgQueued->getByteLength() + SCTP_DATA_CHUNK_LENGTH);
2546  qCounter.bookedSumSendStreams -= datMsgQueued->getBooksize();
2547  delete datMsgQueued;
2548  datMsgQueued = nullptr;
2549  state->queuedMessages--;
2550  }
2551  } // while
2552  }
2553  }
2554  }
2555 }

Referenced by dequeueOutboundDataMsg().

◆ generateSendQueueAbatedIndication()

void inet::sctp::SctpAssociation::generateSendQueueAbatedIndication ( uint64_t  bytes)
private
1991 {
1993  // Just send SCTP_I_SENDQUEUE_ABATED once, after all newly acked
1994  // chunks have been dequeued.
1995  // Only send indication if the sendBuffer size has dropped below the sendQueueLimit
1996 // assert(state->lastSendQueueAbated < simTime());
1997  state->appSendAllowed = true;
1998  EV_INFO << simTime() << ":\tSCTP_I_SENDQUEUE_ABATED("
1999  << bytes << ") to refill buffer "
2000  << state->sendBuffer << "/" << state->sendQueueLimit << endl;
2001 
2002  Indication *msg = new Indication(indicationName(SCTP_I_SENDQUEUE_ABATED), SCTP_I_SENDQUEUE_ABATED);
2003 
2004  msg->addTag<SocketInd>()->setSocketId(assocId);
2005  auto& sendQueueAbatedIndication = msg->addTag<SctpSendQueueAbatedReq>();
2006  sendQueueAbatedIndication->setSocketId(assocId);
2007  sendQueueAbatedIndication->setLocalAddr(localAddr);
2008  sendQueueAbatedIndication->setRemoteAddr(remoteAddr);
2009  sendQueueAbatedIndication->setNumMsgs(bytes); // NOTE: Legacy API!
2010  sendQueueAbatedIndication->setQueuedForStreamArraySize(sendStreams.size());
2011  unsigned int streamID = 0;
2012  for (auto& elem : sendStreams) {
2013  const SctpSendStream *stream = elem.second;
2014  sendQueueAbatedIndication->setQueuedForStream(streamID, stream->getUnorderedStreamQ()->getByteLength() + stream->getStreamQ()->getByteLength());
2015  streamID++;
2016  }
2017 
2018  sendQueueAbatedIndication->setBytesAvailable(state->sendQueueLimit - state->sendBuffer);
2019  sendQueueAbatedIndication->setBytesQueued(state->sendBuffer);
2020  sendQueueAbatedIndication->setBytesLimit(state->sendQueueLimit);
2021 
2022  sctpMain->send(msg, "appOut");
2023 
2024  state->lastSendQueueAbated = simTime();
2025  }
2026 }

Referenced by processSackArrived().

◆ getAddressLevel()

int inet::sctp::SctpAssociation::getAddressLevel ( const L3Address addr)
static

Utility: return IPv4 or IPv6 address level.

2896 {
2897  if (addr.getType() == L3Address::IPv6) {
2898  switch (addr.toIpv6().getScope()) {
2901  return 0;
2902 
2903  case Ipv6Address::LOOPBACK:
2904  return 1;
2905 
2906  case Ipv6Address::LINK:
2907  return 2;
2908 
2909  case Ipv6Address::SITE:
2910  return 3;
2911 
2912  case Ipv6Address::GLOBAL:
2913  return 4;
2914 
2915  default:
2916  throw cRuntimeError("Unknown IPv6 scope: %d", (int)(addr.toIpv6().getScope()));
2917  }
2918  }
2919  else if (addr.getType() == L3Address::IPv4) {
2920  switch (addr.toIpv4().getAddressCategory()) {
2927  case Ipv4Address::IETF:
2928  case Ipv4Address::TEST_NET:
2929  case Ipv4Address::RESERVED:
2930  return 0;
2931 
2932  case Ipv4Address::LOOPBACK:
2933  return 1;
2934 
2936  return 2;
2937 
2939  return 3;
2940 
2941  case Ipv4Address::GLOBAL:
2942  return 4;
2943 
2944  default:
2945  throw cRuntimeError("Unknown Ipv4 address category: %d", (int)(addr.toIpv4().getAddressCategory()));
2946  }
2947  }
2948  throw cRuntimeError("Unknown address type: %d", (int)(addr.getType()));
2949 }

Referenced by inet::sctp::SctpNatHook::datagramForwardHook(), inet::sctp::SctpNatHook::datagramPreRoutingHook(), processInitArrived(), sendAsconf(), and sendInit().

◆ getAllTransQ()

uint32_t inet::sctp::SctpAssociation::getAllTransQ ( )
protected
1477 {
1478  uint32_t sum = 0;
1479  for (auto& elem : qCounter.roomTransQ) {
1480  sum += elem.second;
1481  }
1482  return sum;
1483 }

Referenced by sendOnPath().

◆ getBytesInFlightOfStream()

uint32_t inet::sctp::SctpAssociation::getBytesInFlightOfStream ( uint16_t  sid)
protected
77 {
78  auto streamIterator = sendStreams.find(sid);
79  assert(streamIterator != sendStreams.end());
80  return streamIterator->second->getBytesInFlight();
81 }

Referenced by checkStreamsToReset(), process_STREAM_RESET(), and processIncomingResetRequestArrived().

◆ getExpectedSsnOfStream()

uint32_t inet::sctp::SctpAssociation::getExpectedSsnOfStream ( uint16_t  id)
protected
901 {
902  uint16_t str;
903  auto iterator = receiveStreams.find(id);
904  str = iterator->second->getExpectedStreamSeqNum();
905  return str;
906 }

Referenced by processOutgoingResetRequestArrived().

◆ getFragInProgressOfStream()

bool inet::sctp::SctpAssociation::getFragInProgressOfStream ( uint16_t  sid)
protected
98 {
99  auto streamIterator = sendStreams.find(sid);
100  assert(streamIterator != sendStreams.end());
101  return streamIterator->second->getFragInProgress();
102 }

Referenced by process_STREAM_RESET(), and processIncomingResetRequestArrived().

◆ getFsm()

cFSM* inet::sctp::SctpAssociation::getFsm ( ) const
inline
1014 { return fsm; };

◆ getFsmState()

int32_t inet::sctp::SctpAssociation::getFsmState ( ) const
inline
1008 { return fsm->getState(); };

◆ getInitialCwnd()

uint32_t inet::sctp::SctpAssociation::getInitialCwnd ( const SctpPathVariables path) const
private
378 {
379  uint32_t newCwnd;
380 
381  const uint32_t upperLimit = (state->initialWindow > 0) ? (state->initialWindow * path->pmtu) : max(2 * path->pmtu, 4380);
382  if ((state->allowCMT == false) || (state->cmtCCVariant == SctpStateVariables::CCCV_CMT)) {
383  newCwnd = (int32_t)min((state->initialWindow > 0) ? (state->initialWindow * path->pmtu) : (4 * path->pmtu),
384  upperLimit);
385  }
386  else {
387  newCwnd = (int32_t)min((int32_t)ceil(((state->initialWindow > 0) ?
388  (state->initialWindow * path->pmtu) :
389  (4 * path->pmtu)) / (double)sctpPathMap.size()),
390  upperLimit);
391  if (newCwnd < path->pmtu) { // T.D. 09.09.2010: cwnd < MTU makes no sense ...
392  newCwnd = path->pmtu;
393  }
394  } return newCwnd;
395 }

Referenced by cwndUpdateAfterCwndTimeout(), and initCcParameters().

◆ getInitTimer()

cMessage* inet::sctp::SctpAssociation::getInitTimer ( ) const
inline
1015 { return T1_InitTimer; };

◆ getNextAddress()

const L3Address& inet::sctp::SctpAssociation::getNextAddress ( const SctpPathVariables oldPath) const
inlineprotected
1221  {
1222  const SctpPathVariables *nextPath = getNextPath(oldPath);
1223  if (nextPath != nullptr) {
1224  return nextPath->remoteAddress;
1225  }
1227  }

Referenced by sendAsconf().

◆ getNextDestination()

SctpPathVariables * inet::sctp::SctpAssociation::getNextDestination ( SctpDataVariables chunk) const
protected
2697 {
2698  SctpPathVariables *next;
2699 
2700  EV_DEBUG << "Running getNextDestination()" << endl;
2701  if (chunk->numberOfTransmissions == 0) {
2702  if (chunk->getInitialDestinationPath() == nullptr) {
2703  next = state->getPrimaryPath();
2704  }
2705  else {
2706  next = chunk->getInitialDestinationPath();
2707  }
2708  }
2709  else {
2710  if (chunk->hasBeenFastRetransmitted) {
2711  EV_DETAIL << "Chunk " << chunk->tsn << " is scheduled for FastRetransmission. Next destination = "
2712  << chunk->getLastDestination() << endl;
2713  return chunk->getLastDestinationPath();
2714  }
2715  // If this is a retransmission, we should choose another, active path.
2716  SctpPathVariables *last = chunk->getLastDestinationPath();
2717  next = getNextPath(last);
2718  if ((next == nullptr) || (next->confirmed == false)) {
2719  next = last;
2720  }
2721  }
2722 
2723  EV_INFO << "getNextDestination(): chunk was last sent to " << chunk->getLastDestination()
2724  << ", will next be sent to path " << next->remoteAddress << endl;
2725  return next;
2726 }

Referenced by handleChunkReportedAsMissing(), and process_TIMEOUT_RTX().

◆ getNextPath()

SctpPathVariables * inet::sctp::SctpAssociation::getNextPath ( const SctpPathVariables oldPath) const
protected
2672 {
2673  int32_t hit = 0;
2674  if (sctpPathMap.size() > 1) {
2675  for (const auto& elem : sctpPathMap) {
2676  SctpPathVariables *newPath = elem.second;
2677  if (newPath == oldPath) {
2678  if (++hit == 1) {
2679  continue;
2680  }
2681  else {
2682  break;
2683  }
2684  }
2685  if ((newPath->activePath) &&
2686  ((state->allowCMT == false) || (newPath->blockingTimeout <= 0.0) ||
2687  (simTime() > newPath->blockingTimeout)))
2688  {
2689  return newPath;
2690  }
2691  }
2692  }
2693  return nullptr;
2694 }

Referenced by getNextDestination(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().

◆ getOutboundDataChunk()

SctpDataVariables * inet::sctp::SctpAssociation::getOutboundDataChunk ( const SctpPathVariables path,
int32_t  availableSpace,
int32_t  availableCwnd 
)
protected
2304 {
2305  /* are there chunks in the transmission queue ? If Yes -> dequeue and return it */
2306  EV_INFO << "getOutboundDataChunk(" << path->remoteAddress << "):"
2307  << " availableSpace=" << availableSpace
2308  << " availableCwnd=" << availableCwnd
2309  << endl;
2310  if (!transmissionQ->payloadQueue.empty()) {
2311  for (auto it = transmissionQ->payloadQueue.begin();
2312  it != transmissionQ->payloadQueue.end(); it++)
2313  {
2314  SctpDataVariables *chunk = it->second;
2315  if ((chunkHasBeenAcked(chunk) == false) && !chunk->hasBeenAbandoned &&
2316  (chunk->getNextDestinationPath() == path))
2317  {
2318  const int32_t len = ADD_PADDING(chunk->len / 8 + SCTP_DATA_CHUNK_LENGTH);
2319  EV_DETAIL << "getOutboundDataChunk() found chunk " << chunk->tsn
2320  << " in the transmission queue, length=" << len << endl;
2321  if ((len <= availableSpace) &&
2322  ((int32_t)chunk->booksize <= availableCwnd))
2323  {
2324  // T.D. 05.01.2010: The bookkeeping counters may only be decreased when
2325  // this chunk is actually dequeued. Therefore, the check
2326  // for "chunkHasBeenAcked==false" has been moved into the
2327  // "if" statement above!
2328  transmissionQ->payloadQueue.erase(it);
2329  chunk->enqueuedInTransmissionQ = false;
2330  auto i = qCounter.roomTransQ.find(path->remoteAddress);
2331  i->second -= ADD_PADDING(chunk->len / 8 + SCTP_DATA_CHUNK_LENGTH);
2332  auto ib = qCounter.bookedTransQ.find(path->remoteAddress);
2333  ib->second -= chunk->booksize;
2334  return chunk;
2335  }
2336  }
2337  }
2338  }
2339  EV_INFO << "no chunk found in transmissionQ\n";
2340  return nullptr;
2341 }

Referenced by sendOnPath().

◆ getOutstandingBytes()

int32_t inet::sctp::SctpAssociation::getOutstandingBytes ( ) const
protected
2800 {
2801  int32_t osb = 0;
2802  for (const auto& elem : sctpPathMap) {
2803  osb += elem.second->outstandingBytes;
2804  }
2805  return osb;
2806 }

Referenced by process_CLOSE(), process_RCV_Message(), processPacketDropArrived(), processSackArrived(), sendShutdownAck(), and stateEntered().

◆ getPath()

◆ getRetransmissionQueue()

SctpQueue* inet::sctp::SctpAssociation::getRetransmissionQueue ( ) const
inline

◆ getSackTimer()

cMessage* inet::sctp::SctpAssociation::getSackTimer ( ) const
inline
1017 { return SackTimer; };

◆ getSctpAlgorithm()

SctpAlgorithm* inet::sctp::SctpAssociation::getSctpAlgorithm ( ) const
inline
1012 { return sctpAlgorithm; };

◆ getSctpMain()

Sctp* inet::sctp::SctpAssociation::getSctpMain ( ) const
inline

◆ getShutdownTimer()

cMessage* inet::sctp::SctpAssociation::getShutdownTimer ( ) const
inline
1016 { return T2_ShutdownTimer; };

◆ getSortedPathMap()

std::vector< SctpPathVariables * > inet::sctp::SctpAssociation::getSortedPathMap ( )
private
122 {
123  std::vector<SctpPathVariables *> sortedPaths;
124  for (auto& elem : sctpPathMap) {
125  SctpPathVariables *path = elem.second;
126  sortedPaths.insert(sortedPaths.end(), path);
127  }
128  if (state->cmtSendAllComparisonFunction != nullptr) {
129  std::stable_sort(sortedPaths.begin(), sortedPaths.end(), state->cmtSendAllComparisonFunction);
130  }
131 
132  EV << "SORTED PATH MAP:" << endl;
133  for (auto path : sortedPaths) {
134  EV << " - " << path->remoteAddress
135  << " cwnd=" << path->cwnd
136  << " ssthresh=" << path->ssthresh
137  << " outstanding=" << path->outstandingBytes
138  << " bytesToRetransmit=" << state->bytesToRetransmit << endl;
139  }
140  return sortedPaths;
141 }

Referenced by sendOnAllPaths().

◆ getSsnOfStream()

uint32_t inet::sctp::SctpAssociation::getSsnOfStream ( uint16_t  id)
protected
909 {
910  auto iterator = sendStreams.find(id);
911  return iterator->second->getNextStreamSeqNum();
912 }

Referenced by processIncomingResetRequestArrived().

◆ getState()

SctpStateVariables* inet::sctp::SctpAssociation::getState ( ) const
inline
1009 { return state; };

Referenced by inet::sctp::Sctp::removeAssociation().

◆ getTransmissionQueue()

SctpQueue* inet::sctp::SctpAssociation::getTransmissionQueue ( ) const
inline

◆ handleChunkReportedAsAcked()

void inet::sctp::SctpAssociation::handleChunkReportedAsAcked ( uint32_t &  highestNewAck,
simtime_t &  rttEstimation,
SctpDataVariables myChunk,
SctpPathVariables sackPath,
const bool  sackIsNonRevokable 
)
private
1591 {
1592  SctpPathVariables *myChunkLastPath = myChunk->getLastDestinationPath();
1593  // SFR algorithm
1594  if (state->allowCMT == true) {
1595  EV << "TSN " << myChunk->tsn << " on path " << myChunkLastPath->remoteAddress << ":\t"
1596  << "findPseudoCumAck=" << ((myChunkLastPath->findPseudoCumAck == true) ? "true" : "false") << "\t"
1597  << "pseudoCumAck=" << myChunkLastPath->pseudoCumAck << "\t"
1598  << "newPseudoCumAck=" << ((myChunkLastPath->newPseudoCumAck == true) ? "true" : "false") << "\t"
1599  << "findRTXPseudoCumAck=" << ((myChunkLastPath->findRTXPseudoCumAck == true) ? "true" : "false") << "\t"
1600  << "rtxPseudoCumAck=" << myChunkLastPath->rtxPseudoCumAck << "\t"
1601  << "newRTXPseudoCumAck=" << ((myChunkLastPath->newRTXPseudoCumAck == true) ? "true" : "false") << "\t"
1602  << endl;
1603 
1604  // This chunk has not been acked before -> new ack on its myChunkLastPath.
1605  if (myChunkLastPath->sawNewAck == false) {
1606  EV << "TSN " << myChunk->tsn << " on path " << myChunkLastPath->remoteAddress << ":\t"
1607  << "Saw new ack -> setting highestNewAckInSack!" << endl;
1608  myChunkLastPath->sawNewAck = true;
1609  }
1610 
1611  // Smart Fast RTX
1612  // If chunk has already been transmitted on another path, do not consider it
1613  // for fast RTX handling!
1614  if ((!myChunk->hasBeenTimerBasedRtxed) ||
1615  (state->cmtSmartFastRTX == false))
1616  {
1617  if (myChunkLastPath->lowestNewAckInSack == 0) {
1618  myChunkLastPath->lowestNewAckInSack = myChunk->tsn; // The lowest TSN acked
1619  }
1620  if (myChunkLastPath->highestNewAckInSack == 0) {
1621  myChunkLastPath->highestNewAckInSack = myChunk->tsn; // The highest TSN acked so far
1622  }
1623  else if (tsnLt(myChunkLastPath->highestNewAckInSack, myChunk->tsn)) {
1624  myChunkLastPath->highestNewAckInSack = myChunk->tsn; // The highest TSN acked so far
1625  }
1626  }
1627  }
1628  if ((myChunk->numberOfTransmissions == 1) &&
1629  (myChunk->hasBeenMoved == false) &&
1630  (myChunk->hasBeenReneged == false))
1631  {
1632  if (myChunkLastPath == sackPath) {
1633  const simtime_t timeDifference = simTime() - myChunk->sendTime;
1634  if ((timeDifference < rttEstimation) || (rttEstimation == -1.0)) {
1635  rttEstimation = timeDifference;
1636  }
1637  EV_DETAIL << simTime() << " processSackArrived: computed rtt time diff == "
1638  << timeDifference << " for TSN " << myChunk->tsn << endl;
1639  }
1640  else {
1641  if ((state->allowCMT == true) &&
1642  (state->cmtSlowPathRTTUpdate == true) &&
1643  (myChunkLastPath->waitingForRTTCalculaton == false))
1644  {
1645  // numberOfTransmissions==1, hasBeenReneged==false
1646  // T.D. 25.02.2010: Slow Path Update
1647  // Remember this chunk's TSN and send time in order to update the
1648  // path's RTT using a stale SACK on its own path.
1649  myChunkLastPath->tsnForRTTCalculation = myChunk->tsn;
1650  myChunkLastPath->txTimeForRTTCalculation = myChunk->sendTime;
1651  myChunkLastPath->waitingForRTTCalculaton = true;
1652  }
1653  }
1654  }
1655  if ((myChunk->hasBeenAbandoned == false) &&
1656  (myChunk->hasBeenReneged == false) &&
1657  (myChunk->hasBeenAcked == false))
1658  {
1659  EV_DETAIL << simTime() << ": GapAcked TSN " << myChunk->tsn
1660  << " on path " << myChunkLastPath->remoteAddress << endl;
1661 
1662  if (myChunk->tsn > highestNewAck) {
1663  highestNewAck = myChunk->tsn;
1664  }
1665 
1666  if (sackIsNonRevokable == true) {
1667  myChunkLastPath->gapAckedChunksInLastSACK++;
1668  myChunkLastPath->gapNRAckedChunksInLastSACK++;
1669  }
1670  else {
1671  myChunkLastPath->gapAckedChunksInLastSACK++;
1672  }
1673  }
1674 
1675  // ====== Non-Renegable SACK =============================================
1676  if (sackIsNonRevokable == true) {
1677  // NOTE: nonRenegablyAckChunk() will only work with ChunkMap,
1678  // since the actual chunk object will be gone ...
1679  nonRenegablyAckChunk(myChunk, sackPath, rttEstimation,
1681  }
1682  // ====== Renegable SACK =================================================
1683  else {
1684  renegablyAckChunk(myChunk, sackPath);
1685  }
1686 }

Referenced by processSackArrived().

◆ handleChunkReportedAsMissing()

void inet::sctp::SctpAssociation::handleChunkReportedAsMissing ( const SctpSackChunk sackChunk,
const uint32_t  highestNewAck,
SctpDataVariables myChunk,
SctpPathVariables sackPath 
)
private
1692 {
1693  SctpPathVariables *myChunkLastPath = myChunk->getLastDestinationPath();
1694  EV_INFO << "TSN " << myChunk->tsn << " is missing in gap reports (last "
1695  << myChunkLastPath->remoteAddress << ") ";
1696  if (!chunkHasBeenAcked(myChunk)) {
1697  EV_DETAIL << "has not been acked, highestNewAck=" << highestNewAck
1698  << " countsAsOutstanding=" << myChunk->countsAsOutstanding << endl;
1699 
1700  // ===== Check whether a Fast Retransmission is necessary =============
1701  // Non-CMT behaviour: check for highest TSN
1702  uint32_t chunkReportedAsMissing = (highestNewAck > myChunk->tsn || (myChunk->getLastDestinationPath()->fastRecoveryActive && state->highestTsnAcked >= myChunk->tsn)) ? 1 : 0;
1703 
1704  // Split Fast Retransmission (SFR) algorithm for CMT
1705  if ((state->allowCMT == true) && (state->cmtUseSFR == true)) {
1706  chunkReportedAsMissing = 0; // Default: do not assume chunk as missing.
1707 
1708  // If there has been another chunk with highest TSN acked on this path,
1709  // the current one is missing.
1710  if ((myChunkLastPath->sawNewAck) &&
1711  (tsnGt(myChunkLastPath->highestNewAckInSack, myChunk->tsn)))
1712  {
1713  if (state->cmtUseDAC == false) {
1714  chunkReportedAsMissing = 1;
1715  }
1716  else {
1717  // ------ DAC algorithm at sender side -----------
1718  // Is there a newly acked TSN on another path?
1719  bool sawNewAckOnlyOnThisPath = true;
1720  for (auto& elem : sctpPathMap) {
1721  const SctpPathVariables *otherPath = elem.second;
1722  if ((otherPath != myChunkLastPath) && (otherPath->sawNewAck)) {
1723  sawNewAckOnlyOnThisPath = false;
1724  break;
1725  }
1726  }
1727  if (sawNewAckOnlyOnThisPath == true) {
1728  // All newly acked TSNs were sent on the same path
1729  EV << "SplitFastRTX + DAC: all on same path: "
1730  << "TSN=" << myChunk->tsn
1731  << " lowestNewAckInSack=" << myChunkLastPath->lowestNewAckInSack
1732  << " highestNewAckInSack=" << myChunkLastPath->highestNewAckInSack
1733  << " (on path " << myChunkLastPath->remoteAddress << ")" << endl;
1734  // Are there newly acked TSNs ta, tb, so that ta < myChunk->tsn < tb?
1735  // myChunkLastPath->highestNewAckInSack is highest newly acked TSN on the current path
1736  // -> since all TSNs were on this path, this value can be used as tb
1737  // lowestNewAckInSack is the lowest newly acked TSN of this SACK
1738  // -> since all TSNs were on the same path, this value can be used as ta
1739  if (tsnLt(myChunkLastPath->lowestNewAckInSack, myChunk->tsn) &&
1740  tsnLt(myChunk->tsn, myChunkLastPath->highestNewAckInSack))
1741  {
1742  EV << " => conservative increment of 1" << endl;
1743  chunkReportedAsMissing = 1;
1744  }
1745  else if (tsnGt(myChunkLastPath->lowestNewAckInSack, myChunk->tsn)) { // All newly acked TSNs are larger than myChunk->tsn
1746  EV << " => reported increment of dacPacketsRcvd=" << (unsigned int)sackChunk->getDacPacketsRcvd() << endl;
1747  chunkReportedAsMissing = sackChunk->getDacPacketsRcvd();
1748  }
1749  }
1750  else {
1751  // Mixed SACKS: newly acked TSNs were sent to multiple paths
1752  EV << "SplitFastRTX + DAC: mixed acks, increment is 1" << endl;
1753  chunkReportedAsMissing = 1;
1754  }
1755  }
1756  } // else: There is no need to increment the missing count.
1757 
1758  EV << "SplitFastRTX: chunkReportedAsMissing="
1759  << chunkReportedAsMissing << ", "
1760  << "sawNewAck=" << myChunkLastPath->sawNewAck << ", "
1761  << "lowestNewAckInSack=" << myChunkLastPath->lowestNewAckInSack
1762  << "highestNewAckInSack=" << myChunkLastPath->highestNewAckInSack << ", "
1763  << "TSN=" << myChunk->tsn << endl;
1764  }
1765  if (chunkReportedAsMissing > 0) {
1766  myChunk->gapReports += chunkReportedAsMissing;
1767  myChunkLastPath->gapUnackedChunksInLastSACK++;
1768 
1769  if (myChunk->gapReports >= state->numGapReports) {
1770  bool fastRtx = false;
1771  switch (state->rtxMethod) {
1772  case 0: // Only one Fast RTX after 3 Gap reports
1773  fastRtx = ((myChunk->hasBeenFastRetransmitted == false) &&
1774  ((myChunk->numberOfRetransmissions == 0) ||
1775  ((myChunk->hasBeenMoved) &&
1776  (myChunk->countsAsOutstanding) &&
1777  (state->movedChunkFastRTXFactor > 0) &&
1778  ((simTime() - myChunk->sendTime) > state->movedChunkFastRTXFactor * myChunkLastPath->srtt))));
1779  break;
1780 
1781  case 1: // Just 1 Fast RTX per RTT
1782  fastRtx = ((myChunk->hasBeenFastRetransmitted == false) &&
1783  (myChunk->numberOfRetransmissions == 0 ||
1784  (simTime() - myChunk->sendTime) > myChunkLastPath->srtt));
1785  break;
1786 
1787  case 2: // Switch off Fast RTX
1788  fastRtx = false;
1789  break;
1790 
1791  case 3: // Always Fast RTX
1792  fastRtx = true;
1793  break;
1794  }
1795  if (fastRtx) {
1796  if (myChunk->hasBeenMoved) {
1797  EV << simTime() << ": MovedFastRTX for TSN " << myChunk->tsn << endl;
1798  }
1799  myChunk->hasBeenMoved = false; // Just trigger *one* fast RTX ...
1800  // ====== Add chunk to transmission queue ========
1801  if (transmissionQ->getChunk(myChunk->tsn) == nullptr) {
1802  if (!chunkMustBeAbandoned(myChunk, sackPath)) {
1803  Sctp::AssocStat *assocStat = sctpMain->getAssocStat(assocId);
1804  if (assocStat) {
1805  assocStat->numFastRtx++;
1806  }
1807  }
1808  myChunk->hasBeenFastRetransmitted = true;
1809  myChunk->sendForwardIfAbandoned = true;
1810 
1811  EV_DETAIL << simTime() << ": Fast RTX for TSN "
1812  << myChunk->tsn << " on path " << myChunk->getLastDestination() << endl;
1813  myChunkLastPath->numberOfFastRetransmissions++;
1814 
1815  myChunk->setNextDestination(getNextDestination(myChunk));
1816  SctpPathVariables *myChunkNextPath = myChunk->getNextDestinationPath();
1817  assert(myChunkNextPath != nullptr);
1818 
1819  if (myChunk->countsAsOutstanding) {
1820  decreaseOutstandingBytes(myChunk);
1821  }
1822  if (!transmissionQ->checkAndInsertChunk(myChunk->tsn, myChunk)) {
1823  EV_DETAIL << "Fast RTX: cannot add message/chunk (TSN="
1824  << myChunk->tsn << ") to the transmissionQ" << endl;
1825  }
1826  else {
1827  myChunk->enqueuedInTransmissionQ = true;
1828  auto q = qCounter.roomTransQ.find(myChunk->getNextDestination());
1829  q->second += ADD_PADDING(myChunk->len / 8 + SCTP_DATA_CHUNK_LENGTH);
1830  auto qb = qCounter.bookedTransQ.find(myChunk->getNextDestination());
1831  qb->second += myChunk->booksize;
1832  }
1833  myChunkNextPath->requiresRtx = true;
1834  if (myChunkNextPath->findLowestTsn == true) {
1835  // TD 08.12.09: fixed detection of lowest TSN retransmitted
1836  myChunkNextPath->lowestTsnRetransmitted = true;
1837  }
1838  }
1839  }
1840  }
1841  }
1842  myChunkLastPath->findLowestTsn = false;
1843  }
1844  else {
1845  // Reneging, type 1:
1846  // A chunk in the gap blocks has been un-acked => reneg it.
1847  tsnWasReneged(myChunk, sackPath, 1);
1848  }
1849 }

Referenced by processSackArrived().

◆ increaseOutstandingBytes()

void inet::sctp::SctpAssociation::increaseOutstandingBytes ( SctpDataVariables chunk,
SctpPathVariables path 
)
private
22 {
23  path->outstandingBytes += chunk->booksize;
24  path->statisticsPathOutstandingBytes->record(path->outstandingBytes);
25  state->outstandingBytes += chunk->booksize;
26  SctpSendStream *stream = nullptr;
27  auto associter = sendStreams.find(chunk->sid);
28  if (associter != sendStreams.end()) {
29  stream = associter->second;
30  }
31  else {
32  throw cRuntimeError("Stream with id %d not found", chunk->sid);
33  }
34  stream->setBytesInFlight(stream->getBytesInFlight() + chunk->booksize);
36 
37  auto iterator = qCounter.roomRetransQ.find(path->remoteAddress);
39  if (state->osbWithHeader)
40  iterator->second += ADD_PADDING(chunk->booksize);
41  else
42  iterator->second += ADD_PADDING(chunk->booksize + SCTP_DATA_CHUNK_LENGTH);
43 }

Referenced by loadPacket(), and sendOnPath().

◆ indicationName()

const char * inet::sctp::SctpAssociation::indicationName ( int32_t  code)
static

Utility: returns name of SCTP_I_xxx constants.

206 {
207 #define CASE(x) case x: \
208  s = (char *)#x + 7; break
209  const char *s = "unknown";
210  switch (code) {
211  CASE(SCTP_I_DATA);
232  }
233  return s;
234 #undef CASE
235 }

Referenced by generateSendQueueAbatedIndication(), inet::SctpNatServer::handleMessage(), inet::SctpNatPeer::handleMessage(), sendAvailableIndicationToApp(), sendEstabIndicationToApp(), and sendIndicationToApp().

◆ initAssociation()

void inet::sctp::SctpAssociation::initAssociation ( SctpOpenReq openCmd)
protected

Utility: creates send/receive queues and sctpAlgorithm.

509 {
510  EV_INFO << "SctpAssociationUtil:initAssociation\n";
511  // create send/receive queues
512  const char *queueClass = openCmd->getQueueClass();
513  transmissionQ = check_and_cast<SctpQueue *>(inet::utils::createOne(queueClass));
514 
515  retransmissionQ = check_and_cast<SctpQueue *>(inet::utils::createOne(queueClass));
516  inboundStreams = openCmd->getInboundStreams();
517  outboundStreams = openCmd->getOutboundStreams();
518  // create algorithm
519  const char *sctpAlgorithmClass = openCmd->getSctpAlgorithmClass();
520  if (opp_isempty(sctpAlgorithmClass))
521  sctpAlgorithmClass = sctpMain->par("sctpAlgorithmClass");
522  sctpAlgorithm = check_and_cast<SctpAlgorithm *>(inet::utils::createOne(sctpAlgorithmClass));
525  // create state block
527 
528  if (sctpMain->par("auth").boolValue()) {
529  const char *chunks = sctpMain->par("chunks");
530  bool asc = false;
531  bool asca = false;
532  char *chunkscopy = (char *)malloc(strlen(chunks) + 1);
533  strcpy(chunkscopy, chunks);
534  char *token;
535  token = strtok(chunkscopy, ",");
536  while (token != nullptr) {
537  if (chunkToInt(token) == ASCONF)
538  asc = true;
539  if (chunkToInt(token) == ASCONF_ACK)
540  asca = true;
541  this->state->chunkList.push_back(chunkToInt(token));
542  token = strtok(nullptr, ",");
543  }
544  if (sctpMain->par("addIP").boolValue()) {
545  if (!asc)
546  state->chunkList.push_back(ASCONF);
547  if (!asca)
548  state->chunkList.push_back(ASCONF_ACK);
549  }
550  free(chunkscopy);
551  }
552 }

Referenced by process_ASSOCIATE(), and process_OPEN_PASSIVE().

◆ initCcParameters()

void inet::sctp::SctpAssociation::initCcParameters ( SctpPathVariables path)
protected

SctpCcFunctions.

398 {
399  path->cwnd = getInitialCwnd(path);
400  path->ssthresh = state->peerRwnd;
401  recordCwndUpdate(path);
402 
403  EV_DEBUG << simTime() << ":\tCC [initCCParameters]\t" << path->remoteAddress
404  << " (cmtCCGroup=" << path->cmtCCGroup << ")"
405  << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
406  assocBestPaths.clear();
407  assocMaxWndPaths.clear();
408 }

Referenced by pmStartPathManagement(), and stateEntered().

◆ initStreams()

void inet::sctp::SctpAssociation::initStreams ( uint32_t  inStreams,
uint32_t  outStreams 
)
protected
60  {
61  SctpReceiveStream *rcvStream = new SctpReceiveStream(this);
62  this->receiveStreams[i] = rcvStream;
63  rcvStream->setStreamId(i);
64  this->state->numMsgsReq[i] = 0;
65  snprintf(vectorName, sizeof(vectorName), "Stream %d Throughput", i);
66  streamThroughputVectors[i] = new cOutVector(vectorName);
67  }
68 }
69 
70 void SctpAssociation::addOutStreams(uint32_t outStreams)
71 {
72  uint32_t i, j;
73  EV_INFO << "Add " << outStreams << " outbound streams" << endl;
74  for (i = sendStreams.size(), j = 0; j < outStreams; i++, j++) {
75  SctpSendStream *sendStream = new SctpSendStream(this, i);
76  sendStream->setStreamId(i);
77  this->sendStreams[i] = sendStream;

Referenced by SctpAssociation().

◆ isToBeAccepted()

bool inet::sctp::SctpAssociation::isToBeAccepted ( ) const
inlineprotected
1205 { return listeningAssocId != -1; }

Referenced by stateEntered().

◆ listOrderedQ()

void inet::sctp::SctpAssociation::listOrderedQ ( )
protected
68 {
69  for (auto& elem : receiveStreams) {
70  EV_DEBUG << "stream " << elem.second->getStreamId() << ":\n";
71  elem.second->getOrderedQ()->printQueue();
72  EV_DEBUG << "\n";
73  }
74 }

◆ loadPacket()

void inet::sctp::SctpAssociation::loadPacket ( SctpPathVariables pathVar,
Ptr< SctpHeader > *  sctpMsg,
uint16_t *  chunksAdded,
uint16_t *  dataChunksAdded,
bool *  authAdded 
)
private
88 {
89  *sctpMsg = state->sctpMsg;
90  state->sctpMsg = nullptr;
91  *chunksAdded = state->chunksAdded;
92  *dataChunksAdded = state->dataChunksAdded;
93  *authAdded = state->authAdded;
94  EV_INFO << "loadPacket: path=" << pathVar->remoteAddress << " osb=" << pathVar->outstandingBytes << " -> " << pathVar->outstandingBytes + state->packetBytes << endl;
95  if (state->osbWithHeader) {
97  }
98  else {
100  }
102 
103  for (uint16_t i = 0; i < (*sctpMsg)->getSctpChunksArraySize(); i++) {
104  const SctpChunk *chunkPtr = (*sctpMsg)->getSctpChunks(i);
105  if (chunkPtr->getSctpChunkType() == 0) {
106  const SctpDataChunk *dataChunk = check_and_cast<const SctpDataChunk *>(chunkPtr);
107  if (dataChunk != nullptr) {
108  const uint32_t tsn = dataChunk->getTsn();
109  SctpDataVariables *chunk = retransmissionQ->payloadQueue.find(tsn)->second;
110  assert(chunk != nullptr);
111  chunk->queuedOnPath = pathVar;
112  chunk->queuedOnPath->queuedBytes += chunk->booksize;
113  chunk->setLastDestination(pathVar);
114  increaseOutstandingBytes(chunk, pathVar);
115  chunk->countsAsOutstanding = true;
116  }
117  }
118  }
119 }

Referenced by sendOnPath().

◆ makeAddStreamsRequestParameter()

SctpParameter * inet::sctp::SctpAssociation::makeAddStreamsRequestParameter ( uint32_t  srsn,
SctpResetReq info 
)
protected
377 {
378  SctpAddStreamsRequestParameter *addStreams = new SctpAddStreamsRequestParameter();
379  if (info->getInstreams() > 0) {
380  addStreams->setParameterType(ADD_INCOMING_STREAMS_REQUEST_PARAMETER);
381  addStreams->setNumberOfStreams(info->getInstreams());
384  state->numAddedInStreams = addStreams->getNumberOfStreams();
385  }
386  else if (info->getOutstreams() > 0) {
387  addStreams->setParameterType(ADD_OUTGOING_STREAMS_REQUEST_PARAMETER);
388  addStreams->setNumberOfStreams(info->getOutstreams());
391  state->numAddedOutStreams = addStreams->getNumberOfStreams();
392  }
393  addStreams->setSrReqSn(srsn);
394  addStreams->setByteLength(SCTP_ADD_STREAMS_REQUEST_PARAMETER_LENGTH);
395  return addStreams;
396 }

Referenced by sendStreamResetRequest().

◆ makeDataVarFromDataMsg()

SctpDataVariables * inet::sctp::SctpAssociation::makeDataVarFromDataMsg ( SctpDataMsg datMsg,
SctpPathVariables path 
)
private
178 {
179  SctpDataVariables *datVar = new SctpDataVariables();
180 
181  datMsg->setInitialDestination(path->remoteAddress);
182  datVar->setInitialDestination(path);
183 
184  datVar->bbit = datMsg->getBBit();
185  datVar->ebit = datMsg->getEBit();
186  datVar->ibit = datMsg->getSackNow();
187  datVar->enqueuingTime = datMsg->getEnqueuingTime();
188  datVar->expiryTime = datMsg->getExpiryTime();
189  datVar->ppid = datMsg->getPpid();
190  datVar->len = datMsg->getByteLength() * 8;
191  datVar->sid = datMsg->getSid();
192  datVar->allowedNoRetransmissions = datMsg->getRtx();
193  datVar->booksize = datMsg->getBooksize();
194  datVar->prMethod = datMsg->getPrMethod();
195  datVar->priority = datMsg->getPriority();
196  datVar->strReset = datMsg->getStrReset();
197 
198  // ------ Stream handling ---------------------------------------
199  auto iterator = sendStreams.find(datMsg->getSid());
200  SctpSendStream *stream = iterator->second;
201  uint32_t nextSSN = stream->getNextStreamSeqNum();
202  datVar->userData = datMsg->decapsulate();
203 
204  if (datMsg->getOrdered()) {
205  // ------ Ordered mode: assign SSN ---------
206  if (datMsg->getEBit()) {
207  datVar->ssn = nextSSN++;
208  }
209  else {
210  datVar->ssn = nextSSN;
211  }
212 
213  datVar->ordered = true;
214  if (nextSSN > 65535) {
215  stream->setNextStreamSeqNum(0);
216  }
217  else {
218  stream->setNextStreamSeqNum(nextSSN);
219  }
220  }
221  else {
222  // ------ Ordered mode: no SSN needed ------
223  datVar->ssn = 0;
224  datVar->ordered = false;
225  }
226 
228  return datVar;
229 }

Referenced by sendOnPath().

◆ makeIncomingStreamResetParameter()

SctpParameter * inet::sctp::SctpAssociation::makeIncomingStreamResetParameter ( uint32_t  srsn,
SctpResetReq info 
)
protected
358 {
359  SctpIncomingSsnResetRequestParameter *inResetParam;
360  inResetParam = new SctpIncomingSsnResetRequestParameter();
361  inResetParam->setParameterType(INCOMING_RESET_REQUEST_PARAMETER);
362  inResetParam->setSrReqSn(srsn);
363  if (info->getStreamsArraySize() > 0) {
364  inResetParam->setStreamNumbersArraySize(info->getStreamsArraySize());
365  for (uint i = 0; i < info->getStreamsArraySize(); i++) {
366  inResetParam->setStreamNumbers(i, info->getStreams(i));
367  state->requests[srsn].streams.push_back(inResetParam->getStreamNumbers(i));
368  state->resetInStreams.push_back(inResetParam->getStreamNumbers(i));
369  }
370  }
372  inResetParam->setByteLength(SCTP_INCOMING_RESET_REQUEST_PARAMETER_LENGTH + (info->getStreamsArraySize() * 2));
373  return inResetParam;
374 }

Referenced by sendStreamResetRequest().

◆ makeOutgoingStreamResetParameter()

SctpParameter * inet::sctp::SctpAssociation::makeOutgoingStreamResetParameter ( uint32_t  srsn,
SctpResetReq info 
)
protected
323 {
324  SctpOutgoingSsnResetRequestParameter *outResetParam;
325  outResetParam = new SctpOutgoingSsnResetRequestParameter();
326  outResetParam->setParameterType(OUTGOING_RESET_REQUEST_PARAMETER);
327  outResetParam->setSrReqSn(srsn);
328  outResetParam->setSrResSn(state->expectedStreamResetSequenceNumber - 1);
329  outResetParam->setLastTsn(state->nextTsn - 1);
330  state->requests[srsn].lastTsn = outResetParam->getLastTsn();
331  if (state->outstandingBytes == 0 && state->streamsToReset.size() == 0) {
332  if (info->getStreamsArraySize() > 0) {
333  outResetParam->setStreamNumbersArraySize(info->getStreamsArraySize());
334  for (uint i = 0; i < info->getStreamsArraySize(); i++) {
335  outResetParam->setStreamNumbers(i, (uint16_t)info->getStreams(i));
336  state->resetOutStreams.push_back(outResetParam->getStreamNumbers(i));
337  state->requests[srsn].streams.push_back(outResetParam->getStreamNumbers(i));
338  }
339  }
340  }
341  else if (state->streamsToReset.size() > 0) {
342  outResetParam->setStreamNumbersArraySize(state->streamsToReset.size());
343  uint16_t i = 0;
344  for (std::list<uint16_t>::iterator it = state->streamsToReset.begin(); it != state->streamsToReset.end(); ++it) {
345  outResetParam->setStreamNumbers(i, *it);
346  state->resetOutStreams.push_back(outResetParam->getStreamNumbers(i));
347  state->requests[srsn].streams.push_back(outResetParam->getStreamNumbers(i));
348  i++;
349  }
350  state->streamsToReset.clear();
351  }
353  outResetParam->setByteLength(SCTP_OUTGOING_RESET_REQUEST_PARAMETER_LENGTH + (outResetParam->getStreamNumbersArraySize() * 2));
354  return outResetParam;
355 }

Referenced by sendStreamResetRequest().

◆ makeRoomForTsn()

bool inet::sctp::SctpAssociation::makeRoomForTsn ( const uint32_t  tsn,
const uint32_t  length,
const bool  uBit 
)
protected
2155 {
2156  EV_INFO << simTime() << ":\tmakeRoomForTsn:"
2157  << " tsn=" << tsn
2158  << " length=" << length
2159  << " highestTsn=" << state->gapList.getHighestTsnReceived() << endl;
2161 
2162  // Reneging may not happen when it is turned off!
2163  assert(state->disableReneging == false);
2164 
2165  // Get the highest TSN of the GapAck blocks.
2166  uint32_t tryTsn = state->gapList.getHighestTsnReceived();
2167  uint32_t sum = 0;
2168  while ((sum < length) &&
2169  (tryTsn > state->gapList.getCumAckTsn()))
2170  {
2171  // ====== New TSN is larger than highest one in GapList? ==============
2172  if (tsnGt(tsn, tryTsn)) {
2173  // There is no space for a TSN that high!
2174  EV_DETAIL << "makeRoomForTsn:"
2175  << " tsn=" << tryTsn
2176  << " tryTsn=" << tryTsn << " -> no space" << endl;
2177  return false;
2178  }
2179 
2180  const uint32_t oldSum = sum;
2181  // ====== Iterate all streams to find chunk with TSN "tryTsn" =========
2182  for (auto& elem : receiveStreams) {
2183  SctpReceiveStream *receiveStream = elem.second;
2184 
2185  // ====== Get chunk to drop ========================================
2186  SctpQueue *queue;
2187  if (uBit) {
2188  queue = receiveStream->getUnorderedQ(); // Look in unordered queue
2189  }
2190  else {
2191  queue = receiveStream->getOrderedQ(); // Look in ordered queue
2192  }
2193  SctpDataVariables *chunk = queue->getChunk(tryTsn);
2194  if (chunk == nullptr) { // 12.06.08
2195  EV_DETAIL << tryTsn << " not found in orderedQ. Try deliveryQ" << endl;
2196  // Chunk is already in delivery queue.
2197  queue = receiveStream->getDeliveryQ();
2198  chunk = queue->getChunk(tryTsn);
2199  }
2200 
2201  // ====== A chunk has been found -> drop it ========================
2202  if (chunk != nullptr) {
2203  sum += chunk->len;
2204  if (queue->deleteMsg(tryTsn)) {
2205  EV_INFO << tryTsn << " found and deleted" << endl;
2207  state->queuedReceivedBytes -= chunk->len / 8;
2208  if (ssnGt(receiveStream->getExpectedStreamSeqNum(), chunk->ssn)) {
2209  receiveStream->setExpectedStreamSeqNum(chunk->ssn);
2210  }
2211 
2212  auto iter = sctpMain->assocStatMap.find(assocId);
2213  iter->second.numChunksReneged++;
2214  }
2216  state->gapList.removeFromGapList(tryTsn);
2217 
2218  break;
2219  }
2220  else {
2221  EV_INFO << "TSN " << tryTsn << " not found in stream "
2222  << receiveStream->getStreamId() << endl;
2223  }
2224  }
2225  if (sum == oldSum) {
2226  EV_INFO << tryTsn << " not found in any stream" << endl;
2227  }
2228  tryTsn--;
2229  }
2230 
2231  return true;
2232 }

Referenced by processDataArrived().

◆ makeSsnTsnResetParameter()

SctpParameter * inet::sctp::SctpAssociation::makeSsnTsnResetParameter ( uint32_t  srsn)
protected
399 {
400  SctpSsnTsnResetRequestParameter *resetParam;
401  resetParam = new SctpSsnTsnResetRequestParameter();
402  resetParam->setParameterType(SSN_TSN_RESET_REQUEST_PARAMETER);
403  resetParam->setSrReqSn(srsn);
404  resetParam->setByteLength(SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_LENGTH);
406  return resetParam;
407 }

Referenced by sendStreamResetRequest().

◆ makeVarFromMsg()

SctpDataVariables * inet::sctp::SctpAssociation::makeVarFromMsg ( SctpDataChunk datachunk)
protected
2246 {
2247  SctpDataVariables *chunk = new SctpDataVariables();
2248 
2249  chunk->bbit = dataChunk->getBBit();
2250  chunk->ebit = dataChunk->getEBit();
2251  chunk->ibit = dataChunk->getIBit();
2252  chunk->sid = dataChunk->getSid();
2253  chunk->ssn = dataChunk->getSsn();
2254  chunk->ppid = dataChunk->getPpid();
2255  chunk->tsn = dataChunk->getTsn();
2256  if (!dataChunk->getUBit()) {
2257  chunk->ordered = true;
2258  }
2259  else {
2260  chunk->ordered = false;
2261  }
2262  SctpSimpleMessage *smsg = check_and_cast<SctpSimpleMessage *>(dataChunk->decapsulate());
2263  /* auto& smsg = dataChunk->Chunk::peek<SctpSimpleMessage>(Chunk::BackwardIterator(B(0)));*/
2264 
2265  chunk->userData = smsg;
2266  EV_INFO << "smsg encapsulate? " << smsg->getEncaps() << endl;
2267  if (smsg->getEncaps())
2268  chunk->len = smsg->getByteLength() * 8;
2269  else
2270  chunk->len = smsg->getDataLen() * 8;
2271  chunk->firstSendTime = dataChunk->getFirstSendTime();
2273 
2274  EV_INFO << "makeVarFromMsg: queuedBytes has been increased to "
2275  << state->queuedReceivedBytes << endl;
2276  return chunk;
2277 }

Referenced by processDataArrived().

◆ midGt()

static bool inet::sctp::SctpAssociation::midGt ( const uint32_t  mid1,
const uint32_t  mid2 
)
inlinestatic
1081 { return SCTP_TSN_GT(mid1, mid2); }

◆ moveChunkToOtherPath()

void inet::sctp::SctpAssociation::moveChunkToOtherPath ( SctpDataVariables chunk,
SctpPathVariables newPath 
)
private
3897 {
3898  // ======= Remove chunk from outstanding bytes ===========================
3899  if (chunk->countsAsOutstanding) {
3900  decreaseOutstandingBytes(chunk);
3901  }
3902 
3903  // ====== Prepare next destination =======================================
3904  chunk->hasBeenFastRetransmitted = false;
3905  chunk->gapReports = 0;
3906  chunk->setNextDestination(newPath);
3907 
3908  // ====== Rebook chunk on new path =======================================
3909  assert(chunk->queuedOnPath->queuedBytes >= chunk->booksize);
3910  chunk->queuedOnPath->queuedBytes -= chunk->booksize;
3911  chunk->queuedOnPath->statisticsPathQueuedSentBytes->record(chunk->queuedOnPath->queuedBytes);
3912 
3913  chunk->queuedOnPath = chunk->getNextDestinationPath();
3914  chunk->queuedOnPath->queuedBytes += chunk->booksize;
3915  chunk->queuedOnPath->statisticsPathQueuedSentBytes->record(chunk->queuedOnPath->queuedBytes);
3916 
3917  // ====== Perform bookkeeping ============================================
3918  // Check, if chunk_ptr->tsn is already in transmission queue.
3919  // This can happen in case multiple timeouts occur in succession.
3920  if (!transmissionQ->checkAndInsertChunk(chunk->tsn, chunk)) {
3921  EV_DETAIL << "TSN " << chunk->tsn << " already in transmissionQ" << endl;
3922  return;
3923  }
3924  else {
3925  chunk->enqueuedInTransmissionQ = true;
3926  EV_DETAIL << "Inserting TSN " << chunk->tsn << " into transmissionQ" << endl;
3927  auto q = qCounter.roomTransQ.find(chunk->getNextDestination());
3928  q->second += ADD_PADDING(chunk->len / 8 + SCTP_DATA_CHUNK_LENGTH);
3929  auto qb = qCounter.bookedTransQ.find(chunk->getNextDestination());
3930  qb->second += chunk->booksize;
3931  state->peerRwnd += (chunk->booksize + state->bytesToAddPerPeerChunk);
3932  if (state->peerAllowsChunks) {
3933  state->peerMsgRwnd++;
3934  }
3935  }
3936  if (state->peerRwnd > state->initialPeerRwnd) {
3938  }
3941  }
3942 
3943  // T.D. 02.08.2011: The peer window may not be full anymore!
3944  if ((state->peerWindowFull) && (state->peerRwnd > 0)) {
3945  state->peerWindowFull = false;
3946  }
3947 
3948  statisticsPeerRwnd->record(state->peerRwnd);
3949 }

Referenced by chunkReschedulingControl(), and process_TIMEOUT_RTX().

◆ msgMustBeAbandoned()

bool inet::sctp::SctpAssociation::msgMustBeAbandoned ( SctpDataMsg msg,
int32_t  stream,
bool  ordered 
)
protected

◆ nextChunkFitsIntoPacket()

bool inet::sctp::SctpAssociation::nextChunkFitsIntoPacket ( SctpPathVariables path,
int32_t  bytes 
)
protected
2625 {
2626  int32_t nextStream = -1;
2627  SctpSendStream *stream;
2628 
2629  /* Only change stream if we don't have to finish a fragmented message */
2631  nextStream = state->lastStreamScheduled;
2632  else
2633  nextStream = (this->*ssFunctions.ssGetNextSid)(path, true);
2634 
2635  if (nextStream == -1)
2636  return false;
2637 
2638  stream = sendStreams.find(nextStream)->second;
2639 
2640  if (stream) {
2641  cPacketQueue *streamQ = nullptr;
2642 
2643  if (!stream->getUnorderedStreamQ()->isEmpty())
2644  streamQ = stream->getUnorderedStreamQ();
2645  else if (!stream->getStreamQ()->isEmpty())
2646  streamQ = stream->getStreamQ();
2647 
2648  if (streamQ) {
2649  int32_t b = ADD_PADDING(check_and_cast<SctpDataMsg *>(streamQ->front())->getEncapsulatedPacket()->getByteLength() + SCTP_DATA_CHUNK_LENGTH);
2650 
2651  /* Check if next message would be fragmented */
2652  if (b > (int32_t)state->fragPoint + (int32_t)SCTP_DATA_CHUNK_LENGTH) {
2653  /* Test if fragment fits */
2654  if (bytes >= (int32_t)state->fragPoint)
2655  return true;
2656  else
2657  return false;
2658  }
2659 
2660  /* Message doesn't need to be fragmented, just try if it fits */
2661  if (b <= bytes)
2662  return true;
2663  else
2664  return false;
2665  }
2666  }
2667 
2668  return false;
2669 }

Referenced by sendOnPath().

◆ nonRenegablyAckChunk()

void inet::sctp::SctpAssociation::nonRenegablyAckChunk ( SctpDataVariables chunk,
SctpPathVariables sackPath,
simtime_t &  rttEstimation,
Sctp::AssocStat assocStat 
)
private
1855 {
1856  SctpPathVariables *lastPath = chunk->getLastDestinationPath();
1857  assert(lastPath != nullptr);
1858 
1859  // ====== Bookkeeping ====================================================
1860  // Subtract chunk size from sender buffer size
1861  state->sendBuffer -= chunk->len / 8;
1862 
1863  // Subtract chunk size from the queue size of its stream
1864  auto streamIterator = sendStreams.find(chunk->sid);
1865  assert(streamIterator != sendStreams.end());
1866  SctpSendStream *stream = streamIterator->second;
1867  assert(stream != nullptr);
1868  cPacketQueue *streamQ = (chunk->ordered == false) ? stream->getUnorderedStreamQ() : stream->getStreamQ();
1869  assert(streamQ != nullptr);
1870 
1871  if (chunk->priority > 0) {
1872  state->queuedDroppableBytes -= chunk->len / 8;
1873  }
1874 
1875  if ((chunk->hasBeenCountedAsNewlyAcked == false) &&
1876  (chunk->hasBeenAcked == false))
1877  {
1878  if ((state->cmtMovedChunksReduceCwnd == false) ||
1879  (chunk->hasBeenMoved == false))
1880  {
1881  chunk->hasBeenCountedAsNewlyAcked = true;
1882  // The chunk has not been acked before.
1883  // Therefore, its size may *once* be counted as newly acked.
1884  lastPath->newlyAckedBytes += chunk->booksize;
1885  }
1886  }
1887 
1888  assert(chunk->queuedOnPath->queuedBytes >= chunk->booksize);
1889  chunk->queuedOnPath->queuedBytes -= chunk->booksize;
1890  chunk->queuedOnPath->statisticsPathQueuedSentBytes->record(chunk->queuedOnPath->queuedBytes);
1891  chunk->queuedOnPath = nullptr;
1892 
1893  assert(state->queuedSentBytes >= chunk->booksize);
1894  state->queuedSentBytes -= chunk->booksize;
1896  if (assocStat) {
1897  assocStat->ackedBytes += chunk->len / 8;
1898  }
1899  if ((assocStat) && (fairTimer)) {
1900  assocStat->fairAckedBytes += chunk->len / 8;
1901  }
1902 
1903  if ((state->allowCMT == true) &&
1904  (state->cmtSlowPathRTTUpdate == true) &&
1905  (lastPath->waitingForRTTCalculaton == false) &&
1906  (lastPath != sackPath) &&
1907  (chunk->numberOfTransmissions == 1) &&
1908  (chunk->hasBeenMoved == false) &&
1909  (chunk->hasBeenReneged == false))
1910  {
1911  // Slow Path Update
1912  // Remember this chunk's TSN and send time in order to update the
1913  // path's RTT using a stale SACK on its own path.
1914  lastPath->tsnForRTTCalculation = chunk->tsn;
1915  lastPath->txTimeForRTTCalculation = chunk->sendTime;
1916  lastPath->waitingForRTTCalculaton = true;
1917  }
1918 
1919  // ====== RTT calculation ================================================
1920  if ((chunkHasBeenAcked(chunk) == false) && (chunk->countsAsOutstanding)) {
1921  if ((chunk->numberOfTransmissions == 1) && (lastPath == sackPath) && (chunk->hasBeenMoved == false)) {
1922  const simtime_t timeDifference = simTime() - chunk->sendTime;
1923  if ((timeDifference < rttEstimation) || (rttEstimation == SIMTIME_MAX)) {
1924  rttEstimation = timeDifference;
1925  }
1926  }
1927  decreaseOutstandingBytes(chunk);
1928  }
1929 
1930  // ====== Remove chunk pointer from ChunkMap =============================
1931  // The chunk still has to be remembered as acknowledged!
1932  ackChunk(chunk, sackPath);
1933 
1934  // ====== Remove chunk from transmission queue ===========================
1935  // Dequeue chunk, cause it has been acked
1936  if (transmissionQ->getChunk(chunk->tsn)) {
1937  transmissionQ->removeMsg(chunk->tsn);
1938  chunk->enqueuedInTransmissionQ = false;
1939  auto q = qCounter.roomTransQ.find(chunk->getNextDestination());
1940  q->second -= ADD_PADDING(chunk->len / 8 + SCTP_DATA_CHUNK_LENGTH);
1941  auto qb = qCounter.bookedTransQ.find(chunk->getNextDestination());
1942  qb->second -= chunk->booksize;
1943  }
1944 
1945  // ====== Remove chunk from retransmission queue =========================
1946  chunk = retransmissionQ->getAndExtractChunk(chunk->tsn);
1947  if (chunk->userData != nullptr) {
1948  delete chunk->userData;
1949  }
1950  delete chunk;
1951 }

Referenced by dequeueAckedChunks(), and handleChunkReportedAsAcked().

◆ numUsableStreams()

int32_t inet::sctp::SctpAssociation::numUsableStreams ( )
protected
164  {
165  continue;
166  }
167 
168  if (sendStreams.find(testsid)->second->getUnorderedStreamQ()->getLength() > 0 ||
169  sendStreams.find(testsid)->second->getStreamQ()->getLength() > 0)
170  {
171  sid = testsid;
172  EV_DETAIL << "Stream Scheduler: chose sid " << sid << ".\n";

Referenced by SctpAssociation().

◆ orderedQueueEmptyOfStream()

bool inet::sctp::SctpAssociation::orderedQueueEmptyOfStream ( uint16_t  sid)
protected
84 {
85  auto streamIterator = sendStreams.find(sid);
86  assert(streamIterator != sendStreams.end());
87  return streamIterator->second->getStreamQ()->isEmpty();
88 }

Referenced by process_STREAM_RESET().

◆ pathMapLargestSpace()

bool inet::sctp::SctpAssociation::pathMapLargestSpace ( const SctpPathVariables left,
const SctpPathVariables right 
)
staticprivate
159 {
160  const int l = (left->cwnd - left->outstandingBytes);
161  const int r = (right->cwnd - right->outstandingBytes);
162  return l > r;
163 }

Referenced by stateEntered().

◆ pathMapLargestSpaceAndSSThreshold()

bool inet::sctp::SctpAssociation::pathMapLargestSpaceAndSSThreshold ( const SctpPathVariables left,
const SctpPathVariables right 
)
staticprivate
166 {
167  if (left->ssthresh != right->ssthresh) {
168  return left->ssthresh > right->ssthresh;
169  }
170 
171  const int l = (left->cwnd - left->outstandingBytes);
172  const int r = (right->cwnd - right->outstandingBytes);
173  return l > r;
174 }

Referenced by stateEntered().

◆ pathMapLargestSSThreshold()

bool inet::sctp::SctpAssociation::pathMapLargestSSThreshold ( const SctpPathVariables left,
const SctpPathVariables right 
)
staticprivate
154 {
155  return left->ssthresh > right->ssthresh;
156 }

Referenced by stateEntered().

◆ pathMapRandomized()

bool inet::sctp::SctpAssociation::pathMapRandomized ( const SctpPathVariables left,
const SctpPathVariables right 
)
staticprivate
144 {
145  return left->sendAllRandomizer < right->sendAllRandomizer;
146 }

Referenced by stateEntered().

◆ pathMapSmallestLastTransmission()

bool inet::sctp::SctpAssociation::pathMapSmallestLastTransmission ( const SctpPathVariables left,
const SctpPathVariables right 
)
staticprivate
149 {
150  return left->lastTransmission < right->lastTransmission;
151 }

Referenced by stateEntered().

◆ pathStatusIndication()

void inet::sctp::SctpAssociation::pathStatusIndication ( const SctpPathVariables path,
bool  status 
)
protected
2823 {
2824  Indication *msg = new Indication("StatusInfo", SCTP_I_STATUS);
2825  auto& cmd = msg->addTag<SctpStatusReq>();
2826  cmd->setPathId(path->remoteAddress);
2827  cmd->setSocketId(assocId);
2828  cmd->setActive(status);
2829  if (!status) {
2830  auto iter = sctpMain->assocStatMap.find(assocId);
2831  iter->second.numPathFailures++;
2832  }
2833  sendToApp(msg);
2834 }

Referenced by pmClearPathCounter(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().

◆ pathStreamSchedulerManual()

int32_t inet::sctp::SctpAssociation::pathStreamSchedulerManual ( SctpPathVariables path,
bool  peek 
)
protected
473  {
474  if (path == iterator->second)
475  break;
476  pathNo++;
477  }
478  EV_INFO << "Stream Scheduler: about to send on " << pathNo + 1 << ". path" << endl;
479 
480  testsid = state->lastStreamScheduled;
481 
482  do {
483  testsid = (testsid + 1) % outboundStreams;
484 
485  if (state->ssStreamToPathMap[testsid] == (int32_t)pathNo) {
486  sid = testsid;
487  EV_DETAIL << "Stream Scheduler: chose sid " << sid << ".\n";
488  if (!peek)
489  state->lastStreamScheduled = sid;
490  }
491  } while (sid == -1 && testsid != (int32_t)state->lastStreamScheduled);
492 
493  EV_INFO << "streamScheduler sid=" << sid << " lastStream=" << lastsid << " outboundStreams=" << outboundStreams << " next=" << state->ssNextStream << "\n";
494 
495  return sid;
496 }
497 
499 {
500  int32_t thisPath = -1;
501  int32_t workingPaths = 0;
502  for (auto& elem : sctpPathMap) {
503  SctpPathVariables *myPath = elem.second;
504  if (myPath->activePath) {
505  if (myPath == path) {
506  thisPath = workingPaths;
507  }
508  workingPaths++;
509  }
510  }
511  if (thisPath == -1) {
512  std::cout << "THIS PATH IS NOT WORKING???" << endl;
513  return -1;
514  }
515 
516  int32_t sid = -1;
517  for (SctpSendStreamMap::const_iterator iterator = sendStreams.begin();
518  iterator != sendStreams.end(); iterator++)
519  {
520  SctpSendStream *stream = iterator->second;

Referenced by SctpAssociation().

◆ pathStreamSchedulerMapToPath()

int32_t inet::sctp::SctpAssociation::pathStreamSchedulerMapToPath ( SctpPathVariables path,
bool  peek 
)
protected
524  {
525  assert(sid == -1);
526  sid = stream->getStreamId();
527  break;
528  }
529  }
530  }
531 
532  EV_INFO << "pathStreamSchedulerMapToPath sid=" << sid
533  << " path=" << path->remoteAddress
534  << " (path " << (1 + thisPath)
535  << " of " << workingPaths << ")" << endl;
536  return sid;
537 }
538 
539 } // namespace sctp
540 } // namespace inet
541 

Referenced by SctpAssociation().

◆ peekAbandonedChunk()

SctpDataVariables * inet::sctp::SctpAssociation::peekAbandonedChunk ( const SctpPathVariables path)
protected
2381 {
2382  SctpDataVariables *retChunk = nullptr;
2383 
2384  if (state->prMethod != 0 && !retransmissionQ->payloadQueue.empty()) {
2385  for (auto& elem : retransmissionQ->payloadQueue) {
2386  SctpDataVariables *chunk = elem.second;
2387 
2388  if (chunk->getLastDestinationPath() == path) {
2389  /* Apply policies if necessary */
2390  if (!chunk->hasBeenAbandoned && !chunk->hasBeenAcked &&
2391  (chunk->hasBeenFastRetransmitted || chunk->hasBeenTimerBasedRtxed))
2392  {
2393  switch (chunk->prMethod) {
2394  case PR_TTL:
2395  if (chunk->expiryTime > 0 && chunk->expiryTime <= simTime()) {
2396  if (!chunk->hasBeenAbandoned) {
2397  EV_DETAIL << "TSN " << chunk->tsn << " will be abandoned"
2398  << " (expiryTime=" << chunk->expiryTime
2399  << " sendTime=" << chunk->sendTime << ")" << endl;
2400  chunk->hasBeenAbandoned = true;
2402  }
2403  }
2404  break;
2405 
2406  case PR_RTX:
2407  if (chunk->hasBeenFastRetransmitted && chunk->numberOfRetransmissions >= chunk->allowedNoRetransmissions) {
2408  if (!chunk->hasBeenAbandoned) {
2409  EV_DETAIL << "peekAbandonedChunk: TSN " << chunk->tsn << " will be abandoned"
2410  << " (maxRetransmissions=" << chunk->allowedNoRetransmissions << ")" << endl;
2411  chunk->hasBeenAbandoned = true;
2413  }
2414  }
2415  break;
2416  }
2417  }
2418 
2419  if (chunk->hasBeenAbandoned && chunk->sendForwardIfAbandoned) {
2420  retChunk = chunk;
2421  }
2422  }
2423  }
2424  }
2425  return retChunk;
2426 }

Referenced by processPacketDropArrived(), and sendOnPath().

◆ peekOutboundDataMsg()

SctpDataMsg* inet::sctp::SctpAssociation::peekOutboundDataMsg ( )
protected

◆ performStateTransition()

bool inet::sctp::SctpAssociation::performStateTransition ( const SctpEventCode event)
protected

Implemements the pure SCTP state machine.

1177 {
1178  EV_TRACE << "performStateTransition\n";
1179 
1180  if (event == SCTP_E_IGNORE) { // e.g. discarded segment
1181  EV_DETAIL << "Staying in state: " << stateName(fsm->getState()) << " (no FSM event)\n";
1182  return true;
1183  }
1184 
1185  // state machine
1186  int32_t oldState = fsm->getState();
1187 
1188  switch (fsm->getState()) {
1189  case SCTP_S_CLOSED:
1190  switch (event) {
1191  case SCTP_E_ABORT:
1192  FSM_Goto((*fsm), SCTP_S_CLOSED);
1193  break;
1194 
1195  case SCTP_E_OPEN_PASSIVE:
1196  FSM_Goto((*fsm), SCTP_S_CLOSED);
1197  break;
1198 
1199  case SCTP_E_ASSOCIATE:
1200  FSM_Goto((*fsm), SCTP_S_COOKIE_WAIT);
1201  break;
1202 
1203  case SCTP_E_RCV_INIT:
1204  FSM_Goto((*fsm), SCTP_S_CLOSED);
1205  break;
1206 
1207  case SCTP_E_RCV_ABORT:
1208  FSM_Goto((*fsm), SCTP_S_CLOSED);
1209  break;
1210 
1212  FSM_Goto((*fsm), SCTP_S_ESTABLISHED);
1213  break;
1214 
1215  case SCTP_E_CLOSE:
1216  FSM_Goto((*fsm), SCTP_S_CLOSED);
1217  break;
1218 
1219  default:
1220  break;
1221  }
1222  break;
1223 
1224  case SCTP_S_COOKIE_WAIT:
1225  switch (event) {
1226  case SCTP_E_RCV_ABORT:
1227  FSM_Goto((*fsm), SCTP_S_CLOSED);
1228  break;
1229 
1230  case SCTP_E_ABORT:
1231  FSM_Goto((*fsm), SCTP_S_CLOSED);
1232  break;
1233 
1234  case SCTP_E_RCV_INIT_ACK:
1235  FSM_Goto((*fsm), SCTP_S_COOKIE_ECHOED);
1236  break;
1237 
1239  FSM_Goto((*fsm), SCTP_S_ESTABLISHED);
1240  break;
1241 
1242  default:
1243  break;
1244  }
1245  break;
1246 
1247  case SCTP_S_COOKIE_ECHOED:
1248  switch (event) {
1249  case SCTP_E_RCV_ABORT:
1250  FSM_Goto((*fsm), SCTP_S_CLOSED);
1251  break;
1252 
1253  case SCTP_E_ABORT:
1254  FSM_Goto((*fsm), SCTP_S_CLOSED);
1255  break;
1256 
1257  case SCTP_E_RCV_COOKIE_ACK:
1258  FSM_Goto((*fsm), SCTP_S_ESTABLISHED);
1259 // sendEstabIndicationToApp();
1260  break;
1261 
1262  default:
1263  break;
1264  }
1265  break;
1266 
1267  case SCTP_S_ESTABLISHED:
1268  switch (event) {
1269  case SCTP_E_SEND:
1270  FSM_Goto((*fsm), SCTP_S_ESTABLISHED);
1271  break;
1272 
1273  case SCTP_E_ABORT:
1274  FSM_Goto((*fsm), SCTP_S_CLOSED);
1275  break;
1276 
1277  case SCTP_E_RCV_ABORT:
1278  FSM_Goto((*fsm), SCTP_S_CLOSED);
1279  break;
1280 
1281  case SCTP_E_CLOSE:
1282  case SCTP_E_SHUTDOWN:
1283  FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING);
1284  break;
1285 
1286  case SCTP_E_STOP_SENDING:
1287  FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING);
1288  state->stopSending = true;
1289  state->lastTsn = state->nextTsn - 1;
1290  break;
1291 
1292  case SCTP_E_RCV_SHUTDOWN:
1293  FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED);
1294  break;
1295 
1296  default:
1297  break;
1298  }
1299  break;
1300 
1302  switch (event) {
1303  case SCTP_E_RCV_ABORT:
1304  FSM_Goto((*fsm), SCTP_S_CLOSED);
1305  break;
1306 
1307  case SCTP_E_ABORT:
1308  FSM_Goto((*fsm), SCTP_S_CLOSED);
1309  break;
1310 
1312  FSM_Goto((*fsm), SCTP_S_SHUTDOWN_SENT);
1313  break;
1314 
1315  case SCTP_E_RCV_SHUTDOWN:
1316  FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED);
1317  break;
1318 
1320  FSM_Goto((*fsm), SCTP_S_CLOSED);
1321  break;
1322 
1323  default:
1324  break;
1325  }
1326  break;
1327 
1329  switch (event) {
1330  case SCTP_E_ABORT:
1331  FSM_Goto((*fsm), SCTP_S_CLOSED);
1332  break;
1333 
1334  case SCTP_E_RCV_ABORT:
1335  FSM_Goto((*fsm), SCTP_S_CLOSED);
1336  break;
1337 
1339  FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT);
1340  break;
1341 
1342  case SCTP_E_SHUTDOWN:
1344  break;
1345 
1346  default:
1347  break;
1348  }
1349  break;
1350 
1351  case SCTP_S_SHUTDOWN_SENT:
1352  switch (event) {
1353  case SCTP_E_ABORT:
1354  FSM_Goto((*fsm), SCTP_S_CLOSED);
1355  break;
1356 
1357  case SCTP_E_RCV_ABORT:
1358  FSM_Goto((*fsm), SCTP_S_CLOSED);
1359  break;
1360 
1362  FSM_Goto((*fsm), SCTP_S_CLOSED);
1363  break;
1364 
1365  case SCTP_E_RCV_SHUTDOWN:
1367  FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT);
1368  break;
1369 
1370  default:
1371  break;
1372  }
1373  break;
1374 
1376  switch (event) {
1377  case SCTP_E_ABORT:
1378  FSM_Goto((*fsm), SCTP_S_CLOSED);
1379  break;
1380 
1381  case SCTP_E_RCV_ABORT:
1382  FSM_Goto((*fsm), SCTP_S_CLOSED);
1383  break;
1384 
1386  FSM_Goto((*fsm), SCTP_S_CLOSED);
1387  break;
1388 
1389  default:
1390  break;
1391  }
1392  break;
1393  }
1394 
1395  if (oldState != fsm->getState()) {
1396  EV_DETAIL << "Transition: " << stateName(oldState) << " --> " << stateName(fsm->getState())
1397  << " (event was: " << eventName(event) << ")\n";
1398  EV_DETAIL << sctpMain->getName() << ": " << stateName(oldState) << " --> "
1399  << stateName(fsm->getState()) << " (on " << eventName(event) << ")\n";
1400  stateEntered(fsm->getState());
1401  }
1402  else {
1403  EV << "Staying in state: " << stateName(fsm->getState())
1404  << " (event was: " << eventName(event) << ")\n";
1405  }
1406 
1407  if (event == SCTP_E_ABORT && oldState == fsm->getState() && fsm->getState() == SCTP_S_CLOSED)
1408  return true;
1409 
1410  if (oldState != fsm->getState() && fsm->getState() == SCTP_S_CLOSED) {
1411  EV_DETAIL << "return false because oldState=" << oldState << " and new state is closed\n";
1412  return false;
1413  }
1414  else
1415  return true;
1416 }

Referenced by process_RCV_Message(), processAppCommand(), processCookieAckArrived(), processCookieEchoArrived(), processInitAckArrived(), processInitArrived(), processTimer(), pushUlp(), sendShutdown(), and sendShutdownAck().

◆ pmClearPathCounter()

void inet::sctp::SctpAssociation::pmClearPathCounter ( SctpPathVariables path)
protected
2809 {
2810  state->errorCount = 0;
2811  path->pathErrorCount = 0;
2812  if (path->activePath == false) {
2813  /* notify the application */
2814  pathStatusIndication(path, true);
2815  EV_INFO << "Path " << path->remoteAddress
2816  << " state changes from INACTIVE to ACTIVE !!!" << endl;
2817  path->activePath = true; // Mark path as active!
2818  }
2819 }

Referenced by processHeartbeatAckArrived(), and processSackArrived().

◆ pmDataIsSentOn()

void inet::sctp::SctpAssociation::pmDataIsSentOn ( SctpPathVariables path)
protected
2729 {
2731  /* restart hb_timer on this path */
2732  stopTimer(path->HeartbeatTimer);
2733  if (sctpMain->getEnableHeartbeats()) {
2734  path->heartbeatTimeout = path->pathRto + sctpMain->getHbInterval();
2735  startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
2736  EV_DETAIL << "Restarting HB timer on path " << path->remoteAddress
2737  << " to expire at time " << path->heartbeatTimeout << endl;
2738  }
2739  }
2740 
2741  path->cwndTimeout = path->pathRto;
2742  stopTimer(path->CwndTimer);
2743  startTimer(path->CwndTimer, path->cwndTimeout);
2744 
2745  EV_INFO << "Restarting CWND timer on path " << path->remoteAddress
2746  << " to expire at time " << path->cwndTimeout << endl;
2747 }

Referenced by sendOnPath().

◆ pmRttMeasurement()

void inet::sctp::SctpAssociation::pmRttMeasurement ( SctpPathVariables path,
const simtime_t &  rttEstimation 
)
protected
2838 {
2839  if (rttEstimation < SIMTIME_MAX) {
2840  if (simTime() > path->rttUpdateTime) {
2841  if (path->rttUpdateTime == SIMTIME_ZERO) {
2842  path->rttvar = rttEstimation.dbl() / 2;
2843  path->srtt = rttEstimation;
2844  path->pathRto = 3.0 * rttEstimation.dbl();
2845  path->pathRto = max(min(path->pathRto.dbl(), sctpMain->getRtoMax()), sctpMain->getRtoMin());
2846  }
2847  else {
2848  path->rttvar = (1.0 - sctpMain->par("rtoBeta").doubleValue()) * path->rttvar.dbl()
2849  + sctpMain->par("rtoBeta").doubleValue() * fabs(path->srtt.dbl() - rttEstimation.dbl());
2850  path->srtt = (1.0 - sctpMain->par("rtoAlpha").doubleValue()) * path->srtt.dbl()
2851  + sctpMain->par("rtoAlpha").doubleValue() * rttEstimation.dbl();
2852  path->pathRto = path->srtt.dbl() + 4.0 * path->rttvar.dbl();
2853  path->pathRto = max(min(path->pathRto.dbl(), sctpMain->getRtoMax()), sctpMain->getRtoMin());
2854  }
2855  // RFC 2960, sect. 6.3.1: new RTT measurements SHOULD be made no more
2856  // than once per round-trip.
2857  path->rttUpdateTime = simTime() + path->srtt;
2858  path->statisticsPathRTO->record(path->pathRto);
2859  path->statisticsPathRTT->record(rttEstimation);
2860  }
2861  }
2862 }

Referenced by processHeartbeatAckArrived(), and processSackArrived().

◆ pmStartPathManagement()

void inet::sctp::SctpAssociation::pmStartPathManagement ( )
protected

Flow control.

2750 {
2751  SctpPathVariables *path;
2752  const NetworkInterface *rtie;
2753  int32_t i = 0;
2754  /* populate path structures !!! */
2755  /* set a high start value...this is appropriately decreased later (below) */
2757  for (auto& elem : sctpPathMap) {
2758  path = elem.second;
2759  path->pathErrorCount = 0;
2760  rtie = rt->getOutputInterfaceForDestination(path->remoteAddress);
2761  path->pmtu = rtie->getMtu();
2762  EV_DETAIL << "Path MTU of Interface " << i << " = " << path->pmtu << "\n";
2763  if (path->pmtu < state->assocPmtu) {
2764  state->assocPmtu = path->pmtu;
2765  }
2768  }
2769  initCcParameters(path);
2770  path->pathRto = sctpMain->getRtoInitial();
2771  path->srtt = path->pathRto;
2772  path->rttvar = SIMTIME_ZERO;
2773  /* from now on we may have one update per RTO/SRTT */
2774  path->rttUpdateTime = SIMTIME_ZERO;
2775 
2776  path->partialBytesAcked = 0;
2777  path->outstandingBytes = 0;
2778  path->activePath = true;
2779  // Timer probably not running, but stop it anyway I.R.
2780  stopTimer(path->T3_RtxTimer);
2781 
2782  if (path->remoteAddress == state->initialPrimaryPath && !path->confirmed) {
2783  path->confirmed = true;
2784  }
2785  EV_DETAIL << getFullPath() << " numberOfLocalAddresses=" << state->localAddresses.size() << "\n";
2786  if (sctpMain->getEnableHeartbeats()) {
2787  path->heartbeatTimeout = sctpMain->getHbInterval() + i * path->pathRto;
2788  stopTimer(path->HeartbeatTimer);
2789  if (!path->confirmed)
2790  sendHeartbeat(path);
2791  startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
2792  startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout);
2793  }
2794  path->statisticsPathRTO->record(path->pathRto);
2795  i++;
2796  }
2797 }

Referenced by stateEntered().

◆ preanalyseAppCommandEvent()

SctpEventCode inet::sctp::SctpAssociation::preanalyseAppCommandEvent ( int32_t  commandCode)
protected

Maps app command codes (msg kind of app command msgs) to SCTP_E_xxx event codes.

997 {
998  switch (commandCode) {
999  case SCTP_C_ASSOCIATE:
1000  return SCTP_E_ASSOCIATE;
1001 
1002  case SCTP_C_OPEN_PASSIVE:
1003  return SCTP_E_OPEN_PASSIVE;
1004 
1005  case SCTP_C_SEND:
1006  return SCTP_E_SEND;
1007 
1008  case SCTP_C_CLOSE:
1009  return SCTP_E_CLOSE;
1010 
1011  case SCTP_C_ABORT:
1012  return SCTP_E_ABORT;
1013 
1014  case SCTP_C_RECEIVE:
1015  return SCTP_E_RECEIVE;
1016 
1017  case SCTP_C_SEND_UNORDERED:
1018  return SCTP_E_SEND;
1019 
1020  case SCTP_C_SEND_ORDERED:
1021  return SCTP_E_SEND;
1022 
1023  case SCTP_C_PRIMARY:
1024  return SCTP_E_PRIMARY;
1025 
1027  return SCTP_E_QUEUE_MSGS_LIMIT;
1028 
1030  return SCTP_E_QUEUE_BYTES_LIMIT;
1031 
1032  case SCTP_C_SHUTDOWN:
1033  return SCTP_E_SHUTDOWN;
1034 
1035  case SCTP_C_NO_OUTSTANDING:
1036  return SCTP_E_SEND_SHUTDOWN_ACK;
1037 
1038  case SCTP_C_STREAM_RESET:
1039  return SCTP_E_STREAM_RESET;
1040 
1041  case SCTP_C_RESET_ASSOC:
1042  return SCTP_E_RESET_ASSOC;
1043 
1044  case SCTP_C_ADD_STREAMS:
1045  return SCTP_E_ADD_STREAMS;
1046 
1047  case SCTP_C_SEND_ASCONF:
1048  return SCTP_E_SEND_ASCONF; // Needed for multihomed NAT
1049 
1051  return SCTP_E_SET_STREAM_PRIO;
1052 
1053  case SCTP_C_ACCEPT:
1054  return SCTP_E_ACCEPT;
1055 
1057  return SCTP_E_ACCEPT_SOCKET_ID;
1058 
1059  case SCTP_C_SET_RTO_INFO:
1060  return SCTP_E_SET_RTO_INFO;
1061 
1062  default:
1063  EV_DETAIL << "commandCode=" << commandCode << "\n";
1064  throw cRuntimeError("Unknown message kind in app command");
1065  }
1066 }

Referenced by processAppCommand().

◆ printAssocBrief()

void inet::sctp::SctpAssociation::printAssocBrief ( )
protected

Utility: prints local/remote addr/port and app gate index/assocId.

288 {
289  EV_DETAIL << "Connection " << assocId << " "
290  << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort
291  << " on app[" << appGateIndex << "],assocId=" << assocId
292  << " in " << stateName(fsm->getState()) << "\n";
293 }

Referenced by processAppCommand(), and processSctpMessage().

◆ printOutstandingTsns()

void inet::sctp::SctpAssociation::printOutstandingTsns ( )
protected

◆ printSctpPathMap()

void inet::sctp::SctpAssociation::printSctpPathMap ( ) const
130 {
131  EV_DEBUG << "Sctp PathMap:" << endl;
132  for (const auto& elem : sctpPathMap) {
133  const SctpPathVariables *path = elem.second;
134  EV_DEBUG << " - " << path->remoteAddress << ": osb=" << path->outstandingBytes
135  << " cwnd=" << path->cwnd << endl;
136  }
137 }

Referenced by processInitAckArrived(), processInitArrived(), sendInit(), and sendInitAck().

◆ printSegmentBrief()

void inet::sctp::SctpAssociation::printSegmentBrief ( SctpHeader sctpmsg)
staticprotected

Utility: prints important header fields.

296 {
297  EV_STATICCONTEXT;
298 
299  EV_DETAIL << "." << sctpmsg->getSrcPort() << " > "
300  << "." << sctpmsg->getDestPort() << ": "
301  << "initTag " << sctpmsg->getVTag() << "\n";
302 }

◆ process_ABORT()

void inet::sctp::SctpAssociation::process_ABORT ( SctpEventCode event)
protected
430 {
431  EV_DEBUG << "SctpAssociationEventProc:process_ABORT; assoc=" << assocId << endl;
432  switch (fsm->getState()) {
433  case SCTP_S_ESTABLISHED:
435  sendAbort();
436  break;
437  }
438 }

Referenced by processAppCommand().

◆ process_ASSOCIATE()

void inet::sctp::SctpAssociation::process_ASSOCIATE ( SctpEventCode event,
SctpCommandReq sctpCommand,
cMessage *  msg 
)
protected
28 {
29  L3Address lAddr, rAddr;
30  SctpOpenReq *openCmd = check_and_cast<SctpOpenReq *>(sctpCommand);
31  auto request = check_and_cast<Request *>(msg);
32  auto& tags = request->getTags();
33  const auto& interfaceReq = tags.findTag<InterfaceReq>();
34  if (interfaceReq && interfaceReq->getInterfaceId() != -1) {
35  sctpMain->setInterfaceId(interfaceReq->getInterfaceId());
36  }
37 
38  EV_INFO << "SctpAssociationEventProc:process_ASSOCIATE\n";
39 
40  switch (fsm->getState()) {
41  case SCTP_S_CLOSED:
42  if (msg->getContextPointer() != nullptr) {
43  sctpMain->setSocketOptions((SocketOptions *)(msg->getContextPointer()));
44  }
45  initAssociation(openCmd);
46  state->active = true;
47  localAddressList = openCmd->getLocalAddresses();
48  EV_INFO << "process_ASSOCIATE: number of local addresses=" << localAddressList.size() << "\n";
49  lAddr = openCmd->getLocalAddresses().front();
50  if (!(openCmd->getRemoteAddresses().empty())) {
51  remoteAddressList = openCmd->getRemoteAddresses();
52  rAddr = openCmd->getRemoteAddresses().front();
53  }
54  else
55  rAddr = openCmd->getRemoteAddr();
56  localPort = openCmd->getLocalPort();
57  remotePort = openCmd->getRemotePort();
58  EV_DETAIL << "open active with fd=" << fd << " and assocId=" << assocId << endl;
59  fd = openCmd->getFd();
60  state->streamReset = openCmd->getStreamReset();
61  state->prMethod = openCmd->getPrMethod();
62  state->numRequests = openCmd->getNumRequests();
63  state->appLimited = openCmd->getAppLimited();
64  if (rAddr.isUnspecified() || remotePort == 0)
65  throw cRuntimeError("Error processing command OPEN_ACTIVE: remote address and port must be specified");
66 
67  if (localPort == 0) {
69  }
70  EV_INFO << "OPEN: " << lAddr << ":" << localPort << " --> " << rAddr << ":" << remotePort << "\n";
71 
72  sctpMain->updateSockPair(this, lAddr, rAddr, localPort, remotePort);
73  state->localRwnd = sctpMain->par("arwnd");
74  sendInit();
76  break;
77 
78  default:
79  throw cRuntimeError("Error processing command OPEN_ACTIVE: connection already exists");
80  }
81 }

Referenced by processAppCommand().

◆ process_CLOSE()

void inet::sctp::SctpAssociation::process_CLOSE ( SctpEventCode event)
protected
413 {
414  EV_DEBUG << "SctpAssociationEventProc:process_CLOSE; assoc=" << assocId << endl;
415  switch (fsm->getState()) {
416  case SCTP_S_ESTABLISHED:
418  sendShutdown();
419  break;
420 
422  if (getOutstandingBytes() == 0) {
424  }
425  break;
426  }
427 }

◆ process_OPEN_PASSIVE()

void inet::sctp::SctpAssociation::process_OPEN_PASSIVE ( SctpEventCode event,
SctpCommandReq sctpCommand,
cMessage *  msg 
)
protected
84 {
85  L3Address lAddr;
86  int16_t localPort;
87 
88  SctpOpenReq *openCmd = check_and_cast<SctpOpenReq *>(sctpCommand);
89 
90  EV_DEBUG << "SctpAssociationEventProc:process_OPEN_PASSIVE\n";
91 
92  switch (fsm->getState()) {
93  case SCTP_S_CLOSED:
94  if (msg->getContextPointer() != nullptr)
95  sctpMain->setSocketOptions((SocketOptions *)(msg->getContextPointer()));
96  initAssociation(openCmd);
97  state->fork = openCmd->getFork();
98  localAddressList = openCmd->getLocalAddresses();
99  EV_DEBUG << "process_OPEN_PASSIVE: number of local addresses=" << localAddressList.size() << "\n";
100  lAddr = openCmd->getLocalAddresses().front();
101  localPort = openCmd->getLocalPort();
102  inboundStreams = openCmd->getInboundStreams();
103  outboundStreams = openCmd->getOutboundStreams();
104  listening = true;
105  fd = openCmd->getFd();
106  EV_DETAIL << "open listening socket with fd=" << fd << " and assocId=" << assocId << endl;
107  state->localRwnd = sctpMain->par("arwnd");
108  state->localMsgRwnd = sctpMain->par("messageAcceptLimit");
109  state->streamReset = openCmd->getStreamReset();
110  state->numRequests = openCmd->getNumRequests();
111  state->messagesToPush = openCmd->getMessagesToPush();
112 
113  if (localPort == 0)
114  throw cRuntimeError("Error processing command OPEN_PASSIVE: local port must be specified");
115 
116  EV_DEBUG << "Assoc " << assocId << "::Starting to listen on: " << lAddr << ":" << localPort << "\n";
117 
118  sctpMain->updateSockPair(this, lAddr, L3Address(), localPort, 0);
119  break;
120 
121  default:
122  throw cRuntimeError("Error processing command OPEN_PASSIVE: connection already exists");
123  }
124 }

Referenced by processAppCommand().

◆ process_PRIMARY()

void inet::sctp::SctpAssociation::process_PRIMARY ( SctpEventCode event,
SctpCommandReq sctpCommand 
)
protected
326 {
327  SctpPathInfo *pinfo = check_and_cast<SctpPathInfo *>(sctpCommand);
328  state->setPrimaryPath(getPath(pinfo->getRemoteAddress()));
329 }

Referenced by processAppCommand().

◆ process_QUEUE_BYTES_LIMIT()

void inet::sctp::SctpAssociation::process_QUEUE_BYTES_LIMIT ( const SctpCommandReq sctpCommand)
protected
407 {
408  const SctpInfoReq *qinfo = check_and_cast<const SctpInfoReq *>(sctpCommand);
409  state->sendQueueLimit = qinfo->getText();
410 }

Referenced by processAppCommand().

◆ process_QUEUE_MSGS_LIMIT()

void inet::sctp::SctpAssociation::process_QUEUE_MSGS_LIMIT ( const SctpCommandReq sctpCommand)
protected

Queue Management.

401 {
402  const SctpInfoReq *qinfo = check_and_cast<const SctpInfoReq *>(sctpCommand);
403  state->queueLimit = qinfo->getText();
404 }

Referenced by processAppCommand().

◆ process_RCV_Message()

bool inet::sctp::SctpAssociation::process_RCV_Message ( SctpHeader sctpmsg,
const L3Address src,
const L3Address dest 
)
protected
70 {
71  // ====== Header checks ==================================================
72  EV_DEBUG << getFullPath() << " SctpAssociationRcvMessage:process_RCV_Message"
73  << " localAddr=" << localAddr
74  << " remoteAddr=" << remoteAddr << endl;
75  state->pktDropSent = false;
76 
77  SctpPathVariables *path = getPath(src);
78  const uint16_t srcPort = sctpmsg->getDestPort();
79  const uint16_t destPort = sctpmsg->getSrcPort();
80  const uint32_t numberOfChunks = sctpmsg->getSctpChunksArraySize();
81  EV_DETAIL << "numberOfChunks=" << numberOfChunks << endl;
82 
83 // state->sctpmsg = sctpmsg->dup();
84  bool authenticationNecessary = state->peerAuth;
85  state->sackAlreadySent = false;
86 
87  if (fsm->getState() != SCTP_S_CLOSED &&
88  fsm->getState() != SCTP_S_COOKIE_WAIT &&
89  fsm->getState() != SCTP_S_COOKIE_ECHOED &&
90  fsm->getState() != SCTP_S_SHUTDOWN_ACK_SENT &&
92  assocThroughputVector != nullptr)
93  {
95  state->lastAssocThroughputTime = simTime();
97  }
98  state->assocThroughput += B(sctpmsg->getChunkLength()).get();
99 
100  // ====== Handle chunks ==================================================
101  bool trans = true;
102  bool sendAllowed = false;
103  bool dupReceived = false;
104  bool dataChunkReceived = false;
105  bool shutdownCalled = false;
106  bool sackWasReceived = false;
107  for (uint32_t i = 0; i < numberOfChunks; i++) {
108 // SctpChunk *header = (SctpChunk *)(sctpmsg->getSctpChunks(0));
109  SctpChunk *header = sctpmsg->removeFirstChunk();
110  const uint8_t type = header->getSctpChunkType();
111  EV_DEBUG << "Header length: " << header->getByteLength() << endl;
112 
113  if ((type != INIT) &&
114  (type != ABORT) &&
115  (type != ERRORTYPE) &&
116  (sctpmsg->getVTag() != peerVTag))
117  {
118  EV_WARN << " VTag " << sctpmsg->getVTag() << " incorrect. Should be "
119  << peerVTag << " localVTag=" << localVTag << endl;
120  return true;
121  }
122 
123  if (authenticationNecessary) {
124  if (type == AUTH) {
125  EV_INFO << "AUTH received" << endl;
126  auto authChunk = check_and_cast<SctpAuthenticationChunk *>(header);
127  if (authChunk->getHMacIdentifier() != 1) {
128  sendHMacError(authChunk->getHMacIdentifier());
129  auto it = sctpMain->assocStatMap.find(assocId);
130  it->second.numAuthChunksRejected++;
131 // delete authChunk;
132  return true;
133  }
134  if (authChunk->getHMacOk() == false) {
135  delete authChunk;
136  auto it = sctpMain->assocStatMap.find(assocId);
137  it->second.numAuthChunksRejected++;
138  return true;
139  }
140  authenticationNecessary = false;
141  auto it = sctpMain->assocStatMap.find(assocId);
142  it->second.numAuthChunksAccepted++;
143 // delete authChunk;
144  continue;
145  }
146  else {
147  if (typeInChunkList(type)) {
148  return true;
149  }
150  }
151  }
152 
153  switch (type) {
154  case INIT: {
155  EV_INFO << "INIT received" << endl;
156  auto initChunk = check_and_cast<SctpInitChunk *>(header);
157  if ((initChunk->getNoInStreams() != 0) &&
158  (initChunk->getNoOutStreams() != 0) &&
159  (initChunk->getInitTag() != 0))
160  {
161  trans = processInitArrived(initChunk, srcPort, destPort);
162  }
163  i = numberOfChunks - 1;
164 // delete initChunk;
165  break;
166  }
167 
168  case INIT_ACK:
169  EV_INFO << "INIT_ACK received" << endl;
170  if (fsm->getState() == SCTP_S_COOKIE_WAIT) {
171  auto initAckChunk = check_and_cast<SctpInitAckChunk *>(header);
172  if ((initAckChunk->getNoInStreams() != 0) &&
173  (initAckChunk->getNoOutStreams() != 0) &&
174  (initAckChunk->getInitTag() != 0))
175  {
176  trans = processInitAckArrived(initAckChunk);
177  }
178  else if (initAckChunk->getInitTag() == 0) {
179  sendAbort();
181  return true;
182  }
183  i = numberOfChunks - 1;
184 // delete initAckChunk;
185  }
186  else {
187  EV_INFO << "INIT_ACK will be ignored" << endl;
188  }
189  break;
190 
191  case COOKIE_ECHO: {
192  EV_INFO << "COOKIE_ECHO received" << endl;
193  auto cookieEchoChunk = check_and_cast<SctpCookieEchoChunk *>(header);
194  trans = processCookieEchoArrived(cookieEchoChunk, src);
195 // delete cookieEchoChunk;
196  break;
197  }
198 
199  case COOKIE_ACK:
200  EV_INFO << "COOKIE_ACK received" << endl;
201  if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
202  check_and_cast<SctpCookieAckChunk *>(header);
203  trans = processCookieAckArrived();
204 // delete cookieAckChunk;
205  }
206  break;
207 
208  case DATA:
209  EV_INFO << "DATA received" << endl;
210  if (fsm->getState() == SCTP_S_CLOSED) {
211  EV_INFO << "DATA in state closed: send ABORT\n";
212  sendAbort(1);
214  return true;
215  }
216  if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
218  }
219  if (state->stopReading) {
220  if (state->shutdownChunk) {
221 // delete state->shutdownChunk;
222  state->shutdownChunk = nullptr;
223  }
224  delete header;
225  sendAbort();
226  /* if (state->sctpmsg) {
227  delete state->sctpmsg;
228  state->sctpmsg = nullptr;
229  }*/
231  return true;
232  }
233  if (!(fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED || fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) {
234  auto dataChunk = check_and_cast<SctpDataChunk *>(header);
235  if ((dataChunk->getByteLength() - SCTP_DATA_CHUNK_LENGTH) > 0) {
236  dacPacketsRcvd++;
237  const SctpEventCode event = processDataArrived(dataChunk);
238  if (event == SCTP_E_DELIVERED) {
239  if ((state->streamReset) && (state->incomingRequest != nullptr || state->resetRequested) &&
242  {
244  if (state->inOut) {
246  }
247  else {
249  }
250  }
251  dataChunkReceived = true;
252  state->sackAllowed = true;
253  }
254  else if (event == SCTP_E_SEND) {
255  dataChunkReceived = true;
256  state->sackAllowed = true;
257  }
258  else if (event == SCTP_E_DUP_RECEIVED) {
259  dupReceived = true;
260  }
261  else if (event == SCTP_E_ABORT) {
262  sendAbort();
264  return true;
265  }
266  else {
267  dataChunkReceived = false;
268  state->sackAllowed = false;
269  }
270  }
271  else {
272  sendAbort();
274  return true;
275  }
276 // delete dataChunk;
277  }
278  trans = true;
279  break;
280 
281  case SACK:
282  case NR_SACK: {
283  EV_INFO << "SACK chunk received" << endl;
284  auto sackChunk = check_and_cast<SctpSackChunk *>(header);
285  processSackArrived(sackChunk);
286  trans = true;
287  sendAllowed = true;
288 // delete sackChunk;
290  if (fsm->getState() == SCTP_S_SHUTDOWN_PENDING) {
291  EV_DETAIL << "No more packets: send SHUTDOWN" << endl;
292  sendShutdown();
294  shutdownCalled = true;
295  }
296  else if (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED) {
297  EV_DETAIL << "No more outstanding" << endl;
299  }
300  }
301  sackWasReceived = true;
302  break;
303  }
304 
305  case ABORT: {
306  auto abortChunk = check_and_cast<SctpAbortChunk *>(header);
307  EV_INFO << "ABORT with T-Bit "
308  << abortChunk->getT_Bit() << " received" << endl;
309  if (sctpmsg->getVTag() == localVTag || sctpmsg->getVTag() == peerVTag) {
312  }
313 // delete abortChunk;
314  break;
315  }
316 
317  case HEARTBEAT: {
318  EV_INFO << "HEARTBEAT received" << endl;
319  auto heartbeatChunk = check_and_cast<SctpHeartbeatChunk *>(header);
320  if (!(fsm->getState() == SCTP_S_CLOSED)) {
321  sendHeartbeatAck(heartbeatChunk, dest, src);
322  }
323  trans = true;
324 // delete heartbeatChunk;
325  if (path) {
326  path->numberOfHeartbeatsRcvd++;
327  path->vectorPathRcvdHb->record(path->numberOfHeartbeatsRcvd);
328  }
329  break;
330  }
331 
332  case HEARTBEAT_ACK: {
333  EV_INFO << "HEARTBEAT_ACK received" << endl;
334  if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
336  }
337  auto heartbeatAckChunk = check_and_cast<SctpHeartbeatAckChunk *>(header);
338  if (path) {
339  processHeartbeatAckArrived(heartbeatAckChunk, path);
340  }
341  trans = true;
342 // delete heartbeatAckChunk;
343  break;
344  }
345 
346  case SHUTDOWN: {
347  EV_INFO << "SHUTDOWN received" << endl;
348  auto shutdownChunk = check_and_cast<SctpShutdownChunk *>(header);
349  if (shutdownChunk->getCumTsnAck() > state->lastTsnAck) {
350  simtime_t rttEstimation = SIMTIME_MAX;
351  dequeueAckedChunks(shutdownChunk->getCumTsnAck(),
352  getPath(remoteAddr), rttEstimation);
353  state->lastTsnAck = shutdownChunk->getCumTsnAck();
354  }
357  trans = true;
358 // delete shutdownChunk;
359  /* if (state->resetChunk != nullptr) {
360  delete state->resetChunk;
361  }*/
362  break;
363  }
364 
365  case SHUTDOWN_ACK:
366  EV_INFO << "SHUTDOWN_ACK received" << endl;
367  if (fsm->getState() != SCTP_S_ESTABLISHED) {
368  check_and_cast<SctpShutdownAckChunk *>(header);
370  stopTimers();
373  EV_DETAIL << "state=" << stateName(fsm->getState()) << endl;
374  if ((fsm->getState() == SCTP_S_SHUTDOWN_SENT) ||
375  (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT))
376  {
379  if (state->shutdownChunk) {
380  delete state->shutdownChunk;
381  state->shutdownChunk = nullptr;
382  }
383  }
384 // delete shutdownAckChunk;
385  if (state->resetChunk != nullptr) {
386  delete state->resetChunk;
387  }
388  }
389  break;
390 
391  case SHUTDOWN_COMPLETE: {
392  EV_INFO << "Shutdown Complete arrived" << endl;
393  check_and_cast<SctpShutdownCompleteChunk *>(header);
395  sendIndicationToApp(SCTP_I_PEER_CLOSED); // necessary for NAT-Rendezvous
396  if (trans == true) {
397  stopTimers();
398  }
401  delete state->shutdownAckChunk;
402 // delete shutdownCompleteChunk;
403  break;
404  }
405 
406  case FORWARD_TSN: {
407  EV_INFO << "FORWARD_TSN received" << endl;
408  auto forwChunk = check_and_cast<SctpForwardTsnChunk *>(header);
409  processForwardTsnArrived(forwChunk);
410  trans = true;
411  sendAllowed = true;
412  dataChunkReceived = true;
413 // delete forwChunk;
414  break;
415  }
416 
417  case RE_CONFIG: {
418  EV_INFO << "StreamReset received" << endl;
419  if (fsm->getState() != SCTP_S_ESTABLISHED && fsm->getState() != SCTP_S_SHUTDOWN_PENDING) {
420 // delete header;
421  break;
422  }
423  auto strResChunk = check_and_cast<SctpStreamResetChunk *>(header);
424  processStreamResetArrived(strResChunk);
425  trans = true;
426  sendAllowed = true;
427 // delete strResChunk;
428  break;
429  }
430 
431  case ASCONF:
432  EV_INFO << "ASCONF received" << endl;
433  if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
435  }
436  SctpAsconfChunk *asconfChunk;
437  asconfChunk = check_and_cast<SctpAsconfChunk *>(header);
438  processAsconfArrived(asconfChunk);
439  trans = true;
440 // delete asconfChunk;
441  break;
442 
443  case ASCONF_ACK: {
444  EV_INFO << "ASCONF_ACK received" << endl;
445  auto asconfAckChunk = check_and_cast<SctpAsconfAckChunk *>(header);
446  processAsconfAckArrived(asconfAckChunk);
447  trans = true;
448  delete state->asconfChunk;
449 // delete asconfAckChunk;
450  break;
451  }
452 
453  case PKTDROP:
454  EV_INFO << "PKTDROP received" << endl;
455  if (sctpMain->pktdrop) {
456  auto packetDropChunk = check_and_cast<SctpPacketDropChunk *>(header);
457  if (packetDropChunk->getBFlag() && !packetDropChunk->getMFlag())
458  processPacketDropArrived(packetDropChunk);
459 
460  trans = true;
461  sendAllowed = true;
462 // delete packetDropChunk;
463  }
464  break;
465 
466  case ERRORTYPE: {
467  EV_INFO << "ERROR received" << endl;
468  auto errorChunk = check_and_cast<SctpErrorChunk *>(header);
469  processErrorArrived(errorChunk);
470  trans = true;
471 // delete errorChunk;
472  break;
473  }
474 
475  default:
476  EV_ERROR << "different type" << endl; // TODO
477  break;
478  }
479 
480  if (i == numberOfChunks - 1 && ((dataChunkReceived && !state->sackAlreadySent) || dupReceived)) {
481  sendAllowed = true;
482  EV_DEBUG << "i=" << i << " sendAllowed=true; scheduleSack" << endl;
483  scheduleSack();
484  if (fsm->getState() == SCTP_S_SHUTDOWN_SENT && state->ackState >= sackFrequency) {
485  sendSack();
486  }
487  }
488 
489  // Send any new DATA chunks, SACK chunks, HEARTBEAT chunks etc.
490  EV_DETAIL << "SctpAssociationRcvMessage: send new data? state=" << stateName(fsm->getState())
491  << " sendAllowed=" << sendAllowed
492  << " shutdownCalled=" << shutdownCalled << endl;
493  if (((fsm->getState() == SCTP_S_ESTABLISHED) ||
494  (fsm->getState() == SCTP_S_SHUTDOWN_PENDING) ||
495  (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED)) &&
496  (sendAllowed) &&
497  (!shutdownCalled))
498  {
500  }
501  } // end of for-loop
502  if (state->sendResponse > 0) {
505  if (state->incomingRequest != nullptr)
506  sendStreamResetResponse(check_and_cast<SctpSsnTsnResetRequestParameter *>(state->incomingRequest), PERFORMED, true);
507  }
509  sendAddOutgoingStreamsRequest(check_and_cast<SctpAddStreamsRequestParameter *>(state->incomingRequest)->getNumberOfStreams());
511  sendStreamResetResponse(check_and_cast<SctpAddStreamsRequestParameter *>(state->incomingRequest)->getSrReqSn(), PERFORMED);
512  }
513  else {
515  }
516  state->sendResponse = 0;
517  state->responseSn = 0;
518  }
519  if (sackWasReceived) {
521  sackWasReceived = false;
522  }
523 
524  // ====== Clean-up =======================================================
525  /* if (!state->pktDropSent) {
526  disposeOf(state->sctpmsg);
527  EV_DEBUG << "state->sctpmsg was disposed" << endl;
528  }*/
529  return trans;
530 }

Referenced by processSctpMessage().

◆ process_RECEIVE_REQUEST()

void inet::sctp::SctpAssociation::process_RECEIVE_REQUEST ( SctpEventCode event,
SctpCommandReq sctpCommand 
)
protected
315 {
316  EV_INFO << "SctpAssociation::process_RECEIVE_REQUEST\n";
317  SctpSendReq *sendCommand = check_and_cast<SctpSendReq *>(sctpCommand);
318  if ((uint32_t)sendCommand->getSid() > inboundStreams || sendCommand->getSid() < 0) {
319  EV_DEBUG << "Application tries to read from invalid stream id....\n";
320  }
321  state->numMsgsReq[sendCommand->getSid()] += sendCommand->getNumMsgs();
322  pushUlp();
323 }

Referenced by processAppCommand().

◆ process_SEND()

void inet::sctp::SctpAssociation::process_SEND ( SctpEventCode event,
SctpCommandReq sctpCommand,
cMessage *  msg 
)
protected
127 {
128  SctpSendReq *sendCommand = check_and_cast<SctpSendReq *>(sctpCommand);
129 
130  if (fsm->getState() != SCTP_S_ESTABLISHED) {
131  // TD 12.03.2009: since SCTP_S_ESTABLISHED is the only case, the
132  // switch(...)-block has been removed for enhanced readability.
133  EV_DEBUG << "process_SEND: state is not SCTP_S_ESTABLISHED -> returning" << endl;
134  return;
135  }
136 
137  EV_INFO << "process_SEND:"
138  << " assocId=" << assocId
139  << " localAddr=" << localAddr
140  << " remoteAddr=" << remoteAddr
141  << " cmdRemoteAddr=" << sendCommand->getRemoteAddr()
142  << " cmdPrimary=" << (sendCommand->getPrimary() ? "true" : "false")
143  << " appGateIndex=" << appGateIndex
144  << " streamId=" << sendCommand->getSid() << endl;
145 
146  Packet *applicationPacket = check_and_cast<Packet *>(msg);
147  const auto& applicationData = applicationPacket->peekDataAsBytes();
148  int sendBytes = B(applicationData->getChunkLength()).get();
149  EV_INFO << "got msg of length " << applicationData->getChunkLength() << " sendBytes=" << sendBytes << endl;
150 
151  auto iter = sctpMain->assocStatMap.find(assocId);
152  iter->second.sentBytes += sendBytes;
153 
154  // ------ Prepare SctpDataMsg -----------------------------------------
155  const uint32_t streamId = sendCommand->getSid();
156  const uint32_t sendUnordered = sendCommand->getSendUnordered();
157  const uint32_t ppid = sendCommand->getPpid();
158  SctpSendStream *stream = nullptr;
159  auto associter = sendStreams.find(streamId);
160  if (associter != sendStreams.end()) {
161  stream = associter->second;
162  }
163  else {
164  throw cRuntimeError("Stream with id %d not found", streamId);
165  }
166 
167  SctpDataMsg *datMsg = new SctpDataMsg();
168  SctpSimpleMessage *smsg = new SctpSimpleMessage();
169  smsg->setDataArraySize(sendBytes);
170  std::vector<uint8_t> vec = applicationData->getBytes();
171  for (int i = 0; i < sendBytes; i++)
172  smsg->setData(i, vec[i]);
173  smsg->setDataLen(sendBytes);
174  smsg->setEncaps(false);
175  smsg->setByteLength(sendBytes);
176  datMsg->encapsulate(smsg);
177  datMsg->setSid(streamId);
178  datMsg->setPpid(ppid);
179  datMsg->setEnqueuingTime(simTime());
180  datMsg->setSackNow(sendCommand->getSackNow());
181 
182  // ------ PR-SCTP & Drop messages to free buffer space ----------------
183  datMsg->setPrMethod(sendCommand->getPrMethod());
184  switch (sendCommand->getPrMethod()) {
185  case PR_TTL:
186  if (sendCommand->getPrValue() > 0) {
187  datMsg->setExpiryTime(simTime() + sendCommand->getPrValue());
188  }
189  break;
190 
191  case PR_RTX:
192  datMsg->setRtx((uint32_t)sendCommand->getPrValue());
193  break;
194 
195  case PR_PRIO:
196  datMsg->setPriority((uint32_t)sendCommand->getPrValue());
197  state->queuedDroppableBytes += PK(msg)->getByteLength();
198  break;
199  }
200 
201  if ((state->appSendAllowed) &&
202  (state->sendQueueLimit > 0) &&
203  (state->queuedDroppableBytes > 0) &&
204  ((uint64_t)state->sendBuffer >= state->sendQueueLimit))
205  {
206  uint32_t lowestPriority;
207  cQueue *strq;
208  int64_t dropsize = state->sendBuffer - state->sendQueueLimit;
209 
210  if (sendUnordered)
211  strq = stream->getUnorderedStreamQ();
212  else
213  strq = stream->getStreamQ();
214 
215  while (dropsize >= 0 && state->queuedDroppableBytes > 0) {
216  lowestPriority = 0;
217 
218  // Find lowest priority
219  for (cQueue::Iterator iter(*strq); !iter.end(); iter++) {
220  SctpDataMsg *msg = (SctpDataMsg *)(*iter);
221 
222  if (msg->getPriority() > lowestPriority)
223  lowestPriority = msg->getPriority();
224  }
225 
226  // If just passed message has the lowest priority,
227  // drop it and we're done.
228  if (datMsg->getPriority() > lowestPriority) {
229  EV_DEBUG << "msg will be abandoned, buffer is full and priority too low ("
230  << datMsg->getPriority() << ")\n";
231  state->queuedDroppableBytes -= PK(msg)->getByteLength();
232  delete datMsg;
233  delete smsg;
234  delete msg;
236  return;
237  }
238  }
239  }
240 
241  // ------ Set initial destination address -----------------------------
242  if (sendCommand->getPrimary()) {
243  if (sendCommand->getRemoteAddr().isUnspecified()) {
244  datMsg->setInitialDestination(remoteAddr);
245  }
246  else {
247  datMsg->setInitialDestination(sendCommand->getRemoteAddr());
248  }
249  }
250  else {
251  datMsg->setInitialDestination(state->getPrimaryPathIndex());
252  }
253 
254  // ------ Optional padding and size calculations ----------------------
255  if (state->padding) {
256  datMsg->setBooksize(ADD_PADDING(smsg->getByteLength() + state->header));
257  }
258  else {
259  datMsg->setBooksize(smsg->getByteLength() + state->header);
260  }
261 
263  qCounter.bookedSumSendStreams += datMsg->getBooksize();
264  // Add chunk size to sender buffer size
265  state->sendBuffer += smsg->getByteLength();
266 
267  datMsg->setMsgNum(++state->msgNum);
268 
269  // ------ Ordered/Unordered modes -------------------------------------
270  if (sendUnordered == 1) {
271  datMsg->setOrdered(false);
272  stream->getUnorderedStreamQ()->insert(datMsg);
273  }
274  else {
275  datMsg->setOrdered(true);
276  stream->getStreamQ()->insert(datMsg);
277 
278  sendQueue->record(stream->getStreamQ()->getLength());
279  }
280  EV_INFO << "Size of send queue " << stream->getStreamQ()->getLength() << endl;
281  // ------ Send buffer full? -------------------------------------------
282  if ((state->appSendAllowed) &&
283  (state->sendQueueLimit > 0) &&
284  ((uint64_t)state->sendBuffer >= state->sendQueueLimit))
285  {
286  // If there are not enough messages that could be dropped,
287  // the buffer is really full and the app has to be notified.
290  state->appSendAllowed = false;
291  }
292  }
293 
295  if ((state->queueLimit > 0) && (state->queuedMessages > state->queueLimit)) {
296  state->queueUpdate = false;
297  }
298  EV_INFO << "process_SEND:"
299  << " last=" << sendCommand->getLast()
300  << " queueLimit=" << state->queueLimit << endl;
301 
302  // ------ Call sendCommandInvoked() to send message -------------------
303  // sendCommandInvoked() itself will call sendOnAllPaths() ...
304  if (sendCommand->getLast() == true) {
305  if (sendCommand->getPrimary()) {
307  }
308  else {
309  sctpAlgorithm->sendCommandInvoked(getPath(datMsg->getInitialDestination()));
310  }
311  }
312 }

Referenced by processAppCommand().

◆ process_STATUS()

void inet::sctp::SctpAssociation::process_STATUS ( SctpEventCode event,
SctpCommandReq sctpCommand,
cMessage *  msg 
)
protected
441 {
442  auto& tags = check_and_cast<ITaggedObject *>(msg)->getTags();
443  auto& statusInfo = tags.addTagIfAbsent<SctpStatusReq>();
444  statusInfo->setState(fsm->getState());
445  statusInfo->setStateName(stateName(fsm->getState()));
446  statusInfo->setPathId(remoteAddr);
447  statusInfo->setActive(getPath(remoteAddr)->activePath);
448  sendToApp(msg);
449 }

◆ process_STREAM_RESET()

void inet::sctp::SctpAssociation::process_STREAM_RESET ( SctpCommandReq sctpCommand)
protected
332 {
333  EV_INFO << "process_STREAM_RESET request arriving from App\n";
334  SctpResetReq *rinfo = check_and_cast<SctpResetReq *>(sctpCommand);
335  if (!(getPath(remoteAddr)->ResetTimer->isScheduled())) {
336  if (rinfo->getRequestType() == ADD_BOTH) {
338  }
339  else if (!state->fragInProgress && state->outstandingBytes == 0) {
340  sendStreamResetRequest(rinfo);
341  if (rinfo->getRequestType() == RESET_OUTGOING || rinfo->getRequestType() == RESET_BOTH ||
342  rinfo->getRequestType() == SSN_TSN || rinfo->getRequestType() == ADD_INCOMING ||
343  rinfo->getRequestType() == ADD_OUTGOING)
344  {
345  state->resetPending = true;
346  }
347  }
348  else if (state->outstandingBytes > 0) {
349  if (rinfo->getRequestType() == RESET_OUTGOING || rinfo->getRequestType() == RESET_INCOMING || rinfo->getRequestType() == RESET_BOTH) {
350  if (rinfo->getStreamsArraySize() > 0) {
351  for (uint16_t i = 0; i < rinfo->getStreamsArraySize(); i++) {
352  if ((getBytesInFlightOfStream(rinfo->getStreams(i)) > 0) ||
353  getFragInProgressOfStream(rinfo->getStreams(i)) ||
354  !orderedQueueEmptyOfStream(rinfo->getStreams(i)) ||
355  !unorderedQueueEmptyOfStream(rinfo->getStreams(i)))
356  {
357  state->streamsPending.push_back(rinfo->getStreams(i));
358  }
359  else {
360  state->streamsToReset.push_back(rinfo->getStreams(i));
361  }
362  }
363  }
364  else {
365  if (rinfo->getRequestType() == RESET_OUTGOING) {
366  for (uint16_t i = 0; i < outboundStreams; i++) {
368  state->streamsPending.push_back(i);
369  }
370  else {
371  state->streamsToReset.push_back(i);
372  }
373  }
374  }
375  }
376  if (state->streamsToReset.size() > 0) {
377  sendStreamResetRequest(rinfo);
378  state->resetPending = true;
379  }
380  }
381  if ((rinfo->getRequestType() == SSN_TSN) ||
382  (rinfo->getRequestType() == ADD_INCOMING) ||
383  (rinfo->getRequestType() == ADD_OUTGOING))
384  {
385  state->resetInfo = rinfo;
386 // state->resetInfo->setName("state-resetLater");
388  }
389  if (!state->resetPending || state->streamsPending.size() > 0) {
390  state->resetInfo = rinfo->dup();
391 // state->resetInfo->setName("state-resetInfo");
393  }
394  }
395 
396  state->resetRequested = true;
397  }
398 }

Referenced by processAppCommand().

◆ process_TIMEOUT_ASCONF()

void inet::sctp::SctpAssociation::process_TIMEOUT_ASCONF ( SctpPathVariables path)
protected
3743 {
3744  int32_t value;
3745 
3746  if ((value = updateCounters(path)) == 1) {
3747  retransmitAsconf();
3748 
3749  /* increase the RTO (by doubling it) */
3750  path->pathRto = min(2 * path->pathRto.dbl(), sctpMain->getRtoMax());
3751  path->statisticsPathRTO->record(path->pathRto);
3752 
3753  startTimer(path->AsconfTimer, path->pathRto);
3754  }
3755 }

Referenced by processTimer().

◆ process_TIMEOUT_BLOCKING()

void inet::sctp::SctpAssociation::process_TIMEOUT_BLOCKING ( SctpPathVariables path)
protected
3888 {
3889  EV_INFO << "TIMEOUT_BLOCKING on " << path->remoteAddress
3890  << " cwnd=" << path->cwnd << endl;
3891  path->blockingTimeout = -1.0;
3892  sendOnAllPaths(path);
3893 }

◆ process_TIMEOUT_HEARTBEAT()

void inet::sctp::SctpAssociation::process_TIMEOUT_HEARTBEAT ( SctpPathVariables path)
protected
3614 {
3615  bool oldState = path->activePath;
3616 
3617  /* check if error counters must be increased */
3618  if (path->activePath) {
3619  state->errorCount++;
3620  path->pathErrorCount++;
3621 
3622  EV_INFO << "HB timeout timer expired for path " << path->remoteAddress << " --> Increase Error Counters (Assoc: " << state->errorCount << ", Path: " << path->pathErrorCount << ")\n";
3623  }
3624 
3625  /* RTO must be doubled for this path ! */
3626  path->pathRto = (simtime_t)min(2 * path->pathRto.dbl(), sctpMain->getRtoMax());
3627  path->statisticsPathRTO->record(path->pathRto);
3628  /* check if any thresholds are exceeded, and if so, check if ULP must be notified */
3629  if (state->errorCount > (uint32_t)sctpMain->getAssocMaxRtx()) {
3631  sendAbort();
3632  sctpMain->removeAssociation(this);
3633  return;
3634  }
3635  else {
3636  /* set path state to INACTIVE, if the path error counter is exceeded */
3637  if (path->pathErrorCount > (uint32_t)sctpMain->getPathMaxRetrans()) {
3638  oldState = path->activePath;
3639  path->activePath = false;
3640  if (path == state->getPrimaryPath()) {
3642  }
3643  EV_DETAIL << "pathErrorCount now " << path->pathErrorCount
3644  << "; PP now " << state->getPrimaryPathIndex() << endl;
3645  }
3646  /* then: we can check, if all paths are INACTIVE ! */
3647  if (allPathsInactive()) {
3648  EV_DETAIL << "sctp_do_hb_to_timer() : ALL PATHS INACTIVE --> closing ASSOC\n";
3650  return;
3651  }
3652  else if (path->activePath == false && oldState == true) { // FIXME oldState may be uninitialized
3653  /* notify the application, in case the PATH STATE has changed from ACTIVE to INACTIVE */
3654  pathStatusIndication(path, false);
3655  }
3656  }
3657 }

Referenced by processTimer().

◆ process_TIMEOUT_HEARTBEAT_INTERVAL()

void inet::sctp::SctpAssociation::process_TIMEOUT_HEARTBEAT_INTERVAL ( SctpPathVariables path,
bool  force 
)
protected
3596 {
3597  EV_INFO << "HB Interval timer expired -- sending new HB REQ on path " << path->remoteAddress << "\n";
3598  /* restart hb_send_timer on this path */
3599  stopTimer(path->HeartbeatIntervalTimer);
3600  stopTimer(path->HeartbeatTimer);
3601  path->heartbeatIntervalTimeout = sctpMain->getHbInterval() + path->pathRto;
3602  path->heartbeatTimeout = path->pathRto;
3603  startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout);
3604 
3605  if (sctpMain->getEnableHeartbeats() && (simTime() - path->lastAckTime > path->heartbeatIntervalTimeout / 2 || path->forceHb || state->sendHeartbeatsOnActivePaths)) {
3606  sendHeartbeat(path);
3607  startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
3608 
3609  path->forceHb = false;
3610  }
3611 }

Referenced by processTimer().

◆ process_TIMEOUT_INIT_REXMIT()

void inet::sctp::SctpAssociation::process_TIMEOUT_INIT_REXMIT ( SctpEventCode event)
protected
3545 {
3546  if (++state->initRetransCounter > (int32_t)sctpMain->getMaxInitRetrans()) {
3547  EV_INFO << "Retransmission count during connection setup exceeds " << (int32_t)sctpMain->getMaxInitRetrans() << ", giving up\n";
3549  sendAbort();
3550  return;
3551  }
3552  EV_INFO << "Performing retransmission #" << state->initRetransCounter << "\n";
3553  switch (fsm->getState()) {
3554  case SCTP_S_COOKIE_WAIT:
3555  retransmitInit();
3556  break;
3557 
3558  case SCTP_S_COOKIE_ECHOED:
3560  break;
3561 
3562  default:
3563  throw cRuntimeError("Internal error: INIT-REXMIT timer expired while in state %s",
3564  stateName(fsm->getState()));
3565  }
3566  state->initRexmitTimeout *= 2;
3569  }
3571 }

Referenced by processTimer().

◆ process_TIMEOUT_PROBING()

void inet::sctp::SctpAssociation::process_TIMEOUT_PROBING ( )
protected

◆ process_TIMEOUT_RESET()

void inet::sctp::SctpAssociation::process_TIMEOUT_RESET ( SctpPathVariables path)
protected
3683 {
3684  int32_t value;
3685  std::map<uint32_t, SctpStateVariables::RequestData>::reverse_iterator rit;
3686  rit = state->requests.rbegin();
3687  if (rit->second.result == DEFERRED) {
3688  value = 1;
3689  }
3690  else {
3691  value = updateCounters(path);
3692  }
3693  if (value == 1) {
3694  EV_DETAIL << "Performing timeout reset" << endl;
3695  retransmitReset();
3696 
3697  /* increase the RTO (by doubling it) */
3698  path->pathRto = min(2 * path->pathRto.dbl(), sctpMain->getRtoMax());
3699  path->statisticsPathRTO->record(path->pathRto);
3700  startTimer(path->ResetTimer, path->pathRto);
3701  }
3702 }

Referenced by processTimer().

◆ process_TIMEOUT_RTX()

void inet::sctp::SctpAssociation::process_TIMEOUT_RTX ( SctpPathVariables path)
protected
3758 {
3759  EV_DETAIL << "Processing retransmission timeout ..." << endl;
3760 
3761  // Stop blocking!
3762  if (path->BlockingTimer) {
3763  stopTimer(path->BlockingTimer);
3764  }
3765  path->blockingTimeout = -1.0;
3766 
3767  // ====== Increase the RTO (by doubling it) ==============================
3768  path->pathRto = min(2 * path->pathRto.dbl(), sctpMain->getRtoMax());
3769  path->statisticsPathRTO->record(path->pathRto);
3770  EV_DETAIL << "Schedule T3 based retransmission for path " << path->remoteAddress
3771  << " oldest chunk sent " << simTime() - path->oldestChunkSendTime << " ago"
3772  << " (TSN " << path->oldestChunkTsn << ")" << endl;
3773  EV_DEBUG << "Unacked chunks in Retransmission Queue:" << endl;
3774  for (SctpQueue::PayloadQueue::const_iterator iterator = retransmissionQ->payloadQueue.begin();
3775  iterator != retransmissionQ->payloadQueue.end(); ++iterator)
3776  {
3777  const SctpDataVariables *myChunk = iterator->second;
3778  if (!myChunk->hasBeenAcked) {
3779  const SctpPathVariables *myChunkLastPath = myChunk->getLastDestinationPath();
3780  EV_DEBUG << " - " << myChunk->tsn
3781  << "\tsent=now-" << simTime() - myChunk->sendTime
3782  << "\tlast=" << myChunkLastPath->remoteAddress
3783  << "\tmoved=" << ((myChunk->hasBeenMoved == true) ? "YES!" : "no")
3784  << "\tnumTX=" << myChunk->numberOfTransmissions
3785  << "\tnumRTX=" << myChunk->numberOfRetransmissions
3786  << "\tfastRTX=" << ((myChunk->hasBeenFastRetransmitted == true) ? "YES!" : "no")
3787  << endl;
3788  }
3789  }
3790  EV_DEBUG << "----------------------" << endl;
3791 
3792  // ====== Update congestion window =======================================
3793  (this->*ccFunctions.ccUpdateAfterRtxTimeout)(path);
3794 
3795  // ====== Error Counter Handling =========================================
3796  if (!state->zeroWindowProbing) {
3797  state->errorCount++;
3798  path->pathErrorCount++;
3799  EV_DETAIL << "RTX-Timeout: errorCount increased to " << path->pathErrorCount << " state->errorCount=" << state->errorCount << "\n";
3800  }
3801  if (state->errorCount > (uint32_t)sctpMain->getAssocMaxRtx()) {
3802  /* error counter exceeded terminate the association -- create an SCTPC_EV_CLOSE event and send it to myself */
3803 
3804  EV_DETAIL << "process_TIMEOUT_RTX : ASSOC ERROR COUNTER EXCEEDED, closing ASSOC" << endl;
3806  sendAbort();
3807  sctpMain->removeAssociation(this);
3808  return;
3809  }
3810  else {
3811  if (path->pathErrorCount > static_cast<uint32_t>(sctpMain->par("pathMaxRetrans"))) {
3812  bool notifyUlp = false;
3813 
3814  EV_DETAIL << "pathErrorCount exceeded\n";
3815  if (path->activePath) {
3816  /* tell the source */
3817  notifyUlp = true;
3818  }
3819  path->activePath = false;
3820  if (path->remoteAddress == state->getPrimaryPathIndex()) {
3821  SctpPathVariables *nextPath = getNextPath(path);
3822  if (nextPath != nullptr) {
3823  state->setPrimaryPath(nextPath);
3824  }
3825  }
3826  EV_DETAIL << "process_TIMEOUT_RTX(" << path->remoteAddress
3827  << ") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE" << endl;
3828  if (allPathsInactive()) {
3829  EV_WARN << "process_TIMEOUT_RTX: ALL PATHS INACTIVE --> connection LOST!" << endl;
3831  sendAbort();
3832  sctpMain->removeAssociation(this);
3833  return;
3834  }
3835  else if (notifyUlp) {
3836  // Send notification to the application
3837  pathStatusIndication(path, false);
3838  }
3839  }
3840  EV_DETAIL << "process_TIMEOUT_RTX(" << path->remoteAddress
3841  << ") : PATH ERROR COUNTER now " << path->pathErrorCount << endl;
3842  }
3843 
3844  // ====== Do Retransmission ==============================================
3845  // dequeue all chunks not acked so far and put them in the TransmissionQ
3846  if (!retransmissionQ->payloadQueue.empty()) {
3847  EV_DETAIL << "Still " << retransmissionQ->payloadQueue.size()
3848  << " chunks in retransmissionQ" << endl;
3849 
3850  for (auto& elem : retransmissionQ->payloadQueue) {
3851  SctpDataVariables *chunk = elem.second;
3852  assert(chunk != nullptr);
3853 
3854  // ====== Insert chunks into TransmissionQ ============================
3855  // Only insert chunks that were sent to the path that has timed out
3856  if (!chunkMustBeAbandoned(chunk, path) && ((chunkHasBeenAcked(chunk) == false && chunk->countsAsOutstanding)
3857  || chunk->hasBeenReneged) && (chunk->getLastDestinationPath() == path))
3858  {
3859  SctpPathVariables *nextPath = getNextDestination(chunk);
3860  EV_DETAIL << simTime() << ": Timer-Based RTX for TSN " << chunk->tsn
3861  << ": lastDestination=" << chunk->getLastDestination()
3862  << " lastPathRTO=" << chunk->getLastDestinationPath()->pathRto
3863  << " nextDestination=" << nextPath->remoteAddress
3864  << " nextPathRTO=" << nextPath->pathRto
3865  << " waiting=" << simTime() - chunk->sendTime
3866  << endl;
3867  nextPath->numberOfTimerBasedRetransmissions++;
3868  chunk->hasBeenTimerBasedRtxed = true;
3869  chunk->sendForwardIfAbandoned = true;
3870  chunk->numberOfTransmissions++;
3871 
3872  if (!chunk->hasBeenAbandoned) {
3873  auto iter = sctpMain->assocStatMap.find(assocId);
3874  iter->second.numT3Rtx++;
3875  }
3876 
3877  moveChunkToOtherPath(chunk, nextPath);
3878  }
3879  }
3880  }
3881 
3882  SctpPathVariables *nextPath = getNextPath(path);
3883  EV_DETAIL << "TimeoutRTX: sendOnAllPaths()" << endl;
3884  sendOnAllPaths(nextPath);
3885 }

Referenced by processTimer().

◆ process_TIMEOUT_SHUTDOWN()

void inet::sctp::SctpAssociation::process_TIMEOUT_SHUTDOWN ( SctpEventCode event)
protected
3574 {
3575  if (++state->errorCount > (uint32_t)sctpMain->getAssocMaxRtx()) {
3577  sendAbort();
3578  sctpMain->removeAssociation(this);
3579  return;
3580  }
3581 
3582  EV_INFO << "Performing shutdown retransmission. Assoc error count now " << state->errorCount << " \n";
3583  if (fsm->getState() == SCTP_S_SHUTDOWN_SENT) {
3585  }
3586  else if (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)
3588 
3589  state->initRexmitTimeout *= 2;
3593 }

Referenced by processTimer().

◆ processAddInAndOutResetRequestArrived()

void inet::sctp::SctpAssociation::processAddInAndOutResetRequestArrived ( const SctpAddStreamsRequestParameter addInRequestParam,
SctpAddStreamsRequestParameter addOutRequestParam 
)
protected
2695 {
2696  const auto& msg = makeShared<SctpHeader>();
2697  msg->setChunkLength(B(SCTP_COMMON_HEADER));
2698  msg->setSrcPort(localPort);
2699  msg->setDestPort(remotePort);
2700  SctpStreamResetChunk *resetChunk = new SctpStreamResetChunk("AddInOut_CONFIG");
2701  resetChunk->setSctpChunkType(RE_CONFIG);
2702  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
2703  uint32_t srsn = state->streamResetSequenceNumber;
2704  SctpResetTimer *rt = new SctpResetTimer();
2705  auto it = sctpMain->assocStatMap.find(assocId);
2706  SctpAddStreamsRequestParameter *addStreams = new SctpAddStreamsRequestParameter("Add_Streams");
2707  /* SctpAddStreamsRequestParameter *addStreams = new SctpAddStreamsRequestParameter();*/
2708  addStreams->setParameterType(ADD_OUTGOING_STREAMS_REQUEST_PARAMETER);
2709  addStreams->setNumberOfStreams(addInRequestParam->getNumberOfStreams());
2710  state->numAddedOutStreams = addStreams->getNumberOfStreams();
2712  addStreams->setSrReqSn(srsn);
2713  state->requests[srsn].result = 100;
2715  addStreams->setByteLength(SCTP_ADD_STREAMS_REQUEST_PARAMETER_LENGTH);
2716  resetChunk->addParameter(addStreams);
2717 
2718  SctpStreamResetChunk *responseChunk = new SctpStreamResetChunk("responseRE_CONFIG");
2719  responseChunk->setSctpChunkType(RE_CONFIG);
2720  responseChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
2721  SctpStreamResetResponseParameter *outResponseParam = new SctpStreamResetResponseParameter("Out_Response_Param");
2722  /* SctpStreamResetResponseParameter *outResponseParam = new SctpStreamResetResponseParameter();*/
2723  outResponseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
2724  outResponseParam->setSrResSn(addOutRequestParam->getSrReqSn());
2725  outResponseParam->setResult(PERFORMED);
2726  outResponseParam->setByteLength(SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH);
2727  responseChunk->addParameter(outResponseParam);
2728  SctpStreamResetResponseParameter *inResponseParam = new SctpStreamResetResponseParameter("In_Response_Param");
2729  /* SctpStreamResetResponseParameter *inResponseParam = new SctpStreamResetResponseParameter();*/
2730  inResponseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
2731  inResponseParam->setSrResSn(addInRequestParam->getSrReqSn());
2732  inResponseParam->setResult(PERFORMED);
2733  state->peerRequests[addInRequestParam->getSrReqSn()].result = PERFORMED;
2734  state->peerRequests[addOutRequestParam->getSrReqSn()].result = PERFORMED;
2735  inResponseParam->setByteLength(SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH);
2736  responseChunk->addParameter(inResponseParam);
2737  msg->appendSctpChunks(resetChunk);
2738  msg->appendSctpChunks(responseChunk);
2739  rt->setInSN(0);
2740  rt->setInAcked(true);
2741  rt->setOutSN(srsn);
2742  rt->setOutAcked(false);
2743  it->second.numResetRequestsSent++;
2744  state->streamResetSequenceNumber = ++srsn;
2745  if (state->resetChunk != nullptr) {
2746  delete state->resetChunk;
2747  state->resetChunk = nullptr;
2748  }
2749  state->resetChunk = check_and_cast<SctpStreamResetChunk *>(resetChunk->dup());
2750 // state->resetChunk->setName("stateAddResetChunk");
2751  Packet *pkt = new Packet("RE_CONFIG");
2752  sendToIP(pkt, msg, remoteAddr);
2753  PK(getPath(remoteAddr)->ResetTimer)->encapsulate(rt);
2754  startTimer(getPath(remoteAddr)->ResetTimer, getPath(remoteAddr)->pathRto);
2755 }

Referenced by processStreamResetArrived().

◆ processAppCommand()

bool inet::sctp::SctpAssociation::processAppCommand ( cMessage *  msg,
SctpCommandReq sctpCommand 
)

Process commands from the application.

Normally returns true. A return value of false means that the connection structure must be deleted by the caller (SCTP).

1069 {
1070  printAssocBrief();
1071 
1072  SctpEventCode event = preanalyseAppCommandEvent(msg->getKind());
1073 
1074  EV_INFO << "App command: " << eventName(event) << "\n";
1075 
1076  switch (event) {
1077  case SCTP_E_ASSOCIATE:
1078  process_ASSOCIATE(event, sctpCommand, msg);
1079  break;
1080 
1081  case SCTP_E_OPEN_PASSIVE:
1082  process_OPEN_PASSIVE(event, sctpCommand, msg);
1083  break;
1084 
1085  case SCTP_E_SEND:
1086  process_SEND(event, sctpCommand, msg);
1087  break;
1088 
1089  case SCTP_E_ABORT:
1090  process_ABORT(event);
1091  break;
1092 
1093  case SCTP_E_RECEIVE:
1094  process_RECEIVE_REQUEST(event, sctpCommand);
1095  break;
1096 
1097  case SCTP_E_PRIMARY:
1098  process_PRIMARY(event, sctpCommand);
1099  break;
1100 
1101  case SCTP_E_STREAM_RESET:
1102  case SCTP_E_RESET_ASSOC:
1103  case SCTP_E_ADD_STREAMS:
1104  if (state->peerStreamReset == true) {
1105  process_STREAM_RESET(sctpCommand);
1106  }
1107  event = SCTP_E_IGNORE;
1108  break;
1109 
1110  case SCTP_E_SEND_ASCONF:
1111  sendAsconf(sctpMain->par("addIpType"));
1112  break;
1113 
1114  case SCTP_E_SET_STREAM_PRIO: {
1115  auto sctpSendReq = check_and_cast<SctpSendReq *>(sctpCommand);
1116  state->ssPriorityMap[sctpSendReq->getSid()] = sctpSendReq->getPpid();
1117  break;
1118  }
1119 
1121  process_QUEUE_BYTES_LIMIT(sctpCommand);
1122  break;
1123 
1125  process_QUEUE_MSGS_LIMIT(sctpCommand);
1126  break;
1127 
1128  case SCTP_E_CLOSE:
1129  if (listening) {
1130  event = SCTP_E_IGNORE;
1131  break;
1132  }
1133  state->stopReading = true;
1134  /* fall through */
1135 
1136  case SCTP_E_SHUTDOWN: /*sendShutdown*/
1137  EV_INFO << "SCTP_E_SHUTDOWN in state " << stateName(fsm->getState()) << "\n";
1138 
1139  if (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED) {
1140  EV_INFO << "send shutdown ack\n";
1142  }
1143  break;
1144 
1145  case SCTP_E_STOP_SENDING:
1146  break;
1147 
1149  break;
1150 
1151  case SCTP_E_ACCEPT:
1152  fd = sctpCommand->getFd();
1153  EV_DETAIL << "Accepted fd " << fd << " for assoc " << assocId << endl;
1154  break;
1155 
1158  break;
1159 
1160  case SCTP_E_SET_RTO_INFO: {
1161  auto sctpRtoReq = check_and_cast<SctpRtoReq *>(sctpCommand);
1162  sctpMain->setRtoInitial(sctpRtoReq->getRtoInitial());
1163  sctpMain->setRtoMin(sctpRtoReq->getRtoMin());
1164  sctpMain->setRtoMax(sctpRtoReq->getRtoMax());
1165  break;
1166  }
1167  default:
1168  throw cRuntimeError("Wrong event code");
1169  }
1170 
1171 // delete sctpCommand;
1172  // then state transitions
1173  return performStateTransition(event);
1174 }

Referenced by inet::sctp::Sctp::handleMessage().

◆ processAsconfAckArrived()

SctpEventCode inet::sctp::SctpAssociation::processAsconfAckArrived ( SctpAsconfAckChunk asconfAckChunk)
protected
3305 {
3306  SctpParameter *sctpParam;
3307  L3Address addr;
3308  SctpAsconfChunk *sctpasconf;
3309  std::vector<uint32_t> errorCorrId;
3310  bool errorFound = false;
3311 
3312  sctpasconf = check_and_cast<SctpAsconfChunk *>(state->asconfChunk->dup());
3313  if (asconfAckChunk->getSerialNumber() == sctpasconf->getSerialNumber()) {
3314  stopTimer(getPath(remoteAddr)->AsconfTimer);
3315  state->errorCount = 0;
3316  state->asconfOutstanding = false;
3318  std::vector<L3Address> remAddr = remoteAddressList;
3319  for (uint32_t j = 0; j < asconfAckChunk->getAsconfResponseArraySize(); j++) {
3320  sctpParam = asconfAckChunk->getAsconfResponse(j);
3321  if (sctpParam->getParameterType() == ERROR_CAUSE_INDICATION) {
3322  SctpErrorCauseParameter *error = check_and_cast<SctpErrorCauseParameter *>(sctpParam);
3323  errorCorrId.push_back(error->getResponseCorrelationId());
3324  EV_INFO << "error added with id " << error->getResponseCorrelationId() << "\n";
3325  }
3326  }
3327  for (uint32_t i = 0; i < sctpasconf->getAsconfParamsArraySize(); i++) {
3328  sctpParam = CHK(sctpasconf->removeAsconfParam());
3329  errorFound = false;
3330  switch (sctpParam->getParameterType()) {
3331  case ADD_IP_ADDRESS:
3332  SctpAddIPParameter *ipParam;
3333  ipParam = check_and_cast<SctpAddIPParameter *>(sctpParam);
3334  if (errorCorrId.size() > 0) {
3335  for (auto& elem : errorCorrId)
3336  if ((elem) == ipParam->getRequestCorrelationId()) {
3337  errorFound = true;
3338  break;
3339  }
3340  }
3341  if (errorFound == true) {
3342  delete ipParam;
3343  break;
3344  }
3345  addr = ipParam->getAddressParam();
3346  if (addr.isUnspecified()) {
3347  addr = localAddr;
3349  }
3350  sctpMain->addLocalAddressToAllRemoteAddresses(this, addr, remAddr);
3351  state->localAddresses.push_back(addr);
3352  delete ipParam;
3353  break;
3354 
3355  case DELETE_IP_ADDRESS:
3356  SctpDeleteIPParameter *delParam;
3357  delParam = check_and_cast<SctpDeleteIPParameter *>(sctpParam);
3358  if (errorCorrId.size() > 0) {
3359  for (auto& elem : errorCorrId) {
3360  if ((elem) == delParam->getRequestCorrelationId()) {
3361  errorFound = true;
3362  break;
3363  }
3364  }
3365  }
3366  if (errorFound == true) {
3367  delete delParam;
3368  break;
3369  }
3370  addr = delParam->getAddressParam();
3371  sctpMain->removeLocalAddressFromAllRemoteAddresses(this, addr, remAddr);
3372  for (auto j = state->localAddresses.begin(); j != state->localAddresses.end(); j++) {
3373  if ((*j) == addr) {
3374  EV_DETAIL << "erase address " << (*j) << "\n";
3375  state->localAddresses.erase(j);
3376  break;
3377  }
3378  }
3379  delete delParam;
3380  break;
3381 
3382  case SET_PRIMARY_ADDRESS:
3383  SctpSetPrimaryIPParameter *priParam;
3384  priParam = check_and_cast<SctpSetPrimaryIPParameter *>(sctpParam);
3385  if (errorCorrId.size() > 0) {
3386  for (auto& elem : errorCorrId) {
3387  if ((elem) == priParam->getRequestCorrelationId()) {
3388  errorFound = true;
3389  break;
3390  }
3391  }
3392  }
3393  if (errorFound == true) {
3394  delete priParam;
3395  break;
3396  }
3397  delete priParam;
3398  break;
3399  }
3400  }
3401  }
3402  delete sctpasconf;
3403  return SCTP_E_IGNORE;
3404 }

Referenced by process_RCV_Message().

◆ processAsconfArrived()

SctpEventCode inet::sctp::SctpAssociation::processAsconfArrived ( SctpAsconfChunk asconfChunk)
protected
3171 {
3172  SctpParameter *sctpParam;
3173  SctpPathVariables *path;
3174  L3Address addr;
3175  std::vector<L3Address> locAddr;
3176  SctpAuthenticationChunk *authChunk;
3177  EV_INFO << "Asconf arrived " << asconfChunk->getName() << "\n";
3178 // SctpHeader *sctpAsconfAck = new SctpHeader("ASCONF_ACK");
3179  const auto& sctpAsconfAck = makeShared<SctpHeader>();
3180  sctpAsconfAck->setChunkLength(B(SCTP_COMMON_HEADER));
3181  sctpAsconfAck->setSrcPort(localPort);
3182  sctpAsconfAck->setDestPort(remotePort);
3183  if (state->auth && state->peerAuth) {
3184  authChunk = createAuthChunk();
3185  sctpAsconfAck->appendSctpChunks(authChunk);
3186  auto it = sctpMain->assocStatMap.find(assocId);
3187  it->second.numAuthChunksSent++;
3188  }
3189  if (state->numberAsconfReceived > 0 || (state->numberAsconfReceived == 0 && asconfChunk->getSerialNumber() == initPeerTsn + state->numberAsconfReceived)) {
3190  SctpAsconfAckChunk *asconfAckChunk = createAsconfAckChunk(asconfChunk->getSerialNumber());
3192  int32_t count = asconfChunk->getAsconfParamsArraySize();
3193  EV_DETAIL << "Number of Asconf parameters=" << count << "\n";
3194  for (int32_t c = 0; c < count; c++) {
3195  sctpParam = (SctpParameter *)(asconfChunk->removeAsconfParam());
3196  switch (sctpParam->getParameterType()) {
3197  case ADD_IP_ADDRESS:
3198  EV_INFO << "ADD_IP_PARAMETER\n";
3199  SctpAddIPParameter *ipParam;
3200  ipParam = check_and_cast<SctpAddIPParameter *>(sctpParam);
3201  addr = ipParam->getAddressParam();
3202  if (addr.isUnspecified()) {
3203  EV_INFO << "no address specified, add natted address " << remoteAddr << "\n";
3204  addr = remoteAddr;
3206  }
3207  for (auto& elem : state->localAddresses) {
3208  if (sctpMain->addRemoteAddress(this, (elem), addr)) {
3209  addPath(addr);
3210  EV_INFO << "add remote address " << addr << " to local address " << (elem) << "\n";
3211  this->remoteAddressList.push_back(addr);
3212  }
3213  }
3214  path = getPath(addr);
3215  if (sctpMain->getEnableHeartbeats()) {
3216  stopTimer(path->HeartbeatTimer);
3217  stopTimer(path->HeartbeatIntervalTimer);
3218  path->statisticsPathRTO->record(path->pathRto);
3219  startTimer(path->HeartbeatIntervalTimer, path->pathRto);
3220  path->forceHb = true;
3221  }
3222  else
3223  path->confirmed = true;
3224  delete ipParam;
3225  break;
3226 
3227  case DELETE_IP_ADDRESS:
3228  SctpDeleteIPParameter *delParam;
3229  delParam = check_and_cast<SctpDeleteIPParameter *>(sctpParam);
3230  addr = delParam->getAddressParam();
3231  if (state->localAddresses.size() == 1) {
3232  SctpErrorCauseParameter *errorParam;
3233  errorParam = new SctpErrorCauseParameter("ErrorCause");
3234  errorParam->setParameterType(ERROR_CAUSE_INDICATION);
3235  errorParam->setResponseCorrelationId(delParam->getRequestCorrelationId());
3236  errorParam->setErrorCauseType(ERROR_DELETE_LAST_IP_ADDRESS);
3237  errorParam->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH + 4);
3238  errorParam->encapsulate(delParam->dup());
3239  // FIXME is the c-style conversion need here?
3240  asconfAckChunk->addAsconfResponse(errorParam);
3241  }
3242  else if (addr == remoteAddr) {
3243  EV_INFO << "addr=remoteAddr, make Error Parameter\n";
3244  SctpErrorCauseParameter *errParam;
3245  errParam = new SctpErrorCauseParameter("ErrorCause");
3246 // errParam = new SctpErrorCauseParameter();
3247  errParam->setParameterType(ERROR_CAUSE_INDICATION);
3248  errParam->setResponseCorrelationId(delParam->getRequestCorrelationId());
3249  errParam->setErrorCauseType(ERROR_DELETE_SOURCE_ADDRESS);
3250  errParam->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH + 4);
3251  errParam->encapsulate(delParam->dup());
3252  asconfAckChunk->addAsconfResponse(errParam);
3253  }
3254  else {
3255  locAddr = state->localAddresses;
3256  sctpMain->removeRemoteAddressFromAllAssociations(this, addr, locAddr);
3257  removePath(addr);
3258  EV_INFO << "remove path from address " << addr << "\n";
3259  asconfAckChunk->addAsconfResponse(createSuccessIndication(delParam->getRequestCorrelationId()));
3260  }
3261  delete delParam;
3262  break;
3263 
3264  case SET_PRIMARY_ADDRESS:
3265  EV_INFO << "SET_PRIMARY_ADDRESS\n";
3266  SctpSetPrimaryIPParameter *priParam;
3267  priParam = check_and_cast<SctpSetPrimaryIPParameter *>(sctpParam);
3268  addr = priParam->getAddressParam();
3269  if (addr.isUnspecified()) {
3270  EV_INFO << "no address specified, add natted address " << remoteAddr << "\n";
3271  addr = remoteAddr;
3272  }
3273  for (auto& elem : remoteAddressList) {
3274  if ((elem) == addr) {
3275  if (getPath(addr)->confirmed == true) {
3276  state->setPrimaryPath(getPath(addr));
3277  EV_INFO << "set primaryPath to " << addr << "\n";
3278  }
3279  else {
3280  getPath(addr)->primaryPathCandidate = true;
3281  sendHeartbeat(getPath(addr));
3282  }
3283  break;
3284  }
3285  }
3286  asconfAckChunk->addAsconfResponse(createSuccessIndication(priParam->getRequestCorrelationId()));
3287  delete priParam;
3288  break;
3289  }
3290  }
3291  sctpAsconfAck->appendSctpChunks(asconfAckChunk);
3292  Packet *pkt = new Packet("ASCONF-ACK");
3293  sendToIP(pkt, sctpAsconfAck, remoteAddr);
3294  if (StartAddIP->isScheduled()) {
3297  const char *type = sctpMain->par("addIpType").stringValue();
3298  sendAsconf(type, false);
3299  }
3300  }
3301  return SCTP_E_IGNORE;
3302 }

Referenced by process_RCV_Message().

◆ processCookieAckArrived()

bool inet::sctp::SctpAssociation::processCookieAckArrived ( )
protected
891 {
892  bool trans = false;
893 
894  if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
897  if (state->cookieChunk->getCookieArraySize() == 0) {
898  delete state->cookieChunk->getStateCookie();
899  }
900  delete state->cookieChunk;
901  return trans;
902  }
903  else
904  EV_DETAIL << "State=" << fsm->getState() << "\n";
905 
906  return trans;
907 }

Referenced by process_RCV_Message().

◆ processCookieEchoArrived()

bool inet::sctp::SctpAssociation::processCookieEchoArrived ( SctpCookieEchoChunk cookieEcho,
L3Address  addr 
)
protected
815 {
816  bool trans = false;
817 
818  const SctpCookie *cookie = cookieEcho->getStateCookie();
819  if (cookie->getCreationTime() + simtime_t(sctpMain->par("validCookieLifetime")) < simTime()) {
820  EV_INFO << "stale Cookie: sendAbort\n";
821  sendAbort();
822  delete cookie;
823  return trans;
824  }
825  if (fsm->getState() == SCTP_S_CLOSED) {
826  if (cookie->getLocalTag() != localVTag || cookie->getPeerTag() != peerVTag) {
827  bool same = true;
828  for (int32_t i = 0; i < 32; i++) {
829  if (cookie->getLocalTieTag(i) != state->localTieTag[i]) {
830  same = false;
831  break;
832  }
833  if (cookie->getPeerTieTag(i) != state->peerTieTag[i]) {
834  same = false;
835  break;
836  }
837  }
838  if (!same) {
839  sendAbort();
840  delete cookie;
841  return trans;
842  }
843  }
844  EV_INFO << "State is CLOSED, Cookie_Ack has to be sent\n";
846  if (trans)
847  sendCookieAck(addr); // send to address
848  }
849  else if (fsm->getState() == SCTP_S_ESTABLISHED || fsm->getState() == SCTP_S_COOKIE_WAIT || fsm->getState() == SCTP_S_COOKIE_ECHOED) {
850  EV_INFO << "State is not CLOSED, but COOKIE_ECHO received. Compare the Tags\n";
851  // case A: Peer restarted, retrieve information from cookie
852  if (cookie->getLocalTag() != localVTag && cookie->getPeerTag() != peerVTag) {
853  bool same = true;
854  for (int32_t i = 0; i < 32; i++) {
855  if (cookie->getLocalTieTag(i) != state->localTieTag[i]) {
856  same = false;
857  break;
858  }
859  if (cookie->getPeerTieTag(i) != state->peerTieTag[i]) {
860  same = false;
861  break;
862  }
863  }
864  if (same) {
865  localVTag = cookie->getLocalTag();
866  peerVTag = cookie->getPeerTag();
867  sendCookieAck(addr);
868  }
869  }
870  // case B: Setup collision, retrieve information from cookie
871  else if (cookie->getPeerTag() == peerVTag && (cookie->getLocalTag() != localVTag || cookie->getLocalTag() == 0)) {
872  localVTag = cookie->getLocalTag();
873  peerVTag = cookie->getPeerTag();
875  sendCookieAck(addr);
876  }
877  else if (cookie->getPeerTag() == peerVTag && cookie->getLocalTag() == localVTag) {
878  sendCookieAck(addr); // send to address src
879  }
880  trans = true;
881  }
882  else {
883  EV_DETAIL << "State=" << fsm->getState() << "\n";
884  trans = true;
885  }
886  delete cookie;
887  return trans;
888 }

Referenced by process_RCV_Message().

◆ processDataArrived()

SctpEventCode inet::sctp::SctpAssociation::processDataArrived ( SctpDataChunk dataChunk)
protected
2110 {
2111  const uint32_t tsn = dataChunk->getTsn();
2113 
2114  state->newChunkReceived = false;
2115  state->lastTsnReceived = tsn;
2116 
2117  bool found = false;
2118  for (auto& elem : state->lastDataSourceList) {
2119  if (elem == path) {
2120  found = true;
2121  break;
2122  }
2123  }
2124  if (!found) {
2125  state->lastDataSourceList.push_back(path);
2126  }
2127  state->lastDataSourcePath = path;
2128 
2129  EV_INFO << simTime() << " SctpAssociation::processDataArrived TSN=" << tsn << endl;
2130  path->vectorPathReceivedTsn->record(tsn);
2131  if (dataChunk->getIBit()) {
2133  }
2135 
2136  const uint32_t payloadLength = dataChunk->getByteLength() - SCTP_DATA_CHUNK_LENGTH;
2137 
2138  EV_DETAIL << "state->bytesRcvd=" << state->bytesRcvd << endl;
2139  if (payloadLength == 0) {
2140  EV_DETAIL << "No user data. Send ABORT" << endl;
2141  return SCTP_E_ABORT;
2142  }
2143  state->bytesRcvd += payloadLength;
2144  EV_DETAIL << "state->bytesRcvd now=" << state->bytesRcvd << endl;
2145  path->numberOfBytesReceived += payloadLength;
2146  auto iter = sctpMain->assocStatMap.find(assocId);
2147  iter->second.rcvdBytes += payloadLength;
2148 
2149  if (state->stopReceiving) {
2150  return SCTP_E_SEND;
2151  }
2152 
2153  // ====== Duplicate: tsn < CumAckTsn =====================================
2154  if (tsnLe(tsn, state->gapList.getCumAckTsn())) {
2155  if (state->stopOldData) {
2156  if (tsnGe(tsn, state->peerTsnAfterReset)) {
2157  state->stopOldData = false;
2158  }
2159  return SCTP_E_SEND;
2160  }
2161  else {
2162  EV_DETAIL << simTime() << ": Duplicate TSN " << tsn << " (smaller than CumAck)" << endl;
2163  state->dupList.push_back(tsn);
2164  state->dupList.unique();
2165  path->numberOfDuplicates++;
2166 
2167  return SCTP_E_DUP_RECEIVED;
2168  }
2169  }
2170 
2171  // ====== Duplicate ======================================================
2172  if (tsnIsDuplicate(tsn)) {
2173  // TSN value is duplicate within a fragment
2174  EV_DETAIL << "Duplicate TSN " << tsn << " (copy)" << endl;
2175  state->dupList.push_back(tsn);
2176  state->dupList.unique();
2177  path->numberOfDuplicates++;
2178  return SCTP_E_SEND;
2179  }
2180 
2181  // ====== Out of receiver buffer space? ==================================
2183  if (((state->messageAcceptLimit > 0) &&
2184  (state->localMsgRwnd - state->bufferedMessages <= 0)) ||
2185  ((state->messageAcceptLimit == 0) &&
2186  ((int32_t)(state->localRwnd - state->queuedReceivedBytes
2188  {
2190 
2191  if (tsnGt(tsn, state->gapList.getHighestTsnReceived())) {
2192  EV_DETAIL << "DROP: " << (int)tsn << " high=" << (int)state->gapList.getHighestTsnReceived()
2193  << " Q=" << (int)state->queuedReceivedBytes << " Rwnd=" << (int)state->localRwnd << endl;
2194  if ((!state->pktDropSent) && (sctpMain->pktdrop) && (state->peerPktDrop)) {
2195  EV_DETAIL << "Receive buffer full (case 1): sendPacketDrop" << endl;
2196  sendPacketDrop(false);
2197  }
2198  iter->second.numDropsBecauseNewTsnGreaterThanHighestTsn++;
2199  return SCTP_E_SEND;
2200  // } ????
2201  }
2202  else if ((tsn < state->gapList.getHighestTsnReceived()) &&
2203  (state->disableReneging == false) &&
2204  (!makeRoomForTsn(tsn, dataChunk->getByteLength() - SCTP_DATA_CHUNK_LENGTH * 8, dataChunk->getUBit())))
2205  {
2206  if ((!state->pktDropSent) && (sctpMain->pktdrop) && (state->peerPktDrop)) {
2207  EV_DETAIL << "Receive buffer full (case 2): sendPacketDrop" << endl;
2208  sendPacketDrop(false);
2209  }
2210  iter->second.numDropsBecauseNoRoomInBuffer++;
2211  return SCTP_E_SEND;
2212  }
2213  }
2214 
2215  // ====== Update of CumAckTsn ============================================
2217  (state->disableReneging == false) ? true : false);
2219  EV_DETAIL << "cumAckTsn=" << state->gapList.getCumAckTsn()
2220  << " highestTsnReceived=" << state->gapList.getHighestTsnReceived() << endl;
2221 
2222  // ====== Silly Window Syndrome Avoidance ================================
2223  if (state->swsAvoidanceInvoked) {
2224  // swsAvoidanceInvoked => schedule a SACK to be sent at once in this case
2225  EV_TRACE << "swsAvoidanceInvoked" << endl;
2227  }
2228 
2229  if (dataChunk->getSid() >= inboundStreams) {
2230  sendInvalidStreamError(dataChunk->getSid());
2231  return SCTP_E_IGNORE;
2232  }
2233  // ====== Enqueue new chunk ==============================================
2234  SctpEventCode event = SCTP_E_SEND;
2235  if (state->newChunkReceived) {
2236  auto iter = receiveStreams.find(dataChunk->getSid());
2237  const int ret = iter->second->enqueueNewDataChunk(makeVarFromMsg(dataChunk));
2238  if (ret > 0) {
2239  state->queuedReceivedBytes += payloadLength;
2241 
2242  event = SCTP_E_DELIVERED;
2243  if (ret < 3) {
2245  sendDataArrivedNotification(dataChunk->getSid());
2246  putInDeliveryQ(dataChunk->getSid());
2247  if (simTime() > state->lastThroughputTime + 1) {
2248  for (uint16_t i = 0; i < inboundStreams; i++) {
2250  char vectorName[128];
2251  snprintf(vectorName, sizeof(vectorName), "Stream %d Throughput", i);
2252  streamThroughputVectors[i] = new cOutVector(vectorName);
2253  }
2254 
2256  / (simTime() - state->lastThroughputTime) / 1024);
2257  state->streamThroughput[i] = 0;
2258  }
2259  state->lastThroughputTime = simTime();
2260  }
2261  state->streamThroughput[dataChunk->getSid()] += payloadLength;
2262  }
2264  }
2265  state->newChunkReceived = false;
2266  }
2267 
2268  return event;
2269 }

Referenced by process_RCV_Message().

◆ processErrorArrived()

void inet::sctp::SctpAssociation::processErrorArrived ( SctpErrorChunk error)
protected
3519 {
3520  uint32_t parameterType;
3521  for (uint32_t i = 0; i < errorChunk->getParametersArraySize(); i++) {
3522  SctpParameter *param = (SctpParameter *)errorChunk->getParameters(i);
3523  parameterType = param->getParameterType();
3524  switch (parameterType) {
3525  case MISSING_NAT_ENTRY: {
3526  if (sctpMain->par("addIP").boolValue()) {
3527  if (StartAddIP->isScheduled())
3530  const char *type = sctpMain->par("addIpType").stringValue();
3531  sendAsconf(type, true);
3532  }
3533  break;
3534  }
3535 
3536  case UNSUPPORTED_HMAC: {
3537  sendAbort();
3538  break;
3539  }
3540  }
3541  }
3542 }

Referenced by process_RCV_Message().

◆ processForwardTsnArrived()

SctpEventCode inet::sctp::SctpAssociation::processForwardTsnArrived ( SctpForwardTsnChunk forChunk)
protected
2069 {
2070  EV_TRACE << "processForwardTsnArrived\n";
2071  EV_INFO << "last state->cTsnAck=" << state->gapList.getCumAckTsn() << " fwCumAck=" << fwChunk->getNewCumTsn() << "\n";
2072 
2073  /* Ignore old FORWARD_TSNs, probably stale retransmits. */
2074  if (state->gapList.getCumAckTsn() >= fwChunk->getNewCumTsn()) {
2075  return SCTP_E_IGNORE;
2076  }
2077 
2078  for (uint32_t i = 0; i < fwChunk->getSidArraySize(); i++) {
2079  if (fwChunk->getSsn(i) != -1) {
2080  auto iter = receiveStreams.find(fwChunk->getSid(i));
2081  SctpReceiveStream *rStream = iter->second;
2082 
2083  /* Uncomment the folloing to drop gap-acknowledged messages
2084  * between two abandonend messages rather then delivering them.
2085  */
2086 
2087  if (rStream->getOrderedQ()->getQueueSize() > 0)
2088  rStream->setExpectedStreamSeqNum(rStream->getOrderedQ()->getFirstSsnInQueue(fwChunk->getSid(i)));
2089  else if (rStream->getExpectedStreamSeqNum() <= fwChunk->getSsn(i))
2090  rStream->setExpectedStreamSeqNum(fwChunk->getSsn(i) + 1);
2091  if (rStream->getExpectedStreamSeqNum() > 65535) {
2092  rStream->setExpectedStreamSeqNum(0);
2093  }
2094  sendDataArrivedNotification(fwChunk->getSid(i));
2096  }
2097  }
2098  /* Update Gap lists with abandoned TSNs and advance CumTSNAck */
2099  for (uint32_t i = state->gapList.getCumAckTsn() + 1; i <= fwChunk->getNewCumTsn(); i++) {
2100  if (i > state->gapList.getCumAckTsn() && !state->gapList.tsnInGapList(i)) {
2101  bool dummy;
2102  state->gapList.updateGapList(i, dummy, false);
2104  }
2105  }
2106  return SCTP_E_IGNORE;
2107 }

Referenced by process_RCV_Message().

◆ processHeartbeatAckArrived()

SctpEventCode inet::sctp::SctpAssociation::processHeartbeatAckArrived ( SctpHeartbeatAckChunk heartbeatack,
SctpPathVariables path 
)
protected
2273 {
2274  path->numberOfHeartbeatAcksRcvd++;
2275  path->vectorPathRcvdHbAck->record(path->numberOfHeartbeatAcksRcvd);
2276  /* hb-ack goes to pathmanagement, reset error counters, stop timeout timer */
2277  const L3Address addr = hback->getRemoteAddr();
2278  const simtime_t hbTimeField = hback->getTimeField();
2279  stopTimer(path->HeartbeatTimer);
2280  /* assume a valid RTT measurement on this path */
2281  simtime_t rttEstimation = simTime() - hbTimeField;
2282  pmRttMeasurement(path, rttEstimation);
2283  pmClearPathCounter(path);
2284  path->confirmed = true;
2285  path->lastAckTime = simTime();
2286  if (path->primaryPathCandidate == true) {
2287  state->setPrimaryPath(getPath(addr));
2288  path->primaryPathCandidate = false;
2289  if (path->pmtu < state->assocPmtu) {
2290  state->assocPmtu = path->pmtu;
2291  }
2292  path->ssthresh = state->peerRwnd;
2293  recordCwndUpdate(path);
2294  path->heartbeatTimeout = sctpMain->getHbInterval() + path->pathRto;
2295  }
2296 
2297  if (path->activePath == false) {
2298  EV_INFO << "HB ACK arrived activePath=false. remoteAddress=" << path->remoteAddress
2299  << " initialPP=" << state->initialPrimaryPath << endl;
2300  path->activePath = true;
2301  if (state->reactivatePrimaryPath && path->remoteAddress == state->initialPrimaryPath) {
2302  state->setPrimaryPath(path);
2303  }
2304  EV_DETAIL << "primaryPath now " << state->getPrimaryPathIndex() << endl;
2305  }
2306  EV_INFO << "Received HB ACK chunk...resetting error counters on path " << addr
2307  << ", rttEstimation=" << rttEstimation << endl;
2308  path->pathErrorCount = 0;
2309  return SCTP_E_IGNORE;
2310 }

Referenced by process_RCV_Message().

◆ processInAndOutResetRequestArrived()

SctpEventCode inet::sctp::SctpAssociation::processInAndOutResetRequestArrived ( SctpIncomingSsnResetRequestParameter inRequestParam,
SctpOutgoingSsnResetRequestParameter outRequestParam 
)
protected
2636 {
2637  uint32_t inSrSn = 0;
2638  uint32_t outSrSn = 0;
2639  uint16_t inRes = 0;
2640  uint16_t outRes = 0;
2641  uint16_t num = 0;
2642  if (tsnGt(outRequestParam->getLastTsn(), state->gapList.getHighestTsnReceived())) {
2643  state->lastTsnBeforeReset = outRequestParam->getLastTsn();
2644  state->peerRequestSn = outRequestParam->getSrReqSn();
2645  state->inRequestSn = inRequestParam->getSrReqSn();
2646  state->inOut = true;
2647  }
2648  else {
2649  if (outRequestParam->getStreamNumbersArraySize() > 0) {
2650  num = 0;
2651  for (uint16_t i = 0; i < outRequestParam->getStreamNumbersArraySize(); i++) {
2652  if (!receiveStreamPresent(outRequestParam->getStreamNumbers(i))) {
2653  outSrSn = outRequestParam->getSrReqSn();
2654  outRes = DENIED;
2655  num++;
2656  break;
2657  }
2658  }
2659  if (num == 0) {
2660  for (uint16_t i = 0; i < outRequestParam->getStreamNumbersArraySize(); i++) {
2661  resetExpectedSsn(outRequestParam->getStreamNumbers(i));
2662  }
2663  }
2664  }
2665  else {
2667  EV_DETAIL << "processInAndOutResetRequestArrived: resetExpectedSsns\n";
2668  sendOutgoingRequestAndResponse(inRequestParam->getSrReqSn(), outRequestParam->getSrReqSn());
2669  }
2670  if (inRequestParam->getStreamNumbersArraySize() > 0) {
2671  num = 0;
2672  for (uint16_t i = 0; i < inRequestParam->getStreamNumbersArraySize(); i++) {
2673  if (!receiveStreamPresent(inRequestParam->getStreamNumbers(i))) {
2674  inSrSn = inRequestParam->getSrReqSn();
2675  inRes = DENIED;
2676  num++;
2677 // sendStreamResetResponse(outRequestParam->getSrReqSn(), DENIED);
2678  break;
2679  }
2680  }
2681  if (num == 0) {
2682  sendOutgoingRequestAndResponse(inRequestParam, outRequestParam);
2683  }
2684  }
2685  }
2686  if (inSrSn > 0 && outSrSn > 0) {
2687  sendDoubleStreamResetResponse(inSrSn, inRes, outSrSn, outRes);
2688  state->resetPending = true;
2689  }
2690  return SCTP_E_IGNORE;
2691 }

Referenced by processStreamResetArrived().

◆ processIncomingResetRequestArrived()

void inet::sctp::SctpAssociation::processIncomingResetRequestArrived ( SctpIncomingSsnResetRequestParameter requestParam)
protected
2392 {
2393  uint16_t num = 0;
2394  if (!state->firstPeerRequest && (requestParam->getSrReqSn() < (state->peerRequestSn))) {
2395  // Retransmission
2396  sendStreamResetResponse(requestParam->getSrReqSn(), NO_RESET);
2397  return;
2398  }
2399  if (!state->fragInProgress && state->outstandingBytes == 0) {
2400  if (requestParam->getStreamNumbersArraySize() > 0) {
2401  for (uint16_t i = 0; i < requestParam->getStreamNumbersArraySize(); i++) {
2402  if (!sendStreamPresent(requestParam->getStreamNumbers(i))) {
2403  sendStreamResetResponse(requestParam->getSrReqSn(), DENIED);
2404  return;
2405  }
2406  if (getSsnOfStream(requestParam->getStreamNumbers(i)) == 0) {
2407  num++;
2408  }
2409  }
2410  if (num == requestParam->getStreamNumbersArraySize()) {
2411  sendStreamResetResponse(requestParam->getSrReqSn(), NOTHING_TO_DO);
2412  return;
2413  }
2414  for (uint16_t i = 0; i < requestParam->getStreamNumbersArraySize(); i++) {
2415  if (!state->findPeerStreamToReset(requestParam->getStreamNumbers(i))) {
2416 
2417 // resetSsn(requestParam->getStreamNumbers(i));
2418  state->peerStreamsToReset.push_back(requestParam->getStreamNumbers(i));
2419  }
2420  }
2421  }
2422  else {
2423  resetSsns();
2424  }
2425  sendOutgoingResetRequest(requestParam);
2426 // sendBundledOutgoingResetAndResponse(requestParam);
2427  EV_TRACE << "processIncomingResetRequestArrived: sendOutgoingResetRequestArrived returned\n";
2428  state->resetPending = true;
2429  }
2430  else {
2431  if (requestParam->getStreamNumbersArraySize() > 0) {
2432  state->streamsPending.clear();
2433  state->streamsToReset.clear();
2434  for (uint16_t i = 0; i < requestParam->getStreamNumbersArraySize(); i++) {
2435  if (!sendStreamPresent(requestParam->getStreamNumbers(i))) {
2436  sendStreamResetResponse(requestParam->getSrReqSn(), DENIED);
2437  return;
2438  }
2439  if ((getBytesInFlightOfStream(requestParam->getStreamNumbers(i)) > 0) || getFragInProgressOfStream(requestParam->getStreamNumbers(i))) {
2440  state->streamsPending.push_back(requestParam->getStreamNumbers(i));
2441  }
2442  else {
2443  state->streamsToReset.push_back(requestParam->getStreamNumbers(i));
2444  resetSsn(requestParam->getStreamNumbers(i));
2445  }
2446  }
2447  }
2448  else {
2449  for (uint16_t i = 0; i < outboundStreams; i++) {
2450  if (getBytesInFlightOfStream(i) > 0) {
2451  state->streamsPending.push_back(i);
2452  }
2453  else {
2454  state->streamsToReset.push_back(i);
2455  resetSsn(i);
2456  }
2457  }
2458  }
2459  if (state->streamsToReset.size() > 0) {
2460 // sendBundledOutgoingResetAndResponse(requestParam);
2461  sendOutgoingResetRequest(requestParam);
2462  state->resetPending = true;
2463  }
2464  if (!state->resetPending) {
2465  sendStreamResetResponse(requestParam->getSrReqSn(), DEFERRED);
2466  state->resetDeferred = true;
2467  }
2468  state->peerRequestSn = requestParam->getSrReqSn();
2471  if (state->streamsPending.size() == 0 && state->incomingRequestSet && state->incomingRequest != nullptr) {
2472  delete state->incomingRequest;
2473  state->incomingRequest = nullptr;
2474  state->incomingRequestSet = false;
2475  }
2476  state->incomingRequest = ((SctpParameter *)requestParam)->dup(); // FIXME is the c-style conversion need here?, duplicate only SctpParameter part!!!
2477 // state->incomingRequest->setName("StateIncoming");
2478  state->incomingRequestSet = true;
2479  }
2480 }

Referenced by checkStreamsToReset(), and processStreamResetArrived().

◆ processInitAckArrived()

bool inet::sctp::SctpAssociation::processInitAckArrived ( SctpInitAckChunk initAckChunk)
protected
731 {
732  bool trans = false;
733  uint16_t type;
734 
735  if (fsm->getState() == SCTP_S_COOKIE_WAIT) {
736  EV_INFO << "State is COOKIE_WAIT, Cookie_Echo has to be sent\n";
740 // delete state->initChunk; will be deleted when state ESTABLISHED is entered
741  if (trans) {
742  initPeerTsn = initAckChunk->getInitTsn();
743  localVTag = initAckChunk->getInitTag();
745  state->initialPeerRwnd = initAckChunk->getA_rwnd();
748  if (initAckChunk->getMsg_rwnd() > 0) {
749  state->peerAllowsChunks = true;
750  state->initialPeerMsgRwnd = initAckChunk->getMsg_rwnd();
752  }
754  remoteAddressList.clear();
755  numberOfRemoteAddresses = initAckChunk->getAddressesArraySize();
756  EV_INFO << "number of remote addresses in initAck=" << numberOfRemoteAddresses << "\n";
757  for (uint32_t j = 0; j < numberOfRemoteAddresses; j++) {
758  if (initAckChunk->getAddresses(j).getType() == L3Address::IPv6)
759  continue;
760  for (auto& elem : state->localAddresses) {
761  if (!((elem).isUnspecified())) {
762  EV_INFO << "addPath " << initAckChunk->getAddresses(j) << "\n";
763  if (sctpMain->addRemoteAddress(this, (elem), initAckChunk->getAddresses(j))) {
764  this->remoteAddressList.push_back(initAckChunk->getAddresses(j));
765  addPath(initAckChunk->getAddresses(j));
766  }
767  }
768  }
769  }
771  EV_INFO << " get new path for " << remoteAddr << "\n";
772  SctpPathVariables *path = new SctpPathVariables(remoteAddr, this, rt);
773  sctpPathMap[remoteAddr] = path;
777  }
780  inboundStreams = ((initAckChunk->getNoOutStreams() < inboundStreams) ? initAckChunk->getNoOutStreams() : inboundStreams);
781  outboundStreams = ((initAckChunk->getNoInStreams() < outboundStreams) ? initAckChunk->getNoInStreams() : outboundStreams);
783  if (initAckChunk->getHmacTypesArraySize() != 0) {
784  state->peerAuth = true;
785  for (uint32_t j = 0; j < initAckChunk->getSctpChunkTypesArraySize(); j++) {
786  type = initAckChunk->getSctpChunkTypes(j);
787  if (type != INIT && type != INIT_ACK && type != AUTH && type != SHUTDOWN_COMPLETE) {
788  state->peerChunkList.push_back(type);
789  }
790  }
791  }
792  if (initAckChunk->getSepChunksArraySize() > 0) {
793  for (uint32_t i = 0; i < initAckChunk->getSepChunksArraySize(); i++) {
794  if (initAckChunk->getSepChunks(i) == RE_CONFIG) {
795  state->peerStreamReset = true;
796  continue;
797  }
798  if (initAckChunk->getSepChunks(i) == PKTDROP) {
799  state->peerPktDrop = true;
800  continue;
801  }
802  }
803  }
804  sendCookieEcho(initAckChunk);
805  }
807  }
808  else
809  EV_DETAIL << "State=" << fsm->getState() << "\n";
811  return trans;
812 }

Referenced by process_RCV_Message().

◆ processInitArrived()

bool inet::sctp::SctpAssociation::processInitArrived ( SctpInitChunk initChunk,
int32_t  sport,
int32_t  dport 
)
protected

Process incoming SCTP packets.

Invoked from process_RCV_Message

533 {
534  SctpAssociation *assoc;
535  char timerName[64];
536  bool trans = false;
537  uint16_t type;
538  AddressVector adv;
539 
540  EV_TRACE << "processInitArrived\n";
541  if (fsm->getState() == SCTP_S_CLOSED) {
542  EV_INFO << "fork=" << state->fork << " initReceived=" << state->initReceived << "\n";
543  if (state->fork && !state->initReceived) {
544  EV_TRACE << "cloneAssociation\n";
545  assoc = cloneAssociation();
546  EV_TRACE << "addForkedAssociation\n";
547  sctpMain->addForkedAssociation(this, assoc, localAddr, remoteAddr, srcPort, destPort);
548  assoc->listening = true;
549  this->listening = false;
550 
551  EV_INFO << "Connection forked: this connection got new assocId=" << assocId << ", "
552  "spinoff keeps LISTENing with assocId=" << assoc->assocId << "\n";
553  snprintf(timerName, sizeof(timerName), "T2_SHUTDOWN of assoc %d", assocId);
554  T2_ShutdownTimer->setName(timerName);
555  snprintf(timerName, sizeof(timerName), "T5_SHUTDOWN_GUARD of assoc %d", assocId);
556  T5_ShutdownGuardTimer->setName(timerName);
557  snprintf(timerName, sizeof(timerName), "SACK_TIMER of assoc %d", assocId);
558  SackTimer->setName(timerName);
559  snprintf(timerName, sizeof(timerName), "T1_INIT of assoc %d", assocId);
560  T1_InitTimer->setName(timerName);
561  }
562  else {
563  sctpMain->updateSockPair(this, localAddr, remoteAddr, srcPort, destPort);
564  }
565  if (!state->initReceived) {
566  state->initReceived = true;
569  if (initchunk->getAddressesArraySize() == 0) {
570  EV_INFO << " get new path for " << remoteAddr << "\n";
571  SctpPathVariables *rPath = new SctpPathVariables(remoteAddr, this, rt);
572  sctpPathMap[rPath->remoteAddress] = rPath;
573  qCounter.roomTransQ[rPath->remoteAddress] = 0;
574  qCounter.bookedTransQ[rPath->remoteAddress] = 0;
575  qCounter.roomRetransQ[rPath->remoteAddress] = 0;
576  }
577  initPeerTsn = initchunk->getInitTsn();
579  state->initialPeerRwnd = initchunk->getA_rwnd();
580  if (initchunk->getMsg_rwnd() > 0) {
581  state->peerAllowsChunks = true;
582  state->initialPeerMsgRwnd = initchunk->getMsg_rwnd();
584  }
588  localVTag = initchunk->getInitTag();
589  numberOfRemoteAddresses = initchunk->getAddressesArraySize();
590  state->localAddresses.clear();
591  if (localAddressList.front().isUnspecified()) {
592  for (int32_t i = 0; i < ift->getNumInterfaces(); ++i) {
593 #ifdef INET_WITH_IPv4
594  if (auto ipv4Data = ift->getInterface(i)->findProtocolData<Ipv4InterfaceData>()) {
595  adv.push_back(ipv4Data->getIPAddress());
596  }
597  else
598 #endif // ifdef INET_WITH_IPv4
599 #ifdef INET_WITH_IPv6
600  if (auto ipv6Data = ift->getInterface(i)->findProtocolData<Ipv6InterfaceData>()) {
601  adv.push_back(ipv6Data->getAddress(0));
602  }
603  else
604 #endif // ifdef INET_WITH_IPv6
605  throw cRuntimeError("INET was compiled without IPv4/IPv6 support");
606  }
607  }
608  else {
609  adv = localAddressList;
610  }
611  int rlevel = getAddressLevel(remoteAddr);
612  if (adv.size() == 1) {
613  state->localAddresses.push_back((*adv.begin()));
614  }
615  else if (rlevel > 0) {
616  for (auto& elem : adv) {
617  if (getAddressLevel((elem)) >= rlevel) {
618  sctpMain->addLocalAddress(this, (elem));
619  state->localAddresses.push_back((elem));
620  }
621  }
622  }
623  for (uint32_t j = 0; j < initchunk->getAddressesArraySize(); j++) {
624  // skip IPv6 because we can't send to them yet
625  if (initchunk->getAddresses(j).getType() == L3Address::IPv6)
626  continue;
627  // set path variables for this pathlocalAddresses
628  if (!getPath(initchunk->getAddresses(j))) {
629  SctpPathVariables *path = new SctpPathVariables(initchunk->getAddresses(j), this, rt);
630  EV_INFO << " get new path for " << initchunk->getAddresses(j) << "\n";
631  for (auto& elem : state->localAddresses) {
632  if (sctpMain->addRemoteAddress(this, (elem), initchunk->getAddresses(j))) {
633  this->remoteAddressList.push_back(initchunk->getAddresses(j));
634  }
635  }
636  sctpPathMap[path->remoteAddress] = path;
637  qCounter.roomTransQ[path->remoteAddress] = 0;
638  qCounter.bookedTransQ[path->remoteAddress] = 0;
639  qCounter.roomRetransQ[path->remoteAddress] = 0;
640  }
641  }
643  SctpPathVariables *path = new SctpPathVariables(remoteAddr, this, rt);
644  EV_INFO << "Get new path for " << remoteAddr << "\n";
645  sctpPathMap[remoteAddr] = path;
649  }
650  if (initchunk->getHmacTypesArraySize() != 0) {
651  state->peerAuth = true;
652  for (uint32_t j = 0; j < initchunk->getSctpChunkTypesArraySize(); j++) {
653  type = initchunk->getSctpChunkTypes(j);
654  if (type != INIT && type != INIT_ACK && type != AUTH && type != SHUTDOWN_COMPLETE) {
655  state->peerChunkList.push_back(type);
656  }
657  }
658  }
659  EV_DETAIL << "number supported extensions:" << initchunk->getSepChunksArraySize() << "\n";
660  if (initchunk->getSepChunksArraySize() > 0) {
661  for (uint32_t i = 0; i < initchunk->getSepChunksArraySize(); i++) {
662  if (initchunk->getSepChunks(i) == RE_CONFIG) {
663  state->peerStreamReset = true;
664  continue;
665  }
666  if (initchunk->getSepChunks(i) == PKTDROP) {
667  state->peerPktDrop = true;
668  EV_DEBUG << "set peerPktDrop to true\n";
669  continue;
670  }
671  }
672  }
674  if (trans) {
675  sendInitAck(initchunk);
676  }
677  }
678  else if (fsm->getState() == SCTP_S_CLOSED) {
680  if (trans) {
681  sendInitAck(initchunk);
682  }
683  }
684  else {
685  trans = true;
686  }
687  }
688  else if (fsm->getState() == SCTP_S_COOKIE_WAIT) { // INIT-Collision
689  EV_INFO << "INIT collision: send Init-Ack\n";
690  if (initchunk->getHmacTypesArraySize() != 0) {
691  state->peerAuth = true;
692  if (state->peerChunkList.size() == 0) {
693  for (uint32_t j = 0; j < initchunk->getSctpChunkTypesArraySize(); j++) {
694  type = initchunk->getSctpChunkTypes(j);
695  if (type != INIT && type != INIT_ACK && type != AUTH && type != SHUTDOWN_COMPLETE) {
696  state->peerChunkList.push_back(type);
697  }
698  }
699  }
700  }
701  sendInitAck(initchunk);
702  trans = true;
703  }
704  else if (fsm->getState() == SCTP_S_COOKIE_ECHOED || fsm->getState() == SCTP_S_ESTABLISHED) {
705  // check, whether a new address has been added
706  bool addressPresent = false;
707  for (uint32_t j = 0; j < initchunk->getAddressesArraySize(); j++) {
708  if (initchunk->getAddresses(j).getType() == L3Address::IPv6)
709  continue;
710  for (auto& elem : remoteAddressList) {
711  if ((elem) == (initchunk->getAddresses(j))) {
712  addressPresent = true;
713  break;
714  }
715  }
716  if (!addressPresent) {
717  sendAbort();
718  return true;
719  }
720  }
721  sendInitAck(initchunk);
722  trans = true;
723  }
724  else if (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)
725  trans = true;
727  return trans;
728 }

Referenced by process_RCV_Message().

◆ processOutAndResponseArrived()

SctpEventCode inet::sctp::SctpAssociation::processOutAndResponseArrived ( SctpOutgoingSsnResetRequestParameter outRequestParam,
SctpStreamResetResponseParameter responseParam 
)
protected
2759 {
2760  EV_INFO << "processOutAndResponseArrived\n";
2761  if (getPath(remoteAddr)->ResetTimer->isScheduled()) {
2762  if (state->numResetRequests == 0) {
2763  SctpResetTimer *tm = check_and_cast<SctpResetTimer *>(getPath(remoteAddr)->ResetTimer->decapsulate());
2764  if (tm->getOutSN() == responseParam->getSrResSn()) {
2765  stopTimer(getPath(remoteAddr)->ResetTimer);
2766  delete state->resetChunk;
2767  state->resetChunk = nullptr;
2768  }
2769  delete tm;
2770  }
2771  }
2772  if (state->requests[outRequestParam->getSrResSn()].result != PERFORMED) {
2773  if (outRequestParam->getStreamNumbersArraySize() > 0) {
2774  for (uint16_t i = 0; i < outRequestParam->getStreamNumbersArraySize(); i++) {
2775  resetExpectedSsn(outRequestParam->getStreamNumbers(i));
2776  }
2777  }
2778  else {
2780  }
2781  state->requests[outRequestParam->getSrResSn()].result = PERFORMED;
2782  }
2783  sendStreamResetResponse(outRequestParam->getSrReqSn(), PERFORMED);
2784  if (responseParam->getResult() == PERFORMED) {
2785  if (state->requests[responseParam->getSrResSn()].result != PERFORMED) {
2786  std::list<uint16_t>::iterator iter;
2787  if (state->requests[responseParam->getSrResSn()].streams.size() > 0) {
2788  for (iter = state->requests[responseParam->getSrResSn()].streams.begin(); iter != state->requests[responseParam->getSrResSn()].streams.end(); iter++) {
2789  resetSsn((*iter));
2790  }
2791  }
2792  else {
2793  resetSsns();
2794  }
2795 // resetExpectedSsns();
2796  state->resetPending = false;
2798  auto it = sctpMain->assocStatMap.find(assocId);
2799  it->second.numResetRequestsPerformed++;
2800  }
2801  }
2802  else {
2803  EV_INFO << "Reset Request failed. Send indication to app.\n";
2804  state->resetPending = false;
2806  }
2807  state->requests[responseParam->getSrResSn()].result = responseParam->getResult();
2808  return SCTP_E_IGNORE;
2809 }

Referenced by processStreamResetArrived().

◆ processOutgoingResetRequestArrived()

void inet::sctp::SctpAssociation::processOutgoingResetRequestArrived ( SctpOutgoingSsnResetRequestParameter requestParam)
protected
2313 {
2314  EV_TRACE << "processOutgoingResetRequestArrived\n";
2315  if (!state->firstPeerRequest && (requestParam->getSrReqSn() < (state->peerRequestSn))) {
2316  // Retransmission
2317  sendStreamResetResponse(requestParam->getSrReqSn(), NO_RESET);
2318  return;
2319  }
2320 
2321  if (state->findRequestNum(requestParam->getSrResSn())) {
2322  state->requests[requestParam->getSrResSn()].result = PERFORMED;
2324  state->waitForResponse = false;
2325  }
2326  if (getPath(remoteAddr)->ResetTimer->isScheduled()) {
2327  if (state->numResetRequests == 0) {
2328  SctpResetTimer *tm = check_and_cast<SctpResetTimer *>(PK(getPath(remoteAddr)->ResetTimer)->decapsulate());
2329  if ((tm->getOutSN() == requestParam->getSrResSn() && !tm->getOutAcked()) ||
2330  (tm->getInSN() == requestParam->getSrResSn() && !tm->getInAcked()))
2331  {
2332  stopTimer(getPath(remoteAddr)->ResetTimer);
2333  delete state->resetChunk;
2334  state->resetChunk = nullptr;
2335  state->resetPending = false;
2336  state->localRequestType = 0;
2337  state->stopReceiving = false;
2338  }
2339  delete tm;
2340  }
2341  }
2342  if (requestParam->getStreamNumbersArraySize() > 0) {
2343  uint16_t count = 0;
2344  for (uint16_t i = 0; i < requestParam->getStreamNumbersArraySize(); i++) {
2345  if (!receiveStreamPresent(requestParam->getStreamNumbers(i))) {
2346  sendStreamResetResponse(requestParam->getSrReqSn(), DENIED);
2347  return;
2348  }
2349  if (getExpectedSsnOfStream(requestParam->getStreamNumbers(i)) != 0) {
2350  count++;
2351  }
2352  }
2353  if (count == 0 && !(tsnGt(requestParam->getLastTsn(), state->gapList.getHighestTsnReceived()))) {
2354  sendStreamResetResponse(requestParam->getSrReqSn(), NOTHING_TO_DO);
2355  return;
2356  }
2357  }
2358  if (state->streamReset && !(tsnGt(requestParam->getLastTsn(), state->gapList.getHighestTsnReceived()))) {
2359  if (requestParam->getStreamNumbersArraySize() > 0) {
2360  for (uint16_t i = 0; i < requestParam->getStreamNumbersArraySize(); i++) {
2361  resetExpectedSsn(requestParam->getStreamNumbers(i));
2362  }
2363  }
2364  else {
2366  }
2367  EV_DETAIL << "processOutgoingResetRequestArrived: resetExpectedSsns\n";
2368  if (state->sendResponse == PERFORMED) {
2369  sendStreamResetResponse(requestParam->getSrReqSn(), PERFORMED);
2370  state->sendResponse = 0;
2371  }
2372  else {
2374  state->responseSn = requestParam->getSrReqSn();
2375  }
2376  }
2377  else if (tsnGt(requestParam->getLastTsn(), state->gapList.getHighestTsnReceived())) {
2378  state->lastTsnBeforeReset = requestParam->getLastTsn();
2379  state->peerRequestSn = requestParam->getSrReqSn();
2380  sendStreamResetResponse(requestParam->getSrReqSn(), DEFERRED);
2381  state->incomingRequest = requestParam->dup();
2382  state->incomingRequestSet = true;
2383  state->resetDeferred = true;
2384 // state->firstPeerRequest = false;
2385  }
2386  else {
2387  sendStreamResetResponse(requestParam->getSrReqSn(), PERFORMED);
2388  }
2389 }

Referenced by processStreamResetArrived().

◆ processPacketDropArrived()

bool inet::sctp::SctpAssociation::processPacketDropArrived ( SctpPacketDropChunk pktdrop)
protected
3407 {
3408 #if 0
3409  bool dataReceived = false;
3410 
3411  if (packetDropChunk->getMFlag() == false) {
3412  EV_TRACE << "processPacketDropArrived" << endl;
3413  if (packetDropChunk->getEncapsulatedPacket() != nullptr) {
3414  SctpHeader *sctpmsg = (SctpHeader *)(packetDropChunk->decapsulate());
3415  const uint32_t numberOfChunks = sctpmsg->getChunksArraySize();
3416  EV_DETAIL << "numberOfChunks=" << numberOfChunks << endl;
3417  for (uint32_t i = 0; i < numberOfChunks; i++) {
3418  SctpChunk *chunk = (SctpChunk *)(sctpmsg->removeChunk());
3419  const uint8_t type = chunk->getSctpChunkType();
3420  switch (type) {
3421  case DATA: {
3422  SctpDataChunk *dataChunk = check_and_cast<SctpDataChunk *>(chunk);
3423  const uint32_t tsn = dataChunk->getTsn();
3424  auto pq = retransmissionQ->payloadQueue.find(tsn);
3425  if ((pq != retransmissionQ->payloadQueue.end()) &&
3426  (!chunkHasBeenAcked(pq->second)))
3427  {
3428  EV_DETAIL << simTime() << ": Packet Drop for TSN "
3429  << pq->second->tsn << " on path "
3430  << pq->second->getLastDestination()
3431  << " -> transmitting it again" << endl;
3432  putInTransmissionQ(pq->first, pq->second);
3433  }
3434  delete dataChunk->decapsulate();
3435  dataReceived = true;
3436  break;
3437  }
3438 
3439  case SACK:
3440  sendSack();
3441  break;
3442 
3443  case INIT:
3445  retransmitInit();
3447  break;
3448 
3449  case HEARTBEAT:
3451  break;
3452 
3453  case HEARTBEAT_ACK:
3454  break;
3455 
3456  case SHUTDOWN:
3460  break;
3461 
3462  case SHUTDOWN_ACK:
3466  break;
3467 
3468  case COOKIE_ECHO:
3472  break;
3473 
3474  case COOKIE_ACK:
3476  break;
3477 
3478  case ASCONF:
3479  stopTimer(getPath(remoteAddr)->AsconfTimer);
3480  retransmitAsconf();
3481  startTimer(getPath(remoteAddr)->AsconfTimer, getPath(remoteAddr)->pathRto);
3482  break;
3483 
3484  case FORWARD_TSN:
3485  if (peekAbandonedChunk(getPath(remoteAddr)) != nullptr) {
3486  const auto& sctpmsg = makeShared<SctpHeader>();
3487  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
3488  SctpForwardTsnChunk *forwardChunk = createForwardTsnChunk(remoteAddr);
3490  SctpAuthenticationChunk *authChunk = createAuthChunk();
3491  sctpmsg->appendSctpChunks(authChunk);
3492  }
3493  sctpmsg->appendSctpChunks(forwardChunk);
3494  }
3495  break;
3496  default:
3497  throw cRuntimeError("unknown chunk type");
3498  break;
3499 
3500  }
3501  delete chunk;
3502  }
3503  disposeOf(sctpmsg);
3504  }
3505  else {
3506  EV_INFO << "no chunk encapsulated" << endl;
3507  }
3508  state->peerRwnd = packetDropChunk->getMaxRwnd()
3509  - packetDropChunk->getQueuedData()
3510  - getOutstandingBytes();
3511  statisticsPeerRwnd->record(state->peerRwnd);
3512  return dataReceived;
3513  }
3514 #endif
3515  return false;
3516 }

Referenced by process_RCV_Message().

◆ processResetResponseArrived()

void inet::sctp::SctpAssociation::processResetResponseArrived ( SctpStreamResetResponseParameter responseParam)
protected
2519 {
2520  EV_INFO << "processResetResponseArrived \n";
2521  if (getPath(remoteAddr)->ResetTimer->isScheduled()) {
2522  if (getPath(remoteAddr)->ResetTimer->hasEncapsulatedPacket() &&
2523  (state->numResetRequests == 0 || (state->getNumRequestsNotPerformed() == 1 && responseParam->getResult() != DEFERRED)))
2524  {
2525  SctpResetTimer *tm = check_and_cast<SctpResetTimer *>(getPath(remoteAddr)->ResetTimer->decapsulate());
2526  EV_INFO << "SrResSn=" << responseParam->getSrResSn() << " tmOut=" << tm->getOutSN() << " tmIn= " << tm->getInSN() << "\n";
2527  if (tm->getOutSN() == responseParam->getSrResSn() || tm->getInSN() == responseParam->getSrResSn() || responseParam->getResult() > DEFERRED) {
2528  stopTimer(getPath(remoteAddr)->ResetTimer);
2529  delete state->resetChunk;
2530  state->resetChunk = nullptr;
2532  if (state->streamsPending.size() == 0) {
2533  delete state->resetInfo;
2534  state->resetInfo = nullptr;
2535  }
2536  }
2537  delete tm;
2538  if (responseParam->getResult() > DEFERRED) {
2539  state->resetPending = false;
2540  state->resetRequested = false;
2541  state->waitForResponse = false;
2542  state->streamsPending.clear();
2543  state->resetOutStreams.clear();
2544  state->resetInStreams.clear();
2545  return;
2546  }
2547  }
2548  }
2549  else {
2550  if ((PK(getPath(remoteAddr)->ResetTimer)->hasEncapsulatedPacket())) {
2551  delete (PK(getPath(remoteAddr)->ResetTimer)->decapsulate());
2552  }
2553  }
2554  if (state->requests[responseParam->getSrResSn()].result != PERFORMED) {
2555  if (responseParam->getResult() == PERFORMED) {
2556  if (state->resetRequested) {
2557  if (state->resetOutStreams.size() > 0) {
2558  for (auto& elem : state->resetOutStreams) {
2559  resetSsn((elem));
2560  }
2561  state->resetOutStreams.clear();
2562  }
2563  else if (state->numAddedOutStreams == 0 && state->numAddedInStreams == 0) {
2564  resetSsns();
2565  }
2566  if (state->streamsPending.size() == 0)
2567  state->resetRequested = false;
2568  }
2569  state->resetPending = false;
2570  state->waitForResponse = false;
2571  if (responseParam->getReceiversNextTsn() != 0) {
2572  state->nextTsn = responseParam->getReceiversNextTsn();
2573  state->lastTsnAck = responseParam->getReceiversNextTsn() - 1;
2574  state->gapList.forwardCumAckTsn(responseParam->getSendersNextTsn() - 1);
2575  state->peerTsnAfterReset = responseParam->getSendersNextTsn();
2576  state->stopReceiving = false;
2577  state->stopOldData = true;
2578  if (state->resetInStreams.size() > 0) {
2579  for (auto& elem : state->resetInStreams) {
2580  resetExpectedSsn((elem));
2581  }
2582  state->resetInStreams.clear();
2583  }
2584  else {
2586  }
2587 // sendSack();
2588  }
2589  if (state->localRequestType == ADD_BOTH) {
2590  if (state->numAddedOutStreams > 0) {
2594  }
2595  else if (state->numAddedInStreams > 0) {
2598  state->numAddedInStreams = 0;
2599  }
2600  }
2601  else if (state->localRequestType == ADD_INCOMING) {
2604  state->numAddedInStreams = 0;
2605  }
2606  else if (state->localRequestType == ADD_OUTGOING) {
2610  }
2612  auto it = sctpMain->assocStatMap.find(assocId);
2613  it->second.numResetRequestsPerformed++;
2614  }
2615  else {
2616  EV_INFO << "Reset Request failed. Send indication to app.\n";
2617  if (responseParam->getResult() == DEFERRED) {
2619  }
2620  else {
2621  state->resetPending = false;
2623  }
2624  }
2625  state->requests[responseParam->getSrResSn()].result = responseParam->getResult();
2626  }
2627  if (state->incomingRequestSet && state->incomingRequest != nullptr && state->streamsPending.size() == 0) {
2628  delete state->incomingRequest;
2629  state->incomingRequest = nullptr;
2630  state->incomingRequestSet = false;
2631  }
2632 }

Referenced by processStreamResetArrived().

◆ processSackArrived()

SctpEventCode inet::sctp::SctpAssociation::processSackArrived ( SctpSackChunk sackChunk)
protected
975 {
976  simtime_t rttEstimation = SIMTIME_MAX;
977  const uint64_t sendBufferBeforeUpdate = state->sendBuffer;
978  SctpPathVariables *path = getPath(remoteAddr); // Path for *this* SACK!
979  const uint64_t arwnd = sackChunk->getA_rwnd();
980  const uint32_t tsna = sackChunk->getCumTsnAck();
981  uint32_t highestNewAck = tsna; // Highest newly acked TSN
982  const uint16_t numDups = sackChunk->getNumDupTsns();
983  Sctp::AssocStat *assocStat = sctpMain->getAssocStat(assocId);
984  bool dropFilledGap = false;
985  const uint32_t msgRwnd = sackChunk->getMsg_rwnd();
986 
987  // ====== Put information from SACK into GapList =========================
988  SctpGapList sackGapList;
989  sackGapList.setInitialCumAckTsn(sackChunk->getCumTsnAck());
990  uint32_t lastTsn = sackChunk->getCumTsnAck();
991  for (uint32_t i = 0; i < sackChunk->getNumGaps(); i++) {
992  uint32_t tsn = sackChunk->getGapStart(i);
993  assert(tsnLt(lastTsn + 1, tsn));
994  lastTsn = tsn;
995  while (tsnLe(tsn, sackChunk->getGapStop(i))) {
996  bool dummy;
997  sackGapList.updateGapList(tsn, dummy, true); // revokable TSN
998  tsn++;
999  }
1000  lastTsn = sackChunk->getGapStop(i);
1001  }
1002  if (assocStat) {
1003  assocStat->sumRGapRanges += ((sackChunk->getCumTsnAck() <= lastTsn) ?
1004  (uint64_t)(lastTsn - sackChunk->getCumTsnAck()) :
1005  (uint64_t)(sackChunk->getCumTsnAck() - lastTsn));
1006  }
1007  if (sackChunk->getNrSubtractRGaps() == false) {
1008  lastTsn = sackChunk->getCumTsnAck();
1009  for (uint32_t i = 0; i < sackChunk->getNumNrGaps(); i++) {
1010  uint32_t tsn = sackChunk->getNrGapStart(i);
1011  assert(tsnLt(lastTsn + 1, tsn));
1012  lastTsn = tsn;
1013  while (tsnLe(tsn, sackChunk->getNrGapStop(i))) {
1014  bool dummy;
1015  sackGapList.updateGapList(tsn, dummy, false); // non-revokable TSN
1016  tsn++;
1017  }
1018  lastTsn = sackChunk->getNrGapStop(i);
1019  }
1020  }
1021  else {
1022  lastTsn = sackChunk->getCumTsnAck();
1023  for (uint32_t i = 0; i < sackChunk->getNumNrGaps(); i++) {
1024  uint32_t tsn = sackChunk->getNrGapStart(i);
1025  assert(tsnLt(lastTsn + 1, tsn));
1026  lastTsn = tsn;
1027  while (tsnLe(tsn, sackChunk->getNrGapStop(i))) {
1028  if (sackGapList.tsnIsRevokable(tsn) == false) {
1029  bool dummy;
1030  sackGapList.updateGapList(tsn, dummy, false); // non-revokable TSN
1031  }
1032  tsn++;
1033  }
1034  lastTsn = sackChunk->getNrGapStop(i);
1035  }
1036  }
1037  if (assocStat) {
1038  assocStat->sumNRGapRanges += (sackChunk->getCumTsnAck() <= lastTsn) ?
1039  (uint64_t)(lastTsn - sackChunk->getCumTsnAck()) :
1040  (uint64_t)(sackChunk->getCumTsnAck() - lastTsn);
1041  }
1042  const uint16_t numGaps = sackGapList.getNumGaps(SctpGapList::GT_Any);
1043 
1044  // ====== Print some information =========================================
1045  EV_DETAIL << "##### SACK Processing: TSNa=" << tsna << " #####" << endl;
1046  for (auto& elem : sctpPathMap) {
1047  SctpPathVariables *myPath = elem.second;
1048  EV_DETAIL << "Path " << myPath->remoteAddress << ":\t"
1049  << "outstanding=" << path->outstandingBytes << "\t"
1050  << "T3scheduled=" << path->T3_RtxTimer->getArrivalTime() << " "
1051  << (path->T3_RtxTimer->isScheduled() ? "[ok]" : "[NOT SCHEDULED]") << "\t"
1052  << "findPseudoCumAck=" << ((myPath->findPseudoCumAck == true) ? "true" : "false") << "\t"
1053  << "pseudoCumAck=" << myPath->pseudoCumAck << "\t"
1054  << "newPseudoCumAck=" << ((myPath->newPseudoCumAck == true) ? "true" : "false") << "\t"
1055  << "findRTXPseudoCumAck=" << ((myPath->findRTXPseudoCumAck == true) ? "true" : "false") << "\t"
1056  << "rtxPseudoCumAck=" << myPath->rtxPseudoCumAck << "\t"
1057  << "newRTXPseudoCumAck=" << ((myPath->newRTXPseudoCumAck == true) ? "true" : "false") << "\t"
1058  << endl;
1059  }
1060 
1061  EV_INFO << "Before processSackArrived for path " << path->remoteAddress
1062  << " with tsna=" << tsna << ":" << endl;
1063 
1064  // ====== SACK Sequence Number Check =====================================
1065  EV_INFO << "SACK Seq Number = " << sackChunk->getSackSeqNum() << endl;
1066  if ((state->checkSackSeqNumber == true) &&
1067  (sackChunk->getSackSeqNum() <= state->incomingSackSeqNum))
1068  {
1069  EV_DETAIL << "Out-of-data SACK: " << sackChunk->getSackSeqNum()
1070  << " < " << state->incomingSackSeqNum << endl;
1071  return SCTP_E_IGNORE;
1072  }
1073  state->incomingSackSeqNum = sackChunk->getSackSeqNum();
1074 
1075  // ====== Record statistics ==============================================
1076  numGapBlocks->record(numGaps);
1077  statisticsRevokableGapBlocksInLastSACK->record(sackGapList.getNumGaps(SctpGapList::GT_Revokable));
1079 
1080  path->vectorPathAckedTsnCumAck->record(tsna);
1081  if (assocStat) {
1082  assocStat->numDups += numDups;
1083  }
1084 
1085  // ====== Initialize some variables ======================================
1086  for (auto& elem : sctpPathMap) {
1087  SctpPathVariables *myPath = elem.second;
1088  // T.D. 26.03.09: Remember outstanding bytes before this update
1089  // Values are necessary for updating the congestion window!
1090  myPath->outstandingBytesBeforeUpdate = myPath->outstandingBytes; // copy from myPath, not from path!
1091  myPath->requiresRtx = false;
1092  myPath->lowestTsnRetransmitted = false;
1093  myPath->findLowestTsn = true;
1094  myPath->gapAckedChunksInLastSACK = 0;
1095  myPath->gapNRAckedChunksInLastSACK = 0;
1096  myPath->gapUnackedChunksInLastSACK = 0;
1097  myPath->newlyAckedBytes = 0;
1098  myPath->newCumAck = false; // Check whether CumAck affects this path
1099  // for all destinations, set newPseudoCumAck to FALSE.
1100  myPath->newPseudoCumAck = false;
1101  myPath->newRTXPseudoCumAck = false; // CUCv2
1102  myPath->sawNewAck = false;
1103  myPath->lowestNewAckInSack = 0;
1104  myPath->highestNewAckInSack = 0;
1105  myPath->newOldestChunkSendTime = simTime() + 9999.99; // initialize to more than simTime()
1106  if (myPath == path) {
1107  myPath->lastAckTime = simTime();
1108  }
1109  }
1110 
1111  // ====== Zero Window Probing ============================================
1112  if ((state->peerAllowsChunks) && (msgRwnd > 0) && (state->zeroWindowProbing)) {
1113  state->zeroWindowProbing = false;
1114  }
1115  if ((state->zeroWindowProbing) && (arwnd > 0)) {
1116  state->zeroWindowProbing = false;
1117  }
1118 
1119  // #######################################################################
1120  // #### Processing of CumAck ####
1121  // #######################################################################
1122 
1123  if (tsnGt(tsna, state->lastTsnAck)) { // Handle new CumAck
1124  EV_INFO << "===== Handling new CumAck for TSN " << tsna << " =====" << endl;
1125 
1126  SctpDataVariables *myChunk = retransmissionQ->getChunk(state->lastTsnAck + 1);
1127  if ((myChunk != nullptr) && (myChunk->wasPktDropped) &&
1128  (myChunk->getLastDestinationPath()->fastRecoveryActive))
1129  {
1130  dropFilledGap = true;
1131  EV_DETAIL << "TSN " << myChunk->tsn << " filled gap" << endl;
1132  }
1133 
1134  // We have got new chunks acked, and our cum ack point is advanced ...
1135  // Depending on the parameter osbWithHeader ackedBytes are with or without the header bytes.
1136  // T.D. 23.03.09: path->newlyAckedBytes is updated in dequeueAckedChunks()!
1137  dequeueAckedChunks(tsna, path, rttEstimation); // chunks with tsn between lastTsnAck and tsna are removed from the transmissionQ and the retransmissionQ; outstandingBytes are decreased
1138 
1139  state->lastTsnAck = tsna;
1140  if (tsnGt(tsna, state->advancedPeerAckPoint)) {
1141  state->advancedPeerAckPoint = tsna;
1142  state->ackPointAdvanced = true;
1143  }
1144  // ====== Slow Path RTT Calculation ===================================
1145  if ((state->allowCMT == true) &&
1146  (state->cmtSlowPathRTTUpdate == true) &&
1147  (path->waitingForRTTCalculaton == true) &&
1148  ((path->tsnForRTTCalculation == tsna) ||
1149  (tsnLt(path->tsnForRTTCalculation, tsna))))
1150  {
1151  // Got update from CumAck -> no need for Slow Path RTT calculation
1152  path->waitingForRTTCalculaton = false;
1153  }
1154  }
1155  else if (tsnLt(tsna, state->lastTsnAck)) {
1156  EV_DETAIL << "Stale CumAck (" << tsna << " < " << state->lastTsnAck << ")"
1157  << endl;
1158  // ====== Slow Path RTT Calculation ===================================
1159  if ((state->allowCMT == true) &&
1160  (state->cmtSlowPathRTTUpdate == true) &&
1161  (path->waitingForRTTCalculaton == true))
1162  {
1163  // Slow Path Update
1164  // Look for a CumAck or GapAck of the remembered chunk on this path.
1165  // If it has been found, we can compute the RTT of this path.
1166 
1167  // ====== Look for matching CumAck first ===========================
1168  bool renewRTT = false;
1169  if ((tsnLt(path->tsnForRTTCalculation, tsna)) ||
1170  (path->tsnForRTTCalculation == tsna))
1171  {
1172  renewRTT = true;
1173  }
1174  // ====== Look for matching GapAck =================================
1175  else if ((numGaps > 0) &&
1176  ((path->tsnForRTTCalculation == sackGapList.getGapStop(SctpGapList::GT_Any, numGaps - 1)) ||
1177  (tsnLt(path->tsnForRTTCalculation, sackGapList.getGapStop(SctpGapList::GT_Any, numGaps - 1)))))
1178  {
1179  for (int32_t key = 0; key < numGaps; key++) {
1180  const uint32_t lo = sackGapList.getGapStart(SctpGapList::GT_Any, key);
1181  const uint32_t hi = sackGapList.getGapStop(SctpGapList::GT_Any, key);
1182  if ((path->tsnForRTTCalculation == lo) ||
1183  (path->tsnForRTTCalculation == hi) ||
1184  (tsnLt(lo, path->tsnForRTTCalculation) &&
1185  tsnLt(path->tsnForRTTCalculation, hi)))
1186  {
1187  renewRTT = true;
1188  break;
1189  }
1190  }
1191  }
1192 
1193  if (renewRTT) {
1194  rttEstimation = simTime() - path->txTimeForRTTCalculation;
1195  path->waitingForRTTCalculaton = false;
1196  pmRttMeasurement(path, rttEstimation);
1197 
1198  EV_DETAIL << simTime() << ": SlowPathRTTUpdate from stale SACK - rtt="
1199  << rttEstimation << " from TSN "
1200  << path->tsnForRTTCalculation
1201  << " on path " << path->remoteAddress
1202  << " => RTO=" << path->pathRto << endl;
1203  }
1204  }
1205  return SCTP_E_IGNORE;
1206  }
1207 
1208  // ====== Handle reneging ================================================
1209  if ((numGaps == 0) && (tsnLt(tsna, state->highestTsnAcked))) {
1210  // Reneging, type 0:
1211  // In a previous SACK, chunks up to highestTsnAcked have been acked.
1212  // This SACK contains a CumAck < highestTsnAcked
1213  // => rereg TSNs from CumAck+1 to highestTsnAcked
1214  // => new highestTsnAcked = CumAck
1215  EV_DETAIL << "numGaps=0 && tsna " << tsna
1216  << " < highestTsnAcked " << state->highestTsnAcked << endl;
1217  uint32_t i = state->highestTsnAcked;
1218  while (i >= tsna + 1) {
1219  SctpDataVariables *myChunk = retransmissionQ->getChunk(i);
1220  if (myChunk) {
1221  if (chunkHasBeenAcked(myChunk)) {
1222  tsnWasReneged(myChunk, path, 0);
1223  }
1224  }
1225  i--;
1226  }
1227  state->highestTsnAcked = tsna;
1228  }
1229 
1230  // #######################################################################
1231  // #### Processing of GapAcks ####
1232  // #######################################################################
1233 
1234  if ((numGaps > 0) && (!retransmissionQ->payloadQueue.empty())) {
1235  EV_INFO << "===== Handling GapAcks after CumTSNAck " << tsna << " =====" << endl;
1236  EV_INFO << "We got " << numGaps << " gap reports" << endl;
1237 
1238  // We got fragment reports... check for newly acked chunks.
1239  const uint32_t queuedChunks = retransmissionQ->payloadQueue.size();
1240  EV_DETAIL << "Number of chunks in retransmissionQ: " << queuedChunks
1241  << " highestGapStop: " << sackGapList.getGapStop(SctpGapList::GT_Any, numGaps - 1)
1242  << " highestTsnAcked: " << state->highestTsnAcked << endl;
1243 
1244  // ====== Handle reneging =============================================
1245  // highest gapStop smaller than highestTsnAcked: there might have been reneging
1246  if (tsnLt(sackGapList.getGapStop(SctpGapList::GT_Any, numGaps - 1), state->highestTsnAcked)) {
1247  // Reneging, type 2:
1248  // In a previous SACK, chunks up to highestTsnAcked have been acked.
1249  // This SACK contains a last gap ack < highestTsnAcked
1250  // => rereg TSNs from last gap ack to highestTsnAcked
1251  // => new highestTsnAcked = last gap ack
1252  uint32_t i = state->highestTsnAcked;
1253  while (i >= sackGapList.getGapStop(SctpGapList::GT_Any, numGaps - 1) + 1) {
1254  // ====== Looking up TSN in retransmission queue ================
1255  SctpDataVariables *myChunk = retransmissionQ->getChunk(i);
1256  if (myChunk) {
1257  if (chunkHasBeenAcked(myChunk)) {
1258  EV_INFO << "TSN " << i << " was found. It has been un-acked." << endl;
1259  tsnWasReneged(myChunk, path, 2);
1260  EV_DETAIL << "highestTsnAcked now " << state->highestTsnAcked << endl;
1261  }
1262  }
1263  else {
1264  EV_INFO << "TSN " << i << " not found in retransmissionQ" << endl;
1265  }
1266  i--;
1267  }
1268  state->highestTsnAcked = sackGapList.getGapStop(SctpGapList::GT_Any, numGaps - 1);
1269  }
1270 
1271  // ====== Looking for changes in the gap reports ======================
1272  EV_INFO << "Looking for changes in gap reports" << endl;
1273  // Get Pseudo CumAck for paths
1274  uint32_t lo1 = tsna;
1275  uint32_t tsnCheck = tsna + 1; // Just to make sure that no TSN is misssed
1276  for (int32_t key = 0; key < numGaps; key++) {
1277  const uint32_t lo = sackGapList.getGapStart(SctpGapList::GT_Any, key);
1278  const uint32_t hi = sackGapList.getGapStop(SctpGapList::GT_Any, key);
1279 
1280  // ====== Iterate over TSNs *not* listed in gap reports ============
1281  for (uint32_t pos = lo1 + 1; pos <= lo - 1; pos++) {
1282  assert(tsnCheck == pos);
1283  tsnCheck++;
1284  SctpDataVariables *myChunk = retransmissionQ->getChunk(pos);
1285  if (myChunk) {
1286  SctpPathVariables *myChunkLastPath = myChunk->getLastDestinationPath();
1287  assert(myChunkLastPath != nullptr);
1288  // T.D. 22.11.09: CUCv2 - chunk is *not* acked
1289  cucProcessGapReports(myChunk, myChunkLastPath, false);
1290  }
1291  }
1292  lo1 = sackGapList.getGapStop(SctpGapList::GT_Any, key);
1293  // ====== Iterate over TSNs in gap reports =========================
1294  EV_INFO << "Examine TSNs between " << lo << " and " << hi << endl;
1295  for (uint32_t pos = lo; pos <= hi; pos++) {
1296  bool chunkFirstTime = true;
1297  assert(tsnCheck == pos);
1298  tsnCheck++;
1299  SctpDataVariables *myChunk = retransmissionQ->getChunkFast(pos, chunkFirstTime);
1300  if (myChunk) {
1301  if (chunkHasBeenAcked(myChunk) == false) {
1302  SctpPathVariables *myChunkLastPath = myChunk->getLastDestinationPath();
1303  assert(myChunkLastPath != nullptr);
1304  // CUCv2 - chunk is acked
1305  cucProcessGapReports(myChunk, myChunkLastPath, true);
1306  // This chunk has been acked newly.
1307  // Let's process this new acknowledgement!
1308  handleChunkReportedAsAcked(highestNewAck, rttEstimation, myChunk,
1309  path /* i.e. the SACK path for RTT measurement! */,
1310  sackGapList.tsnIsNonRevokable(myChunk->tsn));
1311  }
1312  else {
1313  // Slow Path RTT Calculation
1314  if ((path->tsnForRTTCalculation == myChunk->tsn) &&
1315  (path->waitingForRTTCalculaton == true) &&
1316  (state->allowCMT == true) &&
1317  (state->cmtSlowPathRTTUpdate == true) &&
1318  (myChunk->getLastDestinationPath() == path))
1319  {
1320  const simtime_t rttEstimation = simTime() - path->txTimeForRTTCalculation;
1321  path->waitingForRTTCalculaton = false;
1322  pmRttMeasurement(path, rttEstimation);
1323 
1324  EV << simTime() << ": SlowPathRTTUpdate from gap report - rtt="
1325  << rttEstimation << " from TSN "
1326  << path->tsnForRTTCalculation
1327  << " on path " << path->remoteAddress
1328  << " => RTO=" << path->pathRto << endl;
1329  }
1330  }
1331  }
1332  // ====== R-acked chunk became NR-acked =========================
1333  else if (sackGapList.tsnIsNonRevokable(pos)) {
1334  bool chunkFirstTime = false;
1335  SctpDataVariables *myChunk = retransmissionQ->getChunkFast(pos, chunkFirstTime);
1336  if (myChunk) {
1337  // myChunk != nullptr -> R-acked before, but not NR-acked
1338  handleChunkReportedAsAcked(highestNewAck, rttEstimation, myChunk,
1339  path /* i.e. the SACK path for RTT measurement! */,
1340  sackGapList.tsnIsNonRevokable(myChunk->tsn));
1341  // All NR-acked chunks have chunkMap->getChunk(pos) == nullptr!
1342  }
1343  }
1344  }
1345  }
1346  state->highestTsnAcked = sackGapList.getGapStop(SctpGapList::GT_Any, numGaps - 1);
1347 
1348  // ====== Examine chunks between the gap reports ======================
1349  // They might have to be retransmitted or they could have been removed
1350  uint32_t lo = tsna;
1351  for (int32_t key = 0; key < numGaps; key++) {
1352  const uint32_t hi = sackGapList.getGapStart(SctpGapList::GT_Any, key);
1353  for (uint32_t pos = lo + 1; pos <= hi - 1; pos++) {
1354  bool chunkFirstTime = true;
1355  SctpDataVariables *myChunk = retransmissionQ->getChunkFast(pos, chunkFirstTime);
1356  if (myChunk) {
1357  handleChunkReportedAsMissing(sackChunk, highestNewAck, myChunk,
1358  path /* i.e. the SACK path for RTT measurement! */);
1359  }
1360  else {
1361  EV_INFO << "TSN " << pos << " not found in retransmissionQ" << endl;
1362  }
1363  }
1364  lo = sackGapList.getGapStop(SctpGapList::GT_Any, key);
1365  }
1366 
1367  // ====== Validity checks =============================================
1368  path->vectorPathAckedTsnGapAck->record(state->highestTsnAcked);
1369  }
1370 
1371  // ====== Buffer space may have been gained => tell application ==========
1372  if (sendBufferBeforeUpdate != state->sendBuffer) {
1373  generateSendQueueAbatedIndication(sendBufferBeforeUpdate - state->sendBuffer);
1374  }
1375 
1376  // ====== Update Fast Recovery status, according to SACK =================
1378 
1379  // ====== Update RTT measurement for newly acked data chunks =============
1380  if (rttEstimation < SIMTIME_MAX) {
1381  EV_DETAIL << simTime() << ": SACK: rtt=" << rttEstimation
1382  << ", path=" << path->remoteAddress << endl;
1383  pmRttMeasurement(path, rttEstimation);
1384  }
1385 
1386  // ====== Record statistics ==============================================
1387  for (auto& elem : sctpPathMap) {
1388  SctpPathVariables *myPath = elem.second;
1389  myPath->statisticsPathGapAckedChunksInLastSACK->record(myPath->gapAckedChunksInLastSACK);
1390  myPath->statisticsPathGapNRAckedChunksInLastSACK->record(myPath->gapNRAckedChunksInLastSACK);
1391  myPath->statisticsPathGapUnackedChunksInLastSACK->record(myPath->gapUnackedChunksInLastSACK);
1392  }
1393 
1394  // #######################################################################
1395  // #### Receiver Window Management ####
1396  // #######################################################################
1397 
1398  const uint32_t osb = getOutstandingBytes();
1399  if (state->bytesToAddPerPeerChunk > 0) {
1401  }
1402  else if (state->peerAllowsChunks) {
1404  state->peerRwnd = arwnd - osb;
1405  if ((int32_t)(state->peerMsgRwnd) < 0) {
1406  state->peerMsgRwnd = 0;
1407  }
1410  }
1411  }
1412  else {
1413  state->peerRwnd = arwnd - osb;
1414  }
1415  if ((int32_t)(state->peerRwnd) < 0) {
1416  state->peerRwnd = 0;
1417  }
1418  // position of statement changed 20.07.05 I.R.
1419  if ((int32_t)(state->peerRwnd) < 0) {
1420  state->peerRwnd = 0;
1421  }
1422  if (state->peerRwnd > state->initialPeerRwnd) {
1424  }
1425  if (state->peerAllowsChunks && msgRwnd == 0) {
1426  state->peerWindowFull = true;
1427  }
1428  if (arwnd == 1 || state->peerRwnd < state->swsLimit || arwnd == 0) {
1429  EV_INFO << "processSackArrived: arwnd=" << arwnd
1430  << " state->peerRwnd=" << state->peerRwnd
1431  << " set peerWindowFull" << endl;
1432  state->peerWindowFull = true;
1433  }
1434  else if ((state->peerAllowsChunks && msgRwnd > 0) || !state->peerAllowsChunks) {
1435  state->peerWindowFull = false;
1436  state->zeroWindowProbing = false;
1437  }
1438  advancePeerTsn();
1439  statisticsArwndInLastSACK->record(arwnd);
1440  statisticsPeerRwnd->record(state->peerRwnd);
1441 
1442  // ====== Need for zero-window probing? ==================================
1443  if (osb == 0) {
1444  if ((state->peerAllowsChunks && msgRwnd == 0) || arwnd == 0)
1445  state->zeroWindowProbing = true;
1446  }
1447 
1448  // #######################################################################
1449  // #### Congestion Window Management ####
1450  // #######################################################################
1451 
1452  // ======= Update congestion window of each path =========================
1453  EV_DEBUG << "Before ccUpdateBytesAcked: ";
1454  for (auto& elem : sctpPathMap) {
1455  SctpPathVariables *myPath = elem.second;
1456  const L3Address& myPathId = myPath->remoteAddress;
1457 
1458  if (myPath->newPseudoCumAck) {
1459  myPath->vectorPathPseudoCumAck->record(myPath->pseudoCumAck);
1460  }
1461  if (myPath->newRTXPseudoCumAck) {
1462  myPath->vectorPathRTXPseudoCumAck->record(myPath->rtxPseudoCumAck);
1463  }
1464  if (myPath->newlyAckedBytes > 0) {
1465  // Only call ccUpdateBytesAcked() when there are
1466  // acked bytes on this path!
1467  bool advanceWindow = myPath->newPseudoCumAck || myPath->newRTXPseudoCumAck;
1468  if (state->allowCMT == true) {
1470  advanceWindow = myPath->newPseudoCumAck || myPath->newRTXPseudoCumAck;
1471  }
1473  advanceWindow = myPath->newPseudoCumAck;
1474  }
1476  advanceWindow = myPath->newCumAck;
1477  }
1478  }
1479  EV_DETAIL << simTime() << ":\tCC " << myPath->newlyAckedBytes
1480  << " newly acked on path " << myPathId << ";"
1481  << "\tpath->newPseudoCumAck=" << ((myPath->newPseudoCumAck == true) ? "true" : "false")
1482  << "\tpath->newRTXPseudoCumAck=" << ((myPath->newRTXPseudoCumAck == true) ? "true" : "false")
1483  << "\tdropFilledGap=" << ((dropFilledGap == true) ? "true" : "false")
1484  << "\t->\tadvanceWindow=" << advanceWindow << endl;
1485 
1486  (this->*ccFunctions.ccUpdateBytesAcked)(myPath, myPath->newlyAckedBytes,
1487  (advanceWindow && dropFilledGap) ? false :
1488  advanceWindow);
1490  myPath->packetsInBurst = 0;
1491  }
1492  }
1493  }
1494 
1495  // ====== Update congestion windows on paths (handling decreases) ========
1496  EV_DEBUG << "Before ccUpdateAfterSack with tsna=" << tsna << endl;
1497  // ccUpdateAfterSack() will iterate over all paths.
1498  (this->*ccFunctions.ccUpdateAfterSack)();
1499 
1500  // #######################################################################
1501  // #### Path Management ####
1502  // #######################################################################
1503 
1504  if ((state->allowCMT == true) &&
1505  (state->cmtSmartT3Reset == true))
1506  {
1507  // ====== Find oldest unacked chunk on each path ======================
1508  for (SctpQueue::PayloadQueue::const_iterator iterator = retransmissionQ->payloadQueue.begin();
1509  iterator != retransmissionQ->payloadQueue.end(); ++iterator)
1510  {
1511  const SctpDataVariables *myChunk = iterator->second;
1512  SctpPathVariables *myChunkLastPath = myChunk->getLastDestinationPath();
1513  if (!chunkHasBeenAcked(myChunk)) {
1514  if (myChunkLastPath->newOldestChunkSendTime > myChunk->sendTime) {
1515  EV_DETAIL << "TSN " << myChunk->tsn << " is new oldest on path "
1516  << myChunkLastPath->remoteAddress << ", rel send time is "
1517  << simTime() - myChunk->sendTime << " ago" << endl;
1518  myChunkLastPath->newOldestChunkSendTime = myChunk->sendTime;
1519  myChunkLastPath->oldestChunkTsn = myChunk->tsn;
1520  }
1521  }
1522  }
1523  }
1524 
1525  // ====== Need to stop or restart T3 timer? ==============================
1526  for (auto& elem : sctpPathMap) {
1527  SctpPathVariables *myPath = elem.second;
1528  const L3Address& myPathId = myPath->remoteAddress;
1529 
1530  // ====== Smart T3 Reset ===============================================
1531  bool updatedOldestChunkSendTime = false;
1532  if ((state->allowCMT == true) &&
1533  (state->cmtSmartT3Reset == true))
1534  {
1535  // ====== Has oldest chunk send time been updated? =================
1536  if (myPath->newOldestChunkSendTime > simTime()) {
1537  myPath->newOldestChunkSendTime = myPath->oldestChunkSendTime;
1538  // newOldestChunkSendTime > simTime => no old chunk found:
1539  // Set newOldestChunkSendTime to oldestChunkSendTime
1540  }
1541  else if (myPath->newOldestChunkSendTime != myPath->oldestChunkSendTime) {
1542  // Update oldestChunkSendTime.
1543  myPath->oldestChunkSendTime = myPath->newOldestChunkSendTime;
1544  updatedOldestChunkSendTime = true;
1545  }
1546  assert(myPath->oldestChunkSendTime <= simTime());
1547  }
1548  if (myPath->outstandingBytes == 0) {
1549  // T.D. 07.01.2010: Only stop T3 timer when there is nothing more to send on this path!
1550  if (qCounter.roomTransQ.find(myPath->remoteAddress)->second == 0) {
1551  // Stop T3 timer, if there are no more outstanding bytes.
1552  stopTimer(myPath->T3_RtxTimer);
1553  myPath->oldestChunkSendTime = SIMTIME_ZERO;
1554  }
1555  }
1556  else if (myPath->newCumAck) { // Only care for CumAcks here!
1557  // NOTE: Due to the existence of retransmissions *before* PseudoCumAck for CUCv2,
1558  // it is *not* possible to check PseudoCumAck here!
1559  // This would miss retransmissions -> chunks would never be retransmitted!
1560  stopTimer(myPath->T3_RtxTimer);
1561  startTimer(myPath->T3_RtxTimer, myPath->pathRto);
1562  }
1563  else if (updatedOldestChunkSendTime) { // Smart T3 Reset
1564  stopTimer(myPath->T3_RtxTimer);
1565  startTimer(myPath->T3_RtxTimer, myPath->pathRto);
1566  }
1567  else {
1568  /* Also restart T3 timer, when lowest TSN is rtx'ed */
1569  if (myPath->lowestTsnRetransmitted == true) {
1570  EV_INFO << "Lowest TSN retransmitted => restart of T3 timer for path "
1571  << myPathId << endl;
1572  stopTimer(myPath->T3_RtxTimer);
1573  startTimer(myPath->T3_RtxTimer, myPath->pathRto);
1574  }
1575  }
1576 
1577  // ====== Clear error counter if TSNs on path have been acked =========
1578  if (myPath->newlyAckedBytes > 0) {
1579  pmClearPathCounter(myPath);
1580  }
1581  }
1582 
1583  return SCTP_E_IGNORE;
1584 }

Referenced by process_RCV_Message().

◆ processSctpMessage()

bool inet::sctp::SctpAssociation::processSctpMessage ( SctpHeader sctpmsg,
const L3Address srcAddr,
const L3Address destAddr 
)

Process incoming SCTP segment.

Normally returns true. A return value of false means that the connection structure must be deleted by the caller (SCTP).

972 {
973  printAssocBrief();
974  localAddr = msgDestAddr;
975  localPort = sctpmsg->getDestPort();
976  remoteAddr = msgSrcAddr;
977  remotePort = sctpmsg->getSrcPort();
978 
979  if (fsm->getState() == SCTP_S_ESTABLISHED) {
980  bool found = false;
981  for (auto& elem : state->localAddresses) {
982  if ((elem) == msgDestAddr) {
983  found = true;
984  break;
985  }
986  }
987  if (!found) {
988  EV_INFO << "destAddr " << msgDestAddr << " is not bound to host\n";
989  return true;
990  }
991  }
992 
993  return process_RCV_Message(sctpmsg, msgSrcAddr, msgDestAddr);
994 }

Referenced by inet::sctp::Sctp::handleMessage().

◆ processSsnTsnResetRequestArrived()

void inet::sctp::SctpAssociation::processSsnTsnResetRequestArrived ( SctpSsnTsnResetRequestParameter requestParam)
protected
2483 {
2484  EV_TRACE << "processSSNTsnResetRequestArrived\n";
2485  if (!state->firstPeerRequest && (requestParam->getSrReqSn() < (state->peerRequestSn))) {
2486  // Retransmission
2487  sendStreamResetResponse(requestParam->getSrReqSn(), NO_RESET);
2488  return;
2489  }
2490  if (!state->fragInProgress && state->outstandingBytes == 0) {
2492  state->stopOldData = true;
2493 // resetExpectedSsns();
2494  if (state->sendResponse == PERFORMED) {
2495  sendStreamResetResponse(requestParam, PERFORMED, true);
2496  state->sendResponse = 0;
2497  }
2498  else {
2500  state->responseSn = requestParam->getSrReqSn();
2502  state->incomingRequest = requestParam->dup();
2503  state->incomingRequestSet = true;
2504  }
2505  }
2506  else {
2507  sendStreamResetResponse(requestParam, DEFERRED, true);
2508  state->incomingRequest = requestParam->dup();
2509  state->incomingRequestSet = true;
2510 // state->incomingRequest->setName("SSNDeferred");
2511  state->peerRequestSn = requestParam->getSrReqSn();
2512 // state->firstPeerRequest = false;
2514  state->resetDeferred = true;
2515  }
2516 }

Referenced by checkStreamsToReset(), and processStreamResetArrived().

◆ processStreamResetArrived()

SctpEventCode inet::sctp::SctpAssociation::processStreamResetArrived ( SctpStreamResetChunk strResChunk)
protected
2812 {
2813  EV_INFO << "processStreamResetArrived\n";
2814  SctpParameter *parameter, *nextParam;
2815  std::map<uint32_t, SctpStateVariables::RequestData>::reverse_iterator rit;
2816  uint32_t numberOfParameters = resetChunk->getParametersArraySize();
2817  if (numberOfParameters == 0)
2818  return SCTP_E_IGNORE;
2819  for (uint16_t i = 0; i < numberOfParameters; i++) {
2820  parameter = (SctpParameter *)(resetChunk->getParameters(i));
2821  switch (parameter->getParameterType()) {
2823  SctpOutgoingSsnResetRequestParameter *outRequestParam;
2824  outRequestParam = check_and_cast<SctpOutgoingSsnResetRequestParameter *>(parameter);
2825  if (state->findPeerRequestNum(outRequestParam->getSrReqSn())) {
2826  // retransmission
2827  if (state->peerRequests[outRequestParam->getSrReqSn()].type != outRequestParam->getParameterType()) {
2828  sendStreamResetResponse(outRequestParam->getSrReqSn(), NO_RESET);
2829  return SCTP_E_IGNORE;
2830  }
2831  if (state->peerRequests[outRequestParam->getSrReqSn()].result != 100) {
2832  std::map<uint32_t, SctpStateVariables::RequestData>::reverse_iterator rit;
2833  rit = state->peerRequests.rbegin();
2834  if (state->peerRequests[outRequestParam->getSrReqSn()].sn == rit->first) {
2835  // send response with same result
2836  sendStreamResetResponse(outRequestParam->getSrReqSn(), state->peerRequests[outRequestParam->getSrReqSn()].result);
2837  return SCTP_E_IGNORE;
2838  }
2839  else {
2840  sendStreamResetResponse(outRequestParam->getSrReqSn(), NO_RESET);
2841  return SCTP_E_IGNORE;
2842  }
2843  }
2844  }
2845  if (state->firstPeerRequest && outRequestParam->getSrReqSn() != state->expectedStreamResetSequenceNumber) {
2846  if (state->peerRequests.size() > 0) {
2847  sendStreamResetResponse(outRequestParam->getSrReqSn(), REQUEST_IN_PROGRESS);
2848  }
2849  else {
2850  sendStreamResetResponse(outRequestParam->getSrReqSn(), NO_RESET);
2851  }
2852  break;
2853  }
2854  state->peerRequests[outRequestParam->getSrReqSn()].sn = outRequestParam->getSrReqSn();
2855  state->peerRequests[outRequestParam->getSrReqSn()].result = 100;
2856  state->peerRequests[outRequestParam->getSrReqSn()].type = outRequestParam->getParameterType();
2857  if (numberOfParameters > i + 1u) {
2858  nextParam = (SctpParameter *)(resetChunk->getParameters(i + 1)); // FIXME const_cast
2859  if (nextParam->getParameterType() != INCOMING_RESET_REQUEST_PARAMETER &&
2860  nextParam->getParameterType() != STREAM_RESET_RESPONSE_PARAMETER)
2861  {
2862  processOutgoingResetRequestArrived(outRequestParam);
2863  delete nextParam;
2864  }
2865  else {
2866  switch (nextParam->getParameterType()) {
2868  SctpIncomingSsnResetRequestParameter *inRequestParam;
2869  inRequestParam = check_and_cast<SctpIncomingSsnResetRequestParameter *>(nextParam);
2870  state->peerRequests[inRequestParam->getSrReqSn()].sn = inRequestParam->getSrReqSn();
2871  state->peerRequests[inRequestParam->getSrReqSn()].result = 100;
2872  state->peerRequests[inRequestParam->getSrReqSn()].type = inRequestParam->getParameterType();
2873  processInAndOutResetRequestArrived(inRequestParam, outRequestParam);
2874  i++;
2875  break;
2876 
2878  SctpStreamResetResponseParameter *responseParam;
2879  responseParam = check_and_cast<SctpStreamResetResponseParameter *>(nextParam);
2880  state->numResetRequests -= 2;
2881  processOutAndResponseArrived(outRequestParam, responseParam);
2882  i++;
2883  break;
2884  }
2885  }
2886  }
2887  else {
2888  processOutgoingResetRequestArrived(outRequestParam);
2889  }
2890  break;
2891  }
2892 
2894  SctpIncomingSsnResetRequestParameter *inRequestParam;
2895  inRequestParam = check_and_cast<SctpIncomingSsnResetRequestParameter *>(parameter);
2896  rit = state->peerRequests.rbegin();
2897  if (state->firstPeerRequest && (inRequestParam->getSrReqSn() != state->expectedStreamResetSequenceNumber)) {
2898  sendStreamResetResponse(inRequestParam->getSrReqSn(), NO_RESET);
2899  return SCTP_E_IGNORE;
2900  }
2901  if (!state->firstPeerRequest &&
2902  (((inRequestParam->getSrReqSn() < (state->peerRequestSn)) &&
2903  (inRequestParam->getSrReqSn() != rit->first + 1)) ||
2904  (state->findPeerRequestNum(inRequestParam->getSrReqSn()) && state->peerRequests[inRequestParam->getSrReqSn()].type != inRequestParam->getParameterType())))
2905  {
2906  sendStreamResetResponse(inRequestParam->getSrReqSn(), NO_RESET);
2907  return SCTP_E_IGNORE;
2908  }
2909  rit = state->requests.rbegin();
2910  if (rit->second.type == OUTGOING_RESET_REQUEST_PARAMETER && (rit->second.result == 100 || rit->second.result == PERFORMED)) {
2911  state->requestsOverlap = true;
2912  if (state->requests[rit->first].lastTsn == state->nextTsn - 1) {
2913  if (inRequestParam->getStreamNumbersArraySize() > 0) {
2914  uint16_t match = 0;
2915  for (uint i = 0; i < inRequestParam->getStreamNumbersArraySize(); i++) {
2916  std::list<uint16_t>::iterator it;
2917  for (it = state->requests[rit->first].streams.begin(); it != state->requests[rit->first].streams.end(); it++) {
2918  if ((*it) == inRequestParam->getStreamNumbers(i))
2919  match++;
2920  }
2921  }
2922  if (match == inRequestParam->getStreamNumbersArraySize()) {
2923  sendStreamResetResponse(inRequestParam->getSrReqSn(), NOTHING_TO_DO);
2924  return SCTP_E_IGNORE;
2925  }
2926  }
2927  else {
2928  sendStreamResetResponse(inRequestParam->getSrReqSn(), NOTHING_TO_DO);
2929  return SCTP_E_IGNORE;
2930  }
2931  }
2932  }
2933  state->peerRequests[inRequestParam->getSrReqSn()].sn = inRequestParam->getSrReqSn();
2934  state->peerRequests[inRequestParam->getSrReqSn()].result = 100;
2935  state->peerRequests[inRequestParam->getSrReqSn()].type = inRequestParam->getParameterType();
2936  if (numberOfParameters > i + 1u) {
2937  nextParam = (SctpParameter *)(resetChunk->getParameters(i + 1));
2938  if (nextParam->getParameterType() != OUTGOING_RESET_REQUEST_PARAMETER) {
2939  processIncomingResetRequestArrived(inRequestParam);
2940  }
2941  else {
2942  if (nextParam->getParameterType() == OUTGOING_RESET_REQUEST_PARAMETER) {
2943  i++;
2944  SctpOutgoingSsnResetRequestParameter *outRequestParam;
2945  outRequestParam = check_and_cast<SctpOutgoingSsnResetRequestParameter *>(nextParam->dup());
2946  state->peerRequests[outRequestParam->getSrReqSn()].sn = outRequestParam->getSrReqSn();
2947  state->peerRequests[outRequestParam->getSrReqSn()].result = 100;
2948  state->peerRequests[outRequestParam->getSrReqSn()].type = outRequestParam->getParameterType();
2949  processInAndOutResetRequestArrived(inRequestParam, outRequestParam);
2950  delete outRequestParam;
2951  }
2952  }
2953  }
2954  else {
2955  processIncomingResetRequestArrived(inRequestParam);
2956  }
2957  break;
2958  }
2959 
2961  SctpSsnTsnResetRequestParameter *ssnRequestParam;
2962  ssnRequestParam = check_and_cast<SctpSsnTsnResetRequestParameter *>(parameter);
2963  rit = state->peerRequests.rbegin();
2964  if (state->firstPeerRequest && ssnRequestParam->getSrReqSn() != state->expectedStreamResetSequenceNumber) {
2965  if (state->peerRequests.size() > 0) {
2966  sendStreamResetResponse(ssnRequestParam->getSrReqSn(), REQUEST_IN_PROGRESS);
2967  }
2968  else {
2969  sendStreamResetResponse(ssnRequestParam->getSrReqSn(), NO_RESET);
2970  }
2971  break;
2972  }
2973  if (!state->firstPeerRequest &&
2974  ((((ssnRequestParam->getSrReqSn() < (state->peerRequestSn)) && (ssnRequestParam->getSrReqSn() != rit->first + 1))) ||
2975  ((state->findPeerRequestNum(ssnRequestParam->getSrReqSn())) &&
2976  state->peerRequests[ssnRequestParam->getSrReqSn()].type != ssnRequestParam->getParameterType())))
2977  {
2978  sendStreamResetResponse(ssnRequestParam->getSrReqSn(), NO_RESET);
2979  return SCTP_E_IGNORE;
2980  }
2982  sendStreamResetResponse(ssnRequestParam, NOTHING_TO_DO, true);
2983  break;
2984  }
2985  state->peerRequests[ssnRequestParam->getSrReqSn()].sn = ssnRequestParam->getSrReqSn();
2986  state->peerRequests[ssnRequestParam->getSrReqSn()].result = 100;
2987  state->peerRequests[ssnRequestParam->getSrReqSn()].type = ssnRequestParam->getParameterType();
2988  processSsnTsnResetRequestArrived(ssnRequestParam);
2989  break;
2990 
2992  SctpAddStreamsRequestParameter *addStreamsParam =
2993  check_and_cast<SctpAddStreamsRequestParameter *>(parameter);
2994  if (addStreamsParam->getNumberOfStreams() == 0) {
2995  sendStreamResetResponse(addStreamsParam->getSrReqSn(), NOTHING_TO_DO);
2996  return SCTP_E_IGNORE;
2997  }
2998  rit = state->peerRequests.rbegin();
2999  if ((state->firstPeerRequest && addStreamsParam->getSrReqSn() != state->expectedStreamResetSequenceNumber) ||
3000  (!state->firstPeerRequest && ((addStreamsParam->getSrReqSn() < (state->peerRequestSn)) &&
3001  (addStreamsParam->getSrReqSn() != rit->first + 1))) ||
3002  (state->findPeerRequestNum(addStreamsParam->getSrReqSn()) &&
3003  state->peerRequests[addStreamsParam->getSrReqSn()].type != addStreamsParam->getParameterType()))
3004  {
3005  sendStreamResetResponse(addStreamsParam->getSrReqSn(), NO_RESET);
3006  return SCTP_E_IGNORE;
3007  }
3008  if (!(addStreamsParam->getNumberOfStreams() + outboundStreams <= 65535)) {
3009  sendStreamResetResponse(addStreamsParam->getSrReqSn(), DENIED);
3010  return SCTP_E_IGNORE;
3011  }
3012  state->peerRequests[addStreamsParam->getSrReqSn()].sn = addStreamsParam->getSrReqSn();
3013  state->peerRequests[addStreamsParam->getSrReqSn()].result = 100;
3014  state->peerRequests[addStreamsParam->getSrReqSn()].type = addStreamsParam->getParameterType();
3015  if (numberOfParameters > i + 1u) {
3016  nextParam = (SctpParameter *)(resetChunk->getParameters(i + 1));
3017  if (nextParam->getParameterType() == ADD_OUTGOING_STREAMS_REQUEST_PARAMETER) {
3018  SctpAddStreamsRequestParameter *addOutStreamsParam;
3019  addOutStreamsParam = check_and_cast<SctpAddStreamsRequestParameter *>(nextParam);
3020  state->peerRequests[addOutStreamsParam->getSrReqSn()].sn = addOutStreamsParam->getSrReqSn();
3021  state->peerRequests[addOutStreamsParam->getSrReqSn()].result = 100;
3022  state->peerRequests[addOutStreamsParam->getSrReqSn()].type = addOutStreamsParam->getParameterType();
3023  processAddInAndOutResetRequestArrived(addStreamsParam, addOutStreamsParam);
3024  i++;
3025  }
3026  }
3027  else {
3028  state->peerRequestSn = addStreamsParam->getSrReqSn();
3030  state->incomingRequest = ((SctpParameter *)addStreamsParam)->dup(); // FIXME is the c-style conversion need here?, this is not a correct dup, duplicate only the SctpParameter part of addStreamsParam
3031  state->incomingRequestSet = true;
3032 // state->incomingRequest->setName("stateIncoming");
3034  }
3035  break;
3036  }
3037 
3039  SctpAddStreamsRequestParameter *addOutStreamsParam =
3040  check_and_cast<SctpAddStreamsRequestParameter *>(parameter);
3041  if (addOutStreamsParam->getNumberOfStreams() == 0) {
3042  sendStreamResetResponse(addOutStreamsParam->getSrReqSn(), NOTHING_TO_DO);
3043  return SCTP_E_IGNORE;
3044  }
3045  rit = state->peerRequests.rbegin();
3046  if ((!(addOutStreamsParam->getNumberOfStreams() + inboundStreams <= 65535)) ||
3047  (state->appLimited && (addOutStreamsParam->getNumberOfStreams() + inboundStreams > initInboundStreams)))
3048  {
3049  sendStreamResetResponse(addOutStreamsParam->getSrReqSn(), DENIED);
3050  return SCTP_E_IGNORE;
3051  }
3052  if (state->findPeerRequestNum(addOutStreamsParam->getSrReqSn())) {
3053  // retransmission
3054  if (state->peerRequests[addOutStreamsParam->getSrReqSn()].type != addOutStreamsParam->getParameterType()) {
3055  sendStreamResetResponse(addOutStreamsParam->getSrReqSn(), NO_RESET);
3056  return SCTP_E_IGNORE;
3057  }
3058  if (state->peerRequests[addOutStreamsParam->getSrReqSn()].result != 100) {
3059  if (state->peerRequests[addOutStreamsParam->getSrReqSn()].sn == rit->first) {
3060  // send response with same result
3061  sendStreamResetResponse(addOutStreamsParam->getSrReqSn(), state->peerRequests[addOutStreamsParam->getSrReqSn()].result);
3062  return SCTP_E_IGNORE;
3063  }
3064  else {
3065  sendStreamResetResponse(addOutStreamsParam->getSrReqSn(), NO_RESET);
3066  return SCTP_E_IGNORE;
3067  }
3068  }
3069  }
3070  if ((state->firstPeerRequest && addOutStreamsParam->getSrReqSn() != state->expectedStreamResetSequenceNumber) ||
3071  (!state->firstPeerRequest && ((addOutStreamsParam->getSrReqSn() < (state->peerRequestSn)) &&
3072  (addOutStreamsParam->getSrReqSn() != rit->first + 1))))
3073  {
3074  // Retransmission
3075  sendStreamResetResponse(addOutStreamsParam->getSrReqSn(), NO_RESET);
3076  return SCTP_E_IGNORE;
3077  }
3078  state->peerRequests[addOutStreamsParam->getSrReqSn()].sn = addOutStreamsParam->getSrReqSn();
3079  state->peerRequests[addOutStreamsParam->getSrReqSn()].result = 100;
3080  state->peerRequests[addOutStreamsParam->getSrReqSn()].type = addOutStreamsParam->getParameterType();
3082  inboundStreams += addOutStreamsParam->getNumberOfStreams();
3084  state->numAddedInStreams = 0;
3085  (this->*ssFunctions.ssAddInStreams)(addOutStreamsParam->getNumberOfStreams());
3086  }
3087  if (numberOfParameters > i + 1u) {
3088  nextParam = (SctpParameter *)(resetChunk->getParameters(i + 1));
3089  if (nextParam->getParameterType() == ADD_INCOMING_STREAMS_REQUEST_PARAMETER) {
3090  SctpAddStreamsRequestParameter *addInStreamsParam;
3091  addInStreamsParam = check_and_cast<SctpAddStreamsRequestParameter *>(nextParam);
3092  state->peerRequests[addInStreamsParam->getSrReqSn()].sn = addInStreamsParam->getSrReqSn();
3093  state->peerRequests[addInStreamsParam->getSrReqSn()].result = 100;
3094  state->peerRequests[addInStreamsParam->getSrReqSn()].type = addInStreamsParam->getParameterType();
3095  processAddInAndOutResetRequestArrived(addInStreamsParam, addOutStreamsParam);
3096  i++;
3097  }
3098  else {
3099  state->peerRequestSn = addOutStreamsParam->getSrReqSn();
3102  state->responseSn = addOutStreamsParam->getSrReqSn();
3103  state->firstPeerRequest = false;
3104 // state->numAddedInStreams = addOutStreamsParam->getNumberOfStreams();
3105  state->resetRequested = true;
3106  }
3107  }
3108  else {
3109  state->peerRequestSn = addOutStreamsParam->getSrReqSn();
3112  state->responseSn = addOutStreamsParam->getSrReqSn();
3113 // state->numAddedInStreams = addOutStreamsParam->getNumberOfStreams();
3114  state->firstPeerRequest = false;
3115  state->resetRequested = true;
3116  }
3117  break;
3118  }
3119 
3121  SctpStreamResetResponseParameter *responseParam;
3122  responseParam = check_and_cast<SctpStreamResetResponseParameter *>(parameter);
3123  if (!state->findRequestNum(responseParam->getSrResSn())) {
3124  delete state->resetChunk;
3125  state->resetChunk = nullptr;
3126  break;
3127  }
3128  if (numberOfParameters > i + 1u) {
3129  nextParam = (SctpParameter *)(resetChunk->getParameters(i + 1));
3130  if (nextParam->getParameterType() != OUTGOING_RESET_REQUEST_PARAMETER) {
3131  if (responseParam->getResult() != DEFERRED)
3133  processResetResponseArrived(responseParam);
3134  }
3135  else {
3136  switch (nextParam->getParameterType()) {
3138  SctpOutgoingSsnResetRequestParameter *outRequestParam;
3139  outRequestParam = check_and_cast<SctpOutgoingSsnResetRequestParameter *>(nextParam);
3140  if ((state->firstPeerRequest && outRequestParam->getSrReqSn() != state->expectedStreamResetSequenceNumber) ||
3141  (!state->firstPeerRequest && (outRequestParam->getSrReqSn() < (state->peerRequestSn))))
3142  {
3143  // Retransmission
3144  sendStreamResetResponse(outRequestParam->getSrReqSn(), NO_RESET);
3145  return SCTP_E_IGNORE;
3146  }
3147  state->peerRequests[outRequestParam->getSrReqSn()].sn = outRequestParam->getSrReqSn();
3148  state->peerRequests[outRequestParam->getSrReqSn()].result = 100;
3149  state->peerRequests[outRequestParam->getSrReqSn()].type = outRequestParam->getParameterType();
3150  state->numResetRequests -= 2;
3151  processOutAndResponseArrived(outRequestParam, responseParam);
3152  i++;
3153  break;
3154  }
3155  }
3156  }
3157  }
3158  else {
3159  if (responseParam->getResult() != DEFERRED)
3161  processResetResponseArrived(responseParam);
3162  }
3163  break;
3164  }
3165  }
3166  }
3167  return SCTP_E_IGNORE;
3168 }

Referenced by process_RCV_Message().

◆ processTimer()

bool inet::sctp::SctpAssociation::processTimer ( cMessage *  msg)
876 {
877  SctpPathVariables *path = nullptr;
878 
879  EV_INFO << msg->getName() << " timer expired at " << simTime() << "\n";
880 
881  SctpPathInfo *pinfo = check_and_cast<SctpPathInfo *>(msg->getControlInfo());
882  L3Address addr = pinfo->getRemoteAddress();
883 
884  if (!addr.isUnspecified())
885  path = getPath(addr);
886 
887  // first do actions
888  SctpEventCode event;
889  event = SCTP_E_IGNORE;
890 
891  if (msg == T1_InitTimer) {
893  }
894  else if (msg == SackTimer) {
895  EV_DETAIL << simTime() << " delayed Sack: cTsnAck=" << state->gapList.getCumAckTsn() << " highestTsnReceived=" << state->gapList.getHighestTsnReceived() << " lastTsnReceived=" << state->lastTsnReceived << " ackState=" << state->ackState << " numGaps=" << state->gapList.getNumGaps(SctpGapList::GT_Any) << "\n";
896  sendSack();
897  }
898  else if (msg == T2_ShutdownTimer) {
901  }
902  else if (msg == T5_ShutdownGuardTimer) {
904  if (state->shutdownChunk) {
905  delete state->shutdownChunk;
906  state->shutdownChunk = nullptr;
907  }
909  sendAbort();
911  return true;
912  }
913  else if (path != nullptr && msg == path->HeartbeatIntervalTimer) {
914  process_TIMEOUT_HEARTBEAT_INTERVAL(path, path->forceHb);
915  }
916  else if (path != nullptr && msg == path->HeartbeatTimer) {
918  }
919  else if (path != nullptr && msg == path->T3_RtxTimer) {
920  process_TIMEOUT_RTX(path);
921  }
922  else if (path != nullptr && msg == path->CwndTimer) {
923  (this->*ccFunctions.ccUpdateAfterCwndTimeout)(path);
924  }
925  else if (strcmp(msg->getName(), "StartTesting") == 0) {
926 // if (sctpMain->testing == false)
927 // {
928 // sctpMain->testing = true;
929  EV_DEBUG << "set testing to true\n";
930 // }
931  // todo: testing was removed.
932  }
933  else if (path != nullptr && msg == path->ResetTimer) {
934  process_TIMEOUT_RESET(path);
935  }
936  else if (path != nullptr && msg == path->AsconfTimer) {
938  }
939  else if (msg == StartAddIP) {
941  const char *type = sctpMain->par("addIpType").stringValue();
942  sendAsconf(type);
943  }
944  else if (msg == FairStartTimer) {
945  auto it = sctpMain->assocStatMap.find(assocId);
946  if (it != sctpMain->assocStatMap.end()) {
947  it->second.fairStart = simTime();
948  fairTimer = true;
949  }
950  }
951  else if (msg == FairStopTimer) {
952  auto it = sctpMain->assocStatMap.find(assocId);
953  if (it != sctpMain->assocStatMap.end()) {
954  it->second.fairStop = simTime();
955  it->second.fairLifeTime = it->second.fairStop - it->second.fairStart;
956  it->second.fairThroughput = it->second.fairAckedBytes / it->second.fairLifeTime.dbl();
957  fairTimer = false;
958  }
959  }
960  else {
961  sctpAlgorithm->processTimer(msg, event);
962  }
963 
964  // then state transitions
965  return performStateTransition(event);
966 }

Referenced by inet::sctp::Sctp::handleMessage().

◆ pushUlp()

void inet::sctp::SctpAssociation::pushUlp ( )
protected
1953 {
1954  int32_t count = 0;
1955 
1956  for (unsigned int i = 0; i < inboundStreams; i++) { // 12.06.08
1957  putInDeliveryQ(i);
1958  }
1959  if (state->pushMessagesLeft <= 0) {
1961  }
1962  bool restrict = false;
1963  if (state->pushMessagesLeft > 0) {
1964  restrict = true;
1965  }
1966 
1968 
1969  EV_DETAIL << simTime() << " Calling pushUlp(" << state->queuedReceivedBytes
1970  << " bytes queued) ..." << endl
1971  << "messagesToPush=" << state->messagesToPush
1972  << " pushMessagesLeft=" << state->pushMessagesLeft
1973  << " restrict=" << restrict
1974  << " buffered Messages=" << state->bufferedMessages << endl;
1975  uint32_t i = state->nextRSid;
1976  uint64_t tempQueuedBytes = 0;
1977  do {
1978  auto iter = receiveStreams.find(i);
1979  SctpReceiveStream *rStream = iter->second;
1980  EV_DETAIL << "Size of stream " << iter->first << ": "
1981  << rStream->getDeliveryQ()->getQueueSize() << endl;
1982 
1983  while ((!rStream->getDeliveryQ()->payloadQueue.empty()) &&
1984  (!restrict || (restrict && state->pushMessagesLeft > 0)))
1985  {
1986  SctpDataVariables *chunk = rStream->getDeliveryQ()->extractMessage();
1988 
1989  if (state->pushMessagesLeft > 0)
1991 
1992  // ====== Non-revokably acknowledge chunks of the message ==========
1993  /* bool dummy;
1994  for (uint32_t j = chunk->tsn; j < chunk->tsn + chunk->fragments; j++)
1995  state->gapList.updateGapList(j, dummy, false);*/
1996 
1997  tempQueuedBytes = state->queuedReceivedBytes;
1998  state->queuedReceivedBytes -= chunk->len / 8;
2000  EV_INFO << "buffered Messages now " << state->bufferedMessages << endl;
2001  if (state->swsAvoidanceInvoked) {
2003  /* now check, if user has read enough so that window opens up more than one MTU */
2004  if ((state->messageAcceptLimit > 0 &&
2005  (int32_t)state->localMsgRwnd - state->bufferedMessages >= 3 &&
2006  (int32_t)state->localMsgRwnd - state->bufferedMessages <= 8)
2007  ||
2008  (state->messageAcceptLimit == 0 &&
2011  {
2012  state->swsMsgInvoked = false;
2013  /* only if the window has opened up more than one MTU we will send a SACK */
2014  state->swsAvoidanceInvoked = false;
2015  EV_DETAIL << "pushUlp: Window opens up to " << (int32_t)state->localRwnd - state->queuedReceivedBytes << " bytes: sending a SACK. SWS Avoidance INACTIVE\n";
2016 
2017  sendSack();
2018  }
2019  }
2020  else if ((int32_t)(state->swsLimit) == 0) {
2021  sendSack();
2022  }
2023  else if ((tempQueuedBytes > state->localRwnd * 3 / 4) && (state->queuedReceivedBytes <= state->localRwnd * 3 / 4)) {
2024  sendSack();
2025  }
2026  EV_DETAIL << "Push TSN " << chunk->tsn
2027  << ": sid=" << chunk->sid << " ssn=" << chunk->ssn << endl;
2028 
2029  SctpSimpleMessage *smsg = check_and_cast<SctpSimpleMessage *>(chunk->userData);
2030  auto applicationPacket = new Packet("ApplicationPacket", SCTP_I_DATA);
2031  std::vector<uint8_t> vec;
2032  int sendBytes = smsg->getDataLen();
2033  vec.resize(sendBytes);
2034  for (int i = 0; i < sendBytes; i++)
2035  vec[i] = smsg->getData(i);
2036  auto applicationData = makeShared<BytesChunk>();
2037  applicationData->setBytes(vec);
2038  applicationData->addTag<CreationTimeTag>()->setCreationTime(smsg->getCreationTime());
2039  auto& cmd = applicationPacket->addTag<SctpRcvReq>();
2040  cmd->setSocketId(assocId);
2041  cmd->setGate(appGateIndex);
2042  cmd->setSid(chunk->sid);
2043  cmd->setSsn(chunk->ssn);
2044  cmd->setSendUnordered(!chunk->ordered);
2045  cmd->setLocalAddr(localAddr);
2046  cmd->setRemoteAddr(remoteAddr);
2047  cmd->setPpid(chunk->ppid);
2048  cmd->setTsn(chunk->tsn);
2049  cmd->setCumTsn(state->lastTsnAck);
2050  applicationPacket->insertAtBack(applicationData);
2051  state->numMsgsReq[count]--;
2052  EndToEndDelay->record(simTime() - chunk->firstSendTime);
2053  auto iter = sctpMain->assocStatMap.find(assocId);
2054  if (iter->second.numEndToEndMessages >= iter->second.startEndToEndDelay &&
2055  (iter->second.numEndToEndMessages < iter->second.stopEndToEndDelay || !iter->second.stopEndToEndDelay))
2056  {
2057  iter->second.cumEndToEndDelay += (simTime() - chunk->firstSendTime);
2058  }
2059  iter->second.numEndToEndMessages++;
2060 
2061  // set timestamp to sending time
2062  chunk->userData->setTimestamp(chunk->firstSendTime);
2063  delete smsg;
2064  delete chunk;
2065  sendToApp(applicationPacket);
2066  }
2067  i = (i + 1) % inboundStreams;
2068  count++;
2069  } while (i != state->nextRSid);
2070 
2072  if (restrict && state->bufferedMessages > 0) {
2073  for (auto& elem : receiveStreams) {
2074  if (!(elem.second->getDeliveryQ()->payloadQueue.empty())) {
2075  sendDataArrivedNotification(elem.second->getStreamId());
2076  break;
2077  }
2078  }
2079  }
2080  if ((state->queuedReceivedBytes == 0) && (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) {
2081  EV_INFO << "SCTP_E_CLOSE" << endl;
2083  }
2084 }

Referenced by process_RECEIVE_REQUEST().

◆ putInDeliveryQ()

void inet::sctp::SctpAssociation::putInDeliveryQ ( uint16_t  sid)
protected
1913 {
1914  SctpReceiveStream *rStream = receiveStreams.find(sid)->second;
1915  EV_INFO << "putInDeliveryQ: SSN=" << rStream->getExpectedStreamSeqNum()
1916  << " SID=" << sid
1917  << " QueueSize=" << rStream->getOrderedQ()->getQueueSize() << endl;
1918  while (rStream->getOrderedQ()->getQueueSize() > 0) {
1919  /* dequeue first from reassembly Q */
1920  SctpDataVariables *chunk =
1921  rStream->getOrderedQ()->dequeueChunkBySSN(rStream->getExpectedStreamSeqNum());
1922  if (chunk) {
1923  EV_DETAIL << "putInDeliveryQ::chunk " << chunk->tsn
1924  << ", sid " << chunk->sid << " and ssn " << chunk->ssn
1925  << " dequeued from ordered queue. queuedReceivedBytes="
1926  << state->queuedReceivedBytes << " will be reduced by "
1927  << chunk->len / 8 << endl;
1929  state->queuedReceivedBytes -= chunk->len / 8;
1931 
1932  if (rStream->getDeliveryQ()->checkAndInsertChunk(chunk->tsn, chunk)) {
1934  state->queuedReceivedBytes += chunk->len / 8;
1935 
1936  EV_DETAIL << "data put in deliveryQ; queuedBytes now "
1937  << state->queuedReceivedBytes << endl;
1939  int32_t seqnum = rStream->getExpectedStreamSeqNum();
1940  rStream->setExpectedStreamSeqNum(++seqnum);
1941  if (rStream->getExpectedStreamSeqNum() > 65535) {
1942  rStream->setExpectedStreamSeqNum(0);
1943  }
1944  }
1945  }
1946  else {
1947  break;
1948  }
1949  }
1950 }

Referenced by processDataArrived(), and pushUlp().

◆ putInTransmissionQ()

void inet::sctp::SctpAssociation::putInTransmissionQ ( uint32_t  tsn,
SctpDataVariables chunk 
)
protected
2952 {
2953  if (chunk->countsAsOutstanding) {
2954  decreaseOutstandingBytes(chunk);
2955  }
2956  if (!containsKey(transmissionQ->payloadQueue, tsn)) {
2957  EV_DETAIL << "putInTransmissionQ: insert tsn=" << tsn << endl;
2958  chunk->wasDropped = true;
2959  chunk->wasPktDropped = true;
2960  chunk->hasBeenFastRetransmitted = true;
2961  chunk->setNextDestination(chunk->getLastDestinationPath());
2962  if (!transmissionQ->checkAndInsertChunk(chunk->tsn, chunk)) {
2963  EV_DETAIL << "putInTransmissionQ: cannot add message/chunk (TSN="
2964  << tsn << ") to the transmissionQ" << endl;
2965  }
2966  else {
2967  chunk->enqueuedInTransmissionQ = true;
2968  auto q = qCounter.roomTransQ.find(chunk->getNextDestination());
2969  q->second += ADD_PADDING(chunk->len / 8 + SCTP_DATA_CHUNK_LENGTH);
2970  auto qb = qCounter.bookedTransQ.find(chunk->getNextDestination());
2971  qb->second += chunk->booksize;
2972  EV_DETAIL << "putInTransmissionQ: " << transmissionQ->getQueueSize() << " chunks="
2973  << q->second << " bytes" << endl;
2974  }
2975  }
2976 }

Referenced by processPacketDropArrived().

◆ recalculateOLIABasis()

void inet::sctp::SctpAssociation::recalculateOLIABasis ( )
private
192  {
193  // it is necessary to calculate all flow information
194  double assoc_best_paths_l_rXl_r__rtt_r = 0.0;
195  // max_w_paths: The set of paths in all_paths with largest congestion windows.
196  // https://tools.ietf.org/html/draft-khalili-mptcp-congestion-control-05
197  uint32_t max_w_paths = 0;
198  uint32_t max_w_paths_cnt = 0;
199  (void)max_w_paths_cnt; // FIXME this variable is unused
200  uint32_t best_paths_cnt = 0;
201 
202  // Create the sets
203  int cnt = 0;
204  assocCollectedPaths.clear();
205  assocBestPaths.clear();
206  assocMaxWndPaths.clear();
207  for (SctpPathMap::iterator iter = sctpPathMap.begin();
208  iter != sctpPathMap.end(); iter++, cnt++)
209  {
210  SctpPathVariables *path = iter->second;
211  bool next = false;
212  double r_sRTT = GET_SRTT(path->srtt.dbl());
213  double r_l_rXl_r__rtt_r = ((path->oliaSentBytes
214  * path->oliaSentBytes) / r_sRTT);
215  if (assocBestPaths.empty()) {
216  assoc_best_paths_l_rXl_r__rtt_r = r_l_rXl_r__rtt_r;
217  assocBestPaths.insert(std::make_pair(cnt, path));
218  next = true;
219  }
220  if (assocMaxWndPaths.empty()) {
221  max_w_paths = path->cwnd;
222  assocMaxWndPaths.insert(std::make_pair(cnt, path));
223  next = true;
224  }
225  if (next)
226  continue;
227  // set up the sets
228  if (r_l_rXl_r__rtt_r > assoc_best_paths_l_rXl_r__rtt_r) {
229  assoc_best_paths_l_rXl_r__rtt_r = r_l_rXl_r__rtt_r;
230  assocBestPaths.insert(std::make_pair(cnt, path));
231  assocBestPaths.erase(best_paths_cnt);
232 
233  best_paths_cnt = cnt;
234  next = true;
235  }
236  if (path->cwnd > max_w_paths) {
237  max_w_paths = path->cwnd;
238  assocMaxWndPaths.insert(std::make_pair(cnt, path));
239  assocMaxWndPaths.erase(best_paths_cnt);
240  max_w_paths_cnt = cnt;
241  next = true;
242  }
243  if (next)
244  continue;
245 
246  assocCollectedPaths.insert(std::make_pair(cnt, path));
247 
248  }
249 }

Referenced by updateOLIA().

◆ receiveStreamPresent()

bool inet::sctp::SctpAssociation::receiveStreamPresent ( uint32_t  sid)
protected

◆ recordCwndUpdate()

void inet::sctp::SctpAssociation::recordCwndUpdate ( SctpPathVariables path)
private
355 {
356  if (path == nullptr) {
357  uint32_t totalSsthresh = 0.0;
358  uint32_t totalCwnd = 0.0;
359  double totalBandwidth = 0.0;
360  for (auto& elem : sctpPathMap) {
361  SctpPathVariables *path = elem.second;
362  totalSsthresh += path->ssthresh;
363  totalCwnd += path->cwnd;
364  totalBandwidth += path->cwnd / GET_SRTT(path->srtt.dbl());
365  }
366  statisticsTotalSSthresh->record(totalSsthresh);
367  statisticsTotalCwnd->record(totalCwnd);
368  statisticsTotalBandwidth->record(totalBandwidth);
369  }
370  else {
371  path->statisticsPathSSthresh->record(path->ssthresh);
372  path->statisticsPathCwnd->record(path->cwnd);
373  path->statisticsPathBandwidth->record(path->cwnd / GET_SRTT(path->srtt.dbl()));
374  }
375 }

Referenced by cwndUpdateAfterCwndTimeout(), cwndUpdateAfterRtxTimeout(), cwndUpdateAfterSack(), cwndUpdateBytesAcked(), cwndUpdateMaxBurst(), initCcParameters(), processHeartbeatAckArrived(), and removePath().

◆ removeFirstChunk()

void inet::sctp::SctpAssociation::removeFirstChunk ( SctpHeader sctpmsg)
protected
2875 {
2876  SctpChunk *chunk = sctpmsg->removeFirstChunk();
2877  delete chunk;
2878 }

◆ removePath() [1/2]

void inet::sctp::SctpAssociation::removePath ( )
1802 {
1803  while (!sctpPathMap.empty()) {
1804  auto pathIterator = sctpPathMap.begin();
1805  SctpPathVariables *path = pathIterator->second;
1806  for (auto j = remoteAddressList.begin(); j != remoteAddressList.end(); j++) {
1807  if ((*j) == path->remoteAddress) {
1808  remoteAddressList.erase(j);
1809  break;
1810  }
1811  }
1812  EV_INFO << getFullPath() << " remove path " << path->remoteAddress << endl;
1813  stopTimer(path->HeartbeatTimer);
1814  delete path->HeartbeatTimer;
1815  stopTimer(path->HeartbeatIntervalTimer);
1816  delete path->HeartbeatIntervalTimer;
1817  stopTimer(path->T3_RtxTimer);
1818  delete path->T3_RtxTimer;
1819  stopTimer(path->CwndTimer);
1820  delete path->CwndTimer;
1821  stopTimer(path->ResetTimer);
1822  delete path->ResetTimer;
1823  stopTimer(path->AsconfTimer);
1824  delete path->AsconfTimer;
1825  stopTimer(path->BlockingTimer);
1826  delete path->BlockingTimer;
1827  delete path;
1828  sctpPathMap.erase(pathIterator);
1829  }
1830 }

Referenced by processAsconfArrived(), and inet::sctp::Sctp::removeAssociation().

◆ removePath() [2/2]

void inet::sctp::SctpAssociation::removePath ( const L3Address addr)
2129 {
2130  auto pathIterator = sctpPathMap.find(addr);
2131  if (pathIterator != sctpPathMap.end()) {
2132  SctpPathVariables *path = pathIterator->second;
2133  path->cwnd = 0;
2134  path->ssthresh = 0;
2135  recordCwndUpdate(path);
2136 
2137  stopTimer(path->HeartbeatTimer);
2138  delete path->HeartbeatTimer;
2139  stopTimer(path->HeartbeatIntervalTimer);
2140  delete path->HeartbeatIntervalTimer;
2141  stopTimer(path->T3_RtxTimer);
2142  delete path->T3_RtxTimer;
2143  stopTimer(path->CwndTimer);
2144  delete path->CwndTimer;
2145  sctpPathMap.erase(pathIterator);
2146  stopTimer(path->ResetTimer);
2147  delete path->ResetTimer;
2148  stopTimer(path->AsconfTimer);
2149  delete path->AsconfTimer;
2150  delete path;
2151  }
2152 }

◆ renegablyAckChunk()

void inet::sctp::SctpAssociation::renegablyAckChunk ( SctpDataVariables chunk,
SctpPathVariables sackPath 
)
private
1955 {
1956  // ====== Bookkeeping ====================================================
1957  if (chunk->countsAsOutstanding) {
1958  decreaseOutstandingBytes(chunk);
1959  }
1960 
1961  if ((chunk->hasBeenCountedAsNewlyAcked == false) &&
1962  (chunk->hasBeenAcked == false))
1963  {
1964  if ((state->cmtMovedChunksReduceCwnd == false) ||
1965  (chunk->hasBeenMoved == false))
1966  {
1967  chunk->hasBeenCountedAsNewlyAcked = true;
1968  // The chunk has not been acked before.
1969  // Therefore, its size may *once* be counted as newly acked.
1970  chunk->getLastDestinationPath()->newlyAckedBytes += chunk->booksize;
1971  }
1972  }
1973 
1974  // ====== Acknowledge chunk =============================================
1975  ackChunk(chunk, sackPath);
1976  chunk->gapReports = 0;
1977 
1978  // ====== Remove chunk from transmission queue ===========================
1979  if (transmissionQ->getChunk(chunk->tsn)) { // I.R. 02.01.2007
1980  EV_INFO << "Found TSN " << chunk->tsn << " in transmissionQ -> remote it" << endl;
1981  transmissionQ->removeMsg(chunk->tsn);
1982  chunk->enqueuedInTransmissionQ = false;
1983  auto q = qCounter.roomTransQ.find(chunk->getNextDestination());
1984  q->second -= ADD_PADDING(chunk->len / 8 + SCTP_DATA_CHUNK_LENGTH);
1985  auto qb = qCounter.bookedTransQ.find(chunk->getNextDestination());
1986  qb->second -= chunk->booksize;
1987  }
1988 }

Referenced by handleChunkReportedAsAcked().

◆ resetExpectedSsn()

void inet::sctp::SctpAssociation::resetExpectedSsn ( uint16_t  id)
protected
893 {
894  auto iterator = receiveStreams.find(id);
895  iterator->second->setExpectedStreamSeqNum(0);
896  EV_INFO << "Expected Ssn " << id << " has been resetted on " << localAddr << "\n";
898 }

Referenced by processInAndOutResetRequestArrived(), processOutAndResponseArrived(), processOutgoingResetRequestArrived(), and processResetResponseArrived().

◆ resetExpectedSsns()

void inet::sctp::SctpAssociation::resetExpectedSsns ( )
protected
885 {
886  for (auto& elem : receiveStreams)
887  elem.second->setExpectedStreamSeqNum(0);
888  EV_INFO << "Expected Ssns have been resetted on " << localAddr << "\n";
890 }

Referenced by checkStreamsToReset(), process_RCV_Message(), processInAndOutResetRequestArrived(), processOutAndResponseArrived(), processOutgoingResetRequestArrived(), processResetResponseArrived(), and sendStreamResetResponse().

◆ resetGapLists()

void inet::sctp::SctpAssociation::resetGapLists ( )
protected
749 {
750  uint32_t newCumAck = state->gapList.getHighestTsnReceived() + (1 << 31);
751  state->gapList.resetGaps(newCumAck);
752 }

Referenced by sendStreamResetResponse().

◆ resetSsn()

void inet::sctp::SctpAssociation::resetSsn ( uint16_t  id)
protected
923 {
924  auto iterator = sendStreams.find(id);
925  iterator->second->setNextStreamSeqNum(0);
926  EV_INFO << "SSn " << id << " resetted on " << localAddr << "\n";
927 }

Referenced by processIncomingResetRequestArrived(), processOutAndResponseArrived(), processResetResponseArrived(), sendBundledOutgoingResetAndResponse(), and sendOutgoingResetRequest().

◆ resetSsns()

void inet::sctp::SctpAssociation::resetSsns ( )
protected

Methods for Stream Reset.

915 {
916  for (auto& elem : sendStreams)
917  elem.second->setNextStreamSeqNum(0);
918  EV_INFO << "all SSns resetted on " << localAddr << "\n";
920 }

Referenced by processIncomingResetRequestArrived(), processOutAndResponseArrived(), processResetResponseArrived(), and sendStreamResetResponse().

◆ retransmitAsconf()

void inet::sctp::SctpAssociation::retransmitAsconf ( )
protected
159 {
160  const auto& sctpmsg = makeShared<SctpHeader>();
161  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
162 
163  SctpAsconfChunk *sctpasconf = new SctpAsconfChunk();
164  sctpasconf = check_and_cast<SctpAsconfChunk *>(state->asconfChunk->dup());
165  sctpasconf->setSctpChunkType(ASCONF);
166  sctpasconf->setByteLength(state->asconfChunk->getByteLength());
167 
168  if (state->auth && state->peerAuth) {
169  SctpAuthenticationChunk *authChunk = createAuthChunk();
170  sctpmsg->appendSctpChunks(authChunk);
171  auto it = sctpMain->assocStatMap.find(assocId);
172  it->second.numAuthChunksSent++;
173  }
174  sctpmsg->appendSctpChunks(sctpasconf);
175  Packet *pkt = new Packet("ASCONF");
176  sendToIP(pkt, sctpmsg);
177 }

Referenced by process_TIMEOUT_ASCONF(), and processPacketDropArrived().

◆ retransmitCookieEcho()

void inet::sctp::SctpAssociation::retransmitCookieEcho ( )
protected
1003 {
1004  SctpAuthenticationChunk *authChunk;
1005  const auto& sctpmsg = makeShared<SctpHeader>();
1006  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
1007  SctpCookieEchoChunk *cookieEchoChunk = check_and_cast<SctpCookieEchoChunk *>(state->cookieChunk->dup());
1008  if (cookieEchoChunk->getCookieArraySize() == 0) {
1009  cookieEchoChunk->setStateCookie(state->cookieChunk->getStateCookie()->dup());
1010  }
1012  authChunk = createAuthChunk();
1013  sctpmsg->appendSctpChunks(authChunk);
1014  auto it = sctpMain->assocStatMap.find(assocId);
1015  it->second.numAuthChunksSent++;
1016  }
1017  sctpmsg->appendSctpChunks(cookieEchoChunk);
1018 
1019  EV_INFO << "retransmitCookieEcho localAddr=" << localAddr << " remoteAddr" << remoteAddr << "\n";
1020  Packet *fp = new Packet("COOKIE-ECHO RTX");
1021  sendToIP(fp, sctpmsg);
1022 }

Referenced by process_TIMEOUT_INIT_REXMIT(), and processPacketDropArrived().

◆ retransmitInit()

void inet::sctp::SctpAssociation::retransmitInit ( )
protected

Retransmitting chunks.

757 {
758  const auto& sctpmsg = makeShared<SctpHeader>();
759  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
760  SctpInitChunk *sctpinit; // = new SctpInitChunk("INIT");
761 
762  EV_INFO << "Retransmit InitChunk=" << &sctpinit << "\n";
763 
764  sctpinit = check_and_cast<SctpInitChunk *>(state->initChunk->dup());
765  sctpinit->setSctpChunkType(INIT);
766  sctpmsg->appendSctpChunks(sctpinit);
767 
768  Packet *fp = new Packet("INIT RTX");
769  sendToIP(fp, sctpmsg);
770 }

Referenced by process_TIMEOUT_INIT_REXMIT(), and processPacketDropArrived().

◆ retransmitReset()

void inet::sctp::SctpAssociation::retransmitReset ( )
protected
16 {
17  if (fsm->getState() == SCTP_S_SHUTDOWN_PENDING || fsm->getState() == SCTP_S_ESTABLISHED) {
18  const auto& sctpmsg = makeShared<SctpHeader>();
19  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
20  SctpStreamResetChunk *sctpreset = check_and_cast<SctpStreamResetChunk *>(state->resetChunk->dup());
21  state->numResetRequests = sctpreset->getParametersArraySize();
22  sctpreset->setSctpChunkType(RE_CONFIG);
23  sctpmsg->appendSctpChunks(sctpreset);
24  state->waitForResponse = true;
25  EV_INFO << "retransmitStreamReset localAddr=" << localAddr << " remoteAddr" << remoteAddr << "\n";
26  Packet *pkt = new Packet("RE_CONFIG");
27  sendToIP(pkt, sctpmsg);
28  }
29 }

Referenced by process_TIMEOUT_RESET().

◆ retransmitShutdown()

void inet::sctp::SctpAssociation::retransmitShutdown ( )
protected
1216 {
1217  const auto& sctpmsg = makeShared<SctpHeader>();
1218  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
1219  SctpShutdownChunk *shutdownChunk;
1220  shutdownChunk = check_and_cast<SctpShutdownChunk *>(state->shutdownChunk->dup());
1221  sctpmsg->appendSctpChunks(shutdownChunk);
1222 
1223  EV_INFO << "retransmitShutdown localAddr=" << localAddr << " remoteAddr" << remoteAddr << "\n";
1224 
1225  Packet *fp = new Packet("SHUTDOWN RTX");
1226  sendToIP(fp, sctpmsg);
1227 }

Referenced by process_TIMEOUT_SHUTDOWN(), and processPacketDropArrived().

◆ retransmitShutdownAck()

void inet::sctp::SctpAssociation::retransmitShutdownAck ( )
protected
1230 {
1231  const auto& sctpmsg = makeShared<SctpHeader>();
1232  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
1233  SctpShutdownAckChunk *shutdownAckChunk;
1234  shutdownAckChunk = check_and_cast<SctpShutdownAckChunk *>(state->shutdownAckChunk->dup());
1235  sctpmsg->appendSctpChunks(shutdownAckChunk);
1236 
1237  EV_INFO << "retransmitShutdownAck localAddr=" << localAddr << " remoteAddr" << remoteAddr << "\n";
1238 
1239  Packet *fp = new Packet("SHUTDOWN-ACK RTX");
1240  sendToIP(fp, sctpmsg);
1241 }

Referenced by process_TIMEOUT_SHUTDOWN(), and processPacketDropArrived().

◆ rpPathBlockingControl()

int32_t inet::sctp::SctpAssociation::rpPathBlockingControl ( SctpPathVariables path,
double  reduction 
)
protected
411 {
412  // ====== Compute new cwnd ===============================================
413  const int32_t newCwnd = (int32_t)ceil(path->cwnd - reduction);
414  // NOTE: newCwnd may be negative!
415  // ====== Block path if newCwnd < 1 MTU ==================================
416  if ((state->rpPathBlocking == true) && (newCwnd < (int32_t)path->pmtu)) {
417  if ((path->blockingTimeout < 0.0) || (path->blockingTimeout < simTime())) {
418 // printf("a=%1.9f b=%1.9f a=%d b=%d\n", path->blockingTimeout.dbl(), simTime().dbl(), (path->blockingTimeout < 0.0), (path->blockingTimeout < simTime()) );
419 
420  const simtime_t timeout = (state->rpScaleBlockingTimeout == true) ?
421  path->cmtGroupPaths * path->pathRto :
422  path->pathRto;
423  EV << "Blocking " << path->remoteAddress << " for " << timeout << endl;
424 
425  path->blockingTimeout = simTime() + timeout;
426  assert(!path->BlockingTimer->isScheduled());
427  startTimer(path->BlockingTimer, timeout);
428  }
429  }
430  return newCwnd;
431 }

Referenced by cwndUpdateAfterSack().

◆ scheduleSack()

void inet::sctp::SctpAssociation::scheduleSack ( )
protected
1325 {
1326  /* increase SACK counter, we received another data PACKET */
1328  state->ackState++;
1329  else {
1331  state->firstChunkReceived = true;
1332  }
1333 
1334  EV_DETAIL << "scheduleSack() : ackState is now: " << state->ackState << "\n";
1335 
1336  if (state->ackState <= sackFrequency - 1) {
1337  /* start a SACK timer if none is running, to expire 200 ms (or parameter) from now */
1338  if (!SackTimer->isScheduled()) {
1340  }
1341  /* else: leave timer running, and do nothing... */ else {
1342  /* is this possible at all ? Check this... */
1343 
1344  EV_DETAIL << "SACK timer running, but scheduleSack() called\n";
1345  }
1346  }
1347 }

Referenced by process_RCV_Message().

◆ scheduleTimeout()

void inet::sctp::SctpAssociation::scheduleTimeout ( cMessage *  msg,
const simtime_t &  timeout 
)
inlineprotected

Utility: start a timer.

1186  {
1187  sctpMain->scheduleAfter(timeout, msg);
1188  }

Referenced by SctpAssociation(), startTimer(), and stateEntered().

◆ SCTP_UINT16_GE()

static bool inet::sctp::SctpAssociation::SCTP_UINT16_GE ( uint16_t  a,
uint16_t  b 
)
inlinestatic
1064 { return (a == b) || SCTP_UINT16_GT(a, b); }

◆ SCTP_UINT16_GT()

static bool inet::sctp::SctpAssociation::SCTP_UINT16_GT ( uint16_t  a,
uint16_t  b 
)
inlinestatic

Compare TSNs.

1059  {
1060  return ((a < b) && ((uint16_t)(b - a) > (1U << 15))) || \
1061  ((a > b) && ((uint16_t)(a - b) < (1U << 15)));
1062  }

◆ SCTP_UINT32_GE()

static bool inet::sctp::SctpAssociation::SCTP_UINT32_GE ( uint32_t  a,
uint32_t  b 
)
inlinestatic
1070 { return SCTP_UINT32_GT(a, b) || (a == b); }

◆ SCTP_UINT32_GT()

static bool inet::sctp::SctpAssociation::SCTP_UINT32_GT ( uint32_t  a,
uint32_t  b 
)
inlinestatic
1065  {
1066  return ((a < b) && ((uint32_t)(b - a) > (1UL << 31))) ||
1067  ((a > b) && ((uint32_t)(a - b) < (1UL << 31)));
1068  }

◆ sendAbort()

void inet::sctp::SctpAssociation::sendAbort ( uint16_t  tBit = 0)
protected
1154 {
1155  SctpAuthenticationChunk *authChunk;
1156  const auto& msg = makeShared<SctpHeader>();
1157  msg->setChunkLength(B(SCTP_COMMON_HEADER));
1158 
1159  EV_INFO << "SctpAssociationUtil:sendABORT localPort=" << localPort << " remotePort=" << remotePort << "\n";
1160 
1161  msg->setSrcPort(localPort);
1162  msg->setDestPort(remotePort);
1163  SctpAbortChunk *abortChunk = new SctpAbortChunk();
1164  abortChunk->setSctpChunkType(ABORT);
1165  abortChunk->setT_Bit(tBit);
1166  abortChunk->setByteLength(SCTP_ABORT_CHUNK_LENGTH);
1167  if (state->auth && state->peerAuth && typeInChunkList(ABORT)) {
1168  authChunk = createAuthChunk();
1169  msg->appendSctpChunks(authChunk);
1170  auto it = sctpMain->assocStatMap.find(assocId);
1171  it->second.numAuthChunksSent++;
1172  }
1173  msg->appendSctpChunks(abortChunk);
1174  if (state->resetChunk != nullptr) {
1175  delete state->resetChunk;
1176  }
1177  Packet *fp = new Packet("ABORT");
1178  sendToIP(fp, msg, remoteAddr);
1179 }

Referenced by process_ABORT(), process_RCV_Message(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processCookieEchoArrived(), processErrorArrived(), processInitArrived(), processTimer(), and updateCounters().

◆ sendAddInAndOutStreamsRequest()

void inet::sctp::SctpAssociation::sendAddInAndOutStreamsRequest ( SctpResetReq info)
protected
698 {
699  EV_INFO << "StreamReset:sendAddInandStreamsRequest\n";
700  const auto& msg = makeShared<SctpHeader>();
701  msg->setChunkLength(B(SCTP_COMMON_HEADER));
702  msg->setSrcPort(localPort);
703  msg->setDestPort(remotePort);
704  SctpResetTimer *rt = new SctpResetTimer();
705  SctpStreamResetChunk *resetChunk = new SctpStreamResetChunk();
706  resetChunk->setSctpChunkType(RE_CONFIG);
707  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
708  uint32_t srsn = state->streamResetSequenceNumber;
709  SctpAddStreamsRequestParameter *addOutStreams = new SctpAddStreamsRequestParameter();
711  addOutStreams->setNumberOfStreams(info->getOutstreams());
712  state->numAddedOutStreams = info->getOutstreams();
713  rt->setOutSN(srsn);
714  rt->setOutAcked(false);
716  state->requests[srsn].result = 100;
718  addOutStreams->setSrReqSn(srsn++);
720  SctpAddStreamsRequestParameter *addInStreams = new SctpAddStreamsRequestParameter();
722  addInStreams->setNumberOfStreams(info->getInstreams());
723  state->numAddedInStreams = info->getInstreams();
724  rt->setInSN(srsn);
725  rt->setInAcked(false);
727  state->requests[srsn].result = 100;
729  addInStreams->setSrReqSn(srsn++);
731  resetChunk->addParameter(addOutStreams);
732  resetChunk->addParameter(addInStreams);
735  if (state->resetChunk != nullptr) {
736  delete state->resetChunk;
737  state->resetChunk = nullptr;
738  }
739  state->resetChunk = check_and_cast<SctpStreamResetChunk *>(resetChunk->dup());
740 // state->resetChunk->setName("stateAddInOutResetChunk");
741  msg->appendSctpChunks(resetChunk);
742  Packet *pkt = new Packet("RE_CONFIG");
743  sendToIP(pkt, msg, remoteAddr);
744  PK(getPath(remoteAddr)->ResetTimer)->encapsulate(rt);
745  startTimer(getPath(remoteAddr)->ResetTimer, getPath(remoteAddr)->pathRto);
746 }

Referenced by process_STREAM_RESET().

◆ sendAddOutgoingStreamsRequest()

void inet::sctp::SctpAssociation::sendAddOutgoingStreamsRequest ( uint16_t  numStreams)
protected
646 {
647  EV_INFO << "StreamReset:sendAddOutgoingStreamsRequest\n";
648  uint32_t srsn = 0;
649  const auto& msg = makeShared<SctpHeader>();
650  msg->setChunkLength(B(SCTP_COMMON_HEADER));
651  msg->setSrcPort(localPort);
652  msg->setDestPort(remotePort);
653  SctpStreamResetChunk *resetChunk = new SctpStreamResetChunk();
654  resetChunk->setSctpChunkType(RE_CONFIG);
655  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
656  SctpStateVariables::RequestData *resDat = state->findTypeInRequests(ADD_OUTGOING_STREAMS_REQUEST_PARAMETER);
657  if (resDat != nullptr && resDat->sn == state->streamResetSequenceNumber - 1) {
658  srsn = state->streamResetSequenceNumber - 1;
659  }
660  else {
662  state->requests[srsn].result = 100;
664  state->requests[srsn].sn = srsn;
665  auto it = sctpMain->assocStatMap.find(assocId);
666  it->second.numResetRequestsSent++;
667  }
668  SctpAddStreamsRequestParameter *addStreams = new SctpAddStreamsRequestParameter();
669  addStreams->setParameterType(ADD_OUTGOING_STREAMS_REQUEST_PARAMETER);
670  addStreams->setNumberOfStreams(numStreams);
671  state->numAddedOutStreams = addStreams->getNumberOfStreams();
673  addStreams->setSrReqSn(srsn);
674  addStreams->setByteLength(SCTP_ADD_STREAMS_REQUEST_PARAMETER_LENGTH);
675  resetChunk->addParameter(addStreams);
676  if (state->resetChunk != nullptr) {
677  delete state->resetChunk;
678  state->resetChunk = nullptr;
679  }
680  state->resetChunk = check_and_cast<SctpStreamResetChunk *>(resetChunk->dup());
681 // state->resetChunk->setName("stateAddResetChunk");
682  msg->appendSctpChunks(resetChunk);
683  Packet *pkt = new Packet("RE_CONFIG");
684  sendToIP(pkt, msg, remoteAddr);
685  if (!(getPath(remoteAddr)->ResetTimer->isScheduled())) {
686  SctpResetTimer *rt = new SctpResetTimer();
687  rt->setInSN(0);
688  rt->setInAcked(true);
689  rt->setOutSN(srsn);
690  rt->setOutAcked(false);
691  PK(getPath(remoteAddr)->ResetTimer)->encapsulate(rt);
692  startTimer(getPath(remoteAddr)->ResetTimer, getPath(remoteAddr)->pathRto);
693  }
695 }

Referenced by process_RCV_Message().

◆ sendAsconf()

void inet::sctp::SctpAssociation::sendAsconf ( const char *  type,
bool  remote = false 
)
protected

Methods for Add-IP and AUTH.

16 {
17  SctpAuthenticationChunk *authChunk = nullptr;
18  bool nat = false;
19  L3Address targetAddr = remoteAddr;
20  uint16_t chunkLength = 0;
21 
22  if (state->asconfOutstanding == false) {
23  EV_DEBUG << "sendAsconf\n";
24  const auto& sctpAsconf = makeShared<SctpHeader>();
25  sctpAsconf->setChunkLength(B(SCTP_COMMON_HEADER));
26  sctpAsconf->setSrcPort(localPort);
27  sctpAsconf->setDestPort(remotePort);
28  SctpAsconfChunk *asconfChunk = new SctpAsconfChunk();
29  asconfChunk->setSctpChunkType(ASCONF);
30  asconfChunk->setSerialNumber(state->asconfSn);
31  chunkLength = SCTP_ADD_IP_CHUNK_LENGTH;
32  EV_INFO << "localAddr=" << localAddr << ", remoteAddr=" << remoteAddr << "\n";
33  if (getAddressLevel(localAddr) == 3 && getAddressLevel(remoteAddr) == 4 && (bool)sctpMain->par("natFriendly")) {
34  asconfChunk->setAddressParam(L3Address("0.0.0.0"));
35  asconfChunk->setPeerVTag(peerVTag);
36  nat = true;
37  }
38  else {
39  asconfChunk->setAddressParam(localAddr);
40  }
41 
43  chunkLength += 20;
44  }
45  else if (localAddr.getType() == L3Address::IPv4) {
46  chunkLength += 8;
47  }
48  else
49  throw cRuntimeError("Unknown address type");
50 
51  asconfChunk->setByteLength(chunkLength);
52 
53  cStringTokenizer tokenizer(type);
54  while (tokenizer.hasMoreTokens()) {
55  const char *token = tokenizer.nextToken();
56  switch (atoi(token)) {
57  case ADD_IP_ADDRESS: {
58  SctpAddIPParameter *ipParam;
59  ipParam = new SctpAddIPParameter();
60  chunkLength += SCTP_ADD_IP_PARAMETER_LENGTH;
61  ipParam->setParameterType(ADD_IP_ADDRESS);
62  ipParam->setRequestCorrelationId(++state->corrIdNum);
63  if (nat) {
64  ipParam->setAddressParam(L3Address("0.0.0.0"));
65  sctpMain->addLocalAddressToAllRemoteAddresses(this, L3AddressResolver().resolve(sctpMain->par("addAddress"), 1), remoteAddressList);
66  state->localAddresses.push_back(L3AddressResolver().resolve(sctpMain->par("addAddress"), 1));
67  if (remote)
68  targetAddr = remoteAddr;
69  else
70  targetAddr = getNextAddress(getPath(remoteAddr));
71  }
72  else {
73  ipParam->setAddressParam(L3AddressResolver().resolve(sctpMain->par("addAddress"), 1));
74  }
75  if (ipParam->getAddressParam().getType() == L3Address::IPv6) {
76  chunkLength += 20;
77  ipParam->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH + 20);
78  }
79  else if (ipParam->getAddressParam().getType() == L3Address::IPv4) {
80  chunkLength += 8;
81  ipParam->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH + 8);
82  }
83  else
84  throw cRuntimeError("Unknown address type");
85  asconfChunk->addAsconfParam(ipParam);
86  break;
87  }
88 
89  case DELETE_IP_ADDRESS: {
90  SctpDeleteIPParameter *delParam;
91  delParam = new SctpDeleteIPParameter();
92  chunkLength += SCTP_ADD_IP_PARAMETER_LENGTH;
93  delParam->setParameterType(DELETE_IP_ADDRESS);
94  delParam->setRequestCorrelationId(++state->corrIdNum);
95  delParam->setAddressParam(L3AddressResolver().resolve(sctpMain->par("addAddress"), 1));
96  if (delParam->getAddressParam().getType() == L3Address::IPv6) {
97  chunkLength += 20;
98  delParam->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH + 20);
99  }
100  else if (delParam->getAddressParam().getType() == L3Address::IPv4) {
101  chunkLength += 8;
102  delParam->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH + 8);
103  }
104  else
105  throw cRuntimeError("Unknown address type");
106  asconfChunk->addAsconfParam(delParam);
107  break;
108  }
109 
110  case SET_PRIMARY_ADDRESS: {
111  SctpSetPrimaryIPParameter *priParam;
112  priParam = new SctpSetPrimaryIPParameter();
113  chunkLength += SCTP_ADD_IP_PARAMETER_LENGTH;
114  priParam->setParameterType(SET_PRIMARY_ADDRESS);
115  priParam->setRequestCorrelationId(++state->corrIdNum);
116  priParam->setAddressParam(L3AddressResolver().resolve(sctpMain->par("addAddress"), 1));
117  if (nat) {
118  priParam->setAddressParam(L3Address("0.0.0.0"));
119  }
120  if (priParam->getAddressParam().getType() == L3Address::IPv6) {
121  chunkLength += 20;
122  priParam->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH + 20);
123  }
124  else if (priParam->getAddressParam().getType() == L3Address::IPv4) {
125  chunkLength += 8;
126  priParam->setByteLength(SCTP_ADD_IP_PARAMETER_LENGTH + 8);
127  }
128  else
129  throw cRuntimeError("Unknown address type");
130  asconfChunk->addAsconfParam(priParam);
131  break;
132  }
133 
134  default:
135  EV_INFO << "type " << atoi(token) << "not known\n";
136  break;
137  }
138  }
139  asconfChunk->setByteLength(chunkLength);
140 
141  if (state->auth && state->peerAuth) {
142  authChunk = createAuthChunk();
143  sctpAsconf->appendSctpChunks(authChunk);
144  auto it = sctpMain->assocStatMap.find(assocId);
145  it->second.numAuthChunksSent++;
146  }
147  sctpAsconf->appendSctpChunks(asconfChunk);
148 
149  state->asconfChunk = check_and_cast<SctpAsconfChunk *>(asconfChunk->dup());
150 // state->asconfChunk->setName("STATE-ASCONF");
151 
152  Packet *pkt = new Packet("ASCONF");
153  sendToIP(pkt, sctpAsconf, targetAddr);
154  state->asconfOutstanding = true;
155  }
156 }

Referenced by processAppCommand(), processAsconfArrived(), processErrorArrived(), and processTimer().

◆ sendAsconfAck()

void inet::sctp::SctpAssociation::sendAsconfAck ( uint32_t  serialNumber)
protected
180 {
181  const auto& sctpAsconfAck = makeShared<SctpHeader>();
182  sctpAsconfAck->setChunkLength(B(SCTP_COMMON_HEADER));
183  sctpAsconfAck->setSrcPort(localPort);
184  sctpAsconfAck->setDestPort(remotePort);
185 
186  SctpAsconfAckChunk *asconfAckChunk = new SctpAsconfAckChunk();
187  asconfAckChunk->setSctpChunkType(ASCONF_ACK);
188  asconfAckChunk->setSerialNumber(serialNumber);
189  asconfAckChunk->setByteLength(SCTP_ADD_IP_CHUNK_LENGTH);
190  if (state->auth && state->peerAuth) {
191  SctpAuthenticationChunk *authChunk = createAuthChunk();
192  sctpAsconfAck->appendSctpChunks(authChunk);
193  auto it = sctpMain->assocStatMap.find(assocId);
194  it->second.numAuthChunksSent++;
195  }
196  sctpAsconfAck->appendSctpChunks(asconfAckChunk);
197  Packet *pkt = new Packet("ASCONF");
198  sendToIP(pkt, sctpAsconfAck, remoteAddr);
199 }

◆ sendAvailableIndicationToApp()

void inet::sctp::SctpAssociation::sendAvailableIndicationToApp ( )
protected
453 {
454  EV_INFO << "sendAvailableIndicationToApp: localPort="
455  << localPort << " remotePort=" << remotePort << endl;
456 
457  Indication *msg = new Indication(indicationName(SCTP_I_AVAILABLE), SCTP_I_AVAILABLE);
458 
459  auto availableIndication = msg->addTag<SctpAvailableReq>();
460 // SctpAvailableInfo *availableIndication = new SctpAvailableInfo("SctpAvailableInfo");
461  availableIndication->setSocketId(listeningAssocId);
462  availableIndication->setLocalAddr(localAddr);
463  availableIndication->setRemoteAddr(remoteAddr);
464  availableIndication->setLocalPort(localPort);
465  availableIndication->setRemotePort(remotePort);
466  availableIndication->setNewSocketId(assocId);
467  msg->addTag<SocketInd>()->setSocketId(listeningAssocId);
468 // msg->setControlInfo(availableIndication);
469  sctpMain->send(msg, "appOut");
470 }

Referenced by stateEntered().

◆ sendBundledOutgoingResetAndResponse()

void inet::sctp::SctpAssociation::sendBundledOutgoingResetAndResponse ( SctpIncomingSsnResetRequestParameter requestParam)
protected
229 {
230  EV_INFO << "sendBundledOutgoingResetAndResponse to " << remoteAddr << "\n";
231  uint16_t len = 0;
232  if (!(getPath(remoteAddr)->ResetTimer->isScheduled())) {
233  SctpStreamResetChunk *resetChunk = new SctpStreamResetChunk();
234  resetChunk->setSctpChunkType(RE_CONFIG);
235  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
236  uint32_t srsn = state->streamResetSequenceNumber;
237  SctpOutgoingSsnResetRequestParameter *outResetParam;
238  outResetParam = new SctpOutgoingSsnResetRequestParameter();
239  outResetParam->setParameterType(OUTGOING_RESET_REQUEST_PARAMETER);
240  state->requests[srsn].result = 100;
243  outResetParam->setSrReqSn(srsn++);
244  outResetParam->setSrResSn(requestParam->getSrReqSn());
245  outResetParam->setLastTsn(state->nextTsn - 1);
246  if (state->streamsToReset.size() > 0) {
247  outResetParam->setStreamNumbersArraySize(state->streamsToReset.size());
248  uint16_t i = 0;
249  for (std::list<uint16_t>::iterator it = state->streamsToReset.begin(); it != state->streamsToReset.end(); ++it) {
250  outResetParam->setStreamNumbers(i, *it);
251  state->resetOutStreams.push_back(outResetParam->getStreamNumbers(i));
252  resetSsn(outResetParam->getStreamNumbers(i));
253  i++;
254  }
255  len = state->streamsToReset.size() * 2;
256  state->streamsToReset.clear();
257  }
258  else if (requestParam->getStreamNumbersArraySize() > 0) {
259  outResetParam->setStreamNumbersArraySize(requestParam->getStreamNumbersArraySize());
260  for (uint16_t i = 0; i < requestParam->getStreamNumbersArraySize(); i++) {
261  outResetParam->setStreamNumbers(i, requestParam->getStreamNumbers(i));
262  }
263  len = requestParam->getStreamNumbersArraySize() * 2;
264  }
265  outResetParam->setByteLength(SCTP_OUTGOING_RESET_REQUEST_PARAMETER_LENGTH + len);
266  resetChunk->addParameter(outResetParam);
268 
269  SctpStreamResetChunk *resetResponseChunk;
270  EV_INFO << "sendbundledStreamResetResponse to " << remoteAddr << "\n";
271  resetResponseChunk = new SctpStreamResetChunk();
272  resetResponseChunk->setSctpChunkType(RE_CONFIG);
273  resetResponseChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
274  SctpStreamResetResponseParameter *responseParam = new SctpStreamResetResponseParameter();
275  responseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
276  responseParam->setSrResSn(requestParam->getSrReqSn());
277  responseParam->setResult(PERFORMED);
278  responseParam->setByteLength(SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH);
279  resetResponseChunk->addParameter(responseParam);
280  state->resetRequested = false;
281 
282  SctpResetTimer *rt = new SctpResetTimer();
283  rt->setInSN(0);
284  rt->setInAcked(true);
285  rt->setOutSN(srsn - 1);
286  rt->setOutAcked(false);
287 
288  const auto& msg = makeShared<SctpHeader>();
289  msg->setChunkLength(B(SCTP_COMMON_HEADER));
290  msg->setSrcPort(localPort);
291  msg->setDestPort(remotePort);
292  msg->appendSctpChunks(resetChunk);
293  msg->appendSctpChunks(resetResponseChunk);
295  if (state->resetChunk != nullptr) {
296  delete state->resetChunk;
297  state->resetChunk = nullptr;
298  }
299  state->resetChunk = check_and_cast<SctpStreamResetChunk *>(resetChunk->dup());
300 // state->resetChunk->setName("State_Resetchunk");
301  if (qCounter.roomSumSendStreams != 0) {
302  storePacket(getPath(remoteAddr), msg, 1, 0, false);
303  state->bundleReset = true;
304  sendOnPath(getPath(remoteAddr), true);
305  state->bundleReset = false;
306  }
307  else {
308  Packet *pkt = new Packet("RE_CONFIG");
309  sendToIP(pkt, msg, remoteAddr);
310  }
311  if (PK(getPath(remoteAddr)->ResetTimer)->hasEncapsulatedPacket()) {
312  PK(getPath(remoteAddr)->ResetTimer)->decapsulate();
313  }
314  PK(getPath(remoteAddr)->ResetTimer)->encapsulate(rt);
315  if (getPath(remoteAddr)->ResetTimer->isScheduled()) {
316  stopTimer(getPath(remoteAddr)->ResetTimer);
317  }
318  startTimer(getPath(remoteAddr)->ResetTimer, getPath(remoteAddr)->pathRto);
319  }
320 }

◆ sendCookieAck()

void inet::sctp::SctpAssociation::sendCookieAck ( const L3Address dest)
protected
1084 {
1085  SctpAuthenticationChunk *authChunk;
1086  const auto& sctpcookieack = makeShared<SctpHeader>();
1087  sctpcookieack->setChunkLength(B(SCTP_COMMON_HEADER));
1088 
1089  EV_INFO << "SctpAssociationUtil:sendCookieACK\n";
1090 
1091  sctpcookieack->setSrcPort(localPort);
1092  sctpcookieack->setDestPort(remotePort);
1093  SctpCookieAckChunk *cookieAckChunk = new SctpCookieAckChunk();
1094  cookieAckChunk->setSctpChunkType(COOKIE_ACK);
1095  cookieAckChunk->setByteLength(SCTP_COOKIE_ACK_LENGTH);
1097  authChunk = createAuthChunk();
1098  sctpcookieack->appendSctpChunks(authChunk);
1099  auto it = sctpMain->assocStatMap.find(assocId);
1100  it->second.numAuthChunksSent++;
1101  }
1102  sctpcookieack->appendSctpChunks(cookieAckChunk);
1103  Packet *fp = new Packet("COOKIE-ACK");
1104  sendToIP(fp, sctpcookieack, dest);
1105 }

Referenced by processCookieEchoArrived(), and processPacketDropArrived().

◆ sendCookieEcho()

void inet::sctp::SctpAssociation::sendCookieEcho ( SctpInitAckChunk initackchunk)
protected
953 {
954  SctpAuthenticationChunk *authChunk;
955  const auto& sctpcookieecho = makeShared<SctpHeader>();
956  sctpcookieecho->setChunkLength(B(SCTP_COMMON_HEADER));
957 
958  EV_INFO << "SctpAssociationUtil:sendCookieEcho\n";
959 
960  sctpcookieecho->setSrcPort(localPort);
961  sctpcookieecho->setDestPort(remotePort);
962  SctpCookieEchoChunk *cookieEchoChunk = new SctpCookieEchoChunk();
963  cookieEchoChunk->setSctpChunkType(COOKIE_ECHO);
964  int32_t len = initAckChunk->getCookieArraySize();
965  cookieEchoChunk->setCookieArraySize(len);
966  if (len > 0) {
967  for (int32_t i = 0; i < len; i++)
968  cookieEchoChunk->setCookie(i, initAckChunk->getCookie(i));
969  cookieEchoChunk->setByteLength(SCTP_COOKIE_ACK_LENGTH + len);
970  }
971  else {
972  SctpCookie *cookie = (SctpCookie *)(initAckChunk->getStateCookie());
973  cookieEchoChunk->setStateCookie(cookie);
974  cookieEchoChunk->setByteLength(SCTP_COOKIE_ACK_LENGTH + cookie->getLength());
975  }
976  uint32_t unknownLen = initAckChunk->getUnrecognizedParametersArraySize();
977  if (unknownLen > 0) {
978  EV_INFO << "Found unrecognized Parameters in INIT-ACK chunk with a length of " << unknownLen << " bytes.\n";
979  cookieEchoChunk->setUnrecognizedParametersArraySize(unknownLen);
980  for (uint32_t i = 0; i < unknownLen; i++)
981  cookieEchoChunk->setUnrecognizedParameters(i, initAckChunk->getUnrecognizedParameters(i));
982  }
983  else
984  cookieEchoChunk->setUnrecognizedParametersArraySize(0);
985  state->cookieChunk = check_and_cast<SctpCookieEchoChunk *>(cookieEchoChunk->dup());
986  if (len == 0) {
987  state->cookieChunk->setStateCookie(initAckChunk->getStateCookie()->dup());
988  }
989 
991  authChunk = createAuthChunk();
992  sctpcookieecho->appendSctpChunks(authChunk);
993  auto it = sctpMain->assocStatMap.find(assocId);
994  it->second.numAuthChunksSent++;
995  }
996 
997  sctpcookieecho->appendSctpChunks(cookieEchoChunk);
998  Packet *fp = new Packet("COOKIE-ECHO");
999  sendToIP(fp, sctpcookieecho);
1000 }

Referenced by processInitAckArrived().

◆ sendDataArrivedNotification()

void inet::sctp::SctpAssociation::sendDataArrivedNotification ( uint16_t  sid)
protected
1856 {
1857  EV_INFO << "SendDataArrivedNotification\n";
1858 
1859  Indication *cmsg = new Indication("SCTP_I_DATA_NOTIFICATION", SCTP_I_DATA_NOTIFICATION);
1860  auto cmd = cmsg->addTag<SctpCommandReq>();
1861  cmd->setSocketId(assocId);
1862  cmd->setSid(sid);
1863  cmd->setNumMsgs(1);
1864 // cmsg->setControlInfo(cmd);
1865 
1866  sendToApp(cmsg);
1867 }

Referenced by processDataArrived(), processForwardTsnArrived(), and pushUlp().

◆ sendDoubleStreamResetResponse()

void inet::sctp::SctpAssociation::sendDoubleStreamResetResponse ( uint32_t  insrrsn,
uint16_t  inresult,
uint32_t  outsrrsn,
uint16_t  outresult 
)
protected
843 {
844  SctpStreamResetChunk *resetChunk;
845  EV_INFO << "sendDoubleStreamResetResponse to " << remoteAddr << "\n";
846  const auto& msg = makeShared<SctpHeader>();
847  msg->setChunkLength(B(SCTP_COMMON_HEADER));
848  msg->setSrcPort(localPort);
849  msg->setDestPort(remotePort);
850  resetChunk = new SctpStreamResetChunk();
851  resetChunk->setSctpChunkType(RE_CONFIG);
852  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
853  SctpStreamResetResponseParameter *outResponseParam = new SctpStreamResetResponseParameter();
854  outResponseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
855  outResponseParam->setSrResSn(outsrrsn);
856  outResponseParam->setResult(outresult);
857  outResponseParam->setByteLength(SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH);
858  resetChunk->addParameter(outResponseParam);
859  SctpStreamResetResponseParameter *inResponseParam = new SctpStreamResetResponseParameter();
860  inResponseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
861  inResponseParam->setSrResSn(insrrsn);
862  inResponseParam->setResult(inresult);
863  state->peerRequests[insrrsn].result = inresult;
864  state->peerRequests[outsrrsn].result = outresult;
865  inResponseParam->setByteLength(SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH);
866  resetChunk->addParameter(inResponseParam);
867  msg->appendSctpChunks(resetChunk);
868  if (qCounter.roomSumSendStreams != 0) {
869  storePacket(getPath(remoteAddr), msg, 1, 0, false);
870  state->bundleReset = true;
871  sendOnPath(getPath(remoteAddr), true);
872  state->bundleReset = false;
873  }
874  else {
875  Packet *pkt = new Packet("RE_CONFIG");
876  sendToIP(pkt, msg, remoteAddr);
877  }
878  if (outresult == PERFORMED || outresult == DENIED) {
879  state->resetRequested = false;
880  state->firstPeerRequest = false;
881  }
882 }

Referenced by processInAndOutResetRequestArrived().

◆ sendEstabIndicationToApp()

void inet::sctp::SctpAssociation::sendEstabIndicationToApp ( )
protected

Utility: sends SCTP_I_ESTABLISHED indication with SctpConnectInfo to application.

473 {
474  EV_INFO << "sendEstabIndicationToApp: localPort="
475  << localPort << " remotePort=" << remotePort << " assocId=" << assocId << endl;
476 
477  Indication *msg = new Indication(indicationName(SCTP_I_ESTABLISHED), SCTP_I_ESTABLISHED);
478 
479  auto establishIndication = msg->addTag<SctpConnectReq>();
480 // SctpConnectInfo *establishIndication = new SctpConnectInfo("ConnectInfo");
481  establishIndication->setSocketId(assocId);
482  establishIndication->setLocalAddr(localAddr);
483  establishIndication->setRemoteAddr(remoteAddr);
484  establishIndication->setLocalPort(localPort);
485  establishIndication->setRemotePort(remotePort);
486  establishIndication->setRemoteAddresses(remoteAddressList);
487  establishIndication->setInboundStreams(inboundStreams);
488  establishIndication->setOutboundStreams(outboundStreams);
489  establishIndication->setNumMsgs(state->sendQueueLimit);
490  msg->addTag<SocketInd>()->setSocketId(assocId);
491 // msg->setControlInfo(establishIndication);
492  sctpMain->send(msg, "appOut");
493 
494  char vectorName[128];
495  for (uint16_t i = 0; i < inboundStreams; i++) {
496  snprintf(vectorName, sizeof(vectorName), "Stream %d Throughput", i);
497  streamThroughputVectors[i] = new cOutVector(vectorName);
498  }
499 }

Referenced by processAppCommand(), and stateEntered().

◆ sendHeartbeat()

void inet::sctp::SctpAssociation::sendHeartbeat ( const SctpPathVariables path)
protected
1025 {
1026  SctpAuthenticationChunk *authChunk;
1027  const auto& sctpHeartbeatbeat = makeShared<SctpHeader>();
1028  sctpHeartbeatbeat->setChunkLength(B(SCTP_COMMON_HEADER));
1029 
1030  sctpHeartbeatbeat->setSrcPort(localPort);
1031  sctpHeartbeatbeat->setDestPort(remotePort);
1032  SctpHeartbeatChunk *heartbeatChunk = new SctpHeartbeatChunk();
1033  heartbeatChunk->setSctpChunkType(HEARTBEAT);
1034  heartbeatChunk->setRemoteAddr(path->remoteAddress);
1035  heartbeatChunk->setTimeField(simTime());
1036  heartbeatChunk->setByteLength(SCTP_HEARTBEAT_CHUNK_LENGTH + 12);
1038  authChunk = createAuthChunk();
1039  sctpHeartbeatbeat->appendSctpChunks(authChunk);
1040  auto it = sctpMain->assocStatMap.find(assocId);
1041  it->second.numAuthChunksSent++;
1042  }
1043  sctpHeartbeatbeat->appendSctpChunks(heartbeatChunk);
1044  EV_INFO << "sendHeartbeat: sendToIP to " << path->remoteAddress << endl;
1045  Packet *fp = new Packet("HEARTBEAT");
1046  sendToIP(fp, sctpHeartbeatbeat, path->remoteAddress);
1047 }

Referenced by pmStartPathManagement(), process_TIMEOUT_HEARTBEAT_INTERVAL(), processAsconfArrived(), and processPacketDropArrived().

◆ sendHeartbeatAck()

void inet::sctp::SctpAssociation::sendHeartbeatAck ( const SctpHeartbeatChunk heartbeatChunk,
const L3Address src,
const L3Address dest 
)
protected
1052 {
1053  SctpAuthenticationChunk *authChunk;
1054  const auto& sctpHeartbeatAck = makeShared<SctpHeader>();
1055  sctpHeartbeatAck->setChunkLength(B(SCTP_COMMON_HEADER));
1056  sctpHeartbeatAck->setSrcPort(localPort);
1057  sctpHeartbeatAck->setDestPort(remotePort);
1058  SctpHeartbeatAckChunk *heartbeatAckChunk = new SctpHeartbeatAckChunk();
1059  heartbeatAckChunk->setSctpChunkType(HEARTBEAT_ACK);
1060  heartbeatAckChunk->setRemoteAddr(heartbeatChunk->getRemoteAddr());
1061  heartbeatAckChunk->setTimeField(heartbeatChunk->getTimeField());
1062  const int32_t len = heartbeatChunk->getInfoArraySize();
1063  if (len > 0) {
1064  heartbeatAckChunk->setInfoArraySize(len);
1065  for (int32_t i = 0; i < len; i++)
1066  heartbeatAckChunk->setInfo(i, heartbeatChunk->getInfo(i));
1067  }
1068 
1069  heartbeatAckChunk->setByteLength(heartbeatChunk->getByteLength());
1071  authChunk = createAuthChunk();
1072  sctpHeartbeatAck->appendSctpChunks(authChunk);
1073  auto it = sctpMain->assocStatMap.find(assocId);
1074  it->second.numAuthChunksSent++;
1075  }
1076  sctpHeartbeatAck->appendSctpChunks(heartbeatAckChunk);
1077 
1078  EV_INFO << "sendHeartbeatAck: sendToIP from " << src << " to " << dest << endl;
1079  Packet *fp = new Packet("HEARTBEAT-ACK");
1080  sendToIP(fp, sctpHeartbeatAck, dest);
1081 }

Referenced by process_RCV_Message().

◆ sendHMacError()

void inet::sctp::SctpAssociation::sendHMacError ( const uint16_t  id)
protected
1898 {
1899  const auto& sctpmsg = makeShared<SctpHeader>();
1900  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
1901  SctpErrorChunk *errorChunk = new SctpErrorChunk();
1902  errorChunk->setSctpChunkType(ERRORTYPE);
1903  SctpSimpleErrorCauseParameter *cause = new SctpSimpleErrorCauseParameter();
1904  cause->setParameterType(UNSUPPORTED_HMAC);
1905  cause->setByteLength(6);
1906  cause->setValue(id);
1907  errorChunk->setByteLength(4);
1908  errorChunk->addParameters(cause);
1909  sctpmsg->appendSctpChunks(errorChunk);
1910 }

Referenced by process_RCV_Message().

◆ sendIndicationToApp()

void inet::sctp::SctpAssociation::sendIndicationToApp ( int32_t  code,
int32_t  value = 0 
)
protected

Utility: sends status indication (SCTP_I_xxx) to application.

436 {
437  EV_INFO << "sendIndicationToApp: " << indicationName(code) << endl;
438  assert(code != SCTP_I_SENDQUEUE_ABATED);
439 
440  Indication *msg = new Indication(indicationName(code), code);
441 
442  auto& indication = msg->addTag<SctpCommandReq>();
443  indication->setSocketId(assocId);
444  indication->setLocalAddr(localAddr);
445  indication->setLocalPort(localPort);
446  indication->setRemoteAddr(remoteAddr);
447  indication->setRemotePort(remotePort);
448  msg->addTag<SocketInd>()->setSocketId(assocId);
449  sctpMain->send(msg, "appOut");
450 }

Referenced by chunkMustBeAbandoned(), peekAbandonedChunk(), process_RCV_Message(), process_SEND(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processAsconfAckArrived(), processAsconfArrived(), processOutAndResponseArrived(), processResetResponseArrived(), processTimer(), resetExpectedSsn(), resetExpectedSsns(), resetSsns(), sendOnPath(), signalConnectionTimeout(), stateEntered(), and updateCounters().

◆ sendInit()

void inet::sctp::SctpAssociation::sendInit ( )
protected

Methods for creating and sending chunks.

555 {
556  AddressVector adv;
557  uint32_t length = SCTP_INIT_CHUNK_LENGTH;
558 
559  if (remoteAddr.isUnspecified() || remotePort == 0)
560  throw cRuntimeError("Error processing command ASSOCIATE: foreign socket unspecified");
561 
562  if (localPort == 0)
563  throw cRuntimeError("Error processing command ASSOCIATE: local port unspecified");
564 
566  // create message consisting of INIT chunk
567  const auto& sctpmsg = makeShared<SctpHeader>();
568  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
569  SctpInitChunk *initChunk = new SctpInitChunk();
570  initChunk->setSctpChunkType(INIT);
571  initChunk->setInitTag((uint32_t)(fmod(RNGCONTEXT intrand(INT32_MAX), 1.0 + (double)(unsigned)0xffffffffUL)) & 0xffffffffUL);
572 
573  peerVTag = initChunk->getInitTag();
574  EV_INFO << "INIT from " << localAddr << ":InitTag=" << peerVTag << "\n";
575  initChunk->setA_rwnd(sctpMain->par("arwnd"));
576  state->localRwnd = sctpMain->par("arwnd");
577  initChunk->setNoOutStreams(outboundStreams);
579  initChunk->setNoInStreams(inboundStreams);
580  initChunk->setInitTsn(1000);
581  initChunk->setMsg_rwnd(sctpMain->par("messageAcceptLimit"));
582  state->nextTsn = initChunk->getInitTsn();
583  state->lastTsn = initChunk->getInitTsn() + state->numRequests - 1;
585  state->asconfSn = 1000;
586 
587  initTsn = initChunk->getInitTsn();
588 #ifdef INET_WITH_IPv4
589  initChunk->setIpv4Supported(true);
590 #else
591  initChunk->setIpv4Supported(false);
592 #endif
593 #ifdef INET_WITH_IPv6
594  initChunk->setIpv6Supported(true);
595 #else
596  initChunk->setIpv6Supported(false);
597 #endif
598  if (localAddressList.front().isUnspecified()) {
599  for (int32_t i = 0; i < ift->getNumInterfaces(); ++i) {
600 #ifdef INET_WITH_IPv4
601  if (auto ipv4Data = ift->getInterface(i)->findProtocolData<Ipv4InterfaceData>()) {
602  adv.push_back(ipv4Data->getIPAddress());
603  }
604  else
605 #endif // ifdef INET_WITH_IPv4
606 #ifdef INET_WITH_IPv6
607  if (auto ipv6Data = ift->getInterface(i)->findProtocolData<Ipv6InterfaceData>()) {
608  for (int32_t j = 0; j < ipv6Data->getNumAddresses(); j++) {
609  EV_DETAIL << "add address " << ipv6Data->getAddress(j) << "\n";
610  adv.push_back(ipv6Data->getAddress(j));
611  }
612  }
613  else
614 #endif // ifdef INET_WITH_IPv6
615  ;
616  }
617  }
618  else {
619  adv = localAddressList;
620  EV_DETAIL << "gebundene Adresse " << localAddr << " wird hinzugefuegt\n"; // todo
621  }
622  if (initChunk->getIpv4Supported() || initChunk->getIpv6Supported()) {
623  length += 8;
624  }
625  uint32_t addrNum = 0;
626  bool friendly = false;
627  if (sctpMain->hasPar("natFriendly")) {
628  friendly = sctpMain->par("natFriendly");
629  }
631  for (auto& elem : adv) {
632  if (!friendly) {
633  initChunk->setAddressesArraySize(addrNum + 1);
634  initChunk->setAddresses(addrNum++, (elem));
635  length += 20;
636  }
637  sctpMain->addLocalAddress(this, (elem));
638  state->localAddresses.push_back((elem));
639  if (localAddr.isUnspecified())
640  localAddr = (elem);
641  }
642  }
643  else if (remoteAddr.getType() == L3Address::IPv4) {
644  int rlevel = getAddressLevel(remoteAddr);
645  EV_DETAIL << "level of remote address=" << rlevel << "\n";
646  for (auto& elem : adv) {
647  int addressLevel = getAddressLevel(elem);
648  EV_DETAIL << "level of address " << (elem) << " = " << addressLevel << "\n";
649  if (addressLevel >= rlevel) {
650  initChunk->setAddressesArraySize(addrNum + 1);
651  initChunk->setAddresses(addrNum++, (elem));
652  length += 8;
653  sctpMain->addLocalAddress(this, (elem));
654  state->localAddresses.push_back((elem));
655  if (localAddr.toIpv4().getInt() == 0)
656  localAddr = (elem);
657  }
658  else if (rlevel == 4 && addressLevel == 3 && friendly) {
659  sctpMain->addLocalAddress(this, (elem));
660  state->localAddresses.push_back((elem));
661  if (localAddr.toIpv4().getInt() == 0)
662  localAddr = (elem);
663  }
664  }
665  }
666  else
667  throw cRuntimeError("Unknown address type: %d", (int)(remoteAddr.getType()));
668 
669  uint16_t count = 0;
670  if (sctpMain->auth == true) {
671  initChunk->setSepChunksArraySize(++count);
672  initChunk->setSepChunks(count - 1, AUTH);
673  state->keyVector[0] = (uint8_t)RANDOM;
674  state->keyVector[2] = 36;
675  for (int32_t k = 0; k < 32; k++) {
676  initChunk->setRandomArraySize(k + 1);
677  initChunk->setRandom(k, (uint8_t)(RNGCONTEXT intrand(256)));
678  state->keyVector[k + 2] = initChunk->getRandom(k);
679  }
680  state->sizeKeyVector = 36;
681  state->keyVector[state->sizeKeyVector] = (uint8_t)CHUNKS;
682  state->sizeKeyVector += 2;
684  state->sizeKeyVector += 2;
685  initChunk->setSctpChunkTypesArraySize(state->chunkList.size());
686  int32_t k = 0;
687  for (auto& elem : state->chunkList) {
688  initChunk->setSctpChunkTypes(k, (elem));
689  state->keyVector[state->sizeKeyVector] = (elem);
690  state->sizeKeyVector++;
691  k++;
692  }
694  state->sizeKeyVector += 2;
695  state->keyVector[state->sizeKeyVector] = 1 + 4;
696  state->sizeKeyVector += 2;
698  state->sizeKeyVector++;
699  initChunk->setHmacTypesArraySize(1);
700  initChunk->setHmacTypes(0, 1);
701  length += initChunk->getSctpChunkTypesArraySize() + 50;
702  }
703  if (sctpMain->pktdrop) {
704  initChunk->setSepChunksArraySize(++count);
705  initChunk->setSepChunks(count - 1, PKTDROP);
706  }
707  if (state->streamReset == true) {
708  initChunk->setSepChunksArraySize(++count);
709  initChunk->setSepChunks(count - 1, RE_CONFIG);
710  }
711  if (sctpMain->par("addIP").boolValue()) {
712  initChunk->setSepChunksArraySize(++count);
713  initChunk->setSepChunks(count - 1, ASCONF);
714  initChunk->setSepChunksArraySize(++count);
715  initChunk->setSepChunks(count - 1, ASCONF_ACK);
716  }
717  if (count > 0) {
719  }
720  if (state->prMethod != 0) {
721  initChunk->setForwardTsn(true);
722  length += 4;
723  }
725  initChunk->setByteLength(length);
726  sctpmsg->appendSctpChunks(initChunk);
727  // set path variables
728  if (remoteAddressList.size() > 0) {
729  for (auto& elem : remoteAddressList) {
730  EV_DEBUG << " get new path for " << (elem) << " at line " << __LINE__ << "\n";
731  SctpPathVariables *path = new SctpPathVariables((elem), this, rt);
732  sctpPathMap[(elem)] = path;
733  qCounter.roomTransQ[(elem)] = 0;
734  qCounter.bookedTransQ[(elem)] = 0;
735  qCounter.roomRetransQ[(elem)] = 0;
736  }
737  }
738  else {
739  EV_DEBUG << " get new path for " << remoteAddr << " at line " << __LINE__ << "\n";
740  SctpPathVariables *path = new SctpPathVariables(remoteAddr, this, rt);
741  sctpPathMap[remoteAddr] = path;
745  }
746  // send it
747  state->initChunk = check_and_cast<SctpInitChunk *>(initChunk->dup());
749  EV_INFO << getFullPath() << " sendInit: localVTag=" << localVTag << " peerVTag=" << peerVTag << "\n";
750  Packet *fp = new Packet("INIT");
751  EV_INFO << "Length sctpmsg " << B(sctpmsg->getChunkLength()).get() << endl;
752  sendToIP(fp, sctpmsg);
753  sctpMain->assocList.push_back(this);
754 }

Referenced by process_ASSOCIATE().

◆ sendInitAck()

void inet::sctp::SctpAssociation::sendInitAck ( SctpInitChunk initchunk)
protected
773 {
774  uint32_t length = SCTP_INIT_CHUNK_LENGTH;
775 
777  // create segment
778  const auto& sctpinitack = makeShared<SctpHeader>();
779  sctpinitack->setChunkLength(B(SCTP_COMMON_HEADER));
780 
781  sctpinitack->setSrcPort(localPort);
782  sctpinitack->setDestPort(remotePort);
783  EV_INFO << "sendInitAck at " << localAddr << ". Provided InitTag=" << initChunk->getInitTag() << "\n";
784  SctpInitAckChunk *initAckChunk = new SctpInitAckChunk();
785  initAckChunk->setSctpChunkType(INIT_ACK);
786  SctpCookie *cookie = new SctpCookie();
787  cookie->setCreationTime(simTime());
788  cookie->setLocalTieTagArraySize(32);
789  cookie->setPeerTieTagArraySize(32);
790  if (fsm->getState() == SCTP_S_CLOSED) {
791  while (peerVTag == 0) {
792  peerVTag = (uint32_t)RNGCONTEXT intrand(INT32_MAX);
793  }
794  initAckChunk->setInitTag(peerVTag);
795  initAckChunk->setInitTsn(2000);
796  state->nextTsn = initAckChunk->getInitTsn();
797  state->lastTsn = initAckChunk->getInitTsn() + state->numRequests - 1;
798  state->asconfSn = 2000;
800  cookie->setLocalTag(localVTag);
801  cookie->setPeerTag(peerVTag);
802  for (int32_t i = 0; i < 32; i++) {
803  cookie->setLocalTieTag(i, 0);
804  cookie->setPeerTieTag(i, 0);
805  }
806  sctpinitack->setVTag(localVTag);
807  EV_INFO << "state=closed: localVTag=" << localVTag << " peerVTag=" << peerVTag << "\n";
808  }
809  else if (fsm->getState() == SCTP_S_COOKIE_WAIT || fsm->getState() == SCTP_S_COOKIE_ECHOED) {
810  initAckChunk->setInitTag(peerVTag);
811  EV_INFO << "different state:set InitTag in InitAck: " << initAckChunk->getInitTag() << "\n";
812  initAckChunk->setInitTsn(state->nextTsn);
813  initPeerTsn = initChunk->getInitTsn();
815  cookie->setLocalTag(initChunk->getInitTag());
816  cookie->setPeerTag(peerVTag);
817  for (int32_t i = 0; i < 32; i++) {
818  cookie->setPeerTieTag(i, (uint8_t)(RNGCONTEXT intrand(256)));
819  state->peerTieTag[i] = cookie->getPeerTieTag(i);
820  if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
821  cookie->setLocalTieTag(i, (uint8_t)(RNGCONTEXT intrand(256)));
822  state->localTieTag[i] = cookie->getLocalTieTag(i);
823  }
824  else
825  cookie->setLocalTieTag(i, 0);
826  }
827  sctpinitack->setVTag(initChunk->getInitTag());
828  EV_DETAIL << "VTag in InitAck: " << sctpinitack->getVTag() << "\n";
829  }
830  else {
831  EV_INFO << "other state\n";
832  uint32_t tag = 0;
833  while (tag == 0) {
834  tag = (uint32_t)(fmod(RNGCONTEXT intrand(INT32_MAX), 1.0 + (double)(unsigned)0xffffffffUL)) & 0xffffffffUL;
835  }
836  initAckChunk->setInitTag(tag);
837  initAckChunk->setInitTsn(state->nextTsn);
838  cookie->setLocalTag(localVTag);
839  cookie->setPeerTag(peerVTag);
840  for (int32_t i = 0; i < 32; i++) {
841  cookie->setPeerTieTag(i, state->peerTieTag[i]);
842  cookie->setLocalTieTag(i, state->localTieTag[i]);
843  }
844  sctpinitack->setVTag(initChunk->getInitTag());
845  }
846  cookie->setLength(SCTP_COOKIE_LENGTH + 4);
847  initAckChunk->setStateCookie(cookie);
848  initAckChunk->setCookieArraySize(0);
849  initAckChunk->setA_rwnd(sctpMain->par("arwnd"));
850  state->localRwnd = sctpMain->par("arwnd");
851  initAckChunk->setMsg_rwnd(sctpMain->par("messageAcceptLimit"));
852  initAckChunk->setNoOutStreams((unsigned int)min(outboundStreams, initChunk->getNoInStreams()));
853  initAckChunk->setNoInStreams((unsigned int)min(inboundStreams, initChunk->getNoOutStreams()));
854  initTsn = initAckChunk->getInitTsn();
855 #ifdef INET_WITH_IPv4
856  initAckChunk->setIpv4Supported(true);
857 #else
858  initAckChunk->setIpv4Supported(false);
859 #endif
860 #ifdef INET_WITH_IPv6
861  initAckChunk->setIpv6Supported(true);
862 #else
863  initAckChunk->setIpv6Supported(false);
864 #endif
865  if (initAckChunk->getIpv4Supported() || initAckChunk->getIpv6Supported()) {
866  length += 8;
867  }
868  uint32_t addrNum = 0;
869  bool friendly = false;
870  if (sctpMain->hasPar("natFriendly")) {
871  friendly = sctpMain->par("natFriendly");
872  }
873  if (!friendly)
874  for (auto& elem : state->localAddresses) {
875  initAckChunk->setAddressesArraySize(addrNum + 1);
876  initAckChunk->setAddresses(addrNum++, (elem));
877  if ((elem).getType() == L3Address::IPv4) {
878  length += 8;
879  }
880  else if ((elem).getType() == L3Address::IPv6) {
881  length += 20;
882  }
883  }
884 
885  uint16_t count = 0;
886  if (sctpMain->auth == true) {
887  initAckChunk->setSepChunksArraySize(++count);
888  initAckChunk->setSepChunks(count - 1, AUTH);
889  for (int32_t k = 0; k < 32; k++) {
890  initAckChunk->setRandomArraySize(k + 1);
891  initAckChunk->setRandom(k, (uint8_t)(RNGCONTEXT intrand(256)));
892  }
893  initAckChunk->setSctpChunkTypesArraySize(state->chunkList.size());
894  int32_t k = 0;
895  for (auto& elem : state->chunkList) {
896  initAckChunk->setSctpChunkTypes(k, (elem));
897  k++;
898  }
899  initAckChunk->setHmacTypesArraySize(1);
900  initAckChunk->setHmacTypes(0, 1);
901  length += ADD_PADDING(initAckChunk->getSctpChunkTypesArraySize() + 48);
902  }
903  uint32_t unknownLen = initChunk->getUnrecognizedParametersArraySize();
904  if (unknownLen > 0) {
905  EV_INFO << "Found unrecognized Parameters in INIT chunk with a length of " << unknownLen << " bytes.\n";
906  initAckChunk->setUnrecognizedParametersArraySize(unknownLen);
907  for (uint32_t i = 0; i < unknownLen; i++)
908  initAckChunk->setUnrecognizedParameters(i, initChunk->getUnrecognizedParameters(i));
909  length += unknownLen;
910  }
911  else
912  initAckChunk->setUnrecognizedParametersArraySize(0);
913 
914  if (sctpMain->pktdrop) {
915  initAckChunk->setSepChunksArraySize(++count);
916  initAckChunk->setSepChunks(count - 1, PKTDROP);
917  }
918 
919  if (state->streamReset == true) {
920  initAckChunk->setSepChunksArraySize(++count);
921  initAckChunk->setSepChunks(count - 1, RE_CONFIG);
922  }
923  if (sctpMain->par("addIP").boolValue()) {
924  initAckChunk->setSepChunksArraySize(++count);
925  initAckChunk->setSepChunks(count - 1, ASCONF);
926  initAckChunk->setSepChunksArraySize(++count);
927  initAckChunk->setSepChunks(count - 1, ASCONF_ACK);
928  }
929  if (count > 0) {
931  }
932  if (state->prMethod != 0) {
933  initAckChunk->setForwardTsn(true);
934  length += 4;
935  }
936  initAckChunk->setByteLength(length + initAckChunk->getCookieArraySize() + cookie->getLength());
937  inboundStreams = ((initChunk->getNoOutStreams() < initAckChunk->getNoInStreams()) ? initChunk->getNoOutStreams() : initAckChunk->getNoInStreams());
938  outboundStreams = ((initChunk->getNoInStreams() < initAckChunk->getNoOutStreams()) ? initChunk->getNoInStreams() : initAckChunk->getNoOutStreams());
940  sctpinitack->appendSctpChunks(initAckChunk);
941  Packet *fp = new Packet("INIT-ACK");
942  if (fsm->getState() == SCTP_S_CLOSED) {
943  sendToIP(fp, sctpinitack, state->initialPrimaryPath);
944  }
945  else {
946  sendToIP(fp, sctpinitack);
947  }
948  sctpMain->assocList.push_back(this);
950 }

Referenced by processInitArrived().

◆ sendInvalidStreamError()

void inet::sctp::SctpAssociation::sendInvalidStreamError ( uint16_t  sid)
protected
1870 {
1871  const auto& sctpmsg = makeShared<SctpHeader>();
1872  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
1873  SctpErrorChunk *errorChunk = new SctpErrorChunk();
1874  errorChunk->setSctpChunkType(ERRORTYPE);
1875  SctpSimpleErrorCauseParameter *cause = new SctpSimpleErrorCauseParameter();
1876  cause->setParameterType(INVALID_STREAM_IDENTIFIER);
1877  cause->setByteLength(8);
1878  cause->setValue(sid);
1879  errorChunk->setByteLength(4);
1880  errorChunk->addParameters(cause);
1881  sctpmsg->appendSctpChunks(errorChunk);
1882 
1884  state->ackState = 0;
1885  SctpSackChunk *sackChunk = createSack();
1886 
1887  if (state->auth && state->peerAuth && typeInChunkList(SACK)) {
1888  SctpAuthenticationChunk *authChunk = createAuthChunk();
1889  sctpmsg->appendSctpChunks(authChunk);
1890  auto it = sctpMain->assocStatMap.find(assocId);
1891  it->second.numAuthChunksSent++;
1892  }
1893  sctpmsg->appendSctpChunks(sackChunk);
1894  sendSACKviaSelectedPath(sctpmsg);
1895 }

Referenced by processDataArrived().

◆ sendOnAllPaths()

void inet::sctp::SctpAssociation::sendOnAllPaths ( SctpPathVariables firstPath)
270 {
271  if (state->allowCMT) {
272  // ------ Send on provided path first ... -----------------------------
273  if (firstPath != nullptr) {
274  sendOnPath(firstPath);
275  }
276 
277  // ------ ... then, try sending on all other paths --------------------
278  std::vector<SctpPathVariables *> sortedPaths = getSortedPathMap();
279  for (auto path : sortedPaths) {
280  EV << path->remoteAddress << " [" << path->lastTransmission << "]\t";
281  }
282  EV << endl;
283 
284  for (auto path : sortedPaths) {
285  if (path != firstPath) {
286  sendOnPath(path);
287  path->sendAllRandomizer = RNGCONTEXT uniform(0, (1 << 31));
288  }
289  }
290  if ((state->strictCwndBooking) &&
291  (sctpPathMap.size() > 1)) // T.D. 08.02.2010: strict behaviour only for more than 1 paths!
292  { // T.D. 14.01.2010: Second pass for "Strict Cwnd Booking" option.
293  for (auto path : sortedPaths) {
294  sendOnPath(path, false);
295  }
296  }
297  }
298  else {
299  // ------ Send on provided path first ... -----------------------------
300  if (firstPath != nullptr) {
301  sendOnPath(firstPath);
302  }
303 
304  // ------ ... then, try sending on all other paths --------------------
305  for (auto& elem : sctpPathMap) {
306  SctpPathVariables *path = elem.second;
307  if (path != firstPath) {
308  sendOnPath(path);
309  }
310  }
311  if (state->strictCwndBooking) {
312  // T.D. 14.01.2010: Second pass for "Strict Cwnd Booking" option.
313  sendOnPath(firstPath, false);
314 
315  // ------ Then, try sending on all other paths ---------------------------
316  for (auto& elem : sctpPathMap) {
317  SctpPathVariables *path = elem.second;
318  if (path != firstPath) {
319  sendOnPath(path, false);
320  }
321  }
322  }
323  }
326  state->resetPending = true;
327  }
328 }

Referenced by process_ABORT(), process_CLOSE(), process_RCV_Message(), process_TIMEOUT_BLOCKING(), process_TIMEOUT_RTX(), inet::sctp::SctpAlg::sendCommandInvoked(), sendShutdownAck(), and stateEntered().

◆ sendOnPath()

void inet::sctp::SctpAssociation::sendOnPath ( SctpPathVariables pathId,
const bool  firstPass = true 
)

Utility: Send data from sendQueue.

660 {
661  // ====== Variables ======================================================
662  SctpPathVariables *path = nullptr; // Path to send next message to
663  Ptr<SctpHeader> sctpMsg;
664  SctpSackChunk *sackChunk = nullptr;
665  SctpDataChunk *dataChunkPtr = nullptr;
666  SctpForwardTsnChunk *forwardChunk = nullptr;
667 
668  uint16_t chunksAdded = 0;
669  uint16_t dataChunksAdded = 0;
670  uint32_t totalChunksSent = 0;
671  uint32_t totalPacketsSent = 0;
672  uint32_t outstandingBytes = 0;
673 
674  uint32_t tcount = 0; // Bytes in transmission queue on the selected path
675  uint32_t Tcount = 0; // Bytes in transmission queue on all paths
676  uint32_t scount = 0; // Bytes in send streams
677  int32_t bytesToSend = 0;
678 
679  bool headerCreated = false;
680  bool sendOneMorePacket = false;
681  bool sendingAllowed = true;
682  bool authAdded = false;
683  bool sackAdded = false;
684  bool forwardPresent = false;
685 
686  // ====== Perform Chunk Rescheduling =====================================
687  if ((state->allowCMT) &&
689  {
690  chunkReschedulingControl((pathId == nullptr) ? state->getPrimaryPath() : pathId);
691  }
692 
693  // ====== Obtain path ====================================================
694  EV_INFO << endl << "##### sendAll(";
695  if (pathId) {
696  EV_INFO << pathId->remoteAddress;
697  }
698  EV_INFO << ") at t=" << simTime() << " #####" << endl;
699 
700  unsigned int safetyCounter = 0;
701  while (sendingAllowed && (!state->resetPending || state->waitForResponse)) {
702  if (safetyCounter++ >= 1000) {
703  throw cRuntimeError("Endless loop in SctpAssociation::sendOnPath()?! This should not happen ...");
704  }
705 
706  headerCreated = false;
707  if (state->bytesToRetransmit > 0) {
708  // There are bytes in the transmissionQ. They have to be sent first.
710  assert(path != nullptr);
711  }
712  else {
713  if (pathId == nullptr) { // No path given => use primary path.
714  path = state->getPrimaryPath();
715  }
716  else {
717  path = pathId;
718  }
719  }
722  {
723  if (state->lastTransmission < simTime()) {
725  }
726  if (path->lastTransmission < simTime()) {
727  // T.D. 18.07.2011: Only reset packetsInBurst once per time-stamp!
728  path->packetsInBurst = 0;
729  }
730  }
731  // packetsInBurst must be checked here!
732  // sendOnPath() may be called multiple times at the same simTime!
736  (path->packetsInBurst >= state->maxBurst))
737  {
738  break;
739  }
740  // TotalMaxBurst variant: limit bursts on all paths.
743  {
744  break;
745  }
746  outstandingBytes = path->outstandingBytes;
747  assert((int32_t)outstandingBytes >= 0);
748  auto tq = qCounter.roomTransQ.find(path->remoteAddress);
749  tcount = tq->second;
750  Tcount = getAllTransQ();
751  scount = qCounter.roomSumSendStreams; // includes header and padding
752  EV_INFO << "\nsendAll: on " << path->remoteAddress << ":"
753  << " tcount=" << tcount
754  << " Tcount=" << Tcount
755  << " scount=" << scount
756  << " nextTsn=" << state->nextTsn << endl;
757 
758  bool sackOnly;
759  bool sackWithData;
760  timeForSack(sackOnly, sackWithData);
761  if ((tcount == 0 && scount == 0) || (!state->allowCMT && tcount == 0 && Tcount > 0)) {
762  // ====== No DATA chunks to send ===================================
763  EV_DETAIL << "No DATA chunk available!" << endl;
764  if (!sackOnly) { // SACK?, no data to send
765  EV_DETAIL << "No SACK to send either" << endl;
766  /* if (state->sctpMsg) {
767  EV_DETAIL << "packet was stored -> load packet" << endl;
768  loadPacket(path, &sctpMsg, &chunksAdded, &dataChunksAdded, &authAdded);
769  Packet *pkt = new Packet("DATA");
770  sendToIP(pkt, sctpMsg, path->remoteAddress);
771  }*/
772  return;
773  }
774  else {
775  bytes.bytesToSend = 0;
776  }
777  }
778  else {
779  bytesAllowedToSend(path, firstPass);
780  }
781  bytesToSend = bytes.bytesToSend;
782 
783  // As there is at least a SACK to be sent, a header can be created
784 
785  if (state->sctpMsg) {
786  EV_DETAIL << "packet was stored -> load packet" << endl;
787  loadPacket(path, &sctpMsg, &chunksAdded, &dataChunksAdded, &authAdded);
788  headerCreated = true;
789  }
790  else if (bytesToSend > 0 || bytes.chunk || bytes.packet || sackWithData || sackOnly || forwardPresent) {
791  sctpMsg = makeShared<SctpHeader>();
792  sctpMsg->setChunkLength(B(SCTP_COMMON_HEADER));
793  headerCreated = true;
794  chunksAdded = 0;
795  }
796 
797  if (!sackAdded && (sackWithData || sackOnly)) {
798  // SACK can be sent
799  assert(headerCreated == true);
800  sackChunk = createSack();
801  // CMT DAC
802  if ((state->allowCMT == true) && (state->cmtUseDAC == true)) {
803  EV << "Adding dacPacketsRcvd=" << (unsigned int)dacPacketsRcvd << " to SACK" << endl;
804  sackChunk->setDacPacketsRcvd(dacPacketsRcvd);
805  }
806  dacPacketsRcvd = 0;
807 
808  chunksAdded++;
809  totalChunksSent++;
810  // ------ Create AUTH chunk, if necessary --------------------------
811  authAdded = addAuthChunkIfNecessary(sctpMsg, SACK, authAdded);
812 
813  // ------ Add SACK chunk -------------------------------------------
814  sctpMsg->appendSctpChunks(sackChunk);
815  sackAdded = true;
816  EV_DETAIL << assocId << ": SACK added, chunksAdded now " << chunksAdded << " sackOnly=" << sackOnly << " sackWithData=" << sackWithData << "\n";
817  if (sackOnly && !(bytesToSend > 0 || bytes.chunk || bytes.packet)) {
818  // There is no data to be sent, just the SACK
819  path->lastTransmission = simTime();
820  path->packetsInBurst++;
821  state->lastTransmission = simTime();
823  state->ackState = 0;
824  // Stop SACK timer if it is running...
827  state->sackAllowed = false;
828  sendSACKviaSelectedPath(sctpMsg);
829  sctpMsg = nullptr;
830  return;
831  }
832  }
833  // ====== FORWARD_TSN =================================================
834  if (!forwardPresent && !state->stopSending) {
835  if (peekAbandonedChunk(path) != nullptr) {
836  forwardChunk = createForwardTsnChunk(path->remoteAddress);
837  chunksAdded++;
838  totalChunksSent++;
839  state->ackPointAdvanced = false;
840  if (!headerCreated) {
841  sctpMsg = makeShared<SctpHeader>();
842  sctpMsg->setChunkLength(B(SCTP_COMMON_HEADER));
843  headerCreated = true;
844  chunksAdded = 0;
845  }
846  // ------ Create AUTH chunk, if necessary -----------------------
847  authAdded = addAuthChunkIfNecessary(sctpMsg, FORWARD_TSN, authAdded);
848  sctpMsg->appendSctpChunks(forwardChunk);
849  forwardPresent = true;
850  if (!path->T3_RtxTimer->isScheduled()) {
851  // Start retransmission timer, if not scheduled before
852  startTimer(path->T3_RtxTimer, path->pathRto);
853  }
854  if (bytesToSend == 0) {
855  Packet *pkt = new Packet("DATA");
856  sendToIP(pkt, sctpMsg, path->remoteAddress);
857  sctpMsg = nullptr;
858  forwardPresent = false;
859  headerCreated = false;
860  chunksAdded = 0;
861  }
862  }
863  }
864 
865  // ####################################################################
866  // #### Data Transmission ####
867  // ####################################################################
868 
869  bool packetFull = false;
870 
871  while (!packetFull && headerCreated) {
872  assert(headerCreated == true);
873  EV_DETAIL << assocId << ": bytesToSend=" << bytesToSend
874  << " bytes.chunk=" << bytes.chunk
875  << " bytes.packet=" << bytes.packet << endl;
876 
877  // ====== How many bytes may be transmitted in next packet? ========
878  int32_t allowance = path->pmtu; // Default behaviour: send 1 path MTU
879  // Restrict amount of data to send to cwnd size.
880  if ((state->strictCwndBooking) &&
881  (sctpPathMap.size() > 1)) // strict behaviour only for more than 1 paths!
882  { // T.D. 19.01.2010: bytesToSend may be less than 1 MTU on this path.
883  // Allow overbooking in second pass, if *total* cwnd allows it.
884  if (!firstPass) {
885  // No "one packet"/"one chunk" in second pass!
886  bytes.packet = false;
887  bytes.chunk = false;
888  }
889 
890  if (bytes.chunk) {
891  // Send 1 chunk: allow one path MTU.
892  }
893  else if (bytes.packet) {
894  // Send 1 chunk: allow one path MTU.
895  }
896  else if ((path->outstandingBytes == 0) && (firstPass)) {
897  // No outstanding data and first pass: allow one path MTU.
898  }
899  else { // There *may* be something more to send ...
900  if ((int32_t)path->cwnd - (int32_t)path->outstandingBytes >= (int32_t)path->pmtu) {
901  // Enough space -> allow one path MTU
902  }
903  else {
904  if (firstPass) {
905  // In first pass, disallow overbooking.
906  allowance = 0;
907  bytesToSend = 0;
908  }
909  else {
910  if (!state->allowCMT) {
911  // For non-CMT in second pass, allow 1 more MTU.
912  }
913  else {
914  // Not CMT in second pass, check total space ...
915  int32_t totalOutstanding = 0;
916  int32_t totalCwnd = 0;
917  for (SctpPathMap::const_iterator pathMapIterator = sctpPathMap.begin();
918  pathMapIterator != sctpPathMap.end(); pathMapIterator++)
919  {
920  const SctpPathVariables *myPath = pathMapIterator->second;
921  totalOutstanding += myPath->outstandingBytes;
922  totalCwnd += myPath->cwnd;
923  }
924  if ((int32_t)(totalCwnd - totalOutstanding) < (int32_t)(path->pmtu)) {
925  // ... and disallow overbooking if there is no more space for 1 MTU
926  allowance = 0;
927  bytesToSend = 0;
928  }
929  else {
930  // ... and allow 1 MTU if there is still space
931  }
932  }
933  }
934  }
935  }
936  }
937  else {
938  if ((bytesToSend > 0) || (bytes.chunk) || (bytes.packet)) {
939  // Allow 1 more MTU
940  }
941  else {
942  // No more sending allowed.
943  allowance = 0;
944  bytesToSend = 0;
945  }
946  }
947  if ((allowance > 0) || (bytes.chunk) || (bytes.packet)) {
948  bool firstTime = false; // Is DATA chunk send for the first time?
949  SctpDataVariables *datVar = nullptr;
950  // ------ Create AUTH chunk, if necessary -----------------------
951  authAdded = addAuthChunkIfNecessary(sctpMsg, DATA, authAdded);
952  if (tcount > 0) {
953  // ====== Retransmission ========================================
954  // If bytes.packet is true, one packet is allowed to be retransmitted!
955  datVar = getOutboundDataChunk(path,
956  path->pmtu - B(sctpMsg->getChunkLength()).get() - 20,
957  (bytes.packet == true) ? path->pmtu : allowance);
958  if (datVar == nullptr) {
959  if (chunksAdded == 1 && sackAdded) {
960  datVar = getOutboundDataChunk(path,
961  path->pmtu - B(sctpMsg->getChunkLength()).get() + sackChunk->getByteLength() - 20,
962  (bytes.packet == true) ? path->pmtu : allowance);
963  if (!sackOnly) {
964  auto x = sctpMsg->removeFirstChunk();
965  ASSERT(x == sackChunk);
966  EV_DETAIL << "RTX: Remove SACK chunk\n";
967  delete sackChunk;
968  chunksAdded--;
969  sackAdded = false;
970  }
971  else {
972  path->lastTransmission = simTime();
973  path->packetsInBurst++;
974  state->lastTransmission = simTime();
976  if (dataChunksAdded > 0) {
977  state->ssNextStream = true;
978  }
979  state->ackState = 0;
980  // Stop SACK timer if it is running...
983  state->sackAllowed = false;
984  EV_DETAIL << "RTX: send only SACK\n";
985  sendSACKviaSelectedPath(sctpMsg);
986  sctpMsg = nullptr;
987 
988  // TD 17.02.2015: There is data to send (on current path) -> create new message structure!
989  sctpMsg = makeShared<SctpHeader>();
990 // sctpMsg = makeShared<SctpHeader>();
991  sctpMsg->setChunkLength(B(SCTP_COMMON_HEADER));
992  headerCreated = true;
993  sackAdded = false;
994  chunksAdded = 0;
995  }
996  }
997  }
998 
999  // Check for FORWARD-TSN again, might just have been triggered...
1000  if (datVar == nullptr && !forwardPresent && !state->stopSending) {
1001  if (peekAbandonedChunk(path) != nullptr) {
1002  forwardChunk = createForwardTsnChunk(path->remoteAddress);
1003  chunksAdded++;
1004  totalChunksSent++;
1005  state->ackPointAdvanced = false;
1006  // ------ Create AUTH chunk, if necessary -----------------------
1007  authAdded = addAuthChunkIfNecessary(sctpMsg, FORWARD_TSN, authAdded);
1008  sctpMsg->appendSctpChunks(forwardChunk);
1009  forwardPresent = true;
1010  if (!path->T3_RtxTimer->isScheduled()) {
1011  // Start retransmission timer, if not scheduled before
1012  startTimer(path->T3_RtxTimer, path->pathRto);
1013  }
1014  }
1015  }
1016 
1017  if (datVar != nullptr) {
1018  assert(datVar->getNextDestinationPath() == path);
1019  datVar->numberOfRetransmissions++;
1020  if (chunkHasBeenAcked(datVar) == false) {
1021  EV_DETAIL << simTime() << ": Retransmission #" << datVar->numberOfRetransmissions
1022  << " of TSN " << datVar->tsn
1023  << " on path " << datVar->getNextDestination()
1024  << " (last was " << datVar->getLastDestination() << ")" << endl;
1025  // The chunk is going to be retransmitted on another path.
1026  // On the original path, it is necessary to find another
1027  // PseudoCumAck!
1028  if (datVar->getLastDestinationPath() != datVar->getNextDestinationPath()) {
1029  SctpPathVariables *oldPath = datVar->getLastDestinationPath();
1030  oldPath->findPseudoCumAck = true;
1031  oldPath->findRTXPseudoCumAck = true;
1032  SctpPathVariables *newPath = datVar->getNextDestinationPath();
1033  newPath->findPseudoCumAck = true;
1034  newPath->findRTXPseudoCumAck = true;
1035  }
1036  datVar->wasDropped = false;
1037  datVar->countsAsOutstanding = true;
1038  datVar->hasBeenReneged = false;
1039  increaseOutstandingBytes(datVar, path); // NOTE: path == datVar->getNextDestinationPath()
1040  }
1041  }
1042  }
1043  // ====== First Transmission ====================================
1044  else if (((scount > 0) && (!state->nagleEnabled)) || // Data to send and Nagle off
1045  ((uint32_t)scount >= path->pmtu - 32 - 20) || // Data to fill at least one path MTU
1046  ((scount > 0) && (state->nagleEnabled) && ((outstandingBytes == 0) || (sackOnly && sackAdded))) || // Data to send, Nagle on and no outstanding bytes
1047  state->bundleReset)
1048  { // ====== Buffer Splitting ===================================
1049  bool rejected = false;
1050  const uint32_t bytesOnPath = (state->cmtBufferSplittingUsesOSB == true) ?
1051  path->outstandingBytes : path->queuedBytes;
1052  if (state->allowCMT) {
1053  // ------ Sender Side -------------------------------------
1056  {
1057  // Limit is 1/n of current sender-side buffer allocation
1058  const uint32_t limit = ((state->sendQueueLimit != 0) ? state->sendQueueLimit : 0xffffffff) / sctpPathMap.size();
1059  if (bytesOnPath + path->pmtu > limit) {
1060  rejected = true;
1061  EV << simTime() << ":\tSenderBufferSplitting: Rejecting transmission on "
1062  << path->remoteAddress << ", since "
1063  << bytesOnPath << " + " << path->pmtu << " > "
1064  << state->sendQueueLimit / sctpPathMap.size() << endl;
1065  }
1066  }
1067 
1068  // ------ Receiver Side -----------------------------------
1069  if ((rejected == false) &&
1072  {
1073  // Limit is 1/n of current receiver-side buffer allocation
1074  const uint32_t limit = (state->peerRwnd + state->outstandingBytes)
1075  / sctpPathMap.size();
1076  if (bytesOnPath + path->pmtu > limit + path->pmtu) {
1077  // T.D. 09.07.2011: Allow overbooking by up to 1 MTU ...
1078  EV << simTime() << ":\tReceiverBufferSplitting: Rejecting transmission on "
1079  << path->remoteAddress << ", since "
1080  << bytesOnPath + path->pmtu << " > " << limit << endl;
1081  rejected = true;
1082  }
1083  }
1084  }
1085 
1086  // ====== Buffer Splitting ===================================
1087  if (((state->allowCMT) || (path == state->getPrimaryPath())) &&
1088  (!rejected))
1089  {
1090  // ------ Dequeue data message ----------------------------
1091  EV_DETAIL << assocId << "sendAll: sctpMsg->length=" << B(sctpMsg->getChunkLength()).get()
1092  << " length datMsg=" << path->pmtu - B(sctpMsg->getChunkLength()).get() - 20 << endl;
1093  SctpDataMsg *datMsg = dequeueOutboundDataMsg(path, path->pmtu - B(sctpMsg->getChunkLength()).get() - 20,
1094  allowance);
1095  if (datMsg == nullptr) {
1096  if (chunksAdded == 1 && sackAdded) {
1097  datMsg = dequeueOutboundDataMsg(path, path->pmtu - B(sctpMsg->getChunkLength()).get() + sackChunk->getByteLength() - 20,
1098  allowance);
1099  if (!sackOnly) {
1100  sctpMsg->removeFirstChunk();
1101  EV_INFO << assocId << ": delete SACK chunk to make room for datMsg (" << &datMsg << "). scount=" << scount << "\n";
1102  delete sackChunk;
1103  chunksAdded--;
1104  sackAdded = false;
1105  }
1106  else {
1107  path->lastTransmission = simTime();
1108  path->packetsInBurst++;
1109  state->lastTransmission = simTime();
1111  if (dataChunksAdded > 0) {
1112  state->ssNextStream = true;
1113  }
1114  state->ackState = 0;
1115  // Stop SACK timer if it is running...
1118  state->sackAllowed = false;
1119  EV_DETAIL << assocId << ": send SACK and make new header for datMsg (" << &datMsg << "). scount=" << scount << "\n";
1120  sendSACKviaSelectedPath(sctpMsg);
1121  sctpMsg = nullptr;
1122  if (datMsg != nullptr) {
1123  sctpMsg = makeShared<SctpHeader>();
1124 // sctpMsg = makeShared<SctpHeader>();
1125  sctpMsg->setChunkLength(B(SCTP_COMMON_HEADER));
1126  headerCreated = true;
1127  sackAdded = false;
1128  chunksAdded = 0;
1129  }
1130  }
1131  }
1132  }
1133  // ------ Handle data message -----------------------------
1134  if (datMsg) {
1135  firstTime = true;
1136  if (datMsg->getFragment()) {
1137  if (datMsg->getBBit() && !datMsg->getEBit()) {
1138  state->fragInProgress = true;
1139  setFragInProgressOfStream(datMsg->getSid(), true);
1140  }
1141  if (datMsg->getEBit()) {
1142  state->fragInProgress = false;
1143  setFragInProgressOfStream(datMsg->getSid(), true);
1144  }
1145  }
1146  state->queuedMessages--;
1147  if ((state->queueLimit > 0) &&
1149  (state->queueUpdate == false))
1150  {
1151  // Tell upper layer readiness to accept more data
1153  state->queueUpdate = true;
1154  }
1155 
1156  datVar = makeDataVarFromDataMsg(datMsg, path);
1157  delete datMsg;
1158 
1159  EV_DETAIL << assocId << ":: sendAll: chunk " << datVar << " dequeued from StreamQ "
1160  << datVar->sid << ": tsn=" << datVar->tsn
1161  << ", bytes now " << qCounter.roomSumSendStreams << "\n";
1162  }
1163  // ------ No data message has been dequeued ---------------
1164  else {
1165  EV_DETAIL << assocId << ": No data message has been dequeued" << endl;
1166  // ------ Are there any chunks to send? ----------------
1167  if (chunksAdded == 0) {
1168  // No -> nothing more to do.
1169  if (state->sctpMsg == sctpMsg) {
1170  state->sctpMsg = nullptr;
1171  state->packetBytes = 0;
1172  }
1173  packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop
1174  }
1175  else {
1176  // Yes.
1177  if (state->nagleEnabled && ((outstandingBytes > 0) && !(sackOnly && sackAdded)) &&
1178  nextChunkFitsIntoPacket(path, path->pmtu - B(sctpMsg->getChunkLength()).get() - 20) &&
1179  (B(sctpMsg->getChunkLength()).get() < path->pmtu - 32 - 20) && (tcount == 0))
1180  {
1181  EV_DETAIL << "Nagle: Packet has to be stored\n";
1182  storePacket(path, sctpMsg, chunksAdded, dataChunksAdded, authAdded);
1183  sctpMsg = nullptr;
1184  chunksAdded = 0;
1185  }
1186  packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop
1187  EV_DETAIL << "sendAll: packetFull: msg length = " << B(sctpMsg->getChunkLength()).get() + 20 << "\n";
1188  }
1189  }
1190  }
1191  else if (chunksAdded == 1 && sackAdded && !sackOnly) {
1192  sctpMsg->removeFirstChunk();
1193  EV_DETAIL << "Nagle or no data: Remove SACK chunk, delete sctpmsg" << endl;
1194  delete sackChunk;
1195  packetFull = true;
1196  sackAdded = false;
1197  chunksAdded--;
1198  }
1199  else if ((chunksAdded == 1 && sackAdded && sackOnly) || headerCreated) {
1200  packetFull = true;
1201  /* TD 19.02.2015:
1202  If we are not on the primary path, and
1203  there is a small chunk to send (bytesToSend > 0),
1204  and Nagle turned on:
1205  leave inner loop. Otherwise, there will be an infinite loop! */
1206  bytesToSend = 0;
1207  }
1208  }
1209  else if (chunksAdded == 1 && sackAdded && !sackOnly) {
1210  sctpMsg->removeFirstChunk();
1211  EV_DETAIL << "Nagle or no data: Remove SACK chunk, delete sctpmsg\n";
1212  delete sackChunk;
1213  packetFull = true;
1214  sackAdded = false;
1215  chunksAdded--;
1216  }
1217  else if (chunksAdded == 1 && sackAdded && sackOnly) {
1218  packetFull = true;
1219  }
1220  else if (datVar == nullptr || chunksAdded == 0) {
1221  EV_DETAIL << "HeaderCreated=" << headerCreated << ", chunksAdded=" << chunksAdded << " datVar=" << datVar << "\n";
1222  if (headerCreated) {
1223  packetFull = true;
1224  }
1225  }
1226 
1227  // ------ Handle DATA chunk -------------------------------------
1228  if (datVar != nullptr && !packetFull) {
1229  // ------ Assign TSN -----------------------------------------
1230  if (firstTime) {
1231  assert(datVar->tsn == 0);
1232  datVar->tsn = state->nextTsn;
1233  EV_DETAIL << "sendAll: set TSN=" << datVar->tsn
1234  << " sid=" << datVar->sid << ", ssn=" << datVar->ssn << "\n";
1235  state->nextTsn++;
1236  path->vectorPathSentTsn->record(datVar->tsn);
1237  }
1238  else {
1239  if (datVar->hasBeenFastRetransmitted) {
1240  path->vectorPathTsnFastRTX->record(datVar->tsn);
1241  }
1242  else {
1243  path->vectorPathTsnTimerBased->record(datVar->tsn);
1244  }
1245  }
1246 
1247  auto iterator = sctpMain->assocStatMap.find(assocId);
1248  iterator->second.transmittedBytes += datVar->len / 8;
1249 
1250  datVar->setLastDestination(path);
1251  datVar->countsAsOutstanding = true;
1252  datVar->hasBeenReneged = false;
1253  datVar->sendTime = simTime(); // I.R. to send Fast RTX just once a RTT
1254  if (datVar->firstSendTime == 0) {
1255  datVar->firstSendTime = simTime();
1256  }
1257 
1258  // ------ First transmission of datVar -----------------------
1259  if (datVar->numberOfTransmissions == 0) {
1260  EV_DETAIL << "sendAll: " << simTime() << " firstTime, TSN "
1261  << datVar->tsn << ": lastDestination set to "
1262  << datVar->getLastDestination() << endl;
1263 
1264  if (!state->firstDataSent) {
1265  state->firstDataSent = true;
1266  }
1267  EV_DETAIL << "sendAll: insert in retransmissionQ tsn=" << datVar->tsn << "\n";
1268  if (!retransmissionQ->checkAndInsertChunk(datVar->tsn, datVar)) {
1269  throw cRuntimeError("Cannot add datVar to retransmissionQ!");
1270  // Falls es hier aufschlaegt, muss ueberlegt werden, ob es OK ist, dass datVars nicht eingefuegt werden koennen.
1271  }
1272  else {
1273  EV_DETAIL << "sendAll: size of retransmissionQ=" << retransmissionQ->getQueueSize() << "\n";
1274  unackChunk(datVar);
1275  increaseOutstandingBytes(datVar, path);
1276  datVar->queuedOnPath = path;
1277  datVar->queuedOnPath->queuedBytes += datVar->booksize;
1278  datVar->queuedOnPath->statisticsPathQueuedSentBytes->record(path->queuedBytes);
1279 
1280  state->queuedSentBytes += datVar->booksize;
1282  }
1283  }
1284 
1285  /* datVar is already in the retransmissionQ */
1286  datVar->numberOfTransmissions++;
1287  datVar->gapReports = 0;
1288  datVar->hasBeenFastRetransmitted = false;
1289  EV_DETAIL << "sendAll(): adding new outbound data datVar to packet (tsn=" << datVar->tsn << ")...!!!\n";
1290  /* update counters */
1291  totalChunksSent++;
1292  chunksAdded++;
1293  dataChunksAdded++;
1294 
1295  dataChunkPtr = transformDataChunk(datVar);
1296  sctpMsg->appendSctpChunks(dataChunkPtr);
1297 
1298  EV_DETAIL << assocId << ": DataChunk added - TSN:" << dataChunkPtr->getTsn() << " - length:" << dataChunkPtr->getByteLength() << " - ssn:" << dataChunkPtr->getSsn() << "\n";
1299 
1300  if (datVar->numberOfTransmissions > 1) {
1301  auto tq = qCounter.roomTransQ.find(path->remoteAddress);
1302  if (tq->second > 0) {
1303  if (transmissionQ->getSizeOfFirstChunk(path->remoteAddress) > path->pmtu - B(sctpMsg->getChunkLength()).get() - 20)
1304  packetFull = true;
1305  }
1306  else if (nextChunkFitsIntoPacket(path, path->pmtu - B(sctpMsg->getChunkLength()).get() - 20) == false) {
1307  packetFull = true;
1308  }
1309  }
1310  else {
1311  if (nextChunkFitsIntoPacket(path, path->pmtu - B(sctpMsg->getChunkLength()).get() - 20) == false) {
1312  packetFull = true;
1313  }
1314  }
1315 
1316  state->peerRwnd -= (datVar->booksize + state->bytesToAddPerPeerChunk);
1317  if (state->peerAllowsChunks) {
1318  state->peerMsgRwnd--;
1319  }
1320  if ((bytes.chunk == false) && (bytes.packet == false)) {
1321  bytesToSend -= datVar->booksize;
1322  }
1323  else if (bytes.chunk) {
1324  bytes.chunk = false;
1325  }
1326  else if ((bytes.packet) && (packetFull)) {
1327  bytes.packet = false;
1328  }
1329 
1330  if (bytesToSend <= 0) {
1331  if ((!packetFull) && (qCounter.roomSumSendStreams > path->pmtu - 32 - 20 || tcount > 0)) {
1332  sendOneMorePacket = true;
1333  bytes.packet = true;
1334  EV_DETAIL << assocId << ": sendAll: one more packet allowed\n";
1335  }
1336  else {
1337  if (state->nagleEnabled && (outstandingBytes > 0) &&
1338  nextChunkFitsIntoPacket(path, path->pmtu - B(sctpMsg->getChunkLength()).get() - 20) &&
1339  (B(sctpMsg->getChunkLength()).get() < path->pmtu - 32 - 20) && (tcount == 0))
1340  {
1341  storePacket(path, sctpMsg, chunksAdded, dataChunksAdded, authAdded);
1342  sctpMsg = nullptr;
1343  chunksAdded = 0;
1344  packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop
1345  }
1346  else {
1347  packetFull = true;
1348  }
1349  }
1350  bytesToSend = 0;
1351  }
1352  else if ((qCounter.roomSumSendStreams == 0) && (tq->second == 0)) {
1353  packetFull = true;
1354  EV_DETAIL << "sendAll: no data in send and transQ: packet full\n";
1355  }
1356  EV_DETAIL << "sendAll: bytesToSend after reduction: " << bytesToSend << "\n";
1357  } // end if (datVar != nullptr && !packetFull)
1358  // ------ There is no DATA chunk, only control chunks possible --
1359  else {
1360  if (chunksAdded == 0) { // Nothing to do -> return
1361  packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop
1362  }
1363  else {
1364  packetFull = true;
1365  EV_DETAIL << assocId << ": sendAll: packetFull: msg length = " << B(sctpMsg->getChunkLength()).get() + 20 << "\n";
1366  datVar = nullptr;
1367  }
1368  delete datVar;
1369  }
1370 
1371  // ====== Send packet ===========================================
1372  if (packetFull) {
1373  if (chunksAdded == 0) { // Nothing to send
1374  sctpMsg = nullptr;
1375  sendingAllowed = false; // sendingAllowed==false => leave outer while loop
1376  }
1377  else {
1378  EV_DETAIL << assocId << ":: sendAll: " << simTime() << " packet full:"
1379  << " totalLength=" << B(sctpMsg->getChunkLength()).get() + 20
1380  << ", path=" << path->remoteAddress
1381  << " " << dataChunksAdded << " chunks added, outstandingBytes now "
1382  << path->outstandingBytes << "\n";
1383 
1384  /* new chunks would exceed MTU, so we send old packet and build a new one */
1385  /* this implies that at least one data chunk is send here */
1386  if (dataChunksAdded > 0) {
1387  if (!path->T3_RtxTimer->isScheduled()) {
1388  // Start retransmission timer, if not scheduled before
1389  startTimer(path->T3_RtxTimer, path->pathRto);
1390  }
1391  else {
1392  EV_DETAIL << "sendAll: RTX Timer already scheduled -> no need to schedule it\n";
1393  }
1394  }
1395  else {
1396  bytes.packet = false; // TD 23.02.2015: no DATA chunks => done.
1397  }
1398 
1399  if (sendOneMorePacket) {
1400  sendOneMorePacket = false;
1401  bytesToSend = 0;
1402  bytes.packet = false;
1403  size_t len = sctpMsg->getSctpChunksArraySize() - 1;
1404  SctpChunk *chunk = (SctpChunk *)sctpMsg->getSctpChunks(len);
1405  SctpDataChunk *pkt = check_and_cast<SctpDataChunk *>(chunk);
1406 // SctpDataChunk *pkt = check_and_cast<SctpDataChunk *>(sctpMsg->getSctpChunks(sctpMsg->getSctpChunksArraySize() - 1));
1407  pkt->setIBit(sctpMain->sackNow);
1408  sctpMsg->setSctpChunks(sctpMsg->getSctpChunksArraySize() - 1, pkt);
1409  }
1410 
1411  // Set I-bit when this is the final packet for this path!
1412  const int32_t a = (int32_t)path->cwnd - (int32_t)path->outstandingBytes;
1413  if ((((a > 0) && (nextChunkFitsIntoPacket(path, a) == false)) || (!firstPass)) && !forwardPresent) {
1414  SctpDataChunk *pkt = check_and_cast<SctpDataChunk *>(sctpMsg->peekLastChunk());
1415  pkt->setIBit(sctpMain->sackNow);
1416  }
1417 
1418  if (dataChunksAdded > 0) {
1419  state->ssNextStream = true;
1420  }
1421  EV_DETAIL << assocId << ":sendToIP: packet size=" << B(sctpMsg->getChunkLength()).get() << " numChunks=" << sctpMsg->getSctpChunksArraySize() << "\n";
1422  Packet *pkt = new Packet("DATA");
1423  sendToIP(pkt, sctpMsg, path->remoteAddress);
1424  sctpMsg = nullptr;
1425  pmDataIsSentOn(path);
1426  totalPacketsSent++;
1427  path->lastTransmission = simTime();
1428  path->packetsInBurst++;
1429  state->lastTransmission = simTime();
1431 
1432  // ------ Reset status ------------------------------------
1433  firstTime = false;
1434  headerCreated = false;
1435  chunksAdded = 0;
1436  dataChunksAdded = 0;
1437  authAdded = false;
1438 
1439  EV_INFO << "sendAll: sending Packet to path " << path->remoteAddress
1440  << " scount=" << scount
1441  << " tcount=" << tcount
1442  << " bytesToSend=" << bytesToSend << endl;
1443  }
1444  }
1445  EV_INFO << "sendAll: still " << bytesToSend
1446  << " bytes to send, headerCreated=" << headerCreated << endl;
1447  } // if (bytesToSend > 0 || bytes.chunk || bytes.packet)
1448  else if (headerCreated && state->bundleReset) {
1449  Packet *pkt = new Packet("DATA");
1450  sendToIP(pkt, sctpMsg, path->remoteAddress);
1451  sctpMsg = nullptr;
1452  return;
1453  }
1454  else {
1455  packetFull = true; // Leave inner while loop
1456  sctpMsg = nullptr;
1457  }
1458 
1459  EV_INFO << "packetFull=" << packetFull << endl;
1460  } // while(!packetFull)
1461 
1462  EV_INFO << "bytesToSend=" << bytesToSend
1463  << " bytes.chunk=" << bytes.chunk
1464  << " bytes.packet=" << bytes.packet << endl;
1465  if (!(bytesToSend > 0 || bytes.chunk || bytes.packet)) {
1466  sendingAllowed = false;
1467  }
1468  } // while(sendingAllowed)
1469 
1470  if (state->ackState >= sackFrequency)
1471  sendSack();
1472 
1473  EV_INFO << "sendAll: nothing more to send... BYE!\n";
1474 }

Referenced by sendBundledOutgoingResetAndResponse(), inet::sctp::SctpAlg::sendCommandInvoked(), sendDoubleStreamResetResponse(), sendOnAllPaths(), sendOutgoingResetRequest(), sendStreamResetRequest(), and sendStreamResetResponse().

◆ sendOutgoingRequestAndResponse() [1/2]

void inet::sctp::SctpAssociation::sendOutgoingRequestAndResponse ( SctpIncomingSsnResetRequestParameter inRequestParam,
SctpOutgoingSsnResetRequestParameter outRequestParam 
)
protected
454 {
455  uint16_t len = 0;
456  EV_INFO << "sendOutgoingRequestAndResponse to " << remoteAddr << "\n";
457  const auto& msg = makeShared<SctpHeader>();
458  msg->setChunkLength(B(SCTP_COMMON_HEADER));
459  msg->setSrcPort(localPort);
460  msg->setDestPort(remotePort);
461  SctpStreamResetChunk *resChunk = new SctpStreamResetChunk();
462  resChunk->setSctpChunkType(RE_CONFIG);
463  resChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
464  uint32_t srsn = state->streamResetSequenceNumber;
465  SctpResetTimer *rt = new SctpResetTimer();
466  SctpOutgoingSsnResetRequestParameter *outResetParam;
467  outResetParam = new SctpOutgoingSsnResetRequestParameter();
468  outResetParam->setParameterType(OUTGOING_RESET_REQUEST_PARAMETER);
469  outResetParam->setSrReqSn(srsn);
470  outResetParam->setSrResSn(inRequestParam->getSrReqSn());
471  outResetParam->setLastTsn(state->nextTsn - 1);
472  if (inRequestParam->getStreamNumbersArraySize() > 0) {
473  outResetParam->setStreamNumbersArraySize(inRequestParam->getStreamNumbersArraySize());
474  for (uint i = 0; i < inRequestParam->getStreamNumbersArraySize(); i++) {
475  outResetParam->setStreamNumbers(i, (uint16_t)inRequestParam->getStreamNumbers(i));
476  state->resetOutStreams.push_back(outResetParam->getStreamNumbers(i));
477  state->requests[srsn].streams.push_back(outResetParam->getStreamNumbers(i));
478  len++;
479  }
480  }
481  outResetParam->setByteLength(SCTP_OUTGOING_RESET_REQUEST_PARAMETER_LENGTH + len * 2);
482  resChunk->addParameter(outResetParam);
484  SctpStreamResetResponseParameter *responseParam = new SctpStreamResetResponseParameter();
485  responseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
486  responseParam->setSrResSn(outRequestParam->getSrReqSn());
487  responseParam->setResult(1);
488  responseParam->setByteLength(SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH);
489  resChunk->addParameter(responseParam);
490  rt->setInSN(srsn - 1);
491  rt->setInAcked(false);
492  rt->setOutSN(outRequestParam->getSrReqSn());
493  rt->setOutAcked(false);
494  if (state->resetChunk != nullptr) {
495  delete state->resetChunk;
496  state->resetChunk = nullptr;
497  }
498  auto it = sctpMain->assocStatMap.find(assocId);
499  it->second.numResetRequestsSent++;
500  state->resetChunk = check_and_cast<SctpStreamResetChunk *>(resChunk->dup());
501 // state->resetChunk->setName("stateRstChunk");
502  msg->appendSctpChunks(resChunk);
503  Packet *pkt = new Packet("RE_CONFIG");
504  sendToIP(pkt, msg, remoteAddr);
505  if (PK(getPath(remoteAddr)->ResetTimer)->hasEncapsulatedPacket()) {
506  PK(getPath(remoteAddr)->ResetTimer)->decapsulate();
507  }
508  PK(getPath(remoteAddr)->ResetTimer)->encapsulate(rt);
509  startTimer(getPath(remoteAddr)->ResetTimer, getPath(remoteAddr)->pathRto);
510 }

◆ sendOutgoingRequestAndResponse() [2/2]

void inet::sctp::SctpAssociation::sendOutgoingRequestAndResponse ( uint32_t  inRequestSn,
uint32_t  outRequestSn 
)
protected
410 {
411  EV_INFO << "sendOutgoingResetRequest to " << remoteAddr << "\n";
412  const auto& msg = makeShared<SctpHeader>();
413  msg->setChunkLength(B(SCTP_COMMON_HEADER));
414  msg->setSrcPort(localPort);
415  msg->setDestPort(remotePort);
416  SctpStreamResetChunk *resChunk = new SctpStreamResetChunk();
417  resChunk->setSctpChunkType(RE_CONFIG);
418  resChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
419  uint32_t srsn = state->streamResetSequenceNumber;
420  SctpResetTimer *rt = new SctpResetTimer();
421  SctpOutgoingSsnResetRequestParameter *outResetParam;
422  outResetParam = new SctpOutgoingSsnResetRequestParameter();
423  outResetParam->setParameterType(OUTGOING_RESET_REQUEST_PARAMETER);
424  outResetParam->setSrReqSn(srsn++);
425  outResetParam->setSrResSn(inRequestSn);
426  outResetParam->setLastTsn(state->nextTsn - 1);
427  outResetParam->setByteLength(SCTP_OUTGOING_RESET_REQUEST_PARAMETER_LENGTH);
428  resChunk->addParameter(outResetParam);
430  SctpStreamResetResponseParameter *responseParam = new SctpStreamResetResponseParameter();
431  responseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
432  responseParam->setSrResSn(outRequestSn);
433  responseParam->setResult(1);
434  responseParam->setByteLength(SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH);
435  resChunk->addParameter(responseParam);
436  rt->setInSN(srsn - 1);
437  rt->setInAcked(false);
438  rt->setOutSN(outRequestSn);
439  rt->setOutAcked(false);
440  if (state->resetChunk != nullptr) {
441  delete state->resetChunk;
442  state->resetChunk = nullptr;
443  }
444  state->resetChunk = resChunk->dup();
445  msg->appendSctpChunks(resChunk);
446  Packet *pkt = new Packet("RE_CONFIG");
447  sendToIP(pkt, msg, remoteAddr);
448  PK(getPath(remoteAddr)->ResetTimer)->encapsulate(rt);
449  startTimer(getPath(remoteAddr)->ResetTimer, getPath(remoteAddr)->pathRto);
450 }

Referenced by process_RCV_Message(), and processInAndOutResetRequestArrived().

◆ sendOutgoingResetRequest()

void inet::sctp::SctpAssociation::sendOutgoingResetRequest ( SctpIncomingSsnResetRequestParameter requestParam)
protected
117 {
118  EV_INFO << "sendOutgoingResetRequest to " << remoteAddr << "\n";
119  uint16_t len = 0;
120  uint32_t srsn = 0;
121  if ((!(getPath(remoteAddr)->ResetTimer->isScheduled())) || state->requestsOverlap) {
122  state->requestsOverlap = false;
123  SctpStreamResetChunk *resetChunk = new SctpStreamResetChunk();
124  resetChunk->setSctpChunkType(RE_CONFIG);
125  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
126  SctpOutgoingSsnResetRequestParameter *outResetParam;
127  outResetParam = new SctpOutgoingSsnResetRequestParameter();
128  outResetParam->setParameterType(OUTGOING_RESET_REQUEST_PARAMETER);
129  SctpStateVariables::RequestData *resDat = state->findTypeInRequests(OUTGOING_RESET_REQUEST_PARAMETER);
130  if (resDat != nullptr && resDat->sn == state->streamResetSequenceNumber - 1) {
131  srsn = state->streamResetSequenceNumber - 1;
132  }
133  else {
135  state->requests[srsn].result = 100;
137  state->requests[srsn].sn = srsn;
139  }
140  outResetParam->setSrReqSn(srsn++);
141  outResetParam->setSrResSn(requestParam->getSrReqSn());
142  if (state->findPeerRequestNum(requestParam->getSrReqSn())) {
143  state->peerRequests[requestParam->getSrReqSn()].result = PERFORMED;
144  state->firstPeerRequest = false;
145  if (state->incomingRequestSet && state->incomingRequest != nullptr) {
146  delete state->incomingRequest;
147  state->incomingRequest = nullptr;
148  state->incomingRequestSet = false;
149  }
150  }
151  outResetParam->setLastTsn(state->nextTsn - 1);
152  if (state->peerStreamsToReset.size() > 0) {
153  outResetParam->setStreamNumbersArraySize(state->peerStreamsToReset.size());
154  uint16_t i = 0;
155  for (std::list<uint16_t>::iterator it = state->peerStreamsToReset.begin(); it != state->peerStreamsToReset.end(); ++it) {
156  outResetParam->setStreamNumbers(i, *it);
157  state->resetOutStreams.push_back(outResetParam->getStreamNumbers(i));
158  state->requests[srsn - 1].streams.push_back(outResetParam->getStreamNumbers(i));
159  i++;
160  }
161  len = state->peerStreamsToReset.size() * 2;
162  state->peerStreamsToReset.clear();
163  }
164  else if (state->streamsToReset.size() > 0) {
165  outResetParam->setStreamNumbersArraySize(state->streamsToReset.size());
166  uint16_t i = 0;
167  for (std::list<uint16_t>::iterator it = state->streamsToReset.begin(); it != state->streamsToReset.end(); ++it) {
168  outResetParam->setStreamNumbers(i, *it);
169  state->resetOutStreams.push_back(outResetParam->getStreamNumbers(i));
170  state->requests[srsn - 1].streams.push_back(outResetParam->getStreamNumbers(i));
171  resetSsn(outResetParam->getStreamNumbers(i));
172  i++;
173  }
174  len = state->streamsToReset.size() * 2;
175  state->streamsToReset.clear();
176  }
177  else if (requestParam->getStreamNumbersArraySize() > 0) {
178  outResetParam->setStreamNumbersArraySize(requestParam->getStreamNumbersArraySize());
179  for (uint16_t i = 0; i < requestParam->getStreamNumbersArraySize(); i++) {
180  outResetParam->setStreamNumbers(i, requestParam->getStreamNumbers(i));
181  state->requests[srsn - 1].streams.push_back(requestParam->getStreamNumbers(i));
182  }
183  len = requestParam->getStreamNumbersArraySize() * 2;
184  }
185  outResetParam->setByteLength(SCTP_OUTGOING_RESET_REQUEST_PARAMETER_LENGTH + len);
186  resetChunk->addParameter(outResetParam);
188  state->resetRequested = true;
189 
190  SctpResetTimer *rt = new SctpResetTimer();
191  rt->setInSN(0);
192  rt->setInAcked(true);
193  rt->setOutSN(srsn - 1);
194  rt->setOutAcked(false);
195 
196  const auto& msg = makeShared<SctpHeader>();
197  msg->setChunkLength(B(SCTP_COMMON_HEADER));
198  msg->setSrcPort(localPort);
199  msg->setDestPort(remotePort);
200  msg->appendSctpChunks(resetChunk);
202  if (state->resetChunk != nullptr) {
203  delete state->resetChunk;
204  state->resetChunk = nullptr;
205  }
206  state->resetChunk = check_and_cast<SctpStreamResetChunk *>(resetChunk->dup());
207  if (qCounter.roomSumSendStreams != 0) {
208  storePacket(getPath(remoteAddr), msg, 1, 0, false);
209  state->bundleReset = true;
210  sendOnPath(getPath(remoteAddr), true);
211  state->bundleReset = false;
212  }
213  else {
214  Packet *pkt = new Packet("RE_CONFIG");
215  sendToIP(pkt, msg, remoteAddr);
216  }
217  if (PK(getPath(remoteAddr)->ResetTimer)->hasEncapsulatedPacket()) {
218  delete PK(getPath(remoteAddr)->ResetTimer)->decapsulate();
219  }
220  PK(getPath(remoteAddr)->ResetTimer)->encapsulate(rt);
221  if (getPath(remoteAddr)->ResetTimer->isScheduled()) {
222  stopTimer(getPath(remoteAddr)->ResetTimer);
223  }
224  startTimer(getPath(remoteAddr)->ResetTimer, getPath(remoteAddr)->pathRto);
225  }
226 }

Referenced by processIncomingResetRequestArrived().

◆ sendPacketDrop()

void inet::sctp::SctpAssociation::sendPacketDrop ( const bool  flag)
protected
1244 {
1245 #if 0
1246  EV_INFO << "sendPacketDrop:\t";
1247  SctpHeader *drop = (SctpHeader *)state->sctpmsg->dup(); // FIXME is the c-style conversion need here?
1248  if (drop->getSctpChunksArraySize() == 1) {
1249  SctpChunk *header = (SctpChunk *)(drop->getSctpChunks(0));
1250  if (header->getSctpChunkType() == PKTDROP) {
1251 // disposeOf(state->sctpmsg);
1252  delete drop;
1253  return;
1254  }
1255  }
1256  const auto& sctpmsg = makeShared<SctpHeader>();
1257  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
1258  SctpPacketDropChunk *pktdrop = new SctpPacketDropChunk();
1259  pktdrop->setSctpChunkType(PKTDROP);
1260  pktdrop->setCFlag(false);
1261  pktdrop->setTFlag(false);
1262  pktdrop->setBFlag(flag);
1263  pktdrop->setMFlag(false);
1264  pktdrop->setMaxRwnd(sctpMain->par("arwnd"));
1265  pktdrop->setQueuedData(state->queuedReceivedBytes);
1266  pktdrop->setTruncLength(0);
1267  pktdrop->setByteLength(SCTP_PKTDROP_CHUNK_LENGTH);
1269  if (B(drop->getChunkLength()).get() > mss) {
1270  uint16_t diff = B(drop->getChunkLength()).get() - mss;
1271  pktdrop->setTruncLength(B(drop->getChunkLength()).get());
1272  SctpChunk *sctpchunk = (SctpChunk *)(drop->removeLastChunk());
1273  if (sctpchunk->getSctpChunkType() == DATA) {
1274  SctpDataChunk *dataChunk = check_and_cast<SctpDataChunk *>(sctpchunk);
1275  /* auto& smsg = sctpchunk->Chunk::peek<SctpSimpleMessage>(Chunk::BackwardIterator(B(0)));*/
1276 
1277  SctpSimpleMessage *smsg = check_and_cast<SctpSimpleMessage *>(dataChunk->decapsulate());
1278 
1279  if (smsg->getDataLen() > diff) {
1280  uint16_t newLength = smsg->getDataLen() - diff;
1281  smsg->setDataArraySize(newLength);
1282  for (uint16_t i = 0; i < newLength; i++)
1283  smsg->setData(i, 'a');
1284  smsg->setDataLen(newLength);
1285  smsg->setEncaps(false);
1286  smsg->setByteLength(newLength);
1287  dataChunk->encapsulate((cPacket *)smsg);
1288 // dataChunk->insertAtBack(smsg);
1289  drop->appendSctpChunks(dataChunk);
1290  }
1291  else if (drop->getSctpChunksArraySize() == 1) {
1292  delete sctpchunk;
1293  delete pktdrop;
1294 // disposeOf(state->sctpmsg);
1295  EV_DETAIL << "laenge=" << B(drop->getChunkLength()).get() << " numberOfChunks=1\n";
1296  disposeOf(drop);
1297  return;
1298  }
1299  }
1300  else {
1301  delete pktdrop;
1302 // disposeOf(state->sctpmsg);
1303  EV_DETAIL << "laenge=" << B(drop->getChunkLength()).get() << " numberOfChunks=1\n";
1304  disposeOf(drop);
1305  return;
1306  }
1307  pktdrop->setTFlag(true);
1308  }
1309 /**** ToDo Irene */
1310 // pktdrop->insertAtBack(drop);
1311 // pktdrop->encapsulate(drop);
1312 
1313  EV_DETAIL << "length of PKTDROP chunk=" << pktdrop->getByteLength() << "\n";
1314  sctpmsg->appendSctpChunks(pktdrop);
1315  EV_DETAIL << "total length now " << B(sctpmsg->getChunkLength()).get() << "\n";
1316 // disposeOf(state->sctpmsg);
1317  state->pktDropSent = true;
1319  Packet *fp = new Packet("PKTDROP");
1320  sendToIP(fp, sctpmsg);
1321 #endif
1322 }

Referenced by processDataArrived().

◆ sendSack()

void inet::sctp::SctpAssociation::sendSack ( )
protected
1831 {
1832  SctpAuthenticationChunk *authChunk;
1833  SctpSackChunk *sackChunk;
1834 
1835  EV_INFO << "Sending SACK" << endl;
1836 
1837  /* sack timer has expired, reset flag, and send SACK */
1839  state->ackState = 0;
1840  sackChunk = createSack();
1841 
1842  const auto& sctpmsg = makeShared<SctpHeader>();
1843  sctpmsg->setChunkLength(B(SCTP_COMMON_HEADER));
1844  if (state->auth && state->peerAuth && typeInChunkList(SACK)) {
1845  authChunk = createAuthChunk();
1846  sctpmsg->appendSctpChunks(authChunk);
1847  auto it = sctpMain->assocStatMap.find(assocId);
1848  it->second.numAuthChunksSent++;
1849  }
1850  sctpmsg->appendSctpChunks(sackChunk);
1851 
1852  sendSACKviaSelectedPath(sctpmsg);
1853 }

Referenced by process_RCV_Message(), processPacketDropArrived(), processTimer(), pushUlp(), and sendOnPath().

◆ sendSACKviaSelectedPath()

void inet::sctp::SctpAssociation::sendSACKviaSelectedPath ( const Ptr< SctpHeader > &  sctpMsg)
private
500 {
501  SctpPathVariables *sackPath =
502  (state->lastDataSourceList.size() > 0) ? state->lastDataSourceList.front() :
504  assert(sackPath != nullptr);
505 
506  if (state->allowCMT) {
508  /* Observation:
509  For same bandwidths but different delays, chunks on both paths arrive
510  with same interleave time =>
511  Chunk on A / Chunk on B => SACK on B
512  Chunk on A / Chunk on B => SACK on B
513  Chunk on A / Chunk on B => SACK on B
514  Chunk on A / Chunk on B => SACK on B
515  Chunk on A / Chunk on B => SACK on B
516  ...
517  RESULT: Losts of SACKs on B, no SACK on A => Bad performance! */
518 
519  // Solution is now to make a round-robin selection among paths,
520  // taking the path with the longest time passed since last SACK.
521  for (auto path : state->lastDataSourceList) {
522  if (path->lastSACKSent < sackPath->lastSACKSent) {
523  sackPath = path;
524  }
525  }
526  }
528  /* Instead of RR among last DATA paths, send SACK on
529  the DATA path having the smallest SRTT. */
530  for (auto path : state->lastDataSourceList) {
531  if (path->srtt < sackPath->srtt) {
532  sackPath = path;
533  }
534  }
535  }
537  sackPath = state->getPrimaryPath();
538  }
539  }
540  EV_INFO << assocId << ": sending SACK to " << sackPath->remoteAddress << endl;
541  Packet *pkt = new Packet("SACK");
542  sendToIP(pkt, sctpMsg, sackPath->remoteAddress);
543  sackPath->lastSACKSent = simTime();
544  state->lastDataSourceList.clear(); // Clear the address list!
545 }

Referenced by sendInvalidStreamError(), sendOnPath(), and sendSack().

◆ sendShutdown()

void inet::sctp::SctpAssociation::sendShutdown ( )
protected
1182 {
1183  SctpAuthenticationChunk *authChunk;
1184  const auto& msg = makeShared<SctpHeader>();
1185  msg->setChunkLength(B(SCTP_COMMON_HEADER));
1186 
1187  EV_INFO << "SctpAssociationUtil:sendShutdown localPort=" << localPort << " remotePort=" << remotePort << "\n";
1188 
1189  msg->setSrcPort(localPort);
1190  msg->setDestPort(remotePort);
1191  SctpShutdownChunk *shutdownChunk = new SctpShutdownChunk();
1192  shutdownChunk->setSctpChunkType(SHUTDOWN);
1193 // shutdownChunk->setCumTsnAck(state->lastTsnAck);
1194  shutdownChunk->setCumTsnAck(state->gapList.getCumAckTsn());
1195  shutdownChunk->setByteLength(SCTP_SHUTDOWN_CHUNK_LENGTH);
1197  authChunk = createAuthChunk();
1198  msg->appendSctpChunks(authChunk);
1199  auto it = sctpMain->assocStatMap.find(assocId);
1200  it->second.numAuthChunksSent++;
1201  }
1208  state->shutdownChunk = check_and_cast<SctpShutdownChunk *>(shutdownChunk->dup());
1209  msg->appendSctpChunks(shutdownChunk);
1210  Packet *fp = new Packet("SHUTDOWN");
1211  sendToIP(fp, msg, remoteAddr);
1213 }

Referenced by process_CLOSE(), process_RCV_Message(), and stateEntered().

◆ sendShutdownAck()

void inet::sctp::SctpAssociation::sendShutdownAck ( const L3Address dest)
protected
1108 {
1109  sendOnAllPaths(getPath(dest));
1110  if (getOutstandingBytes() == 0) {
1112  const auto& sctpshutdownack = makeShared<SctpHeader>();
1113  sctpshutdownack->setChunkLength(B(SCTP_COMMON_HEADER));
1114 
1115  EV_INFO << "SctpAssociationUtil:sendShutdownACK" << endl;
1116 
1117  sctpshutdownack->setSrcPort(localPort);
1118  sctpshutdownack->setDestPort(remotePort);
1119  SctpShutdownAckChunk *shutdownAckChunk = new SctpShutdownAckChunk();
1120  shutdownAckChunk->setSctpChunkType(SHUTDOWN_ACK);
1121  shutdownAckChunk->setByteLength(SCTP_COOKIE_ACK_LENGTH);
1122  sctpshutdownack->appendSctpChunks(shutdownAckChunk);
1129  state->shutdownAckChunk = check_and_cast<SctpShutdownAckChunk *>(shutdownAckChunk->dup());
1130  Packet *fp = new Packet("SHUTDOWN-ACK");
1131  sendToIP(fp, sctpshutdownack, dest);
1132  }
1133 }

Referenced by performStateTransition(), process_CLOSE(), process_RCV_Message(), processAppCommand(), and stateEntered().

◆ sendShutdownComplete()

void inet::sctp::SctpAssociation::sendShutdownComplete ( )
protected
1136 {
1137  const auto& sctpshutdowncomplete = makeShared<SctpHeader>();
1138  sctpshutdowncomplete->setChunkLength(B(SCTP_COMMON_HEADER));
1139 
1140  EV_INFO << "SctpAssociationUtil:sendShutdownComplete\n";
1141 
1142  sctpshutdowncomplete->setSrcPort(localPort);
1143  sctpshutdowncomplete->setDestPort(remotePort);
1144  SctpShutdownCompleteChunk *shutdownCompleteChunk = new SctpShutdownCompleteChunk();
1145  shutdownCompleteChunk->setSctpChunkType(SHUTDOWN_COMPLETE);
1146  shutdownCompleteChunk->setTBit(0);
1147  shutdownCompleteChunk->setByteLength(SCTP_SHUTDOWN_ACK_LENGTH);
1148  sctpshutdowncomplete->appendSctpChunks(shutdownCompleteChunk);
1149  Packet *fp = new Packet("SHUTDOWN-COMPLETE");
1150  sendToIP(fp, sctpshutdowncomplete);
1151 }

Referenced by process_RCV_Message().

◆ sendStreamPresent()

bool inet::sctp::SctpAssociation::sendStreamPresent ( uint32_t  sid)
protected
930 {
931  return containsKey(sendStreams, id);
932 }

Referenced by processIncomingResetRequestArrived().

◆ sendStreamResetRequest()

void inet::sctp::SctpAssociation::sendStreamResetRequest ( SctpResetReq info)
protected
513 {
514  EV_INFO << "StreamReset:sendStreamResetRequest\n";
515  SctpParameter *param;
516  uint16_t type;
517  const auto& msg = makeShared<SctpHeader>();
518  msg->setChunkLength(B(SCTP_COMMON_HEADER));
519  msg->setSrcPort(localPort);
520  msg->setDestPort(remotePort);
521  SctpStreamResetChunk *resetChunk = new SctpStreamResetChunk();
522  resetChunk->setSctpChunkType(RE_CONFIG);
523  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
524  uint32_t srsn = state->streamResetSequenceNumber;
525  SctpResetTimer *rt = new SctpResetTimer();
526  auto it = sctpMain->assocStatMap.find(assocId);
527  if (rinfo)
528  type = rinfo->getRequestType();
529  else
531  switch (type) {
532  case RESET_OUTGOING:
533  EV_INFO << "RESET_OUTGOING\n";
534  state->requests[srsn].result = 100;
536  state->requests[srsn].sn = srsn;
537  param = makeOutgoingStreamResetParameter(srsn, rinfo);
538  resetChunk->addParameter(param);
539  rt->setInSN(0);
540  rt->setInAcked(true);
541  rt->setOutSN(srsn);
542  rt->setOutAcked(false);
543  it->second.numResetRequestsSent++;
545 
546  state->waitForResponse = true;
547  state->resetRequested = true;
548  break;
549 
550  case RESET_INCOMING:
551  EV_INFO << "RESET_INCOMING\n";
552  state->requests[srsn].result = 100;
554  state->requests[srsn].sn = srsn;
555  param = makeIncomingStreamResetParameter(srsn, rinfo);
556  resetChunk->addParameter(param);
557  rt->setInSN(srsn);
558  rt->setInAcked(false);
559  rt->setOutSN(0);
560  rt->setOutAcked(true);
561  it->second.numResetRequestsSent++;
563  state->waitForResponse = true;
564  break;
565 
566  case RESET_BOTH:
567  EV_INFO << "RESET_BOTH\n";
568  SctpParameter *outParam;
569  state->requests[srsn].result = 100;
571  state->requests[srsn].sn = srsn;
572  outParam = makeOutgoingStreamResetParameter(srsn, rinfo);
573  rt->setOutSN(srsn++);
574  rt->setOutAcked(false);
575  resetChunk->addParameter(outParam);
576  state->requests[srsn].result = 100;
578  state->requests[srsn].sn = srsn;
579  SctpParameter *inParam;
580  inParam = makeIncomingStreamResetParameter(srsn, rinfo);
581  resetChunk->addParameter(inParam);
582  rt->setInSN(srsn);
583  rt->setInAcked(false);
584  it->second.numResetRequestsSent += 2;
585  state->numResetRequests += 2;
586  state->waitForResponse = true;
587  break;
588 
589  case SSN_TSN:
590  param = makeSsnTsnResetParameter(srsn);
591  resetChunk->addParameter(param);
592  rt->setInSN(srsn);
593  rt->setInAcked(false);
594  rt->setOutSN(srsn);
595  rt->setOutAcked(false);
596  state->requests[srsn].result = 100;
598  it->second.numResetRequestsSent++;
600  break;
601 
602  case ADD_INCOMING:
603  case ADD_OUTGOING:
604  EV_INFO << "ADD_INCOMING or ADD_OUTGOING\n";
605  state->requests[srsn].result = 100;
606  param = makeAddStreamsRequestParameter(srsn, rinfo);
607  resetChunk->addParameter(param);
608  rt->setInSN(srsn);
609  rt->setInAcked(false);
610  rt->setOutSN(0);
611  rt->setOutAcked(true);
612  it->second.numResetRequestsSent++;
614  break;
615  default: EV_INFO << "Request type %d not known\n";
616 
617  }
619  if (state->resetChunk != nullptr) {
620  delete state->resetChunk;
621  state->resetChunk = nullptr;
622  }
623  state->resetChunk = check_and_cast<SctpStreamResetChunk *>(resetChunk->dup());
624  msg->appendSctpChunks(resetChunk);
625  if (qCounter.roomSumSendStreams != 0) {
626  storePacket(getPath(remoteAddr), msg, 1, 0, false);
627  state->bundleReset = true;
628  sendOnPath(getPath(remoteAddr), true);
629  state->bundleReset = false;
630  }
631  else {
632  Packet *pkt = new Packet("RE_CONFIG");
633  sendToIP(pkt, msg, remoteAddr);
634  }
635  if (PK(getPath(remoteAddr)->ResetTimer)->hasEncapsulatedPacket()) {
636  PK(getPath(remoteAddr)->ResetTimer)->decapsulate();
637  }
638  PK(getPath(remoteAddr)->ResetTimer)->encapsulate(rt);
639  if (getPath(remoteAddr)->ResetTimer->isScheduled()) {
640  stopTimer(getPath(remoteAddr)->ResetTimer);
641  }
642  startTimer(getPath(remoteAddr)->ResetTimer, getPath(remoteAddr)->pathRto);
643 }

Referenced by checkStreamsToReset(), process_STREAM_RESET(), and sendOnAllPaths().

◆ sendStreamResetResponse() [1/2]

void inet::sctp::SctpAssociation::sendStreamResetResponse ( SctpSsnTsnResetRequestParameter requestParam,
int  result,
bool  options 
)
protected
755 {
756  uint32_t len = 0;
757  EV_INFO << "sendStreamResetResponse to " << remoteAddr << " with options\n";
758  const auto& msg = makeShared<SctpHeader>();
759  msg->setChunkLength(B(SCTP_COMMON_HEADER));
760  msg->setSrcPort(localPort);
761  msg->setDestPort(remotePort);
762  SctpStreamResetChunk *resetChunk = new SctpStreamResetChunk();
763  resetChunk->setSctpChunkType(RE_CONFIG);
764  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
765  SctpStreamResetResponseParameter *responseParam = new SctpStreamResetResponseParameter();
766  responseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
767  responseParam->setSrResSn(requestParam->getSrReqSn());
768  responseParam->setResult(result);
769  state->peerRequests[requestParam->getSrReqSn()].result = result;
771  if (options && result == PERFORMED) {
772  responseParam->setSendersNextTsn(state->nextTsn);
773  responseParam->setReceiversNextTsn(state->gapList.getHighestTsnReceived() + (1 << 31) + 1);
774  resetSsns();
776  state->stopOldData = true;
777  if (state->incomingRequestSet && state->incomingRequest != nullptr) {
778  delete state->incomingRequest;
779  state->incomingRequest = nullptr;
780  state->incomingRequestSet = false;
781  }
782  len += 8;
783  resetGapLists();
785  state->firstPeerRequest = false;
786  }
787  responseParam->setByteLength(len);
788  resetChunk->addParameter(responseParam);
789  msg->appendSctpChunks(resetChunk);
791  msg->appendSctpChunks(createSack());
792  state->ackState = 0;
793  state->sackAlreadySent = true;
794  Packet *pkt = new Packet("RE_CONFIG");
795  sendToIP(pkt, msg);
796 }

◆ sendStreamResetResponse() [2/2]

void inet::sctp::SctpAssociation::sendStreamResetResponse ( uint32_t  srrsn,
int  result 
)
protected
799 {
800  SctpStreamResetChunk *resetChunk;
801  EV_INFO << "sendStreamResetResponse to " << remoteAddr << "\n";
802  const auto& msg = makeShared<SctpHeader>();
803  msg->setChunkLength(B(SCTP_COMMON_HEADER));
804  msg->setSrcPort(localPort);
805  msg->setDestPort(remotePort);
806  resetChunk = new SctpStreamResetChunk();
807  resetChunk->setSctpChunkType(RE_CONFIG);
808  resetChunk->setByteLength(SCTP_STREAM_RESET_CHUNK_LENGTH);
809  SctpStreamResetResponseParameter *responseParam = new SctpStreamResetResponseParameter();
810  responseParam->setParameterType(STREAM_RESET_RESPONSE_PARAMETER);
811  responseParam->setSrResSn(srrsn);
812  responseParam->setResult(result);
813  state->peerRequests[srrsn].result = result;
814  responseParam->setByteLength(SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH);
815  resetChunk->addParameter(responseParam);
816  msg->appendSctpChunks(resetChunk);
817  if (qCounter.roomSumSendStreams != 0) {
818  storePacket(getPath(remoteAddr), msg, 1, 0, false);
819  state->bundleReset = true;
820  sendOnPath(getPath(remoteAddr), true);
821  state->bundleReset = false;
822  }
823  else {
824  msg->appendSctpChunks(createSack());
826  state->ackState = 0;
827  state->sackAlreadySent = true;
828  if (state->incomingRequestSet && state->incomingRequest != nullptr) {
829  delete state->incomingRequest;
830  state->incomingRequest = nullptr;
831  state->incomingRequestSet = false;
832  }
833  Packet *pkt = new Packet("RE_CONFIG");
834  sendToIP(pkt, msg, remoteAddr);
835  }
836  if (result != DEFERRED) {
837  state->resetRequested = false;
838  state->firstPeerRequest = false;
839  }
840 }

Referenced by checkStreamsToReset(), process_RCV_Message(), processIncomingResetRequestArrived(), processOutAndResponseArrived(), processOutgoingResetRequestArrived(), processSsnTsnResetRequestArrived(), and processStreamResetArrived().

◆ sendToApp()

void inet::sctp::SctpAssociation::sendToApp ( cMessage *  msg)
protected

Utility: sends packet to application.

502 {
503  auto& tags = check_and_cast<ITaggedObject *>(msg)->getTags();
504  tags.addTagIfAbsent<SocketInd>()->setSocketId(assocId);
505  sctpMain->send(msg, "appOut");
506 }

Referenced by pathStatusIndication(), process_STATUS(), pushUlp(), and sendDataArrivedNotification().

◆ sendToIP() [1/2]

void inet::sctp::SctpAssociation::sendToIP ( Packet pkt,
const Ptr< SctpHeader > &  sctpmsg 
)
inlineprotected
1176  {
1177  sendToIP(pkt, sctpmsg, remoteAddr);
1178  }

◆ sendToIP() [2/2]

void inet::sctp::SctpAssociation::sendToIP ( Packet pkt,
const Ptr< SctpHeader > &  sctpmsg,
L3Address  dest 
)
protected

Utility: adds control info to message and sends it to IP.

362 {
363  // Final touches on the segment before sending
364  sctpmsg->setSrcPort(localPort);
365  sctpmsg->setDestPort(remotePort);
366  sctpmsg->setCrc(0);
367  sctpmsg->setCrcMode(sctpMain->crcMode);
368  sctpmsg->setChecksumOk(true);
369  EV_INFO << "SendToIP: localPort=" << localPort << " remotePort=" << remotePort << " dest=" << dest << "\n";
370  const SctpChunk *chunk = sctpmsg->peekFirstChunk();
371  uint8_t chunkType = chunk->getSctpChunkType();
372  if (chunkType == ABORT) {
373  const SctpAbortChunk *abortChunk = check_and_cast<const SctpAbortChunk *>(chunk);
374  if (abortChunk->getT_Bit() == 1) {
375  sctpmsg->setVTag(peerVTag);
376  }
377  else {
378  sctpmsg->setVTag(localVTag);
379  }
380  }
381  else if (sctpmsg->getVTag() == 0) {
382  sctpmsg->setVTag(localVTag);
383  }
384 
385  EV_INFO << "insertTransportProtocolHeader sctpmsg\n";
387 
388  if (sctpMain->par("udpEncapsEnabled").boolValue()) {
389  auto udpHeader = makeShared<UdpHeader>();
390  udpHeader->setSourcePort(SCTP_UDP_PORT);
391  udpHeader->setDestinationPort(SCTP_UDP_PORT);
392  udpHeader->setTotalLengthField(udpHeader->getChunkLength() + pkt->getTotalLength());
393  EV_INFO << "Packet: " << pkt << endl;
394  udpHeader->setCrcMode(sctpMain->crcMode);
396  EV_INFO << "After udp header added " << pkt << endl;
397  pkt->addTagIfAbsent<PacketProtocolTag>()->setProtocol(&Protocol::udp);
398  }
399  else {
400  pkt->addTagIfAbsent<PacketProtocolTag>()->setProtocol(&Protocol::sctp);
401  }
402 
403  IL3AddressType *addressType = dest.getAddressType();
404  pkt->addTagIfAbsent<DispatchProtocolReq>()->setProtocol(addressType->getNetworkProtocol());
405 
406  if (sctpMain->getInterfaceId() != -1) {
407  pkt->addTagIfAbsent<InterfaceReq>()->setInterfaceId(sctpMain->getInterfaceId());
408  }
409  auto addresses = pkt->addTagIfAbsent<L3AddressReq>();
410 // addresses->setSrcAddress(localAddr);
411  addresses->setDestAddress(dest);
412  pkt->addTagIfAbsent<SocketReq>()->setSocketId(assocId);
413  EV_INFO << "send packet " << pkt << " to ipOut\n";
414  check_and_cast<Sctp *>(getSimulation()->getContextModule())->send(pkt, "ipOut");
415 
416  if (chunkType == HEARTBEAT) {
417  SctpPathVariables *path = getPath(dest);
418  path->numberOfHeartbeatsSent++;
419  path->vectorPathHb->record(path->numberOfHeartbeatsSent);
420  }
421  else if (chunkType == HEARTBEAT_ACK) {
422  SctpPathVariables *path = getPath(dest);
423  path->numberOfHeartbeatAcksSent++;
424  path->vectorPathHbAck->record(path->numberOfHeartbeatAcksSent);
425  }
426 
427  EV_INFO << "Sent to " << dest << endl;
428 }

Referenced by processAddInAndOutResetRequestArrived(), processAsconfArrived(), retransmitAsconf(), retransmitCookieEcho(), retransmitInit(), retransmitReset(), retransmitShutdown(), retransmitShutdownAck(), sendAbort(), sendAddInAndOutStreamsRequest(), sendAddOutgoingStreamsRequest(), sendAsconf(), sendAsconfAck(), sendBundledOutgoingResetAndResponse(), sendCookieAck(), sendCookieEcho(), sendDoubleStreamResetResponse(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendOnPath(), sendOutgoingRequestAndResponse(), sendOutgoingResetRequest(), sendPacketDrop(), sendSACKviaSelectedPath(), sendShutdown(), sendShutdownAck(), sendShutdownComplete(), sendStreamResetRequest(), and sendStreamResetResponse().

◆ setFragInProgressOfStream()

void inet::sctp::SctpAssociation::setFragInProgressOfStream ( uint16_t  sid,
bool  frag 
)
protected
105 {
106  auto streamIterator = sendStreams.find(sid);
107  assert(streamIterator != sendStreams.end());
108  return streamIterator->second->setFragInProgress(frag);
109 }

Referenced by sendOnPath().

◆ signalConnectionTimeout()

void inet::sctp::SctpAssociation::signalConnectionTimeout ( )
protected

Utility: signal to user that connection timed out.

431 {
433 }

◆ ssnGt()

static bool inet::sctp::SctpAssociation::ssnGt ( const uint16_t  ssn1,
const uint16_t  ssn2 
)
inlinestatic
1080 { return SCTP_SSN_GT(ssn1, ssn2); }

Referenced by makeRoomForTsn().

◆ startTimer()

◆ stateEntered()

void inet::sctp::SctpAssociation::stateEntered ( int32_t  state)
protected
1419 {
1420  switch (status) {
1421  case SCTP_S_COOKIE_WAIT:
1422  break;
1423 
1424  case SCTP_S_ESTABLISHED: {
1425  EV_INFO << "State ESTABLISHED entered" << endl;
1427 
1428  if (state->initChunk) {
1429  delete state->initChunk;
1430  state->initChunk = nullptr;
1431  }
1432 
1433  state->nagleEnabled = (bool)sctpMain->getNagle();
1435  state->sendHeartbeatsOnActivePaths = sctpMain->par("sendHeartbeatsOnActivePaths");
1436  state->numGapReports = sctpMain->par("numGapReports");
1437  state->maxBurst = (uint32_t)sctpMain->getMaxBurst();
1438  state->rtxMethod = sctpMain->par("RTXMethod");
1439  state->nrSack = sctpMain->par("nrSack");
1440  state->disableReneging = sctpMain->par("disableReneging");
1441  state->checkSackSeqNumber = sctpMain->par("checkSackSeqNumber");
1444  state->fragPoint = (uint32_t)sctpMain->getFragPoint();
1445  state->highSpeedCC = sctpMain->par("highSpeedCC");
1446  state->initialWindow = sctpMain->par("initialWindow");
1447  const char *maxBurstVariantPar = sctpMain->par("maxBurstVariant").stringValue();
1448  if (strcmp(maxBurstVariantPar, "useItOrLoseIt") == 0) {
1450  }
1451  else if (strcmp(maxBurstVariantPar, "congestionWindowLimiting") == 0) {
1453  }
1454  else if (strcmp(maxBurstVariantPar, "maxBurst") == 0) {
1456  }
1457  else if (strcmp(maxBurstVariantPar, "aggressiveMaxBurst") == 0) {
1459  }
1460  else if (strcmp(maxBurstVariantPar, "totalMaxBurst") == 0) {
1462  }
1463  else if (strcmp(maxBurstVariantPar, "useItOrLoseItTempCwnd") == 0) {
1465  }
1466  else if (strcmp(maxBurstVariantPar, "congestionWindowLimitingTempCwnd") == 0) {
1468  }
1469  else {
1470  throw cRuntimeError("Invalid setting of maxBurstVariant: %s.",
1471  maxBurstVariantPar);
1472  }
1473 
1474  const char *cmtSendAllVariantPar = sctpMain->par("cmtSendAllVariant").stringValue();
1475  if (strcmp(cmtSendAllVariantPar, "normal") == 0) {
1477  }
1478  else if (strcmp(cmtSendAllVariantPar, "smallestLastTransmission") == 0) {
1480  }
1481  else if (strcmp(cmtSendAllVariantPar, "randomized") == 0) {
1483  }
1484  else if (strcmp(cmtSendAllVariantPar, "largestSSThreshold") == 0) {
1486  }
1487  else if (strcmp(cmtSendAllVariantPar, "largestSpace") == 0) {
1489  }
1490  else if (strcmp(cmtSendAllVariantPar, "largestSpaceAndSSThreshold") == 0) {
1492  }
1493  else {
1494  throw cRuntimeError("Invalid setting of cmtSendAllVariant: %s.",
1495  cmtSendAllVariantPar);
1496  }
1497 
1498  state->cmtRetransmissionVariant = sctpMain->par("cmtRetransmissionVariant");
1499  const char *cmtCUCVariantPar = sctpMain->par("cmtCUCVariant").stringValue();
1500  if (strcmp(cmtCUCVariantPar, "normal") == 0) {
1502  }
1503  else if (strcmp(cmtCUCVariantPar, "pseudoCumAck") == 0) {
1505  }
1506  else if (strcmp(cmtCUCVariantPar, "pseudoCumAckV2") == 0) {
1508  }
1509  else {
1510  throw cRuntimeError("Bad setting for cmtCUCVariant: %s\n",
1511  cmtCUCVariantPar);
1512  }
1513  state->smartOverfullSACKHandling = sctpMain->par("smartOverfullSACKHandling");
1514 
1515  const char *cmtChunkReschedulingVariantPar = sctpMain->par("cmtChunkReschedulingVariant").stringValue();
1516  if (strcmp(cmtChunkReschedulingVariantPar, "none") == 0) {
1518  }
1519  else if (strcmp(cmtChunkReschedulingVariantPar, "senderOnly") == 0) {
1521  }
1522  else if (strcmp(cmtChunkReschedulingVariantPar, "receiverOnly") == 0) {
1524  }
1525  else if (strcmp(cmtChunkReschedulingVariantPar, "bothSides") == 0) {
1527  }
1528  else if (strcmp(cmtChunkReschedulingVariantPar, "test") == 0) {
1530  }
1531  else {
1532  throw cRuntimeError("Bad setting for cmtChunkReschedulingVariant: %s\n",
1533  cmtChunkReschedulingVariantPar);
1534  }
1535 
1536  const char *cmtBufferSplitVariantPar = sctpMain->par("cmtBufferSplitVariant").stringValue();
1537  if (strcmp(cmtBufferSplitVariantPar, "none") == 0) {
1539  }
1540  else if (strcmp(cmtBufferSplitVariantPar, "senderOnly") == 0) {
1542  }
1543  else if (strcmp(cmtBufferSplitVariantPar, "receiverOnly") == 0) {
1545  }
1546  else if (strcmp(cmtBufferSplitVariantPar, "bothSides") == 0) {
1548  }
1549  else {
1550  throw cRuntimeError("Bad setting for cmtBufferSplitVariant: %s\n",
1551  cmtBufferSplitVariantPar);
1552  }
1553  state->cmtBufferSplittingUsesOSB = sctpMain->par("cmtBufferSplittingUsesOSB");
1554 
1555  const char *gapListOptimizationVariantPar = sctpMain->par("gapListOptimizationVariant").stringValue();
1556  if (strcmp(gapListOptimizationVariantPar, "none") == 0) {
1558  }
1559  else if (strcmp(gapListOptimizationVariantPar, "optimized1") == 0) {
1561  }
1562  else if (strcmp(gapListOptimizationVariantPar, "optimized2") == 0) {
1564  }
1565  else if (strcmp(gapListOptimizationVariantPar, "shrunken") == 0) {
1567  }
1568  else {
1569  throw cRuntimeError("Bad setting for gapListOptimizationVariant: %s\n",
1570  gapListOptimizationVariantPar);
1571  }
1572 
1573  state->cmtUseSFR = sctpMain->par("cmtUseSFR");
1574  state->cmtUseDAC = sctpMain->par("cmtUseDAC");
1575  state->cmtUseFRC = sctpMain->par("cmtUseFRC");
1576  state->gapReportLimit = sctpMain->par("gapReportLimit");
1577  state->cmtSmartT3Reset = sctpMain->par("cmtSmartT3Reset");
1578  state->cmtSmartReneging = sctpMain->par("cmtSmartReneging");
1579  state->cmtSmartFastRTX = sctpMain->par("cmtSmartFastRTX");
1580  state->cmtSlowPathRTTUpdate = sctpMain->par("cmtSlowPathRTTUpdate");
1581  state->cmtMovedChunksReduceCwnd = sctpMain->par("cmtMovedChunksReduceCwnd");
1582  state->cmtChunkReschedulingThreshold = sctpMain->par("cmtChunkReschedulingThreshold");
1583  state->movedChunkFastRTXFactor = sctpMain->par("movedChunkFastRTXFactor");
1584  state->strictCwndBooking = sctpMain->par("strictCwndBooking");
1585 
1586  const char *cmtSackPathPar = sctpMain->par("cmtSackPath").stringValue();
1587  if (strcmp(cmtSackPathPar, "standard") == 0) {
1589  }
1590  else if (strcmp(cmtSackPathPar, "primary") == 0) {
1592  }
1593  else if (strcmp(cmtSackPathPar, "roundRobin") == 0) {
1595  }
1596  else if (strcmp(cmtSackPathPar, "smallestSRTT") == 0) {
1598  }
1599  else {
1600  throw cRuntimeError("Bad setting for cmtSackPath: %s\n",
1601  cmtSackPathPar);
1602  }
1603 
1604  const char *cmtCCVariantPar = sctpMain->par("cmtCCVariant").stringValue();
1605  if (strcmp(cmtCCVariantPar, "off") == 0) {
1607  state->allowCMT = false;
1608  }
1609  else if (strcmp(cmtCCVariantPar, "cmt") == 0) {
1611  state->allowCMT = true;
1612  }
1613  else if (strcmp(sctpMain->par("cmtCCVariant").stringValue(), "lia") == 0) {
1615  state->allowCMT = true;
1616  }
1617  else if (strcmp(sctpMain->par("cmtCCVariant").stringValue(), "olia") == 0) {
1619  state->allowCMT = true;
1620  }
1621  else if ((strcmp(cmtCCVariantPar, "cmtrp") == 0) ||
1622  (strcmp(cmtCCVariantPar, "cmtrpv1") == 0))
1623  {
1625  state->allowCMT = true;
1626  }
1627  else if (strcmp(cmtCCVariantPar, "cmtrpv2") == 0) {
1629  state->allowCMT = true;
1630  }
1631  else if (strcmp(cmtCCVariantPar, "cmtrp-t1") == 0) {
1633  state->allowCMT = true;
1634  }
1635  else if (strcmp(cmtCCVariantPar, "cmtrp-t2") == 0) {
1637  state->allowCMT = true;
1638  }
1639  else {
1640  throw cRuntimeError("Bad setting for cmtCCVariant: %s\n",
1641  cmtCCVariantPar);
1642  }
1643 
1644  state->rpPathBlocking = sctpMain->par("rpPathBlocking");
1645  state->rpScaleBlockingTimeout = sctpMain->par("rpScaleBlockingTimeout");
1646  state->rpMinCwnd = sctpMain->par("rpMinCwnd");
1647 
1648  cStringTokenizer pathGroupsTokenizer(sctpMain->par("cmtCCPathGroups").stringValue());
1649  if (pathGroupsTokenizer.hasMoreTokens()) {
1650  auto pathIterator = sctpPathMap.begin();
1651  while (pathIterator != sctpPathMap.end()) {
1652  const char *token = pathGroupsTokenizer.nextToken();
1653  if (token == nullptr) {
1654  throw cRuntimeError("Too few cmtCCGroup values to cover all paths!");
1655  }
1656  SctpPathVariables *path = pathIterator->second;
1657  path->cmtCCGroup = atol(token);
1658  pathIterator++;
1659  }
1660  }
1661 
1662  state->osbWithHeader = sctpMain->par("osbWithHeader");
1663  state->padding = sctpMain->par("padding");
1664  if (state->osbWithHeader)
1666  else
1667  state->header = 0;
1668  state->swsLimit = sctpMain->par("swsLimit");
1669  state->fastRecoverySupported = sctpMain->par("fastRecoverySupported");
1670  state->reactivatePrimaryPath = sctpMain->par("reactivatePrimaryPath");
1672  state->auth = sctpMain->auth;
1673  state->messageAcceptLimit = sctpMain->par("messageAcceptLimit");
1674  state->bytesToAddPerRcvdChunk = sctpMain->par("bytesToAddPerRcvdChunk");
1675  state->bytesToAddPerPeerChunk = sctpMain->par("bytesToAddPerPeerChunk");
1676  state->tellArwnd = sctpMain->par("tellArwnd");
1677  state->throughputInterval = sctpMain->par("throughputInterval");
1680  Sctp::AssocStat stat;
1681  stat.assocId = assocId;
1682  stat.start = simTime();
1683  stat.stop = 0;
1684  stat.rcvdBytes = 0;
1685  stat.ackedBytes = 0;
1686  stat.sentBytes = 0;
1687  stat.transmittedBytes = 0;
1688  stat.numFastRtx = 0;
1689  stat.numT3Rtx = 0;
1690  stat.numDups = 0;
1691  stat.numPathFailures = 0;
1692  stat.numForwardTsn = 0;
1693  stat.sumRGapRanges = 0;
1694  stat.sumNRGapRanges = 0;
1695  stat.numOverfullSACKs = 0;
1696  stat.lifeTime = 0;
1697  stat.throughput = 0;
1698  stat.numDropsBecauseNewTsnGreaterThanHighestTsn = 0;
1699  stat.numDropsBecauseNoRoomInBuffer = 0;
1700  stat.numChunksReneged = 0;
1701  stat.numAuthChunksSent = 0;
1702  stat.numAuthChunksAccepted = 0;
1703  stat.numAuthChunksRejected = 0;
1704  stat.numResetRequestsSent = 0;
1705  stat.numResetRequestsPerformed = 0;
1706  fairTimer = false;
1707  stat.fairStart = 0;
1708  stat.fairStop = 0;
1709  stat.fairLifeTime = 0;
1710  stat.fairThroughput = 0;
1711  stat.fairAckedBytes = 0;
1712  stat.numEndToEndMessages = 0;
1713  stat.cumEndToEndDelay = 0;
1714  stat.startEndToEndDelay = sctpMain->par("startEndToEndDelay");
1715  stat.stopEndToEndDelay = sctpMain->par("stopEndToEndDelay");
1716  sctpMain->assocStatMap[stat.assocId] = stat;
1717  ccModule = sctpMain->par("ccModule");
1718 
1719  switch (ccModule) {
1720  case RFC4960: {
1728  break;
1729  }
1730  }
1731 
1733  state->sendQueueLimit = sctpMain->par("sendQueueLimit");
1734  EV_INFO << "stateEntered: Established socketId= " << assocId << endl;
1735  if (isToBeAccepted()) {
1736  EV_INFO << "Listening socket can accept now\n";
1738  }
1739  else {
1741  }
1742  if (sctpMain->hasPar("addIP")) {
1743  const bool addIP = sctpMain->par("addIP");
1744  simtime_t addTime = sctpMain->par("addTime");
1745  EV_DETAIL << getFullPath() << ": addIP = " << addIP << " time = " << addTime << "\n";
1746  if (addIP == true && addTime > SIMTIME_ZERO) {
1747  EV_DETAIL << "startTimer addTime to expire at " << simTime() + addTime << "\n";
1748 
1749  scheduleTimeout(StartAddIP, addTime);
1750  }
1751  }
1752  if ((double)sctpMain->par("fairStart") > 0) {
1753  sctpMain->scheduleAt(sctpMain->par("fairStart"), FairStartTimer);
1754  sctpMain->scheduleAt(sctpMain->par("fairStop"), FairStopTimer);
1755  sctpMain->recordScalar("rtoMin", sctpMain->par("rtoMin").doubleValue());
1756  }
1757  char str[128];
1758  snprintf(str, sizeof(str), "Cumulated TSN Ack of Association %d", assocId);
1759  cumTsnAck = new cOutVector(str);
1760  snprintf(str, sizeof(str), "Number of Gap Blocks in Last SACK of Association %d", assocId);
1761  numGapBlocks = new cOutVector(str);
1762  snprintf(str, sizeof(str), "SendQueue of Association %d", assocId);
1763  sendQueue = new cOutVector(str);
1764  state->sendQueueLimit = sctpMain->par("sendQueueLimit");
1765  Sctp::VTagPair vtagPair;
1766  vtagPair.peerVTag = peerVTag;
1767  vtagPair.localVTag = localVTag;
1768  vtagPair.localPort = localPort;
1769  vtagPair.remotePort = remotePort;
1770  sctpMain->sctpVTagMap[assocId] = vtagPair;
1771  break;
1772  }
1773 
1774  case SCTP_S_CLOSED: {
1776  break;
1777  }
1778 
1779  case SCTP_S_SHUTDOWN_PENDING: {
1781  sendShutdown();
1782  break;
1783  }
1784 
1785  case SCTP_S_SHUTDOWN_RECEIVED: {
1786  EV_INFO << "Entered state SHUTDOWN_RECEIVED, osb=" << getOutstandingBytes()
1787  << ", transQ=" << transmissionQ->getQueueSize()
1788  << ", scount=" << qCounter.roomSumSendStreams << endl;
1789 
1792  }
1793  else {
1795  }
1796  break;
1797  }
1798  }
1799 }

Referenced by performStateTransition().

◆ stateName()

const char * inet::sctp::SctpAssociation::stateName ( int32_t  state)
static

Utility: returns name of SCTP_S_xxx constants.

140 {
141 #define CASE(x) case x: \
142  s = (char *)#x + 7; break
143  const char *s = "unknown";
144  switch (state) {
153  }
154  return s;
155 #undef CASE
156 }

Referenced by performStateTransition(), printAssocBrief(), process_RCV_Message(), process_STATUS(), process_TIMEOUT_INIT_REXMIT(), and processAppCommand().

◆ stopTimer()

◆ stopTimers()

void inet::sctp::SctpAssociation::stopTimers ( )
3660 {
3661  for (auto& elem : sctpPathMap) {
3662  stopTimer(elem.second->HeartbeatTimer);
3663  stopTimer(elem.second->HeartbeatIntervalTimer);
3664  }
3665 }

Referenced by process_RCV_Message().

◆ storePacket()

void inet::sctp::SctpAssociation::storePacket ( SctpPathVariables pathVar,
const Ptr< SctpHeader > &  sctpMsg,
uint16_t  chunksAdded,
uint16_t  dataChunksAdded,
bool  authAdded 
)
private
50 {
51  uint32_t packetBytes = 0;
52  for (uint16_t i = 0; i < sctpMsg->getSctpChunksArraySize(); i++) {
53  const SctpChunk *chunkPtr = sctpMsg->getSctpChunks(i);
54  if (chunkPtr->getSctpChunkType() == DATA) {
55  const SctpDataChunk *dataChunk = check_and_cast<const SctpDataChunk *>(chunkPtr);
56  if (dataChunk != nullptr) {
57  const uint32_t tsn = dataChunk->getTsn();
58  SctpDataVariables *chunk = retransmissionQ->payloadQueue.find(tsn)->second;
59  assert(chunk != nullptr);
61  chunk->queuedOnPath->queuedBytes -= chunk->booksize;
62  chunk->queuedOnPath = nullptr;
63  packetBytes += chunk->booksize;
64  }
65  }
66  }
67  state->sctpMsg = dynamicPtrCast<SctpHeader>(sctpMsg->dupShared());
68  state->chunksAdded = chunksAdded;
69  state->dataChunksAdded = dataChunksAdded;
70  state->packetBytes = packetBytes;
71  state->authAdded = authAdded;
72  EV_INFO << "storePacket: path=" << pathVar->remoteAddress
73  << " state->packetBytes=" << state->packetBytes
74  << " osb=" << pathVar->outstandingBytes << " -> "
75  << pathVar->outstandingBytes - state->packetBytes << endl;
76  if (state->osbWithHeader)
78  else
81 }

Referenced by sendBundledOutgoingResetAndResponse(), sendDoubleStreamResetResponse(), sendOnPath(), sendOutgoingResetRequest(), sendStreamResetRequest(), and sendStreamResetResponse().

◆ streamIsPending()

bool inet::sctp::SctpAssociation::streamIsPending ( int32_t  sid)
protected
32 {
33  if (state->streamsPending.size() > 0 || (state->resetOutStreams.size() > 0 && state->resetPending)) {
34  std::list<uint16_t>::iterator it;
35  if (state->streamsPending.size() > 0) {
36  for (it = state->streamsPending.begin(); it != state->streamsPending.end(); it++) {
37  if (sid == (*it)) {
38  return true;
39  }
40  }
41  }
42  if (state->resetOutStreams.size() > 0) {
43  for (it = state->resetOutStreams.begin(); it != state->resetOutStreams.end(); it++) {
44  if (sid == (*it)) {
45  return true;
46  }
47  }
48  }
49  }
50  return false;
51 }

◆ streamScheduler()

int32_t inet::sctp::SctpAssociation::streamScheduler ( SctpPathVariables path,
bool  peek 
)
protected

Dealing with streams.

119  {
120  sid = testsid;
121  EV_DETAIL << "Stream Scheduler: chose sid " << sid << ".\n";
122 
123  if (!peek) {
124  state->lastStreamScheduled = sid;
125  break;
126  }
127  }
128  } while (sid == -1 && testsid != (int32_t)state->lastStreamScheduled);
129  }
130 
131  EV_INFO << "streamScheduler sid=" << sid << " lastStream=" << state->lastStreamScheduled << " outboundStreams=" << outboundStreams << " next=" << state->ssNextStream << "\n";
132 
133  if (sid >= 0 && !peek)
134  state->ssLastDataChunkSizeSet = false;
135 
136  return sid;
137 }
138 
140 {
141  int32_t count = 0;
142 
143  for (auto& elem : sendStreams)
144  if (elem.second->getStreamQ()->getLength() > 0 || elem.second->getUnorderedStreamQ()->getLength() > 0) {
145  count++;
146  }
147  return count;
148 }
149 
150 int32_t SctpAssociation::streamSchedulerRoundRobinPacket(SctpPathVariables *path, bool peek) // peek indicates that no data is sent, but we just want to peek
151 {
152  int32_t sid, testsid, lastsid = state->lastStreamScheduled;
153 
154  EV_INFO << "Stream Scheduler: RoundRobinPacket (peek: " << peek << ")" << endl;
155 
156  sid = -1;
157 
158  if (state->ssNextStream) {
159  testsid = state->lastStreamScheduled;
160 
161  do {

Referenced by SctpAssociation().

◆ streamSchedulerFairBandwidth()

int32_t inet::sctp::SctpAssociation::streamSchedulerFairBandwidth ( SctpPathVariables path,
bool  peek 
)
protected
320  peekMap[elem.first] = elem.second;
321  }
322  mapPointer = &peekMap;
323  }

Referenced by SctpAssociation().

◆ streamSchedulerFairBandwidthPacket()

int32_t inet::sctp::SctpAssociation::streamSchedulerFairBandwidthPacket ( SctpPathVariables path,
bool  peek 
)
protected
327  : sendStreams) {
328  /* There is data in this stream */
329  if (elem.second->getUnorderedStreamQ()->getLength() > 0 || elem.second->getStreamQ()->getLength() > 0) {
330  /* Get size of the first packet in stream */
331  if (elem.second->getUnorderedStreamQ()->getLength() > 0) {
332  packetsize = check_and_cast<SctpSimpleMessage *>(check_and_cast<SctpDataMsg *>(elem.second->getUnorderedStreamQ()->front())->getEncapsulatedPacket())->getByteLength();
333  }
334  else if (elem.second->getStreamQ()->getLength() > 0) {
335  packetsize = check_and_cast<SctpSimpleMessage *>(check_and_cast<SctpDataMsg *>(elem.second->getStreamQ()->front())->getEncapsulatedPacket())->getByteLength();
336  }
337 
338  /* This stream is new to the map, so add it */
339  if ((*mapPointer)[elem.first] < 0) {
340  if (packetsize > 0) {
341  (*mapPointer)[elem.first] = packetsize;
342  if (!peek)
343  EV_DETAIL << "Stream Scheduler: add sid " << elem.first << " with size " << packetsize << " to fair bandwidth map.\n";
344  }
345  }
346  /* This stream is already in the map, so update it if necessary */
347  else if (state->ssLastDataChunkSizeSet) {
348  /* Subtract the size of the last scheduled chunk from all streams */
349  (*mapPointer)[elem.first] -= lastDataChunkSize;
350  if ((*mapPointer)[elem.first] < 0)
351  (*mapPointer)[elem.first] = 0;
352 
353  /* We sent from this stream the last time, so add a new message to it */
354  if (elem.first == state->lastStreamScheduled) {
355  (*mapPointer)[elem.first] += packetsize;
356  if (!peek)
357  EV_DETAIL << "Stream Scheduler: updated sid " << elem.first << " with new packet of size " << packetsize << endl;
358  }
359 
360  if (!peek)
361  EV_DETAIL << "Stream Scheduler: updated sid " << elem.first << " entry to size " << (*mapPointer)[elem.first] << endl;
362  }
363  }
364  /* There is no data in this stream, so delete it from map */
365  else {
366  (*mapPointer)[elem.first] = -1;
367  if (!peek)
368  EV_DETAIL << "Stream Scheduler: sid " << elem.first << " removed from fb map" << endl;
369  }
370  }
371 
372  if (!peek) {
373  state->ssLastDataChunkSizeSet = false;
374  }
375 
376  if (state->ssNextStream) {
377  for (auto& elem : *mapPointer) {
378  if ((sid < 0 || (uint32_t)elem.second < bandwidth) && elem.second >= 0) {
379  sid = elem.first;
380  bandwidth = elem.second;
381  if (!peek)
382  EV_DETAIL << "Stream Scheduler: chose sid " << sid << ".\n";
383  }
384  }
385  }
386  else {
387  if (sendStreams.find(state->lastStreamScheduled)->second->getUnorderedStreamQ()->getLength() > 0 ||
388  sendStreams.find(state->lastStreamScheduled)->second->getStreamQ()->getLength() > 0)
389  {
390  sid = state->lastStreamScheduled;
391  if (!peek)
392  EV_DETAIL << "Stream Scheduler: again sid " << sid << ".\n";
393  }
394  }
395 
396  if (sid >= 0 && !peek) {
397  state->lastStreamScheduled = sid;
398  state->ssNextStream = false;
399  }
400 
401  return sid;
402 }
403 
404 int32_t SctpAssociation::streamSchedulerFCFS(SctpPathVariables *path, bool peek) // peek indicates that no data is sent, but we just want to peek
405 {
406  int32_t sid, testsid;
407  simtime_t oldestEnqueuing, testTime;
408 
409  EV_INFO << "Stream Scheduler: First-come, first-serve (peek: " << peek << ")" << endl;
410 
411  sid = -1;
412 
413  if (!state->ssNextStream) {
414  testsid = -1;
415  state->ssNextStream = true;
416  }
417  else
418  testsid = state->lastStreamScheduled;
419 
420  do {
421  testsid = (testsid + 1) % outboundStreams;
422 
423  if (sendStreams.find(testsid)->second->getUnorderedStreamQ()->getLength() > 0) {
424  testTime = check_and_cast<SctpDataMsg *>(sendStreams.find(testsid)->second->getUnorderedStreamQ()->front())->getEnqueuingTime();
425  if (sid < 0 || oldestEnqueuing > testTime) {
426  oldestEnqueuing = testTime;

Referenced by SctpAssociation().

◆ streamSchedulerFCFS()

int32_t inet::sctp::SctpAssociation::streamSchedulerFCFS ( SctpPathVariables path,
bool  peek 
)
protected
428  : chose sid " << sid << ".\n";
429  }
430  }
431 
432  if (sendStreams.find(testsid)->second->getStreamQ()->getLength() > 0) {
433  testTime = check_and_cast<SctpDataMsg *>(sendStreams.find(testsid)->second->getStreamQ()->front())->getEnqueuingTime();
434  if (sid < 0 || oldestEnqueuing > testTime) {
435  oldestEnqueuing = testTime;
436  sid = testsid;
437  EV_DETAIL << "Stream Scheduler: chose sid " << sid << ".\n";
438  }
439  }
440  } while (testsid != (int32_t)state->lastStreamScheduled);
441 
442  if (!peek && sid >= 0)
443  state->lastStreamScheduled = sid;
444 
445  return sid;
446 }
447 
448 int32_t SctpAssociation::pathStreamSchedulerManual(SctpPathVariables *path, bool peek)
449 {
450  uint32_t pathNo = 0;
451  int32_t testsid, sid = -1;
452  uint32_t lastsid = state->lastStreamScheduled;
453 
454  EV_INFO << "Stream Scheduler: path-aware Manual (peek: " << peek << ")" << endl;
455 
456  if (state->ssStreamToPathMap.empty()) {
457  for (uint16_t str = 0; str < outboundStreams; str++) {
458  state->ssStreamToPathMap[str] = 0;
459  }
460 
461  // Fill Stream to Path map
462  uint16_t streamNum = 0;
463  cStringTokenizer prioTokenizer(sctpMain->par("streamsToPaths"));
464  while (prioTokenizer.hasMoreTokens()) {
465  const char *token = prioTokenizer.nextToken();
466  state->ssStreamToPathMap[streamNum] = (uint32_t)atoi(token);
467  streamNum++;
468  }
469  if (state->ssStreamToPathMap.empty())
470  throw cRuntimeError("streamsToPaths not defined");

Referenced by SctpAssociation().

◆ streamSchedulerPriority()

int32_t inet::sctp::SctpAssociation::streamSchedulerPriority ( SctpPathVariables path,
bool  peek 
)
protected
273  {
274  testsid = (testsid + 1) % outboundStreams;
275 
276  if (sendStreams.find(testsid)->second->getUnorderedStreamQ()->getLength() > 0 ||
277  sendStreams.find(testsid)->second->getStreamQ()->getLength() > 0)
278  {
279  if (sid < 0 || state->ssPriorityMap[testsid] < state->ssPriorityMap[sid]) {
280  sid = testsid;
281  EV_DETAIL << "Stream Scheduler: chose sid " << sid << ".\n";
282  }
283  }
284  } while (testsid != (int32_t)state->lastStreamScheduled);
285 
286  if (!peek && sid >= 0) {
287  state->lastStreamScheduled = sid;
288  state->ssLastDataChunkSizeSet = false;
289  }
290 
291  return sid;
292 }
293 
294 int32_t SctpAssociation::streamSchedulerFairBandwidth(SctpPathVariables *path, bool peek) // peek indicates that no data is sent, but we just want to peek
295 {
296  EV_INFO << "Stream Scheduler: FairBandwidth (peek: " << peek << ")" << endl;
297  state->ssNextStream = true;
298  return streamSchedulerFairBandwidthPacket(path, peek);
299 }
300 
301 int32_t SctpAssociation::streamSchedulerFairBandwidthPacket(SctpPathVariables *path, bool peek) // peek indicates that no data is sent, but we just want to peek
302 {
303  uint32_t bandwidth = 0, packetsize = 0, lastDataChunkSize;
304  int32_t sid = -1;
305  std::map<uint16_t, int32_t> peekMap;
306  std::map<uint16_t, int32_t> *mapPointer = &(state->ssFairBandwidthMap);
307 
308  EV_INFO << "Stream Scheduler: FairBandwidthPacket (peek: " << peek << ")" << endl;
309 
310  if (state->ssFairBandwidthMap.empty()) {
311  for (auto& elem : sendStreams) {
312  state->ssFairBandwidthMap[elem.first] = -1;
313  EV_DETAIL << "initialize sid " << elem.first << " in fb map." << endl;
314  }
315  }
316 

Referenced by SctpAssociation().

◆ streamSchedulerRandom()

int32_t inet::sctp::SctpAssociation::streamSchedulerRandom ( SctpPathVariables path,
bool  peek 
)
protected
220  {
221  rnd = (int)(ceil(RNGCONTEXT uniform(1, SctpWaitingSendStreamsList.size()) - 0.5));
222  EV_DETAIL << "Stream Scheduler: go to " << rnd << ". element of waiting stream list.\n";
223  sid = SctpWaitingSendStreamsList[rnd - 1];
224  if (!peek)
225  state->lastStreamScheduled = sid;

Referenced by SctpAssociation().

◆ streamSchedulerRandomPacket()

int32_t inet::sctp::SctpAssociation::streamSchedulerRandomPacket ( SctpPathVariables path,
bool  peek 
)
protected
229  {
230  if (sendStreams.find(state->lastStreamScheduled)->second->getUnorderedStreamQ()->getLength() > 0 ||
231  sendStreams.find(state->lastStreamScheduled)->second->getStreamQ()->getLength() > 0)
232  {
233  sid = state->lastStreamScheduled;
234  EV_DETAIL << "Stream Scheduler: again sid " << sid << ".\n";
235  }
236  }
237 
238  EV_INFO << "streamScheduler sid=" << sid << " lastStream=" << lastsid << " outboundStreams=" << outboundStreams << " next=" << state->ssNextStream << "\n";
239 
240  if (sid >= 0 && !peek)
241  state->ssNextStream = false;
242 
243  return sid;
244 }
245 
246 int32_t SctpAssociation::streamSchedulerPriority(SctpPathVariables *path, bool peek) // peek indicates that no data is sent, but we just want to peek
247 {
248  int32_t sid = 0, testsid;
249  std::list<uint32_t> PriorityList;
250  std::list<uint32_t> StreamList;
251 
252  EV_INFO << "Stream Scheduler: Priority (peek: " << peek << ")" << endl;
253 
254  sid = -1;
255 
256  if ((state->ssLastDataChunkSizeSet == false && state->ssNextStream == true) &&
257  (sendStreams.find(state->lastStreamScheduled)->second->getUnorderedStreamQ()->getLength() > 0 ||
258  sendStreams.find(state->lastStreamScheduled)->second->getStreamQ()->getLength() > 0))
259  {
260  sid = state->lastStreamScheduled;
261  EV_DETAIL << "Stream Scheduler: again sid " << sid << ".\n";
262 
263  return sid;
264  }
265 
266  if (!state->ssNextStream) {
267  testsid = -1;
268  state->ssNextStream = true;

Referenced by SctpAssociation().

◆ streamSchedulerRoundRobinPacket()

int32_t inet::sctp::SctpAssociation::streamSchedulerRoundRobinPacket ( SctpPathVariables path,
bool  peek 
)
protected
179  {
180  if (sendStreams.find(state->lastStreamScheduled)->second->getUnorderedStreamQ()->getLength() > 0 ||
181  sendStreams.find(state->lastStreamScheduled)->second->getStreamQ()->getLength() > 0)
182  {
183  sid = state->lastStreamScheduled;
184  EV_DETAIL << "Stream Scheduler: again sid " << sid << ".\n";
185  }
186  }
187 
188  EV_INFO << "streamScheduler sid=" << sid << " lastStream=" << lastsid << " outboundStreams=" << outboundStreams << " next=" << state->ssNextStream << "\n";
189 
190  if (sid >= 0 && !peek)
191  state->ssNextStream = false;
192 
193  return sid;
194 }
195 
196 int32_t SctpAssociation::streamSchedulerRandom(SctpPathVariables *path, bool peek) // peek indicates that no data is sent, but we just want to peek
197 {
198  EV_INFO << "Stream Scheduler: Random (peek: " << peek << ")" << endl;
199  state->ssNextStream = true;
200  return streamSchedulerRandomPacket(path, peek);
201 }
202 
203 int32_t SctpAssociation::streamSchedulerRandomPacket(SctpPathVariables *path, bool peek) // peek indicates that no data is sent, but we just want to peek
204 {
205  int32_t sid = -1, rnd;
206  uint32_t lastsid = state->lastStreamScheduled;
207  std::vector<uint32_t> SctpWaitingSendStreamsList;
208 
209  EV_INFO << "Stream Scheduler: RandomPacket (peek: " << peek << ")" << endl;
210 
211  if (state->ssNextStream) {
212  for (auto& elem : sendStreams) {
213  if (elem.second->getUnorderedStreamQ()->getLength() > 0 ||
214  elem.second->getStreamQ()->getLength() > 0)
215  {
216  SctpWaitingSendStreamsList.push_back(elem.first);
217  EV_DETAIL << "Stream Scheduler: add sid " << elem.first << " to list of waiting streams.\n";
218  }

Referenced by SctpAssociation().

◆ timeForSack()

void inet::sctp::SctpAssociation::timeForSack ( bool &  sackOnly,
bool &  sackWithData 
)
private
248 {
249  sackOnly = sackWithData = false;
250  // CMT DAC implementation at the receiver side
251  // If CMT DAC is used, a SACK is *not* immediately transferred upon reordering
252  if (((state->gapList.getNumGaps(SctpGapList::GT_Any) > 0) || (state->dupList.size() > 0)) &&
253  (state->sackAllowed) &&
254  (!((state->allowCMT == true) && (state->cmtUseDAC == true))))
255  {
256  // Schedule sending of SACKs at once, when we have fragments to report
258  sackOnly = sackWithData = true; // SACK necessary, regardless of data available
259  }
260  if (state->ackState >= sackFrequency) {
261  sackOnly = sackWithData = true; // SACK necessary, regardless of data available
262  }
263  else if (SackTimer->isScheduled()) {
264  sackOnly = false;
265  sackWithData = true; // Only send SACK when data is present.
266  }
267 }

Referenced by sendOnPath().

◆ transformDataChunk()

SctpDataChunk * inet::sctp::SctpAssociation::transformDataChunk ( SctpDataVariables chunk)
protected

Manipulating chunks.

2087 {
2088  SctpDataChunk *dataChunk = new SctpDataChunk();
2089  SctpSimpleMessage *msg = check_and_cast<SctpSimpleMessage *>(chunk->userData->dup());
2090  dataChunk->setSctpChunkType(DATA);
2091  dataChunk->setBBit(chunk->bbit);
2092  dataChunk->setEBit(chunk->ebit);
2093  if (chunk->ordered) {
2094  dataChunk->setUBit(0);
2095  }
2096  else {
2097  dataChunk->setUBit(1);
2098  }
2099  dataChunk->setTsn(chunk->tsn);
2100  dataChunk->setSid(chunk->sid);
2101  dataChunk->setSsn(chunk->ssn);
2102  dataChunk->setPpid(chunk->ppid);
2103  dataChunk->setIBit(chunk->ibit);
2104  dataChunk->setEnqueuingTime(chunk->enqueuingTime);
2105  dataChunk->setFirstSendTime(chunk->firstSendTime);
2106  dataChunk->setByteLength(SCTP_DATA_CHUNK_LENGTH);
2107  msg->setByteLength(chunk->len / 8);
2108  dataChunk->encapsulate(msg);
2109  dataChunk->setLength(dataChunk->getByteLength());
2110  return dataChunk;
2111 }

Referenced by sendOnPath().

◆ tsnBetween()

static bool inet::sctp::SctpAssociation::tsnBetween ( const uint32_t  tsn1,
const uint32_t  midtsn,
const uint32_t  tsn2 
)
inlinestatic

◆ tsnGe()

static bool inet::sctp::SctpAssociation::tsnGe ( const uint32_t  tsn1,
const uint32_t  tsn2 
)
inlinestatic

◆ tsnGt()

◆ tsnIsDuplicate()

bool inet::sctp::SctpAssociation::tsnIsDuplicate ( const uint32_t  tsn) const
protected

Methods dealing with the handling of TSNs

2235 {
2236  for (std::list<uint32_t>::const_iterator iterator = state->dupList.begin();
2237  iterator != state->dupList.end(); iterator++)
2238  {
2239  if ((*iterator) == tsn)
2240  return true;
2241  }
2242  return state->gapList.tsnInGapList(tsn);
2243 }

Referenced by processDataArrived().

◆ tsnLe()

static bool inet::sctp::SctpAssociation::tsnLe ( const uint32_t  tsn1,
const uint32_t  tsn2 
)
inlinestatic

◆ tsnLt()

static bool inet::sctp::SctpAssociation::tsnLt ( const uint32_t  tsn1,
const uint32_t  tsn2 
)
inlinestatic

◆ tsnWasReneged()

void inet::sctp::SctpAssociation::tsnWasReneged ( SctpDataVariables chunk,
const SctpPathVariables sackPath,
const int  type 
)
protected
912 {
913  if ((state->allowCMT) && (state->cmtSmartReneging) &&
914  (sackPath != chunk->ackedOnPath))
915  {
916  return;
917  }
918  EV_INFO << "TSN " << chunk->tsn << " has been reneged (type "
919  << type << ")" << endl;
920  unackChunk(chunk);
921  if (chunk->countsAsOutstanding) {
923  }
924  chunk->hasBeenReneged = true;
925  chunk->gapReports = 1;
926  if (!chunk->getLastDestinationPath()->T3_RtxTimer->isScheduled()) {
927  startTimer(chunk->getLastDestinationPath()->T3_RtxTimer,
928  chunk->getLastDestinationPath()->pathRto);
929  }
930 }

Referenced by handleChunkReportedAsMissing(), and processSackArrived().

◆ typeInChunkList()

bool inet::sctp::SctpAssociation::typeInChunkList ( uint16_t  type)
protected
278 {
279  for (auto& elem : state->peerChunkList) {
280  if ((elem) == type) {
281  return true;
282  }
283  }
284  return false;
285 }

Referenced by process_RCV_Message(), processPacketDropArrived(), retransmitCookieEcho(), sendAbort(), sendCookieAck(), sendCookieEcho(), sendHeartbeat(), sendHeartbeatAck(), sendInvalidStreamError(), sendSack(), and sendShutdown().

◆ typeInOwnChunkList()

bool inet::sctp::SctpAssociation::typeInOwnChunkList ( uint16_t  type)
protected
288 {
289  for (auto& elem : state->chunkList) {
290  if ((elem) == type) {
291  return true;
292  }
293  }
294  return false;
295 }

Referenced by cloneAssociation().

◆ unackChunk()

void inet::sctp::SctpAssociation::unackChunk ( SctpDataVariables chunk)
inlineprivate
1446  {
1447  chunk->hasBeenAcked = false;
1448  }

Referenced by sendOnPath(), and tsnWasReneged().

◆ unorderedQueueEmptyOfStream()

bool inet::sctp::SctpAssociation::unorderedQueueEmptyOfStream ( uint16_t  sid)
protected
91 {
92  auto streamIterator = sendStreams.find(sid);
93  assert(streamIterator != sendStreams.end());
94  return streamIterator->second->getUnorderedStreamQ()->isEmpty();
95 }

Referenced by process_STREAM_RESET().

◆ updateCounters()

int32_t inet::sctp::SctpAssociation::updateCounters ( SctpPathVariables path)
protected
3705 {
3706  bool notifyUlp = false;
3707  if (++state->errorCount > (uint32_t)sctpMain->getAssocMaxRtx()) {
3708  EV_DETAIL << "Retransmission count during connection setup exceeds " << (int32_t)sctpMain->getAssocMaxRtx() << ", giving up\n";
3710  sendAbort();
3711  sctpMain->removeAssociation(this);
3712  return 0;
3713  }
3714  else if (++path->pathErrorCount > (uint32_t)sctpMain->getPathMaxRetrans()) {
3715  if (path->activePath) {
3716  /* tell the source */
3717  notifyUlp = true;
3718  }
3719 
3720  path->activePath = false;
3721  if (path == state->getPrimaryPath()) {
3723  }
3724  EV_DETAIL << "process_TIMEOUT_RESET(" << (path->remoteAddress) << ") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE\n";
3725  if (allPathsInactive()) {
3726  EV_DETAIL << "process_TIMEOUT_RESET : ALL PATHS INACTIVE --> closing ASSOC\n";
3728  sendAbort();
3729  sctpMain->removeAssociation(this);
3730  return 0;
3731  }
3732  else if (notifyUlp) {
3733  /* notify the application */
3734  pathStatusIndication(path, false);
3735  }
3736  EV_DETAIL << "process_TIMEOUT_RESET(" << (path->remoteAddress) << ") : PATH ERROR COUNTER now " << path->pathErrorCount << "\n";
3737  return 2;
3738  }
3739  return 1;
3740 }

Referenced by process_TIMEOUT_ASCONF(), and process_TIMEOUT_RESET().

◆ updateFastRecoveryStatus()

void inet::sctp::SctpAssociation::updateFastRecoveryStatus ( uint32_t  lastTsnAck)
protected
579 {
580  for (auto& elem : sctpPathMap) {
581  SctpPathVariables *path = elem.second;
582 
583  if (path->fastRecoveryActive) {
584  if ((tsnGt(lastTsnAck, path->fastRecoveryExitPoint)) ||
585  (lastTsnAck == path->fastRecoveryExitPoint) || ((state->allowCMT) && (state->cmtUseFRC) &&
586  ((path->newPseudoCumAck && tsnGt(path->pseudoCumAck, path->fastRecoveryExitPoint)) ||
587  (path->newRTXPseudoCumAck && tsnGt(path->rtxPseudoCumAck, path->fastRecoveryExitPoint)))))
588  {
589  path->fastRecoveryActive = false;
590  path->fastRecoveryExitPoint = 0;
591 
592  EV_INFO << simTime() << ":\tCC [cwndUpdateAfterSack] Leaving Fast Recovery on path "
593  << path->remoteAddress
594  << ", lastTsnAck=" << lastTsnAck
595  << ", pseudoCumAck=" << path->pseudoCumAck
596  << ", rtxPseudoCumAck=" << path->rtxPseudoCumAck
597  << ", newPseudoCumAck=" << path->newPseudoCumAck
598  << ", newRTXPseudoCumAck=" << path->newRTXPseudoCumAck
599  << endl;
600  }
601  }
602  }
603 }

Referenced by processSackArrived().

◆ updateHighSpeedCCThresholdIdx()

void inet::sctp::SctpAssociation::updateHighSpeedCCThresholdIdx ( SctpPathVariables path)
private
114 {
115  ASSERT(path->highSpeedCCThresholdIdx < HIGHSPEED_ENTRIES);
116 
117  if (path->cwnd > HighSpeedCwndAdjustmentTable[path->highSpeedCCThresholdIdx].cwndThreshold * path->pmtu) {
118  while ((path->highSpeedCCThresholdIdx < HIGHSPEED_ENTRIES)
119  && (path->cwnd > HighSpeedCwndAdjustmentTable[path->highSpeedCCThresholdIdx].cwndThreshold * path->pmtu))
120  {
121  path->highSpeedCCThresholdIdx++;
122  }
123  }
124  else {
125  while ((path->highSpeedCCThresholdIdx > 0) // FIXME check the condition: '>' or '>='
126  && (path->cwnd <= HighSpeedCwndAdjustmentTable[path->highSpeedCCThresholdIdx].cwndThreshold * path->pmtu))
127  {
128  path->highSpeedCCThresholdIdx--;
129  }
130  }
131 }

Referenced by cwndUpdateAfterSack(), and cwndUpdateBytesAcked().

◆ updateOLIA()

uint32_t inet::sctp::SctpAssociation::updateOLIA ( uint32_t  w,
uint32_t  s,
uint32_t  totalW,
double  a,
uint32_t  mtu,
uint32_t  ackedBytes,
SctpPathVariables path 
)
private

w: cwnd of the path s: ssthresh of the path totalW: Sum of all cwnds of the association a: factor alpha of olia calculation - see https://tools.ietf.org/html/draft-khalili-mptcp-congestion-control-05 mtu: mtu of the path ackedBytes: ackednowlged bytes path: path variable (for further investigation, debug, etc)

253  {
254  int32_t increase = 0;
255  bool isInCollectedPath = false;
256  bool isMaxWndPaths = false;
257 
258  if ((!(w < s)) && (!path->fastRecoveryActive)) {
259  // in CA
261 
262  int cnt = 0;
263  for (SctpPathCollection::iterator it = assocCollectedPaths.begin();
264  it != assocCollectedPaths.end(); it++, cnt++)
265  {
266  if (it->second == path) {
267  isInCollectedPath = true;
268  break;
269  }
270  }
271  cnt = 0;
272  for (SctpPathCollection::iterator it = assocMaxWndPaths.begin();
273  it != assocMaxWndPaths.end(); it++, cnt++)
274  {
275  if (it->second == path) {
276  isMaxWndPaths = true;
277  break;
278  }
279  }
280 
281  double r_sRTT = GET_SRTT(path->srtt.dbl());
282 
283  double numerator1 = path->cwnd / (r_sRTT * r_sRTT);
284  double denominator1 = 0;
285 
286  for (auto& elem : sctpPathMap) {
287  SctpPathVariables *p_path = elem.second;
288  double p_sRTT = GET_SRTT(p_path->srtt.dbl());
289  denominator1 += (p_path->cwnd / p_sRTT);
290  }
291  denominator1 = denominator1 * denominator1;
292  double term1 = numerator1 / denominator1;
293 
294  if (isInCollectedPath) {
295  /*
296  For each ACK on the path r:
297  - If r is in collected_paths, increase w_r by
298 
299  w_r/rtt_r^2 1
300  ------------------- + ----------------------- (2)
301  (SUM (w_p/rtt_p))^2 w_r * number_of_paths * |collected_paths|
302 
303  multiplied by MSS_r * bytes_acked.
304  */
305 
306  double numerator2 = 1 / sctpPathMap.size();
307  double denominator2 = assocCollectedPaths.size();
308  double term2 = 0.0;
309  if (denominator2 > 0.0) {
310  term2 = numerator2 / denominator2;
311  }
312  increase = (uint32_t)ceil(
313  (term1 * path->cwnd * path->pmtu) + (term2 * path->pmtu));
314  }
315  else if ((isMaxWndPaths) && (!assocCollectedPaths.empty())) {
316  /*
317  - If r is in max_w_paths and if collected_paths is not empty,
318  increase w_r by
319 
320  w_r/rtt_r^2 1
321  -------------------- - ------------------------ (3)
322  (SUM (w_p/rtt_p))^2 w_r * number_of_paths * |max_w_paths|
323 
324  multiplied by MSS_r * bytes_acked.
325  */
326  double numerator2 = 1.0 / (double)sctpPathMap.size();
327  double denominator2 = assocMaxWndPaths.size();
328  double term2 = 0.0;
329  if (denominator2 > 0.0) {
330  term2 = numerator2 / denominator2;
331  }
332  increase = (int32_t)ceil(
333  (term1 * path->cwnd * path->pmtu) - (term2 * path->pmtu)); // TODO
334  }
335  else {
336  /*
337  - Otherwise, increase w_r by
338 
339  (w_r/rtt_r^2)
340  ---------------------------------- (4)
341  (SUM (w_p/rtt_p))^2
342 
343  multiplied by MSS_r * bytes_acked.
344  */
345  increase = (int32_t)ceil(term1 * path->cwnd * path->pmtu); // TODO std::min(acked,
346  }
347  }
348  else {
349  increase = (int32_t)min(path->pmtu, ackedBytes); // slow start
350  }
351  return w + increase;
352 }

Referenced by cwndUpdateBytesAcked().

Friends And Related Function Documentation

◆ Sctp

friend class Sctp
friend

◆ SctpPathVariables

Member Data Documentation

◆ advMsgRwnd

cOutVector* inet::sctp::SctpAssociation::advMsgRwnd

◆ advRwnd

cOutVector* inet::sctp::SctpAssociation::advRwnd
protected

◆ appGateIndex

◆ assocBestPaths

SctpPathCollection inet::sctp::SctpAssociation::assocBestPaths
private

◆ assocCollectedPaths

SctpPathCollection inet::sctp::SctpAssociation::assocCollectedPaths
private

Referenced by recalculateOLIABasis(), and updateOLIA().

◆ assocId

int32_t inet::sctp::SctpAssociation::assocId

Referenced by inet::sctp::Sctp::addForkedAssociation(), cloneAssociation(), createForwardTsnChunk(), createSack(), cwndUpdateAfterCwndTimeout(), cwndUpdateAfterRtxTimeout(), cwndUpdateAfterSack(), cwndUpdateBytesAcked(), cwndUpdateMaxBurst(), dequeueAckedChunks(), inet::sctp::Sctp::findAssocForFd(), fragmentOutboundDataMsgs(), generateSendQueueAbatedIndication(), handleChunkReportedAsAcked(), handleChunkReportedAsMissing(), inet::sctp::Sctp::handleMessage(), makeRoomForTsn(), pathStatusIndication(), printAssocBrief(), inet::sctp::Sctp::printInfoAssocMap(), process_ABORT(), process_ASSOCIATE(), process_CLOSE(), process_OPEN_PASSIVE(), process_RCV_Message(), process_SEND(), process_TIMEOUT_RTX(), processAddInAndOutResetRequestArrived(), processAppCommand(), processAsconfArrived(), processDataArrived(), processInitArrived(), processOutAndResponseArrived(), processResetResponseArrived(), processSackArrived(), processTimer(), pushUlp(), inet::sctp::Sctp::removeAssociation(), retransmitAsconf(), retransmitCookieEcho(), SctpAssociation(), inet::sctp::SctpPathVariables::SctpPathVariables(), sendAbort(), sendAddOutgoingStreamsRequest(), sendAsconf(), sendAsconfAck(), sendAvailableIndicationToApp(), sendCookieAck(), sendCookieEcho(), sendDataArrivedNotification(), sendEstabIndicationToApp(), sendHeartbeat(), sendHeartbeatAck(), sendIndicationToApp(), sendInvalidStreamError(), sendOnPath(), sendOutgoingRequestAndResponse(), sendSack(), sendSACKviaSelectedPath(), sendShutdown(), sendStreamResetRequest(), sendToApp(), sendToIP(), stateEntered(), inet::sctp::Sctp::updateSockPair(), and ~SctpAssociation().

◆ assocMaxWndPaths

SctpPathCollection inet::sctp::SctpAssociation::assocMaxWndPaths
private

◆ assocThroughputVector

cOutVector* inet::sctp::SctpAssociation::assocThroughputVector

◆ bytes

◆ ccFunctions

◆ ccModule

uint16_t inet::sctp::SctpAssociation::ccModule
protected

Referenced by SctpAssociation(), and stateEntered().

◆ cumTsnAck

cOutVector* inet::sctp::SctpAssociation::cumTsnAck
protected

◆ dacPacketsRcvd

uint8_t inet::sctp::SctpAssociation::dacPacketsRcvd

◆ EndToEndDelay

cOutVector* inet::sctp::SctpAssociation::EndToEndDelay

◆ FairStartTimer

cMessage* inet::sctp::SctpAssociation::FairStartTimer

◆ FairStopTimer

cMessage* inet::sctp::SctpAssociation::FairStopTimer

◆ fairTimer

bool inet::sctp::SctpAssociation::fairTimer

◆ fd

◆ fsm

◆ ift

IInterfaceTable* inet::sctp::SctpAssociation::ift
protected

◆ inboundStreams

◆ initInboundStreams

uint32_t inet::sctp::SctpAssociation::initInboundStreams
protected

◆ initPeerTsn

uint32_t inet::sctp::SctpAssociation::initPeerTsn
protected

◆ initTsn

uint32_t inet::sctp::SctpAssociation::initTsn
protected

◆ listening

bool inet::sctp::SctpAssociation::listening

◆ listeningAssocId

int32_t inet::sctp::SctpAssociation::listeningAssocId

◆ localAddr

◆ localAddressList

AddressVector inet::sctp::SctpAssociation::localAddressList
protected

◆ localPort

◆ localVTag

◆ numberOfRemoteAddresses

uint32_t inet::sctp::SctpAssociation::numberOfRemoteAddresses
protected

◆ numGapBlocks

cOutVector* inet::sctp::SctpAssociation::numGapBlocks
protected

◆ outboundStreams

◆ peerVTag

uint32_t inet::sctp::SctpAssociation::peerVTag

◆ qCounter

◆ receiveStreams

◆ remoteAddr

◆ remoteAddressList

◆ remotePort

◆ retransmissionQ

◆ rt

◆ sackFrequency

uint32_t inet::sctp::SctpAssociation::sackFrequency
protected

◆ sackPeriod

double inet::sctp::SctpAssociation::sackPeriod
protected

◆ SackTimer

◆ sctpAlgorithm

SctpAlgorithm* inet::sctp::SctpAssociation::sctpAlgorithm
protected

◆ sctpMain

Sctp* inet::sctp::SctpAssociation::sctpMain
protected

Referenced by chunkReschedulingControl(), cloneAssociation(), createForwardTsnChunk(), createSack(), dequeueAckedChunks(), fragmentOutboundDataMsgs(), generateSendQueueAbatedIndication(), handleChunkReportedAsAcked(), handleChunkReportedAsMissing(), initAssociation(), makeRoomForTsn(), pathStatusIndication(), performStateTransition(), pmDataIsSentOn(), pmRttMeasurement(), pmStartPathManagement(), process_ASSOCIATE(), process_OPEN_PASSIVE(), process_RCV_Message(), process_SEND(), process_TIMEOUT_ASCONF(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_HEARTBEAT_INTERVAL(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RESET(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processAddInAndOutResetRequestArrived(), processAppCommand(), processAsconfAckArrived(), processAsconfArrived(), processCookieEchoArrived(), processDataArrived(), processErrorArrived(), processHeartbeatAckArrived(), processInitAckArrived(), processInitArrived(), processOutAndResponseArrived(), processResetResponseArrived(), processSackArrived(), processTimer(), pushUlp(), retransmitAsconf(), retransmitCookieEcho(), SctpAssociation(), sendAbort(), sendAddOutgoingStreamsRequest(), sendAsconf(), sendAsconfAck(), sendAvailableIndicationToApp(), sendCookieAck(), sendCookieEcho(), sendEstabIndicationToApp(), sendHeartbeat(), sendHeartbeatAck(), sendIndicationToApp(), sendInit(), sendInitAck(), sendInvalidStreamError(), sendOnPath(), sendOutgoingRequestAndResponse(), sendPacketDrop(), sendSack(), sendShutdown(), sendStreamResetRequest(), sendToApp(), sendToIP(), stateEntered(), and updateCounters().

◆ sctpPathMap

◆ sendQueue

cOutVector* inet::sctp::SctpAssociation::sendQueue
protected

◆ sendStreams

◆ ssFunctions

◆ ssModule

uint16_t inet::sctp::SctpAssociation::ssModule
protected

Referenced by SctpAssociation().

◆ StartAddIP

◆ StartTesting

cMessage* inet::sctp::SctpAssociation::StartTesting

Referenced by SctpAssociation().

◆ state

SctpStateVariables* inet::sctp::SctpAssociation::state
protected

Referenced by addOutStreams(), advancePeerTsn(), bytesAllowedToSend(), calculateAssocSharedKey(), calculateRcvBuffer(), checkStreamsToReset(), chunkReschedulingControl(), cloneAssociation(), compareRandom(), createForwardTsnChunk(), createSack(), cucProcessGapReports(), cwndUpdateAfterRtxTimeout(), cwndUpdateAfterSack(), cwndUpdateBytesAcked(), cwndUpdateMaxBurst(), decreaseOutstandingBytes(), dequeueOutboundDataMsg(), fragmentOutboundDataMsgs(), generateSendQueueAbatedIndication(), getInitialCwnd(), getNextDestination(), getNextPath(), getSortedPathMap(), handleChunkReportedAsAcked(), handleChunkReportedAsMissing(), increaseOutstandingBytes(), initAssociation(), initCcParameters(), initStreams(), loadPacket(), makeAddStreamsRequestParameter(), makeDataVarFromDataMsg(), makeIncomingStreamResetParameter(), makeOutgoingStreamResetParameter(), makeRoomForTsn(), makeSsnTsnResetParameter(), makeVarFromMsg(), moveChunkToOtherPath(), nextChunkFitsIntoPacket(), nonRenegablyAckChunk(), peekAbandonedChunk(), performStateTransition(), pmClearPathCounter(), pmDataIsSentOn(), pmStartPathManagement(), process_ABORT(), process_ASSOCIATE(), process_CLOSE(), process_OPEN_PASSIVE(), process_PRIMARY(), process_QUEUE_BYTES_LIMIT(), process_QUEUE_MSGS_LIMIT(), process_RCV_Message(), process_RECEIVE_REQUEST(), process_SEND(), process_STREAM_RESET(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_HEARTBEAT_INTERVAL(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RESET(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processAddInAndOutResetRequestArrived(), processAppCommand(), processAsconfAckArrived(), processAsconfArrived(), processCookieAckArrived(), processCookieEchoArrived(), processDataArrived(), processErrorArrived(), processForwardTsnArrived(), processHeartbeatAckArrived(), processInAndOutResetRequestArrived(), processIncomingResetRequestArrived(), processInitAckArrived(), processInitArrived(), processOutAndResponseArrived(), processOutgoingResetRequestArrived(), processPacketDropArrived(), processResetResponseArrived(), processSackArrived(), processSctpMessage(), processSsnTsnResetRequestArrived(), processStreamResetArrived(), processTimer(), pushUlp(), putInDeliveryQ(), inet::sctp::Sctp::removeAssociation(), renegablyAckChunk(), resetGapLists(), retransmitAsconf(), retransmitCookieEcho(), retransmitInit(), retransmitReset(), retransmitShutdown(), retransmitShutdownAck(), rpPathBlockingControl(), scheduleSack(), SctpAssociation(), sendAbort(), sendAddInAndOutStreamsRequest(), sendAddOutgoingStreamsRequest(), sendAsconf(), sendAsconfAck(), sendBundledOutgoingResetAndResponse(), sendCookieAck(), sendCookieEcho(), sendDoubleStreamResetResponse(), sendEstabIndicationToApp(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendInvalidStreamError(), sendOnAllPaths(), sendOnPath(), sendOutgoingRequestAndResponse(), sendOutgoingResetRequest(), sendPacketDrop(), sendSack(), sendSACKviaSelectedPath(), sendShutdown(), sendShutdownAck(), sendStreamResetRequest(), sendStreamResetResponse(), stateEntered(), stateName(), storePacket(), streamIsPending(), streamSchedulerFairBandwidthPacket(), streamSchedulerPriority(), streamSchedulerRandom(), timeForSack(), tsnIsDuplicate(), tsnWasReneged(), typeInChunkList(), typeInOwnChunkList(), updateCounters(), updateFastRecoveryStatus(), and ~SctpAssociation().

◆ statisticsArwndInLastSACK

cOutVector* inet::sctp::SctpAssociation::statisticsArwndInLastSACK
protected

◆ statisticsNonRevokableGapBlocksInLastSACK

cOutVector* inet::sctp::SctpAssociation::statisticsNonRevokableGapBlocksInLastSACK
protected

◆ statisticsNumDuplicatesSent

cOutVector* inet::sctp::SctpAssociation::statisticsNumDuplicatesSent
protected

◆ statisticsNumDuplicatesStored

cOutVector* inet::sctp::SctpAssociation::statisticsNumDuplicatesStored
protected

◆ statisticsNumNonRevokableGapBlocksSent

cOutVector* inet::sctp::SctpAssociation::statisticsNumNonRevokableGapBlocksSent
protected

◆ statisticsNumNonRevokableGapBlocksStored

cOutVector* inet::sctp::SctpAssociation::statisticsNumNonRevokableGapBlocksStored
protected

◆ statisticsNumRevokableGapBlocksSent

cOutVector* inet::sctp::SctpAssociation::statisticsNumRevokableGapBlocksSent
protected

◆ statisticsNumRevokableGapBlocksStored

cOutVector* inet::sctp::SctpAssociation::statisticsNumRevokableGapBlocksStored
protected

◆ statisticsNumTotalGapBlocksStored

cOutVector* inet::sctp::SctpAssociation::statisticsNumTotalGapBlocksStored
protected

◆ statisticsOutstandingBytes

cOutVector* inet::sctp::SctpAssociation::statisticsOutstandingBytes
protected

◆ statisticsPeerRwnd

cOutVector* inet::sctp::SctpAssociation::statisticsPeerRwnd
protected

◆ statisticsQueuedReceivedBytes

cOutVector* inet::sctp::SctpAssociation::statisticsQueuedReceivedBytes
protected

◆ statisticsQueuedSentBytes

cOutVector* inet::sctp::SctpAssociation::statisticsQueuedSentBytes
protected

◆ statisticsRevokableGapBlocksInLastSACK

cOutVector* inet::sctp::SctpAssociation::statisticsRevokableGapBlocksInLastSACK
protected

◆ statisticsSACKLengthSent

cOutVector* inet::sctp::SctpAssociation::statisticsSACKLengthSent
protected

◆ statisticsTotalBandwidth

cOutVector* inet::sctp::SctpAssociation::statisticsTotalBandwidth
protected

◆ statisticsTotalCwnd

cOutVector* inet::sctp::SctpAssociation::statisticsTotalCwnd
protected

◆ statisticsTotalSSthresh

cOutVector* inet::sctp::SctpAssociation::statisticsTotalSSthresh
protected

◆ status

int32_t inet::sctp::SctpAssociation::status
protected

◆ streamThroughputVectors

std::map<uint16_t, cOutVector *> inet::sctp::SctpAssociation::streamThroughputVectors

◆ T1_InitTimer

◆ T2_ShutdownTimer

◆ T5_ShutdownGuardTimer

◆ transmissionQ


The documentation for this class was generated from the following files:
inet::sctp::SCTP_E_RCV_INIT
@ SCTP_E_RCV_INIT
Definition: SctpAssociation.h:68
inet::sctp::FAIR_BANDWITH
@ FAIR_BANDWITH
Definition: SctpAssociation.h:195
inet::sctp::SctpStateVariables::requests
std::map< uint32_t, RequestData > requests
Definition: SctpAssociation.h:795
inet::SCTP_I_RCV_STREAMS_RESETTED
@ SCTP_I_RCV_STREAMS_RESETTED
Definition: SctpCommand_m.h:214
inet::SCTP_C_STREAM_RESET
@ SCTP_C_STREAM_RESET
Definition: SctpCommand_m.h:144
inet::sctp::SctpAssociation::processStreamResetArrived
SctpEventCode processStreamResetArrived(SctpStreamResetChunk *strResChunk)
Definition: SctpAssociationRcvMessage.cc:2811
CHK
#define CHK(x)
Definition: INETDefs.h:87
inet::sctp::SctpAssociation::statisticsOutstandingBytes
cOutVector * statisticsOutstandingBytes
Definition: SctpAssociation.h:964
inet::sctp::SctpStateVariables::streamReset
bool streamReset
Definition: SctpAssociation.h:774
inet::sctp::SctpStateVariables::zeroWindowProbing
bool zeroWindowProbing
Definition: SctpAssociation.h:572
inet::Ipv6Address::UNSPECIFIED
@ UNSPECIFIED
Definition: Ipv6Address.h:43
inet::sctp::SCTP_S_SHUTDOWN_PENDING
@ SCTP_S_SHUTDOWN_PENDING
Definition: SctpAssociation.h:51
inet::sctp::SctpAssociation::statisticsQueuedReceivedBytes
cOutVector * statisticsQueuedReceivedBytes
Definition: SctpAssociation.h:965
inet::sctp::SctpAssociation::statisticsNumTotalGapBlocksStored
cOutVector * statisticsNumTotalGapBlocksStored
Definition: SctpAssociation.h:976
inet::sctp::SctpAssociation::makeDataVarFromDataMsg
SctpDataVariables * makeDataVarFromDataMsg(SctpDataMsg *datMsg, SctpPathVariables *path)
Definition: SctpAssociationSendAll.cc:176
inet::sctp::SctpAssociation::FairStartTimer
cMessage * FairStartTimer
Definition: SctpAssociation.h:921
inet::sctp::Sctp::setInterfaceId
void setInterfaceId(int id)
Definition: Sctp.h:272
inet::sctp::SctpAssociation::transformDataChunk
SctpDataChunk * transformDataChunk(SctpDataVariables *chunk)
Manipulating chunks.
Definition: SctpAssociationUtil.cc:2086
SCTP_SSN_GT
#define SCTP_SSN_GT(a, b)
Definition: SctpAssociation.h:1073
inet::sctp::SctpGapList::tryToAdvanceCumAckTsn
bool tryToAdvanceCumAckTsn()
Definition: SctpGapList.cc:337
inet::SCTP_C_SEND_UNORDERED
@ SCTP_C_SEND_UNORDERED
Definition: SctpCommand_m.h:138
HIGHSPEED_ENTRIES
#define HIGHSPEED_ENTRIES
Definition: SctpCcFunctions.cc:22
inet::sctp::SctpAlgorithm::processTimer
virtual void processTimer(cMessage *timer, SctpEventCode &event)=0
inet::sctp::SctpAssociation::retransmitCookieEcho
void retransmitCookieEcho()
Definition: SctpAssociationUtil.cc:1002
inet::sctp::SctpAssociation::processAddInAndOutResetRequestArrived
void processAddInAndOutResetRequestArrived(const SctpAddStreamsRequestParameter *addInRequestParam, SctpAddStreamsRequestParameter *addOutRequestParam)
Definition: SctpAssociationRcvMessage.cc:2693
inet::sctp::SCTP_E_RCV_SHUTDOWN_COMPLETE
@ SCTP_E_RCV_SHUTDOWN_COMPLETE
Definition: SctpAssociation.h:75
inet::sctp::SctpAssociation::SCTP_UINT32_GT
static bool SCTP_UINT32_GT(uint32_t a, uint32_t b)
Definition: SctpAssociation.h:1065
inet::sctp::SctpAssociation::processAsconfAckArrived
SctpEventCode processAsconfAckArrived(SctpAsconfAckChunk *asconfAckChunk)
Definition: SctpAssociationRcvMessage.cc:3304
inet::sctp::SctpStateVariables::maxBurst
uint32_t maxBurst
Definition: SctpAssociation.h:681
inet::sctp::SctpAssociation::qCounter
QueueCounter qCounter
Definition: SctpAssociation.h:956
inet::SCTP_C_SEND_ASCONF
@ SCTP_C_SEND_ASCONF
Definition: SctpCommand_m.h:148
inet::sctp::SctpAssociation::processForwardTsnArrived
SctpEventCode processForwardTsnArrived(SctpForwardTsnChunk *forChunk)
Definition: SctpAssociationRcvMessage.cc:2068
inet::SCTP_I_SENDSOCKETOPTIONS
@ SCTP_I_SENDSOCKETOPTIONS
Definition: SctpCommand_m.h:217
inet::sctp::SctpAssociation::getNextDestination
SctpPathVariables * getNextDestination(SctpDataVariables *chunk) const
Definition: SctpAssociationUtil.cc:2696
inet::sctp::SctpAssociation::dequeueOutboundDataMsg
SctpDataMsg * dequeueOutboundDataMsg(SctpPathVariables *path, int32_t availableSpace, int32_t availableCwnd)
Definition: SctpAssociationUtil.cc:2557
inet::sctp::SCTP_E_TIMEOUT_HEARTBEAT_TIMER
@ SCTP_E_TIMEOUT_HEARTBEAT_TIMER
Definition: SctpAssociation.h:80
inet::Ipv4Address::getInt
uint32_t getInt() const
Returns the address as an uint32_t in host byte order (e.g.
Definition: Ipv4Address.h:186
inet::sctp::SctpStateVariables::CCRV_Test
@ CCRV_Test
Definition: SctpAssociation.h:719
inet::sctp::SctpStateVariables::initRetransCounter
int16_t initRetransCounter
Counter for init and cookie retransmissions.
Definition: SctpAssociation.h:639
inet::sctp::SctpAssociation::localPort
uint16_t localPort
Definition: SctpAssociation.h:904
inet::sctp::SctpStateVariables::CCRV_ReceiverOnly
@ CCRV_ReceiverOnly
Definition: SctpAssociation.h:717
inet::sctp::Sctp::getRtoInitial
double getRtoInitial()
Definition: Sctp.h:257
inet::sctp::SctpStateVariables::nextTsn
uint32_t nextTsn
Definition: SctpAssociation.h:603
inet::sctp::SctpAssociation::tsnGt
static bool tsnGt(const uint32_t tsn1, const uint32_t tsn2)
Definition: SctpAssociation.h:1076
SCTP_ADD_IP_PARAMETER_LENGTH
#define SCTP_ADD_IP_PARAMETER_LENGTH
Definition: SctpAssociation.h:223
inet::sctp::SctpStateVariables::disableReneging
bool disableReneging
Definition: SctpAssociation.h:676
inet::units::constants::c
const value< double, compose< units::m, pow< units::s, -1 > > > c(299792458)
inet::sctp::Sctp::numPktDropReports
uint64_t numPktDropReports
Definition: Sctp.h:204
inet::sctp::SCTP_E_RECEIVE
@ SCTP_E_RECEIVE
Definition: SctpAssociation.h:82
inet::sctp::SctpStateVariables::MBV_TotalMaxBurst
@ MBV_TotalMaxBurst
Definition: SctpAssociation.h:689
inet::sctp::SctpAssociation::processOutgoingResetRequestArrived
void processOutgoingResetRequestArrived(SctpOutgoingSsnResetRequestParameter *requestParam)
Definition: SctpAssociationRcvMessage.cc:2312
inet::sctp::SctpStateVariables::MBV_CongestionWindowLimiting
@ MBV_CongestionWindowLimiting
Definition: SctpAssociation.h:684
inet::sctp::SctpAssociation::appGateIndex
int32_t appGateIndex
Definition: SctpAssociation.h:897
inet::sctp::SCTP_E_RCV_COOKIE_ACK
@ SCTP_E_RCV_COOKIE_ACK
Definition: SctpAssociation.h:72
inet::sctp::SctpStateVariables::nextRSid
uint32_t nextRSid
Definition: SctpAssociation.h:652
inet::sctp::SctpAssociation::CCFunctions::ccUpdateAfterCwndTimeout
void(SctpAssociation::* ccUpdateAfterCwndTimeout)(SctpPathVariables *path)
Definition: SctpAssociation.h:882
inet::sctp::SctpAssociation::bytesAllowedToSend
void bytesAllowedToSend(SctpPathVariables *path, bool firstPass)
Definition: SctpAssociationSendAll.cc:547
inet::sctp::SctpAssociation::allPathsInactive
bool allPathsInactive() const
Definition: SctpAssociationUtil.cc:2864
inet::sctp::SctpAssociation::updateOLIA
uint32_t updateOLIA(uint32_t w, uint32_t s, uint32_t totalW, double a, uint32_t mtu, uint32_t ackedBytes, SctpPathVariables *path)
w: cwnd of the path s: ssthresh of the path totalW: Sum of all cwnds of the association a: factor alp...
Definition: SctpCcFunctions.cc:251
inet::sctp::SctpStateVariables::cmtMovedChunksReduceCwnd
bool cmtMovedChunksReduceCwnd
Definition: SctpAssociation.h:731
inet::sctp::SctpStateVariables::GLOV_Optimized1
@ GLOV_Optimized1
Definition: SctpAssociation.h:670
inet::sctp::SctpStateVariables::pktDropSent
bool pktDropSent
Definition: SctpAssociation.h:823
inet::sctp::SctpAssociation::CCFunctions::ccInitParams
void(SctpAssociation::* ccInitParams)(SctpPathVariables *path)
Definition: SctpAssociation.h:879
inet::sctp::SctpAssociation::sendSack
void sendSack()
Definition: SctpAssociationUtil.cc:1830
inet::sctp::SCTP_S_ESTABLISHED
@ SCTP_S_ESTABLISHED
Definition: SctpAssociation.h:50
inet::sctp::SctpAssociation::streamSchedulerRoundRobinPacket
int32_t streamSchedulerRoundRobinPacket(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:174
inet::sctp::SCTP_E_RCV_SHUTDOWN
@ SCTP_E_RCV_SHUTDOWN
Definition: SctpAssociation.h:73
inet::sctp::SctpAssociation::retransmitShutdownAck
void retransmitShutdownAck()
Definition: SctpAssociationUtil.cc:1229
inet::sctp::SctpStateVariables::initChunk
SctpInitChunk * initChunk
pointer to the init chunk data structure (for retransmissions)
Definition: SctpAssociation.h:642
inet::sctp::SctpAssociation::generateSendQueueAbatedIndication
void generateSendQueueAbatedIndication(uint64_t bytes)
Definition: SctpAssociationRcvMessage.cc:1990
inet::sctp::SctpAssociation::indicationName
static const char * indicationName(int32_t code)
Utility: returns name of SCTP_I_xxx constants.
Definition: SctpAssociationUtil.cc:205
inet::sctp::SctpAssociation::sendOutgoingRequestAndResponse
void sendOutgoingRequestAndResponse(uint32_t inRequestSn, uint32_t outRequestSn)
Definition: SctpAssociationStreamReset.cc:409
inet::sctp::SctpAssociation::getExpectedSsnOfStream
uint32_t getExpectedSsnOfStream(uint16_t id)
Definition: SctpAssociationStreamReset.cc:900
inet::sctp::SctpAssociation::peerVTag
uint32_t peerVTag
Definition: SctpAssociation.h:907
inet::sctp::SET_PRIMARY_ADDRESS
@ SET_PRIMARY_ADDRESS
Definition: SctpAssociation.h:159
inet::sctp::ROUND_ROBIN_PACKET
@ ROUND_ROBIN_PACKET
Definition: SctpAssociation.h:192
inet::sctp::SctpAssociation::makeIncomingStreamResetParameter
SctpParameter * makeIncomingStreamResetParameter(uint32_t srsn, SctpResetReq *info)
Definition: SctpAssociationStreamReset.cc:357
inet::sctp::SctpAssociation::assocId
int32_t assocId
Definition: SctpAssociation.h:898
inet::sctp::SctpPathVariables::pathErrorCount
uint32_t pathErrorCount
Definition: SctpAssociation.h:290
inet::sctp::SctpStateVariables::CCRV_BothSides
@ CCRV_BothSides
Definition: SctpAssociation.h:718
inet::sctp::SctpAssociation::retransmitReset
void retransmitReset()
Definition: SctpAssociationStreamReset.cc:15
inet::sctp::SctpAssociation::resetExpectedSsn
void resetExpectedSsn(uint16_t id)
Definition: SctpAssociationStreamReset.cc:892
inet::sctp::ADD_INCOMING
@ ADD_INCOMING
Definition: SctpAssociation.h:145
inet::sctp::SCTP_S_SHUTDOWN_RECEIVED
@ SCTP_S_SHUTDOWN_RECEIVED
Definition: SctpAssociation.h:53
inet::sctp::SctpStateVariables::fastRecoverySupported
bool fastRecoverySupported
Definition: SctpAssociation.h:574
inet::sctp::SctpStateVariables::authAdded
bool authAdded
Definition: SctpAssociation.h:663
inet::sctp::RANDOM
@ RANDOM
Definition: SctpAssociation.h:174
inet::sctp::SctpAssociation::pathMapLargestSpaceAndSSThreshold
static bool pathMapLargestSpaceAndSSThreshold(const SctpPathVariables *left, const SctpPathVariables *right)
Definition: SctpAssociationSendAll.cc:165
inet::sctp::SctpAssociation::processErrorArrived
void processErrorArrived(SctpErrorChunk *error)
Definition: SctpAssociationRcvMessage.cc:3518
inet::sctp::ADD_BOTH
@ ADD_BOTH
Definition: SctpAssociation.h:153
inet::sctp::SctpQueue::getChunk
SctpDataVariables * getChunk(const uint32_t key) const
Definition: SctpQueue.cc:111
inet::sctp::SctpAssociation::process_ABORT
void process_ABORT(SctpEventCode &event)
Definition: SctpAssociationEventProc.cc:429
inet::sctp::SctpStateVariables::rtxMethod
uint32_t rtxMethod
Definition: SctpAssociation.h:679
inet::sctp::SctpAssociation::QueueCounter::roomSumRcvStreams
uint64_t roomSumRcvStreams
Definition: SctpAssociation.h:866
inet::SCTP_I_CLOSED
@ SCTP_I_CLOSED
Definition: SctpCommand_m.h:201
inet::sctp::SctpAssociation::statisticsSACKLengthSent
cOutVector * statisticsSACKLengthSent
Definition: SctpAssociation.h:983
inet::sctp::SctpAssociation::pathStreamSchedulerManual
int32_t pathStreamSchedulerManual(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:472
inet::SCTP_C_OPEN_PASSIVE
@ SCTP_C_OPEN_PASSIVE
Definition: SctpCommand_m.h:131
inet::sctp::SctpAssociation::cancelEvent
cMessage * cancelEvent(cMessage *msg)
Utility: cancel a timer.
Definition: SctpAssociation.h:1191
inet::sctp::SctpStateVariables::inRequestSn
uint32_t inRequestSn
Definition: SctpAssociation.h:785
inet::sctp::SctpStateVariables::incomingSackSeqNum
uint32_t incomingSackSeqNum
Definition: SctpAssociation.h:764
inet::sctp::SctpQueue::payloadQueue
PayloadQueue payloadQueue
Definition: SctpQueue.h:88
inet::sctp::Sctp::addRemoteAddress
bool addRemoteAddress(SctpAssociation *assoc, L3Address localAddress, L3Address remoteAddress)
Definition: Sctp.cc:781
inet::sctp::SCTP_E_SHUTDOWN
@ SCTP_E_SHUTDOWN
Definition: SctpAssociation.h:65
inet::sctp::SctpAssociation::process_QUEUE_MSGS_LIMIT
void process_QUEUE_MSGS_LIMIT(const SctpCommandReq *sctpCommand)
Queue Management.
Definition: SctpAssociationEventProc.cc:400
inet::sctp::FORWARD_TSN
@ FORWARD_TSN
Definition: SctpAssociation.h:120
SCTP_FORWARD_TSN_CHUNK_LENGTH
#define SCTP_FORWARD_TSN_CHUNK_LENGTH
Definition: SctpAssociation.h:211
inet::sctp::Sctp::getRtoMax
double getRtoMax()
Definition: Sctp.h:259
inet::SCTP_I_SENDQUEUE_FULL
@ SCTP_I_SENDQUEUE_FULL
Definition: SctpCommand_m.h:210
inet::sctp::SctpAssociation::sendHeartbeat
void sendHeartbeat(const SctpPathVariables *path)
Definition: SctpAssociationUtil.cc:1024
inet::sctp::SctpStateVariables::appSendAllowed
bool appSendAllowed
Definition: SctpAssociation.h:650
inet::sctp::SctpStateVariables::inOut
bool inOut
Definition: SctpAssociation.h:589
inet::sctp::SctpAssociation::pathMapRandomized
static bool pathMapRandomized(const SctpPathVariables *left, const SctpPathVariables *right)
Definition: SctpAssociationSendAll.cc:143
inet::sctp::SctpStateVariables::gapReportLimit
uint32_t gapReportLimit
Definition: SctpAssociation.h:667
inet::sctp::ROUND_ROBIN
@ ROUND_ROBIN
Definition: SctpAssociation.h:191
inet::Ipv6Address::LINK
@ LINK
Definition: Ipv6Address.h:46
SCTP_DEFAULT_OUTBOUND_STREAMS
#define SCTP_DEFAULT_OUTBOUND_STREAMS
Definition: SctpAssociation.h:230
inet::sctp::Sctp::getPathMaxRetrans
int getPathMaxRetrans()
Definition: Sctp.h:266
inet::sctp::SctpAssociation::QueueCounter::bookedSumSendStreams
uint64_t bookedSumSendStreams
Definition: SctpAssociation.h:865
inet::sctp::SCTP_E_QUEUE_MSGS_LIMIT
@ SCTP_E_QUEUE_MSGS_LIMIT
Definition: SctpAssociation.h:86
inet::sctp::SctpAssociation::SackTimer
cMessage * SackTimer
Definition: SctpAssociation.h:913
inet::SCTP_C_PRIMARY
@ SCTP_C_PRIMARY
Definition: SctpCommand_m.h:139
inet::sctp::SctpAssociation::cwndUpdateAfterCwndTimeout
void cwndUpdateAfterCwndTimeout(SctpPathVariables *path)
Definition: SctpCcFunctions.cc:978
inet::sctp::SctpStateVariables::sizePeerKeyVector
uint32_t sizePeerKeyVector
Definition: SctpAssociation.h:817
inet::sctp::SctpStateVariables::CSP_SmallestSRTT
@ CSP_SmallestSRTT
Definition: SctpAssociation.h:739
inet::sctp::SctpStateVariables::firstDataSent
bool firstDataSent
Definition: SctpAssociation.h:584
inet::sctp::SctpStateVariables::movedChunkFastRTXFactor
double movedChunkFastRTXFactor
Definition: SctpAssociation.h:732
inet::sctp::SctpStateVariables::ssNextStream
bool ssNextStream
Definition: SctpAssociation.h:842
inet::sctp::SctpStateVariables::peerPktDrop
bool peerPktDrop
Definition: SctpAssociation.h:824
inet::sctp::SctpAssociation::getInitialCwnd
uint32_t getInitialCwnd(const SctpPathVariables *path) const
Definition: SctpCcFunctions.cc:377
inet::sctp::SctpAssociation::printSctpPathMap
void printSctpPathMap() const
Definition: SctpAssociationUtil.cc:129
inet::sctp::SctpStateVariables::enableHeartbeats
bool enableHeartbeats
Definition: SctpAssociation.h:655
inet::SCTP_I_RESET_REQUEST_FAILED
@ SCTP_I_RESET_REQUEST_FAILED
Definition: SctpCommand_m.h:215
inet::sctp::Sctp::testTimeout
simtime_t testTimeout
Definition: Sctp.h:196
inet::sctp::SctpAssociation::QueueCounter::roomRetransQ
CounterMap roomRetransQ
Definition: SctpAssociation.h:869
inet::sctp::Sctp::getFragPoint
int getFragPoint()
Definition: Sctp.h:263
inet::sctp::Sctp::getRtoMin
double getRtoMin()
Definition: Sctp.h:258
inet::Ipv6Address::LOOPBACK
@ LOOPBACK
Definition: Ipv6Address.h:44
inet::sctp::SctpStateVariables::localRwnd
uint64_t localRwnd
Definition: SctpAssociation.h:602
inet::sctp::SctpStateVariables::header
uint16_t header
Definition: SctpAssociation.h:631
inet::sctp::SctpAssociation::streamSchedulerRandomPacket
int32_t streamSchedulerRandomPacket(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:227
inet::sctp::SctpShutdownAckChunk::dup
virtual SctpShutdownAckChunk * dup() const override
Definition: SctpHeader_m.h:1357
inet::sctp::SctpEventCode
SctpEventCode
Definition: SctpAssociation.h:61
inet::sctp::SctpAssociation::sendInvalidStreamError
void sendInvalidStreamError(uint16_t sid)
Definition: SctpAssociationUtil.cc:1869
RNGCONTEXT
#define RNGCONTEXT
Definition: INETDefs.h:82
inet::sctp::SctpAssociation::process_QUEUE_BYTES_LIMIT
void process_QUEUE_BYTES_LIMIT(const SctpCommandReq *sctpCommand)
Definition: SctpAssociationEventProc.cc:406
inet::sctp::Sctp::getSackPeriod
double getSackPeriod()
Definition: Sctp.h:261
inet::sctp::SctpAssociation::pmClearPathCounter
void pmClearPathCounter(SctpPathVariables *path)
Definition: SctpAssociationUtil.cc:2808
inet::sctp::SctpStateVariables::lastTsn
uint32_t lastTsn
Definition: SctpAssociation.h:607
inet::sctp::SctpAssociation::resetGapLists
void resetGapLists()
Definition: SctpAssociationStreamReset.cc:748
inet::Ipv4Address::IETF
@ IETF
Definition: Ipv4Address.h:79
inet::Ipv4Address::UNSPECIFIED
@ UNSPECIFIED
Definition: Ipv4Address.h:74
inet::sctp::SctpStateVariables::ackState
uint32_t ackState
Definition: SctpAssociation.h:608
inet::sctp::ADD_IP_ADDRESS
@ ADD_IP_ADDRESS
Definition: SctpAssociation.h:162
inet::sctp::SctpStateVariables::lastAssocThroughputTime
simtime_t lastAssocThroughputTime
Definition: SctpAssociation.h:839
inet::sctp::PKTDROP
@ PKTDROP
Definition: SctpAssociation.h:118
inet::sctp::Sctp::printInfoAssocMap
void printInfoAssocMap()
Definition: Sctp.cc:37
inet::sctp::SctpQueue::findEarliestOutstandingTsnsForPath
void findEarliestOutstandingTsnsForPath(const L3Address &remoteAddress, uint32_t &earliestOutstandingTsn, uint32_t &rtxEarliestOutstandingTsn) const
Definition: SctpQueue.cc:195
inet::sctp::SctpAssociation::sendStreamResetResponse
void sendStreamResetResponse(uint32_t srrsn, int result)
Definition: SctpAssociationStreamReset.cc:798
inet::sctp::ERROR_CAUSE_INDICATION
@ ERROR_CAUSE_INDICATION
Definition: SctpAssociation.h:164
inet::sctp::SCTP_E_STREAM_RESET
@ SCTP_E_STREAM_RESET
Definition: SctpAssociation.h:91
inet::sctp::SctpAssociation::process_TIMEOUT_INIT_REXMIT
void process_TIMEOUT_INIT_REXMIT(SctpEventCode &event)
Definition: SctpAssociationRcvMessage.cc:3544
inet::sctp::SctpAssociation::pathMapLargestSSThreshold
static bool pathMapLargestSSThreshold(const SctpPathVariables *left, const SctpPathVariables *right)
Definition: SctpAssociationSendAll.cc:153
inet::sctp::RESET_INCOMING
@ RESET_INCOMING
Definition: SctpAssociation.h:142
inet::sctp::SctpAssociation::CCFunctions::ccUpdateAfterRtxTimeout
void(SctpAssociation::* ccUpdateAfterRtxTimeout)(SctpPathVariables *path)
Definition: SctpAssociation.h:883
inet::sctp::SctpAssociation::preanalyseAppCommandEvent
SctpEventCode preanalyseAppCommandEvent(int32_t commandCode)
Maps app command codes (msg kind of app command msgs) to SCTP_E_xxx event codes.
Definition: SctpAssociationBase.cc:996
inet::sctp::SctpAssociation::QueueCounter::roomTransQ
CounterMap roomTransQ
Definition: SctpAssociation.h:867
inet::sctp::SctpStateVariables::numberAsconfReceived
uint16_t numberAsconfReceived
Definition: SctpAssociation.h:768
inet::sctp::SctpStateVariables::firstChunkReceived
bool firstChunkReceived
Definition: SctpAssociation.h:569
inet::count
int count(const std::vector< T > &v, const Tk &a)
Definition: stlutils.h:54
inet::sctp::SctpStateVariables::streamThroughput
std::map< uint16_t, uint32_t > streamThroughput
Definition: SctpAssociation.h:838
inet::sctp::SctpStreamResetChunk::dup
virtual SctpStreamResetChunk * dup() const override
Definition: SctpHeader.h:139
inet::sctp::SctpStateVariables::lastSendQueueAbated
simtime_t lastSendQueueAbated
Definition: SctpAssociation.h:651
inet::sctp::SctpAssociation::sendDataArrivedNotification
void sendDataArrivedNotification(uint16_t sid)
Definition: SctpAssociationUtil.cc:1855
inet::sctp::SctpStateVariables::peerRwnd
uint64_t peerRwnd
Definition: SctpAssociation.h:600
inet::sctp::SctpQueue::getAndExtractChunk
SctpDataVariables * getAndExtractChunk(const uint32_t tsn)
Definition: SctpQueue.cc:65
inet::sctp::PERFORMED_WITH_ADDOUT
@ PERFORMED_WITH_ADDOUT
Definition: SctpAssociation.h:155
inet::sctp::SctpAssociation::CCFunctions::ccUpdateAfterSack
void(SctpAssociation::* ccUpdateAfterSack)()
Definition: SctpAssociation.h:881
inet::Ipv6Address::SITE
@ SITE
Definition: Ipv6Address.h:47
inet::SCTP_I_SENDQUEUE_ABATED
@ SCTP_I_SENDQUEUE_ABATED
Definition: SctpCommand_m.h:211
inet::sctp::SctpAssociation::stateEntered
void stateEntered(int32_t state)
Definition: SctpAssociationBase.cc:1418
inet::sctp::PATH_MANUAL
@ PATH_MANUAL
Definition: SctpAssociation.h:199
inet::sctp::SctpAssociation::streamSchedulerFairBandwidthPacket
int32_t streamSchedulerFairBandwidthPacket(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:325
inet::sctp::Sctp::getHbInterval
double getHbInterval()
Definition: Sctp.h:268
inet::sctp::SctpAssociation::ssnGt
static bool ssnGt(const uint16_t ssn1, const uint16_t ssn2)
Definition: SctpAssociation.h:1080
inet::sctp::SctpAssociation::sendIndicationToApp
void sendIndicationToApp(int32_t code, int32_t value=0)
Utility: sends status indication (SCTP_I_xxx) to application.
Definition: SctpAssociationUtil.cc:435
inet::sctp::ADD_OUTGOING_STREAMS_REQUEST_PARAMETER
@ ADD_OUTGOING_STREAMS_REQUEST_PARAMETER
Definition: SctpAssociation.h:151
inet::sctp::SctpAssociation::sendQueue
cOutVector * sendQueue
Definition: SctpAssociation.h:947
inet::sctp::SctpAssociation::remoteAddr
L3Address remoteAddr
Definition: SctpAssociation.h:902
inet::sctp::SCTP_E_QUEUE_BYTES_LIMIT
@ SCTP_E_QUEUE_BYTES_LIMIT
Definition: SctpAssociation.h:87
inet::sctp::SctpStateVariables::lastStreamScheduled
uint32_t lastStreamScheduled
Definition: SctpAssociation.h:616
inet::sctp::NR_SACK
@ NR_SACK
Definition: SctpAssociation.h:116
inet::sctp::SctpStateVariables::bytesToRetransmit
uint32_t bytesToRetransmit
Definition: SctpAssociation.h:622
inet::sctp::SctpStateVariables::lastDataSourceList
std::list< SctpPathVariables * > lastDataSourceList
Definition: SctpAssociation.h:595
inet::sctp::min
double min(const double a, const double b)
Returns the minimum of a and b.
Definition: SctpAssociation.h:261
inet::Ipv4Address::GLOBAL
@ GLOBAL
Definition: Ipv4Address.h:86
inet::sctp::SctpAssociation::listeningAssocId
int32_t listeningAssocId
Definition: SctpAssociation.h:899
inet::sctp::SctpAssociation::assocThroughputVector
cOutVector * assocThroughputVector
Definition: SctpAssociation.h:920
inet::sctp::DELETE_IP_ADDRESS
@ DELETE_IP_ADDRESS
Definition: SctpAssociation.h:163
inet::sctp::SctpAssociation::localVTag
uint32_t localVTag
Definition: SctpAssociation.h:906
inet::sctp::SctpStateVariables::sharedKey
uint8_t sharedKey[512]
Definition: SctpAssociation.h:818
inet::sctp::SctpAssociation::process_STREAM_RESET
void process_STREAM_RESET(SctpCommandReq *sctpCommand)
Definition: SctpAssociationEventProc.cc:331
inet::sctp::SctpStateVariables::CCCV_CMTRPv2
@ CCCV_CMTRPv2
Definition: SctpAssociation.h:750
inet::sctp::SctpAssociation::sctpPathMap
SctpPathMap sctpPathMap
Definition: SctpAssociation.h:955
inet::sctp::CHUNKS
@ CHUNKS
Definition: SctpAssociation.h:175
inet::sctp::RANDOM_SCHEDULE
@ RANDOM_SCHEDULE
Definition: SctpAssociation.h:193
inet::sctp::SctpAssociation::nextChunkFitsIntoPacket
bool nextChunkFitsIntoPacket(SctpPathVariables *path, int32_t bytes)
Definition: SctpAssociationUtil.cc:2624
inet::sctp::SctpAssociation::streamSchedulerPriority
int32_t streamSchedulerPriority(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:270
inet::Ipv4Address::BENCHMARK
@ BENCHMARK
Definition: Ipv4Address.h:82
inet::sctp::SctpStateVariables::resetChunk
SctpStreamResetChunk * resetChunk
Definition: SctpAssociation.h:788
inet::sctp::SctpAssociation::numGapBlocks
cOutVector * numGapBlocks
Definition: SctpAssociation.h:948
inet::sctp::SctpAssociation::sctpMain
Sctp * sctpMain
Definition: SctpAssociation.h:953
InterfaceReq
removed InterfaceReq
Definition: IUdp-gates.txt:11
inet::sctp::SctpAssociation::process_RECEIVE_REQUEST
void process_RECEIVE_REQUEST(SctpEventCode &event, SctpCommandReq *sctpCommand)
Definition: SctpAssociationEventProc.cc:314
inet::sctp::SctpAssociation::ccModule
uint16_t ccModule
Definition: SctpAssociation.h:943
inet::sctp::AUTH
@ AUTH
Definition: SctpAssociation.h:115
inet::sctp::SctpAssociation::receiveStreamPresent
bool receiveStreamPresent(uint32_t sid)
Definition: SctpAssociationStreamReset.cc:934
inet::sctp::SctpStateVariables::resetInStreams
std::list< uint16_t > resetInStreams
Definition: SctpAssociation.h:791
inet::sctp::SctpAlgorithm::sackSent
virtual void sackSent()=0
DispatchProtocolReq
removed DscpReq Ipv4ControlInfo Ipv6ControlInfo up L3AddressInd DispatchProtocolReq L4PortInd Ipv4ControlInfo Ipv6ControlInfo down DispatchProtocolReq
Definition: IUdp-gates.txt:25
inet::sctp::SctpStateVariables::CBSV_ReceiverOnly
@ CBSV_ReceiverOnly
Definition: SctpAssociation.h:708
inet::sctp::SctpAssociation::statisticsTotalCwnd
cOutVector * statisticsTotalCwnd
Definition: SctpAssociation.h:968
inet::sctp::HEARTBEAT_ACK
@ HEARTBEAT_ACK
Definition: SctpAssociation.h:107
inet::sctp::SctpDataVariables::zeroAddress
static const L3Address zeroAddress
Definition: SctpAssociation.h:519
inet::sctp::SctpAssociation::sendHeartbeatAck
void sendHeartbeatAck(const SctpHeartbeatChunk *heartbeatChunk, const L3Address &src, const L3Address &dest)
Definition: SctpAssociationUtil.cc:1049
inet::sctp::SctpAssociation::SSFunctions::ssGetNextSid
int32_t(SctpAssociation::* ssGetNextSid)(SctpPathVariables *path, bool peek)
Definition: SctpAssociation.h:1292
inet::sctp::SctpStateVariables::gapList
SctpGapList gapList
Definition: SctpAssociation.h:609
inet::SCTP_C_SEND
@ SCTP_C_SEND
Definition: SctpCommand_m.h:132
inet::sctp::SctpStateVariables::streamsPending
std::list< uint16_t > streamsPending
Definition: SctpAssociation.h:792
inet::sctp::SctpStateVariables::ssFairBandwidthMap
std::map< uint16_t, int32_t > ssFairBandwidthMap
Definition: SctpAssociation.h:846
inet::sctp::COOKIE_ACK
@ COOKIE_ACK
Definition: SctpAssociation.h:113
inet::sctp::SctpAssociation::initTsn
uint32_t initTsn
Definition: SctpAssociation.h:938
inet::sctp::SctpGapList::GT_Any
@ GT_Any
Definition: SctpGapList.h:95
inet::sctp::SctpAssociation::BytesToBeSent::chunk
bool chunk
Definition: SctpAssociation.h:873
inet::sctp::SctpStateVariables::swsAvoidanceInvoked
bool swsAvoidanceInvoked
Definition: SctpAssociation.h:570
inet::sctp::SctpAssociation::cwndUpdateBeforeSack
void cwndUpdateBeforeSack()
Definition: SctpCcFunctions.cc:133
inet::sctp::SctpStateVariables::peerMsgRwnd
uint32_t peerMsgRwnd
Definition: SctpAssociation.h:830
inet::sctp::SctpStateVariables::messageAcceptLimit
uint32_t messageAcceptLimit
Definition: SctpAssociation.h:629
inet::sctp::SctpPathVariables::pmtu
uint32_t pmtu
Definition: SctpAssociation.h:292
inet::SCTP_I_CONN_LOST
@ SCTP_I_CONN_LOST
Definition: SctpCommand_m.h:207
inet::sctp::SctpStateVariables::osbWithHeader
bool osbWithHeader
Definition: SctpAssociation.h:821
inet::sctp::SctpStateVariables::responseSn
uint32_t responseSn
Definition: SctpAssociation.h:633
inet::sctp::SctpAssociation::streamThroughputVectors
std::map< uint16_t, cOutVector * > streamThroughputVectors
Definition: SctpAssociation.h:919
inet::sctp::SctpStateVariables::appLimited
bool appLimited
Definition: SctpAssociation.h:780
inet::sctp::SctpAssociation::statisticsNumRevokableGapBlocksSent
cOutVector * statisticsNumRevokableGapBlocksSent
Definition: SctpAssociation.h:980
inet::sctp::SctpStateVariables::auth
bool auth
Definition: SctpAssociation.h:811
inet::sctp::SctpAssociation::getBytesInFlightOfStream
uint32_t getBytesInFlightOfStream(uint16_t sid)
Definition: SctpAssociationUtil.cc:76
inet::sctp::SctpStateVariables::sackAlreadySent
bool sackAlreadySent
Definition: SctpAssociation.h:577
inet::SCTP_C_SHUTDOWN
@ SCTP_C_SHUTDOWN
Definition: SctpCommand_m.h:142
inet::SCTP_I_SEND_STREAMS_RESETTED
@ SCTP_I_SEND_STREAMS_RESETTED
Definition: SctpCommand_m.h:213
inet::NetworkInterface::getMtu
int getMtu() const
Definition: NetworkInterface.h:236
inet::sctp::SctpAssociation::addInStreams
void addInStreams(uint32_t inStreams)
Definition: SctpSsFunctions.cc:79
inet::sctp::SctpStateVariables::GLOV_Optimized2
@ GLOV_Optimized2
Definition: SctpAssociation.h:671
inet::sctp::SctpStateVariables::MBV_UseItOrLoseIt
@ MBV_UseItOrLoseIt
Definition: SctpAssociation.h:683
inet::sctp::SctpAlgorithm::setAssociation
void setAssociation(SctpAssociation *_assoc)
Definition: SctpAlgorithm.h:41
inet::sctp::SctpAssociation::processPacketDropArrived
bool processPacketDropArrived(SctpPacketDropChunk *pktdrop)
Definition: SctpAssociationRcvMessage.cc:3406
inet::sctp::SCTP_E_NO_MORE_OUTSTANDING
@ SCTP_E_NO_MORE_OUTSTANDING
Definition: SctpAssociation.h:76
inet::sctp::SctpAssociation::startTimer
void startTimer(cMessage *timer, const simtime_t &timeout)
Definition: SctpAssociationRcvMessage.cc:3675
inet::SCTP_I_CONNECTION_REFUSED
@ SCTP_I_CONNECTION_REFUSED
Definition: SctpCommand_m.h:202
inet::sctp::SctpStateVariables::dataChunksAdded
uint16_t dataChunksAdded
Definition: SctpAssociation.h:659
inet::sctp::SctpStateVariables::queueUpdate
bool queueUpdate
Definition: SctpAssociation.h:583
inet::sctp::MISSING_NAT_ENTRY
@ MISSING_NAT_ENTRY
Definition: SctpAssociation.h:183
inet::sctp::Sctp::getMaxInitRetrans
int getMaxInitRetrans()
Definition: Sctp.h:255
inet::sctp::SctpStateVariables::initReceived
bool initReceived
Definition: SctpAssociation.h:566
inet::sctp::Sctp::getInterfaceId
int getInterfaceId()
Definition: Sctp.h:273
inet::sctp::SctpAssociation::BytesToBeSent::bytesToSend
uint32_t bytesToSend
Definition: SctpAssociation.h:875
inet::SCTP_C_ACCEPT_SOCKET_ID
@ SCTP_C_ACCEPT_SOCKET_ID
Definition: SctpCommand_m.h:153
inet::sctp::SctpAssociation::processInitArrived
bool processInitArrived(SctpInitChunk *initChunk, int32_t sport, int32_t dport)
Process incoming SCTP packets.
Definition: SctpAssociationRcvMessage.cc:532
inet::sctp::SctpAssociation::streamScheduler
int32_t streamScheduler(SctpPathVariables *path, bool peek)
Dealing with streams.
Definition: SctpSsFunctions.cc:115
inet::sctp::SctpStateVariables::CBSV_SenderOnly
@ CBSV_SenderOnly
Definition: SctpAssociation.h:707
inet::sctp::SctpStateVariables::resetPending
bool resetPending
Definition: SctpAssociation.h:579
inet::sctp::SCTP_E_RCV_SHUTDOWN_ACK
@ SCTP_E_RCV_SHUTDOWN_ACK
Definition: SctpAssociation.h:74
inet::sctp::SctpAssociation::ift
IInterfaceTable * ift
Definition: SctpAssociation.h:928
inet::sctp::Sctp::getNagle
int getNagle()
Definition: Sctp.h:264
inet::sctp::ADD_OUTGOING
@ ADD_OUTGOING
Definition: SctpAssociation.h:146
inet::sctp::ASCONF
@ ASCONF
Definition: SctpAssociation.h:121
SCTP_TIMEOUT_INIT_REXMIT
#define SCTP_TIMEOUT_INIT_REXMIT
Definition: SctpAssociation.h:237
inet::sctp::SctpStateVariables::lastMsgWasFragment
bool lastMsgWasFragment
Definition: SctpAssociation.h:654
inet::sctp::SctpAssociation::sendOnAllPaths
void sendOnAllPaths(SctpPathVariables *firstPath)
Definition: SctpAssociationSendAll.cc:269
inet::sctp::SctpAssociation::addOutStreams
void addOutStreams(uint32_t outStreams)
Definition: SctpSsFunctions.cc:94
inet::sctp::SctpAssociation::process_RCV_Message
bool process_RCV_Message(SctpHeader *sctpmsg, const L3Address &src, const L3Address &dest)
Definition: SctpAssociationRcvMessage.cc:67
inet::sctp::SctpAssociation::sackFrequency
uint32_t sackFrequency
Definition: SctpAssociation.h:940
inet::sctp::SctpAssociation::createAuthChunk
SctpAuthenticationChunk * createAuthChunk()
Definition: SctpAssociationAddIp.cc:210
SCTP_TIMEOUT_INIT_REXMIT_MAX
#define SCTP_TIMEOUT_INIT_REXMIT_MAX
Definition: SctpAssociation.h:238
inet::sctp::SctpStateVariables::queuedSentBytes
uint64_t queuedSentBytes
Definition: SctpAssociation.h:613
inet::sctp::SctpGapList::updateGapList
bool updateGapList(const uint32_t receivedTsn, bool &newChunkReceived, bool tsnIsRevokable=true)
Definition: SctpGapList.cc:356
inet::SCTP_C_RESET_ASSOC
@ SCTP_C_RESET_ASSOC
Definition: SctpCommand_m.h:145
inet::sctp::UNSUPPORTED_HMAC
@ UNSUPPORTED_HMAC
Definition: SctpAssociation.h:182
inet::sctp::SctpStateVariables::initialPeerMsgRwnd
uint32_t initialPeerMsgRwnd
Definition: SctpAssociation.h:828
inet::sctp::SctpStateVariables::CCCV_CMTRPv1
@ CCCV_CMTRPv1
Definition: SctpAssociation.h:749
inet::sctp::SctpAssociation::localAddressList
AddressVector localAddressList
Definition: SctpAssociation.h:930
inet::sctp::SctpAssociation::sendStreams
SctpSendStreamMap sendStreams
Definition: SctpAssociation.h:959
inet::sctp::Sctp::assocStatMap
AssocStatMap assocStatMap
Definition: Sctp.h:160
inet::Ipv4Address::LOOPBACK
@ LOOPBACK
Definition: Ipv4Address.h:76
inet::sctp::SctpGapList::getNumGaps
uint32_t getNumGaps(const GapType type) const
Definition: SctpGapList.h:100
inet::sctp::SCTP_E_TIMEOUT_INIT_TIMER
@ SCTP_E_TIMEOUT_INIT_TIMER
Definition: SctpAssociation.h:77
inet::sctp::SctpAssociation::statisticsNumRevokableGapBlocksStored
cOutVector * statisticsNumRevokableGapBlocksStored
Definition: SctpAssociation.h:977
inet::NetworkInterface::findProtocolData
const T * findProtocolData() const
Returns the protocol data for the provided type or returns nullptr if no such protocol data is found.
Definition: NetworkInterface.h:299
inet::sctp::SctpAssociation::updateFastRecoveryStatus
void updateFastRecoveryStatus(uint32_t lastTsnAck)
Definition: SctpCcFunctions.cc:578
inet::sctp::ABORT
@ ABORT
Definition: SctpAssociation.h:108
inet::sctp::SctpAssociation::pmDataIsSentOn
void pmDataIsSentOn(SctpPathVariables *path)
Definition: SctpAssociationUtil.cc:2728
inet::sctp::SctpStateVariables::numAddedOutStreams
uint16_t numAddedOutStreams
Definition: SctpAssociation.h:661
inet::L3Address::IPv4
@ IPv4
Definition: L3Address.h:35
inet::sctp::SctpStateVariables::rpScaleBlockingTimeout
bool rpScaleBlockingTimeout
Definition: SctpAssociation.h:758
inet::sctp::SctpAssociation::isToBeAccepted
bool isToBeAccepted() const
Definition: SctpAssociation.h:1205
SCTP_INIT_CHUNK_LENGTH
#define SCTP_INIT_CHUNK_LENGTH
Definition: SctpAssociation.h:204
inet::sctp::SctpAssociation::sendCookieAck
void sendCookieAck(const L3Address &dest)
Definition: SctpAssociationUtil.cc:1083
inet::sctp::SctpAssociation::process_OPEN_PASSIVE
void process_OPEN_PASSIVE(SctpEventCode &event, SctpCommandReq *sctpCommand, cMessage *msg)
Definition: SctpAssociationEventProc.cc:83
inet::sctp::SctpAssociation::recalculateOLIABasis
void recalculateOLIABasis()
Definition: SctpCcFunctions.cc:192
inet::sctp::SctpStateVariables::asconfOutstanding
bool asconfOutstanding
Definition: SctpAssociation.h:770
inet::sctp::SctpStateVariables::ssLastDataChunkSizeSet
bool ssLastDataChunkSizeSet
Definition: SctpAssociation.h:843
inet::sctp::SctpAssociation::tsnGe
static bool tsnGe(const uint32_t tsn1, const uint32_t tsn2)
Definition: SctpAssociation.h:1075
inet::sctp::SctpAssociation::pathMapSmallestLastTransmission
static bool pathMapSmallestLastTransmission(const SctpPathVariables *left, const SctpPathVariables *right)
Definition: SctpAssociationSendAll.cc:148
inet::sctp::SctpStateVariables::outgoingSackSeqNum
uint32_t outgoingSackSeqNum
Definition: SctpAssociation.h:763
inet::sctp::SctpAssociation::pushUlp
void pushUlp()
Definition: SctpAssociationUtil.cc:1952
SCTP_UDP_PORT
#define SCTP_UDP_PORT
Definition: Sctp.h:31
inet::sctp::SctpAssociation::advRwnd
cOutVector * advRwnd
Definition: SctpAssociation.h:945
inet::sctp::SctpAssociation::cwndUpdateBytesAcked
void cwndUpdateBytesAcked(SctpPathVariables *path, uint32_t ackedBytes, bool ctsnaAdvanced)
Definition: SctpCcFunctions.cc:605
inet::utils::createOne
cObject * createOne(const char *className, const char *defaultNamespace)
Like cObjectFactory::createOne(), except it starts searching for the class in the given namespace.
Definition: INETUtils.cc:147
inet::sctp::SctpStateVariables::gapListOptimizationVariant
uint32_t gapListOptimizationVariant
Definition: SctpAssociation.h:674
inet::sctp::SctpStateVariables::peerKeyVector
uint8_t peerKeyVector[512]
Definition: SctpAssociation.h:816
inet::sctp::SctpPathVariables::primaryPathCandidate
bool primaryPathCandidate
Definition: SctpAssociation.h:281
inet::sctp::SctpQueue::getSizeOfFirstChunk
uint32_t getSizeOfFirstChunk(const L3Address &remoteAddress)
Definition: SctpQueue.cc:224
inet::sctp::SctpAlgorithm::initialize
virtual void initialize()
Definition: SctpAlgorithm.h:48
inet::sctp::SctpStateVariables::sendResponse
uint16_t sendResponse
Definition: SctpAssociation.h:632
inet::sctp::INVALID_STREAM_IDENTIFIER
@ INVALID_STREAM_IDENTIFIER
Definition: SctpAssociation.h:180
inet::L3Address::isUnspecified
bool isUnspecified() const
Definition: L3Address.cc:138
inet::sctp::SctpStateVariables::MBV_AggressiveMaxBurst
@ MBV_AggressiveMaxBurst
Definition: SctpAssociation.h:688
inet::sctp::SctpStateVariables::peerAuth
bool peerAuth
Definition: SctpAssociation.h:810
inet::sctp::SctpAssociation::moveChunkToOtherPath
void moveChunkToOtherPath(SctpDataVariables *chunk, SctpPathVariables *newPath)
Definition: SctpAssociationRcvMessage.cc:3895
inet::sctp::SctpAssociation::initAssociation
void initAssociation(SctpOpenReq *openCmd)
Utility: creates send/receive queues and sctpAlgorithm.
Definition: SctpAssociationUtil.cc:508
inet::sctp::SctpStateVariables::initialPrimaryPath
L3Address initialPrimaryPath
Definition: SctpAssociation.h:594
inet::sctp::SctpGapList::tsnInGapList
bool tsnInGapList(const uint32_t tsn) const
Definition: SctpGapList.h:113
inet::sctp::SctpAssociation::statisticsTotalSSthresh
cOutVector * statisticsTotalSSthresh
Definition: SctpAssociation.h:967
SCTP_ADD_IP_CHUNK_LENGTH
#define SCTP_ADD_IP_CHUNK_LENGTH
Definition: SctpAssociation.h:222
inet::sctp::SctpStateVariables::expectedStreamResetSequenceNumber
uint32_t expectedStreamResetSequenceNumber
Definition: SctpAssociation.h:783
inet::SCTP_C_RECEIVE
@ SCTP_C_RECEIVE
Definition: SctpCommand_m.h:136
inet::sctp::SctpStateVariables::cmtUseDAC
bool cmtUseDAC
Definition: SctpAssociation.h:729
inet::sctp::SctpStateVariables::cmtSmartReneging
bool cmtSmartReneging
Definition: SctpAssociation.h:726
inet::sctp::SctpStateVariables::asconfChunk
SctpAsconfChunk * asconfChunk
Definition: SctpAssociation.h:771
inet::sctp::SctpAssociation::outboundStreams
uint32_t outboundStreams
Definition: SctpAssociation.h:934
inet::sctp::SctpStateVariables::ssPriorityMap
std::map< uint16_t, uint32_t > ssPriorityMap
Definition: SctpAssociation.h:845
inet::SCTP_I_DATA
@ SCTP_I_DATA
Definition: SctpCommand_m.h:197
inet::sctp::SctpAssociation::updateCounters
int32_t updateCounters(SctpPathVariables *path)
Definition: SctpAssociationRcvMessage.cc:3704
inet::sctp::SctpStateVariables::stopSending
bool stopSending
Definition: SctpAssociation.h:587
inet::sctp::SctpStateVariables::cmtSmartFastRTX
bool cmtSmartFastRTX
Definition: SctpAssociation.h:725
PacketProtocolTag
removed DscpReq Ipv4ControlInfo Ipv6ControlInfo up L3AddressInd DispatchProtocolReq L4PortInd Ipv4ControlInfo Ipv6ControlInfo down PacketProtocolTag
Definition: IUdp-gates.txt:25
inet::sctp::SctpAssociation::SSFunctions::ssAddInStreams
void(SctpAssociation::* ssAddInStreams)(uint32_t inStreams)
Definition: SctpAssociation.h:1290
inet::sctp::SctpStateVariables::highSpeedCC
bool highSpeedCC
Definition: SctpAssociation.h:743
inet::sctp::SctpAssociation::processCookieAckArrived
bool processCookieAckArrived()
Definition: SctpAssociationRcvMessage.cc:890
inet::sctp::SctpStateVariables::padding
bool padding
Definition: SctpAssociation.h:822
inet::sctp::SctpStateVariables::resetOutStreams
std::list< uint16_t > resetOutStreams
Definition: SctpAssociation.h:790
inet::sctp::SctpGapList::setInitialCumAckTsn
void setInitialCumAckTsn(const uint32_t cumAckTsn)
Definition: SctpGapList.h:73
SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_LENGTH
#define SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_LENGTH
Definition: SctpAssociation.h:218
inet::sctp::SctpQueue::getChunkFast
SctpDataVariables * getChunkFast(const uint32_t tsn, bool &firstTime)
Definition: SctpQueue.cc:121
inet::SCTP_C_ABORT
@ SCTP_C_ABORT
Definition: SctpCommand_m.h:134
inet::sctp::ERROR_DELETE_LAST_IP_ADDRESS
@ ERROR_DELETE_LAST_IP_ADDRESS
Definition: SctpAssociation.h:166
inet::sctp::SHUTDOWN
@ SHUTDOWN
Definition: SctpAssociation.h:109
inet::sctp::SCTP_E_RCV_ABORT
@ SCTP_E_RCV_ABORT
Definition: SctpAssociation.h:69
inet::sctp::SCTP_E_CLOSE
@ SCTP_E_CLOSE
Definition: SctpAssociation.h:66
inet::sctp::NOTHING_TO_DO
@ NOTHING_TO_DO
Definition: SctpAssociation.h:134
inet::sctp::SctpAssociation::SctpPathVariables
friend class SctpPathVariables
Definition: SctpAssociation.h:856
inet::sctp::PERFORMED_WITH_OPTION
@ PERFORMED_WITH_OPTION
Definition: SctpAssociation.h:154
inet::sctp::SctpAssociation::fragmentOutboundDataMsgs
void fragmentOutboundDataMsgs()
Definition: SctpAssociationUtil.cc:2428
inet::sctp::SSN_TSN_RESET_REQUEST_PARAMETER
@ SSN_TSN_RESET_REQUEST_PARAMETER
Definition: SctpAssociation.h:149
inet::sctp::SctpPathVariables::vectorPathReceivedTsn
cOutVector * vectorPathReceivedTsn
Definition: SctpAssociation.h:394
inet::sctp::SctpAssociation::listening
bool listening
Definition: SctpAssociation.h:901
inet::sctp::SctpStateVariables::getPrimaryPathIndex
const L3Address & getPrimaryPathIndex() const
Definition: SctpAssociation.h:541
inet::sctp::SctpStateVariables::numGapReports
uint32_t numGapReports
Definition: SctpAssociation.h:593
inet::sctp::SctpStateVariables::lastTransmission
simtime_t lastTransmission
Definition: SctpAssociation.h:611
inet::sctp::SctpAssociation::statisticsPeerRwnd
cOutVector * statisticsPeerRwnd
Definition: SctpAssociation.h:974
inet::sctp::SUCCESS_INDICATION
@ SUCCESS_INDICATION
Definition: SctpAssociation.h:165
inet::sctp::SctpShutdownChunk::dup
virtual SctpShutdownChunk * dup() const override
Definition: SctpHeader_m.h:1323
inet::sctp::Sctp::addLocalAddressToAllRemoteAddresses
void addLocalAddressToAllRemoteAddresses(SctpAssociation *assoc, L3Address address, std::vector< L3Address > remAddresses)
Definition: Sctp.cc:704
inet::sctp::SctpAlgorithm::sendCommandInvoked
virtual void sendCommandInvoked(SctpPathVariables *path)=0
inet::sctp::REQUEST_IN_PROGRESS
@ REQUEST_IN_PROGRESS
Definition: SctpAssociation.h:138
inet::sctp::SctpAssociation::peekAbandonedChunk
SctpDataVariables * peekAbandonedChunk(const SctpPathVariables *path)
Definition: SctpAssociationUtil.cc:2380
inet::sctp::SctpStateVariables::assocThroughput
uint32_t assocThroughput
Definition: SctpAssociation.h:840
inet::sctp::SctpStateVariables::messagesToPush
uint32_t messagesToPush
Definition: SctpAssociation.h:623
inet::sctp::SctpAssociation::process_TIMEOUT_ASCONF
void process_TIMEOUT_ASCONF(SctpPathVariables *path)
Definition: SctpAssociationRcvMessage.cc:3742
inet::sctp::Sctp::setRtoMax
void setRtoMax(double rtoMax)
Definition: Sctp.h:271
inet::sctp::SCTP_S_SHUTDOWN_SENT
@ SCTP_S_SHUTDOWN_SENT
Definition: SctpAssociation.h:52
inet::sctp::SctpStateVariables::peerAllowsChunks
bool peerAllowsChunks
Definition: SctpAssociation.h:827
inet::Ipv6Address::MULTICAST
@ MULTICAST
Definition: Ipv6Address.h:45
inet::SCTP_I_ESTABLISHED
@ SCTP_I_ESTABLISHED
Definition: SctpCommand_m.h:199
inet::sctp::SctpAssociation::handleChunkReportedAsAcked
void handleChunkReportedAsAcked(uint32_t &highestNewAck, simtime_t &rttEstimation, SctpDataVariables *myChunk, SctpPathVariables *sackPath, const bool sackIsNonRevokable)
Definition: SctpAssociationRcvMessage.cc:1586
inet::sctp::SctpAssociation::numberOfRemoteAddresses
uint32_t numberOfRemoteAddresses
Definition: SctpAssociation.h:932
inet::sctp::SctpStateVariables::allowCMT
bool allowCMT
Definition: SctpAssociation.h:694
inet::sctp::Sctp::setRtoInitial
void setRtoInitial(double rtoInitial)
Definition: Sctp.h:269
inet::sctp::SctpAssociation::putInDeliveryQ
void putInDeliveryQ(uint16_t sid)
Definition: SctpAssociationUtil.cc:1912
inet::sctp::SctpAssociation::T5_ShutdownGuardTimer
cMessage * T5_ShutdownGuardTimer
Definition: SctpAssociation.h:912
inet::sctp::ASCONF_ACK
@ ASCONF_ACK
Definition: SctpAssociation.h:117
inet::sctp::SctpStateVariables::findPeerRequestNum
bool findPeerRequestNum(uint32_t num)
Definition: SctpAssociationBase.cc:505
inet::sctp::SCTP_E_RCV_VALID_COOKIE_ECHO
@ SCTP_E_RCV_VALID_COOKIE_ECHO
Definition: SctpAssociation.h:70
inet::sctp::SctpStateVariables::CCCV_CMTRP_Test1
@ CCCV_CMTRP_Test1
Definition: SctpAssociation.h:753
inet::sctp::SctpStateVariables::cmtChunkReschedulingThreshold
double cmtChunkReschedulingThreshold
Definition: SctpAssociation.h:722
inet::sctp::SctpAssociation::processOutAndResponseArrived
SctpEventCode processOutAndResponseArrived(SctpOutgoingSsnResetRequestParameter *outRequestParam, SctpStreamResetResponseParameter *responseParam)
Definition: SctpAssociationRcvMessage.cc:2757
inet::sctp::SctpAssociation::SSFunctions::ssUsableStreams
int32_t(SctpAssociation::* ssUsableStreams)()
Definition: SctpAssociation.h:1293
inet::sctp::SctpStateVariables::CCRV_None
@ CCRV_None
Definition: SctpAssociation.h:715
inet::sctp::SctpAssociation::sendShutdownAck
void sendShutdownAck(const L3Address &dest)
Definition: SctpAssociationUtil.cc:1107
inet::units::values::s
value< double, units::s > s
Definition: Units.h:1235
inet::sctp::SctpStateVariables::streamsToReset
std::list< uint16_t > streamsToReset
Definition: SctpAssociation.h:793
inet::sctp::SCTP_E_ACCEPT_SOCKET_ID
@ SCTP_E_ACCEPT_SOCKET_ID
Definition: SctpAssociation.h:98
SCTP_COMMON_HEADER
#define SCTP_COMMON_HEADER
Definition: SctpAssociation.h:203
inet::sctp::SctpAssociation::loadPacket
void loadPacket(SctpPathVariables *pathVar, Ptr< SctpHeader > *sctpMsg, uint16_t *chunksAdded, uint16_t *dataChunksAdded, bool *authAdded)
Definition: SctpAssociationSendAll.cc:83
inet::units::units::B
intscale< b, 1, 8 > B
Definition: Units.h:1168
inet::sctp::SctpAssociation::choosePathForRetransmission
SctpPathVariables * choosePathForRetransmission()
Definition: SctpAssociationSendAll.cc:231
inet::Ipv4Address::BROADCAST
@ BROADCAST
Definition: Ipv4Address.h:78
inet::sctp::SctpQueue::checkAndInsertChunk
bool checkAndInsertChunk(const uint32_t key, SctpDataVariables *chunk)
Definition: SctpQueue.cc:39
inet::sctp::SctpAssociation::cumTsnAck
cOutVector * cumTsnAck
Definition: SctpAssociation.h:946
inet::sctp::SctpAssociation::fairTimer
bool fairTimer
Definition: SctpAssociation.h:918
inet::IRoutingTable::getOutputInterfaceForDestination
virtual NetworkInterface * getOutputInterfaceForDestination(const L3Address &dest) const =0
Convenience function based on findBestMatchingRoute().
inet::sctp::SctpStateVariables::cmtSlowPathRTTUpdate
bool cmtSlowPathRTTUpdate
Definition: SctpAssociation.h:727
inet::sctp::Sctp::crcMode
CrcMode crcMode
Definition: Sctp.h:206
inet::sctp::SctpAssociation::retransmissionQ
SctpQueue * retransmissionQ
Definition: SctpAssociation.h:958
SCTP_OUTGOING_RESET_REQUEST_PARAMETER_LENGTH
#define SCTP_OUTGOING_RESET_REQUEST_PARAMETER_LENGTH
Definition: SctpAssociation.h:216
inet::sctp::SctpPathVariables::activePath
bool activePath
Definition: SctpAssociation.h:278
inet::SCTP_C_SEND_ORDERED
@ SCTP_C_SEND_ORDERED
Definition: SctpCommand_m.h:137
inet::sctp::PATH_MAP_TO_PATH
@ PATH_MAP_TO_PATH
Definition: SctpAssociation.h:200
inet::sctp::SctpAssociation::retransmitAsconf
void retransmitAsconf()
Definition: SctpAssociationAddIp.cc:158
inet::sctp::SctpStateVariables::sizeKeyVector
uint32_t sizeKeyVector
Definition: SctpAssociation.h:815
inet::sctp::SctpStateVariables::streamResetSequenceNumber
uint32_t streamResetSequenceNumber
Definition: SctpAssociation.h:782
inet::sctp::SctpAssociation::typeInOwnChunkList
bool typeInOwnChunkList(uint16_t type)
Definition: SctpAssociationAddIp.cc:287
inet::SCTP_I_CONNECTION_RESET
@ SCTP_I_CONNECTION_RESET
Definition: SctpCommand_m.h:203
ADD_PADDING
#define ADD_PADDING(x)
Definition: SctpAssociation.h:252
inet::sctp::PRIORITY
@ PRIORITY
Definition: SctpAssociation.h:197
inet::sctp::SCTP_E_RCV_INIT_ACK
@ SCTP_E_RCV_INIT_ACK
Definition: SctpAssociation.h:71
inet::sctp::STREAM_RESET_RESPONSE_PARAMETER
@ STREAM_RESET_RESPONSE_PARAMETER
Definition: SctpAssociation.h:150
inet::sctp::SctpAssociation::processAsconfArrived
SctpEventCode processAsconfArrived(SctpAsconfChunk *asconfChunk)
Definition: SctpAssociationRcvMessage.cc:3170
inet::sctp::SctpAssociation::sctpAlgorithm
SctpAlgorithm * sctpAlgorithm
Definition: SctpAssociation.h:961
inet::Protocol::udp
static const Protocol udp
Definition: Protocol.h:117
inet::sctp::SHUTDOWN_ACK
@ SHUTDOWN_ACK
Definition: SctpAssociation.h:110
inet::sctp::SctpAssociation::getNextAddress
const L3Address & getNextAddress(const SctpPathVariables *oldPath) const
Definition: SctpAssociation.h:1220
inet::sctp::SctpAssociation::fsm
cFSM * fsm
Definition: SctpAssociation.h:954
inet::sctp::SctpAssociation::QueueCounter::bookedTransQ
CounterMap bookedTransQ
Definition: SctpAssociation.h:868
inet::sctp::SctpAssociation::remotePort
uint16_t remotePort
Definition: SctpAssociation.h:905
inet::SCTP_C_QUEUE_BYTES_LIMIT
@ SCTP_C_QUEUE_BYTES_LIMIT
Definition: SctpCommand_m.h:140
inet::sctp::SctpAssociation::process_ASSOCIATE
void process_ASSOCIATE(SctpEventCode &event, SctpCommandReq *sctpCommand, cMessage *msg)
Definition: SctpAssociationEventProc.cc:27
inet::sctp::PR_TTL
@ PR_TTL
Definition: SctpAssociation.h:127
inet::sctp::SctpStateVariables::lastTsnReceived
uint32_t lastTsnReceived
Definition: SctpAssociation.h:606
inet::sctp::SctpStateVariables::dupList
std::list< uint32_t > dupList
Definition: SctpAssociation.h:598
inet::sctp::SctpStateVariables::strictCwndBooking
bool strictCwndBooking
Definition: SctpAssociation.h:734
inet::sctp::INIT
@ INIT
Definition: SctpAssociation.h:103
if
if(cwndVector) cwndVector -> record(state->snd_cwnd)
inet::SCTP_I_SHUTDOWN_RECEIVED
@ SCTP_I_SHUTDOWN_RECEIVED
Definition: SctpCommand_m.h:209
inet::sctp::SctpAssociation::initCcParameters
void initCcParameters(SctpPathVariables *path)
SctpCcFunctions.
Definition: SctpCcFunctions.cc:397
inet::sctp::SctpAssociation::initInboundStreams
uint32_t initInboundStreams
Definition: SctpAssociation.h:935
inet::SCTP_C_NO_OUTSTANDING
@ SCTP_C_NO_OUTSTANDING
Definition: SctpCommand_m.h:143
inet::sctp::SctpStateVariables::initRexmitTimeout
simtime_t initRexmitTimeout
Definition: SctpAssociation.h:640
inet::sctp::SctpStateVariables::bufferedMessages
uint32_t bufferedMessages
Definition: SctpAssociation.h:831
inet::sctp::SctpAssociation::T2_ShutdownTimer
cMessage * T2_ShutdownTimer
Definition: SctpAssociation.h:911
inet::sctp::SctpAssociation::getSortedPathMap
std::vector< SctpPathVariables * > getSortedPathMap()
Definition: SctpAssociationSendAll.cc:121
inet::sctp::SctpAssociation::assocBestPaths
SctpPathCollection assocBestPaths
Definition: SctpAssociation.h:891
inet::sctp::SctpAssociation::sendToApp
void sendToApp(cMessage *msg)
Utility: sends packet to application.
Definition: SctpAssociationUtil.cc:501
inet::sctp::PR_PRIO
@ PR_PRIO
Definition: SctpAssociation.h:129
inet::sctp::SctpAssociation::bytes
BytesToBeSent bytes
Definition: SctpAssociation.h:952
inet::SCTP_I_PEER_CLOSED
@ SCTP_I_PEER_CLOSED
Definition: SctpCommand_m.h:200
inet::sctp::SctpAssociation::compareRandom
bool compareRandom()
Definition: SctpAssociationAddIp.cc:226
inet::SCTP_C_ASSOCIATE
@ SCTP_C_ASSOCIATE
Definition: SctpCommand_m.h:130
inet::sctp::SctpAssociation::chunkToInt
static uint16_t chunkToInt(const char *type)
Definition: SctpAssociationUtil.cc:237
inet::sctp::SctpStateVariables::localMsgRwnd
uint32_t localMsgRwnd
Definition: SctpAssociation.h:829
inet::sctp::SctpAssociation::sendPacketDrop
void sendPacketDrop(const bool flag)
Definition: SctpAssociationUtil.cc:1243
inet::sctp::SctpStateVariables::cmtBufferSplitVariant
BufferSplitVariant cmtBufferSplitVariant
Definition: SctpAssociation.h:711
inet::insertTransportProtocolHeader
void insertTransportProtocolHeader(Packet *packet, const Protocol &protocol, const Ptr< TransportHeaderBase > &header)
Definition: L4Tools.cc:77
inet::sctp::SctpAssociation::FairStopTimer
cMessage * FairStopTimer
Definition: SctpAssociation.h:922
inet::sctp::SctpAssociation::streamSchedulerFCFS
int32_t streamSchedulerFCFS(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:428
inet::sctp::SctpAssociation::unorderedQueueEmptyOfStream
bool unorderedQueueEmptyOfStream(uint16_t sid)
Definition: SctpAssociationUtil.cc:90
inet::sctp::SctpStateVariables::cookieChunk
SctpCookieEchoChunk * cookieChunk
pointer to the cookie chunk data structure (for retransmissions)
Definition: SctpAssociation.h:644
inet::sctp::SctpStateVariables::stopReading
bool stopReading
Definition: SctpAssociation.h:588
inet::sctp::DEFERRED
@ DEFERRED
Definition: SctpAssociation.h:140
inet::sctp::SctpAssociation::chunkReschedulingControl
void chunkReschedulingControl(SctpPathVariables *path)
Definition: SctpAssociationSendAll.cc:330
inet::sctp::Sctp::setRtoMin
void setRtoMin(double rtoMin)
Definition: Sctp.h:270
inet::sctp::SctpAssociation::localAddr
L3Address localAddr
Definition: SctpAssociation.h:903
SCTP_COOKIE_LENGTH
#define SCTP_COOKIE_LENGTH
Definition: SctpAssociation.h:232
inet::sctp::SctpAssociation::ssModule
uint16_t ssModule
Definition: SctpAssociation.h:1296
inet::sctp::SctpStateVariables::CCCV_CMT_OLIA
@ CCCV_CMT_OLIA
Definition: SctpAssociation.h:752
inet::sctp::SctpAssociation::CCFunctions::ccUpdateMaxBurst
void(SctpAssociation::* ccUpdateMaxBurst)(SctpPathVariables *path)
Definition: SctpAssociation.h:884
inet::sctp::SctpStateVariables::peerRequestType
uint16_t peerRequestType
Definition: SctpAssociation.h:798
inet::sctp::ERROR_DELETE_SOURCE_ADDRESS
@ ERROR_DELETE_SOURCE_ADDRESS
Definition: SctpAssociation.h:167
inet::sctp::SctpStateVariables::CBSV_None
@ CBSV_None
Definition: SctpAssociation.h:706
inet::sctp::SctpAssociation::processResetResponseArrived
void processResetResponseArrived(SctpStreamResetResponseParameter *responseParam)
Definition: SctpAssociationRcvMessage.cc:2518
inet::sctp::SctpStateVariables::resetInfo
SctpResetReq * resetInfo
Definition: SctpAssociation.h:797
inet::sctp::SctpAssociation::stopTimers
void stopTimers()
Definition: SctpAssociationRcvMessage.cc:3659
inet::sctp::Sctp::AssocStat::numFastRtx
uint32_t numFastRtx
Definition: Sctp.h:130
inet::sctp::SctpAssociation::sendStreamResetRequest
void sendStreamResetRequest(SctpResetReq *info)
Definition: SctpAssociationStreamReset.cc:512
type
removed type
Definition: IUdp-gates.txt:7
inet::sctp::SctpAssociation::CCFunctions::ccUpdateBytesAcked
void(SctpAssociation::* ccUpdateBytesAcked)(SctpPathVariables *path, const uint32_t ackedBytes, const bool ctsnaAdvanced)
Definition: SctpAssociation.h:885
inet::sctp::SctpAssociation::chunkHasBeenAcked
bool chunkHasBeenAcked(const SctpDataVariables *chunk) const
Definition: SctpAssociation.h:1450
inet::sctp::SctpAssociation::process_SEND
void process_SEND(SctpEventCode &event, SctpCommandReq *sctpCommand, cMessage *msg)
Definition: SctpAssociationEventProc.cc:126
inet::sctp::SctpStateVariables::lastTsnAck
uint32_t lastTsnAck
Definition: SctpAssociation.h:604
inet::sctp::SctpAssociation::handleChunkReportedAsMissing
void handleChunkReportedAsMissing(const SctpSackChunk *sackChunk, const uint32_t highestNewAck, SctpDataVariables *myChunk, SctpPathVariables *sackPath)
Definition: SctpAssociationRcvMessage.cc:1688
inet::sctp::Sctp::removeRemoteAddressFromAllAssociations
void removeRemoteAddressFromAllAssociations(SctpAssociation *assoc, L3Address address, std::vector< L3Address > locAddresses)
Definition: Sctp.cc:758
inet::sctp::SctpStateVariables::cmtCUCVariant
CUCVariant cmtCUCVariant
Definition: SctpAssociation.h:703
inet::sctp::SctpGapList::removeFromGapList
void removeFromGapList(const uint32_t removedTsn)
Definition: SctpGapList.cc:348
inet::SCTP_C_QUEUE_MSGS_LIMIT
@ SCTP_C_QUEUE_MSGS_LIMIT
Definition: SctpCommand_m.h:141
inet::sctp::SctpStateVariables::swsLimit
uint32_t swsLimit
Definition: SctpAssociation.h:653
inet::sctp::SctpAssociation::sendInitAck
void sendInitAck(SctpInitChunk *initchunk)
Definition: SctpAssociationUtil.cc:772
inet::sctp::SctpStateVariables::fragPoint
uint32_t fragPoint
Definition: SctpAssociation.h:618
inet::sctp::SctpStateVariables::getNumRequestsNotPerformed
uint16_t getNumRequestsNotPerformed()
Definition: SctpAssociationBase.cc:540
inet::sctp::SctpAssociation::makeRoomForTsn
bool makeRoomForTsn(const uint32_t tsn, const uint32_t length, const bool uBit)
Definition: SctpAssociationUtil.cc:2154
inet::sctp::SctpAssociation::makeVarFromMsg
SctpDataVariables * makeVarFromMsg(SctpDataChunk *datachunk)
Definition: SctpAssociationUtil.cc:2245
inet::sctp::SctpStateVariables::cmtSmartT3Reset
bool cmtSmartT3Reset
Definition: SctpAssociation.h:724
inet::Ipv4Address::RESERVED
@ RESERVED
Definition: Ipv4Address.h:83
inet::sctp::HighSpeedCwndAdjustmentEntry::increaseFactor
double increaseFactor
Definition: SctpCcFunctions.cc:33
inet::sctp::SctpAssociation::typeInChunkList
bool typeInChunkList(uint16_t type)
Definition: SctpAssociationAddIp.cc:277
inet::sctp::SctpStateVariables::rpMinCwnd
uint32_t rpMinCwnd
Definition: SctpAssociation.h:759
inet::sctp::SctpStateVariables::lastThroughputTime
simtime_t lastThroughputTime
Definition: SctpAssociation.h:837
inet::sctp::SctpAssociation::createForwardTsnChunk
SctpForwardTsnChunk * createForwardTsnChunk(const L3Address &pid)
Definition: SctpAssociationUtil.cc:1349
inet::sctp::SctpStateVariables::peerTieTag
uint8_t peerTieTag[32]
Definition: SctpAssociation.h:627
inet::sctp::Sctp::getMaxInitRetransTimeout
int getMaxInitRetransTimeout()
Definition: Sctp.h:256
inet::sctp::SctpAssociation::statisticsTotalBandwidth
cOutVector * statisticsTotalBandwidth
Definition: SctpAssociation.h:969
inet::sctp::SCTP_S_COOKIE_ECHOED
@ SCTP_S_COOKIE_ECHOED
Definition: SctpAssociation.h:49
inet::sctp::SctpAssociation::status
int32_t status
Definition: SctpAssociation.h:937
inet::sctp::SctpAssociation::BytesToBeSent::packet
bool packet
Definition: SctpAssociation.h:874
inet::sctp::SctpAssociation::resetExpectedSsns
void resetExpectedSsns()
Definition: SctpAssociationStreamReset.cc:884
inet::sctp::SCTP_E_RESET_ASSOC
@ SCTP_E_RESET_ASSOC
Definition: SctpAssociation.h:92
inet::sctp::SctpAssociation::calculateRcvBuffer
void calculateRcvBuffer()
Definition: SctpAssociationUtil.cc:47
inet::sctp::SctpAssociation::increaseOutstandingBytes
void increaseOutstandingBytes(SctpDataVariables *chunk, SctpPathVariables *path)
Definition: SctpAssociationSendAll.cc:20
inet::sctp::SctpAssociation::rpPathBlockingControl
int32_t rpPathBlockingControl(SctpPathVariables *path, double reduction)
Definition: SctpCcFunctions.cc:410
inet::sctp::SctpStateVariables::rpPathBlocking
bool rpPathBlocking
Definition: SctpAssociation.h:757
inet::sctp::SctpAssociation::sendInit
void sendInit()
Methods for creating and sending chunks.
Definition: SctpAssociationUtil.cc:554
inet::sctp::SctpAssociation::statisticsNumDuplicatesStored
cOutVector * statisticsNumDuplicatesStored
Definition: SctpAssociation.h:979
inet::sctp::SctpStateVariables::initialWindow
uint32_t initialWindow
Definition: SctpAssociation.h:692
inet::SCTP_C_SET_RTO_INFO
@ SCTP_C_SET_RTO_INFO
Definition: SctpCommand_m.h:152
inet::sctp::SctpAssociation::processSsnTsnResetRequestArrived
void processSsnTsnResetRequestArrived(SctpSsnTsnResetRequestParameter *requestParam)
Definition: SctpAssociationRcvMessage.cc:2482
inet::sctp::SctpStateVariables::CUCV_PseudoCumAck
@ CUCV_PseudoCumAck
Definition: SctpAssociation.h:700
inet::sctp::SctpStateVariables::sackAllowed
bool sackAllowed
Definition: SctpAssociation.h:576
inet::sctp::SctpGapList::resetGaps
void resetGaps(const uint32_t newCumAck)
Definition: SctpGapList.cc:384
inet::sctp::SctpGapList::GT_Revokable
@ GT_Revokable
Definition: SctpGapList.h:96
inet::sctp::SctpAssociation::rt
IRoutingTable * rt
Definition: SctpAssociation.h:927
inet::sctp::SctpStateVariables::CCCV_Off
@ CCCV_Off
Definition: SctpAssociation.h:747
inet::sctp::SctpAssociation::sackPeriod
double sackPeriod
Definition: SctpAssociation.h:941
inet::sctp::OUTGOING_RESET_REQUEST_PARAMETER
@ OUTGOING_RESET_REQUEST_PARAMETER
Definition: SctpAssociation.h:147
inet::sctp::SctpAssociation::processSackArrived
SctpEventCode processSackArrived(SctpSackChunk *sackChunk)
Definition: SctpAssociationRcvMessage.cc:974
inet::sctp::SctpAssociation::statisticsNumNonRevokableGapBlocksSent
cOutVector * statisticsNumNonRevokableGapBlocksSent
Definition: SctpAssociation.h:981
inet::sctp::SctpStateVariables::findPeerStreamToReset
bool findPeerStreamToReset(uint16_t sn)
Definition: SctpAssociationBase.cc:510
inet::sctp::SCTP_E_ABORT
@ SCTP_E_ABORT
Definition: SctpAssociation.h:64
inet::units::values::b
value< int64_t, units::b > b
Definition: Units.h:1241
inet::sctp::SctpStateVariables::lastTsnBeforeReset
uint32_t lastTsnBeforeReset
Definition: SctpAssociation.h:787
inet::sctp::Sctp::getEnableHeartbeats
bool getEnableHeartbeats()
Definition: Sctp.h:265
inet::sctp::Sctp::removeAssociation
void removeAssociation(SctpAssociation *assoc)
Definition: Sctp.cc:846
inet::sctp::SctpAssociation::getAllTransQ
uint32_t getAllTransQ()
Definition: SctpAssociationSendAll.cc:1476
inet::sctp::SctpAssociation::process_PRIMARY
void process_PRIMARY(SctpEventCode &event, SctpCommandReq *sctpCommand)
Definition: SctpAssociationEventProc.cc:325
SCTP_SHUTDOWN_CHUNK_LENGTH
#define SCTP_SHUTDOWN_CHUNK_LENGTH
Definition: SctpAssociation.h:212
inet::sctp::SctpAssociation::sendToIP
void sendToIP(Packet *pkt, const Ptr< SctpHeader > &sctpmsg, L3Address dest)
Utility: adds control info to message and sends it to IP.
Definition: SctpAssociationUtil.cc:360
inet::sctp::SctpAssociation::tsnIsDuplicate
bool tsnIsDuplicate(const uint32_t tsn) const
Methods dealing with the handling of TSNs
Definition: SctpAssociationUtil.cc:2234
inet::sctp::SctpAssociation::sendShutdownComplete
void sendShutdownComplete()
Definition: SctpAssociationUtil.cc:1135
inet::sctp::SctpStateVariables::pushMessagesLeft
int32_t pushMessagesLeft
Definition: SctpAssociation.h:624
inet::sctp::SctpStateVariables::MBV_MaxBurst
@ MBV_MaxBurst
Definition: SctpAssociation.h:687
inet::sctp::SctpStateVariables::chunksAdded
uint16_t chunksAdded
Definition: SctpAssociation.h:658
inet::Ipv4Address::MULTICAST
@ MULTICAST
Definition: Ipv4Address.h:77
inet::sctp::SctpAssociation::SCTP_UINT16_GT
static bool SCTP_UINT16_GT(uint16_t a, uint16_t b)
Compare TSNs.
Definition: SctpAssociation.h:1059
SCTP_HEARTBEAT_CHUNK_LENGTH
#define SCTP_HEARTBEAT_CHUNK_LENGTH
Definition: SctpAssociation.h:208
inet::sctp::SctpStateVariables::stopOldData
bool stopOldData
Definition: SctpAssociation.h:582
inet::sctp::Sctp::sctpVTagMap
SctpVTagMap sctpVTagMap
Definition: Sctp.h:162
inet::SCTP_I_DATA_NOTIFICATION
@ SCTP_I_DATA_NOTIFICATION
Definition: SctpCommand_m.h:198
inet::sctp::PR_RTX
@ PR_RTX
Definition: SctpAssociation.h:128
SCTP_DATA_CHUNK_LENGTH
#define SCTP_DATA_CHUNK_LENGTH
Definition: SctpAssociation.h:205
SCTP_ABORT_CHUNK_LENGTH
#define SCTP_ABORT_CHUNK_LENGTH
Definition: SctpAssociation.h:209
inet::sctp::HMAC_ALGO
@ HMAC_ALGO
Definition: SctpAssociation.h:176
inet::sctp::NO_RESET
@ NO_RESET
Definition: SctpAssociation.h:139
inet::SCTP_I_STATUS
@ SCTP_I_STATUS
Definition: SctpCommand_m.h:205
inet::sctp::SctpAssociation::performStateTransition
bool performStateTransition(const SctpEventCode &event)
Implemements the pure SCTP state machine.
Definition: SctpAssociationBase.cc:1176
inet::sctp::ADD_INCOMING_STREAMS_REQUEST_PARAMETER
@ ADD_INCOMING_STREAMS_REQUEST_PARAMETER
Definition: SctpAssociation.h:152
inet::sctp::SctpAssociation::sendCookieEcho
void sendCookieEcho(SctpInitAckChunk *initackchunk)
Definition: SctpAssociationUtil.cc:952
SCTP_ADD_STREAMS_REQUEST_PARAMETER_LENGTH
#define SCTP_ADD_STREAMS_REQUEST_PARAMETER_LENGTH
Definition: SctpAssociation.h:220
inet::Ipv4Address::LINKLOCAL
@ LINKLOCAL
Definition: Ipv4Address.h:84
inet::sctp::SctpAssociation::getPath
SctpPathVariables * getPath(const L3Address &pathId) const
Definition: SctpAssociation.h:1047
inet::sctp::SctpStateVariables::requestsOverlap
bool requestsOverlap
Definition: SctpAssociation.h:781
inet::sctp::SctpStateVariables::corrIdNum
uint32_t corrIdNum
Definition: SctpAssociation.h:769
inet::sctp::SctpStateVariables::sendHeartbeatsOnActivePaths
bool sendHeartbeatsOnActivePaths
Definition: SctpAssociation.h:656
inet::sctp::SctpAssociation::retransmitShutdown
void retransmitShutdown()
Definition: SctpAssociationUtil.cc:1215
inet::sctp::SctpAssociation::processInAndOutResetRequestArrived
SctpEventCode processInAndOutResetRequestArrived(SctpIncomingSsnResetRequestParameter *inRequestParam, SctpOutgoingSsnResetRequestParameter *outRequestParam)
Definition: SctpAssociationRcvMessage.cc:2634
inet::sctp::max
double max(const double a, const double b)
Returns the maximum of a and b.
Definition: SctpAssociation.h:266
inet::sctp::SCTP_S_SHUTDOWN_ACK_SENT
@ SCTP_S_SHUTDOWN_ACK_SENT
Definition: SctpAssociation.h:54
inet::sctp::SCTP_S_COOKIE_WAIT
@ SCTP_S_COOKIE_WAIT
Definition: SctpAssociation.h:48
IP_HEADER_LENGTH
#define IP_HEADER_LENGTH
Definition: SctpAssociation.h:227
inet::sctp::SCTP_E_TIMEOUT_RTX_TIMER
@ SCTP_E_TIMEOUT_RTX_TIMER
Definition: SctpAssociation.h:79
inet::physicallayer::k
const double k
Definition: Qam1024Modulation.cc:14
SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH
#define SCTP_STREAM_RESET_RESPONSE_PARAMETER_LENGTH
Definition: SctpAssociation.h:219
inet::sctp::SctpStateVariables::checkSackSeqNumber
bool checkSackSeqNumber
Definition: SctpAssociation.h:762
inet::SCTP_I_TIMED_OUT
@ SCTP_I_TIMED_OUT
Definition: SctpCommand_m.h:204
inet::sctp::SctpStateVariables::bytesRcvd
uint64_t bytesRcvd
Definition: SctpAssociation.h:620
inet::sctp::ERRORTYPE
@ ERRORTYPE
Definition: SctpAssociation.h:111
inet::sctp::SCTP_E_PRIMARY
@ SCTP_E_PRIMARY
Definition: SctpAssociation.h:84
inet::sctp::SctpAssociation::sendShutdown
void sendShutdown()
Definition: SctpAssociationUtil.cc:1181
inet::sctp::SctpAssociation::pmRttMeasurement
void pmRttMeasurement(SctpPathVariables *path, const simtime_t &rttEstimation)
Definition: SctpAssociationUtil.cc:2836
inet::sctp::SctpStateVariables::newChunkReceived
bool newChunkReceived
Definition: SctpAssociation.h:568
inet::sctp::SctpAssociation::stateName
static const char * stateName(int32_t state)
Utility: returns name of SCTP_S_xxx constants.
Definition: SctpAssociationUtil.cc:139
inet::sctp::SctpAssociation::remoteAddressList
AddressVector remoteAddressList
Definition: SctpAssociation.h:931
inet::sctp::SctpAssociation::SctpAssociation
SctpAssociation(Sctp *mod, int32_t appGateIndex, int32_t assocId, IRoutingTable *rt, IInterfaceTable *ift)
Constructor.
Definition: SctpAssociationBase.cc:555
inet::sctp::SctpStateVariables::queuedReceivedBytes
uint64_t queuedReceivedBytes
Definition: SctpAssociation.h:615
inet::sctp::SctpGapList::GT_NonRevokable
@ GT_NonRevokable
Definition: SctpGapList.h:97
inet::sctp::SctpAssociation::storePacket
void storePacket(SctpPathVariables *pathVar, const Ptr< SctpHeader > &sctpMsg, uint16_t chunksAdded, uint16_t dataChunksAdded, bool authAdded)
Definition: SctpAssociationSendAll.cc:45
inet::sctp::DATA
@ DATA
Definition: SctpAssociation.h:102
PK
#define PK(msg)
Definition: INETDefs.h:89
inet::sctp::SctpStateVariables::sendBuffer
uint64_t sendBuffer
Definition: SctpAssociation.h:649
inet::sctp::Sctp::auth
bool auth
Definition: Sctp.h:200
inet::sctp::SctpAssociation::nonRenegablyAckChunk
void nonRenegablyAckChunk(SctpDataVariables *chunk, SctpPathVariables *sackPath, simtime_t &rttEstimation, Sctp::AssocStat *assocStat)
Definition: SctpAssociationRcvMessage.cc:1851
inet::sctp::SctpAlgorithm::createStateVariables
virtual SctpStateVariables * createStateVariables()=0
inet::sctp::SctpAssociation::process_TIMEOUT_HEARTBEAT_INTERVAL
void process_TIMEOUT_HEARTBEAT_INTERVAL(SctpPathVariables *path, bool force)
Definition: SctpAssociationRcvMessage.cc:3595
inet::sctp::SctpAssociation::statisticsRevokableGapBlocksInLastSACK
cOutVector * statisticsRevokableGapBlocksInLastSACK
Definition: SctpAssociation.h:971
inet::sctp::SctpAssociation::resetSsns
void resetSsns()
Methods for Stream Reset.
Definition: SctpAssociationStreamReset.cc:914
inet::sctp::SctpStateVariables::cmtUseSFR
bool cmtUseSFR
Definition: SctpAssociation.h:728
inet::sctp::SctpAssociation::createSack
SctpSackChunk * createSack()
Definition: SctpAssociationUtil.cc:1537
inet::sctp::INCOMING_RESET_REQUEST_PARAMETER
@ INCOMING_RESET_REQUEST_PARAMETER
Definition: SctpAssociation.h:148
inet::SCTP_C_SET_STREAM_PRIO
@ SCTP_C_SET_STREAM_PRIO
Definition: SctpCommand_m.h:149
inet::sctp::SctpAssociation::ssFunctions
SSFunctions ssFunctions
Definition: SctpAssociation.h:1295
inet::sctp::SctpStateVariables::ssStreamToPathMap
std::map< uint16_t, int32_t > ssStreamToPathMap
Definition: SctpAssociation.h:847
inet::sctp::SctpStateVariables::packetsInTotalBurst
uint32_t packetsInTotalBurst
Definition: SctpAssociation.h:610
SCTP_AUTH_CHUNK_LENGTH
#define SCTP_AUTH_CHUNK_LENGTH
Definition: SctpAssociation.h:224
inet::sctp::SCTP_S_CLOSED
@ SCTP_S_CLOSED
Definition: SctpAssociation.h:47
inet::sctp::SctpAssociation::QueueCounter::roomSumSendStreams
uint64_t roomSumSendStreams
Definition: SctpAssociation.h:864
inet::sctp::SctpStateVariables::cmtRetransmissionVariant
const char * cmtRetransmissionVariant
Definition: SctpAssociation.h:696
inet::sctp::SctpStateVariables::CCRV_SenderOnly
@ CCRV_SenderOnly
Definition: SctpAssociation.h:716
inet::sctp::SctpStateVariables::CSP_Standard
@ CSP_Standard
Definition: SctpAssociation.h:736
inet::sctp::Sctp::addForkedAssociation
void addForkedAssociation(SctpAssociation *assoc, SctpAssociation *newAssoc, L3Address localAddr, L3Address remoteAddr, int32_t localPort, int32_t remotePort)
Update assocs socket pair, and register newAssoc (which'll keep LISTENing).
Definition: Sctp.cc:805
inet::sctp::SctpStateVariables::maxBurstVariant
MBVariant maxBurstVariant
Definition: SctpAssociation.h:691
inet::sctp::SctpAssociation::StartAddIP
cMessage * StartAddIP
Definition: SctpAssociation.h:915
inet::sctp::SCTP_E_TIMEOUT_SHUTDOWN_TIMER
@ SCTP_E_TIMEOUT_SHUTDOWN_TIMER
Definition: SctpAssociation.h:78
inet::sctp::SctpStateVariables::findTypeInRequests
RequestData * findTypeInRequests(uint16_t type)
Definition: SctpAssociationBase.cc:530
inet::sctp::SctpStateVariables::queuedDroppableBytes
uint64_t queuedDroppableBytes
Definition: SctpAssociation.h:614
SCTP_SUPPORTED_EXTENSIONS_PARAMETER_LENGTH
#define SCTP_SUPPORTED_EXTENSIONS_PARAMETER_LENGTH
Definition: SctpAssociation.h:221
inet::L3Address::IPv6
@ IPv6
Definition: L3Address.h:36
inet::sctp::SCTP_E_DELIVERED
@ SCTP_E_DELIVERED
Definition: SctpAssociation.h:85
inet::sctp::SctpAssociation::orderedQueueEmptyOfStream
bool orderedQueueEmptyOfStream(uint16_t sid)
Definition: SctpAssociationUtil.cc:83
inet::sctp::SctpAssociation::sendAddOutgoingStreamsRequest
void sendAddOutgoingStreamsRequest(uint16_t numStreams)
Definition: SctpAssociationStreamReset.cc:645
inet::sctp::SctpStateVariables::outstandingMessages
uint32_t outstandingMessages
Definition: SctpAssociation.h:832
inet::sctp::SctpAssociation::statisticsNonRevokableGapBlocksInLastSACK
cOutVector * statisticsNonRevokableGapBlocksInLastSACK
Definition: SctpAssociation.h:972
inet::sctp::SctpStateVariables::sctpMsg
Ptr< SctpHeader > sctpMsg
Definition: SctpAssociation.h:657
inet::sctp::Sctp::getAssocStat
AssocStat * getAssocStat(uint32_t assocId)
Definition: Sctp.h:216
inet::sctp::SctpAssociation::fd
int32_t fd
Definition: SctpAssociation.h:900
inet::sctp::SctpStateVariables::keyVector
uint8_t keyVector[512]
Definition: SctpAssociation.h:814
inet::sctp::SctpStateVariables::CUCV_Normal
@ CUCV_Normal
Definition: SctpAssociation.h:699
inet::sctp::SctpStateVariables::stopReceiving
bool stopReceiving
Definition: SctpAssociation.h:581
inet::sctp::RE_CONFIG
@ RE_CONFIG
Definition: SctpAssociation.h:119
inet::sctp::SctpAssociation::EndToEndDelay
cOutVector * EndToEndDelay
Definition: SctpAssociation.h:917
SCTP_COMPRESSED_NRSACK_CHUNK_LENGTH
#define SCTP_COMPRESSED_NRSACK_CHUNK_LENGTH
Definition: SctpAssociation.h:235
inet::sctp::SctpAssociation::streamIsPending
bool streamIsPending(int32_t sid)
Definition: SctpAssociationStreamReset.cc:31
inet::sctp::SctpStateVariables::bundleReset
bool bundleReset
Definition: SctpAssociation.h:777
inet::sctp::SctpAssociation::statisticsNumNonRevokableGapBlocksStored
cOutVector * statisticsNumNonRevokableGapBlocksStored
Definition: SctpAssociation.h:978
inet::sctp::SctpAssociation::tsnWasReneged
void tsnWasReneged(SctpDataVariables *chunk, const SctpPathVariables *sackPath, const int type)
Definition: SctpAssociationRcvMessage.cc:909
CASE
#define CASE(x)
inet::sctp::SctpStateVariables::cmtChunkReschedulingVariant
ChunkReschedulingVariant cmtChunkReschedulingVariant
Definition: SctpAssociation.h:721
inet::sctp::SctpStateVariables::fragInProgress
bool fragInProgress
Definition: SctpAssociation.h:591
inet::sctp::SctpAssociation::eventName
static const char * eventName(int32_t event)
Utility: returns name of SCTP_E_xxx constants.
Definition: SctpAssociationUtil.cc:158
SCTP_TSN_GE
#define SCTP_TSN_GE(a, b)
Definition: SctpAssociation.h:1072
inet::sctp::FAIR_BANDWITH_PACKET
@ FAIR_BANDWITH_PACKET
Definition: SctpAssociation.h:196
inet::sctp::SctpAssociation::advMsgRwnd
cOutVector * advMsgRwnd
Definition: SctpAssociation.h:916
inet::SCTP_I_ABORT
@ SCTP_I_ABORT
Definition: SctpCommand_m.h:206
inet::Protocol::sctp
static const Protocol sctp
Definition: Protocol.h:108
inet::sctp::SctpAssociation::getAddressLevel
static int getAddressLevel(const L3Address &addr)
Utility: return IPv4 or IPv6 address level.
Definition: SctpAssociationUtil.cc:2895
inet::sctp::SctpAssociation::sendOnPath
void sendOnPath(SctpPathVariables *pathId, const bool firstPass=true)
Utility: Send data from sendQueue.
Definition: SctpAssociationSendAll.cc:659
inet::sctp::SctpStateVariables::advancedPeerAckPoint
uint32_t advancedPeerAckPoint
Definition: SctpAssociation.h:825
inet::sctp::SctpAssociation::CCFunctions::ccUpdateBeforeSack
void(SctpAssociation::* ccUpdateBeforeSack)()
Definition: SctpAssociation.h:880
inet::sctp::SctpStateVariables::tellArwnd
bool tellArwnd
Definition: SctpAssociation.h:835
inet::sctp::SctpStateVariables::GLOV_None
@ GLOV_None
Definition: SctpAssociation.h:669
inet::sctp::SctpAssociation::ackChunk
void ackChunk(SctpDataVariables *chunk, SctpPathVariables *sackPath)
Definition: SctpAssociation.h:1439
SCTP_DEFAULT_INBOUND_STREAMS
#define SCTP_DEFAULT_INBOUND_STREAMS
Definition: SctpAssociation.h:229
inet::IInterfaceTable::getNumInterfaces
virtual int getNumInterfaces() const =0
Returns the number of interfaces.
inet::sctp::SctpStateVariables::packetBytes
uint32_t packetBytes
Definition: SctpAssociation.h:660
inet::sctp::SctpDataVariables::userData
cPacket * userData
Definition: SctpAssociation.h:473
inet::sctp::SctpStateVariables::firstPeerRequest
bool firstPeerRequest
Definition: SctpAssociation.h:779
inet::sctp::SctpAssociation::makeSsnTsnResetParameter
SctpParameter * makeSsnTsnResetParameter(uint32_t srsn)
Definition: SctpAssociationStreamReset.cc:398
inet::sctp::SctpStateVariables::MBV_CongestionWindowLimitingTempCwnd
@ MBV_CongestionWindowLimitingTempCwnd
Definition: SctpAssociation.h:686
inet::SCTP_I_SEND_MSG
@ SCTP_I_SEND_MSG
Definition: SctpCommand_m.h:208
inet::sctp::SctpAssociation::pathStreamSchedulerMapToPath
int32_t pathStreamSchedulerMapToPath(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:522
inet::sctp::SctpAssociation::pathMapLargestSpace
static bool pathMapLargestSpace(const SctpPathVariables *left, const SctpPathVariables *right)
Definition: SctpAssociationSendAll.cc:158
inet::sctp::SctpStateVariables::nrSack
bool nrSack
Definition: SctpAssociation.h:666
inet::sctp::SctpAssociation::receiveStreams
SctpReceiveStreamMap receiveStreams
Definition: SctpAssociation.h:960
inet::sctp::SSN_TSN
@ SSN_TSN
Definition: SctpAssociation.h:144
inet::sctp::SctpStateVariables::nagleEnabled
bool nagleEnabled
Definition: SctpAssociation.h:575
inet::sctp::Sctp::pktdrop
bool pktdrop
Definition: Sctp.h:202
inet::sctp::SctpStateVariables::smartOverfullSACKHandling
bool smartOverfullSACKHandling
Definition: SctpAssociation.h:675
inet::sctp::SctpAssociation::assocMaxWndPaths
SctpPathCollection assocMaxWndPaths
Definition: SctpAssociation.h:892
inet::sctp::SctpAssociation::pathStatusIndication
void pathStatusIndication(const SctpPathVariables *path, bool status)
Definition: SctpAssociationUtil.cc:2821
inet::sctp::SctpStateVariables::cmtBufferSplittingUsesOSB
bool cmtBufferSplittingUsesOSB
Definition: SctpAssociation.h:712
SHUTDOWN_GUARD_TIMEOUT
#define SHUTDOWN_GUARD_TIMEOUT
Definition: SctpAssociation.h:256
inet::sctp::SctpAssociation::cloneAssociation
SctpAssociation * cloneAssociation()
Utility: clone a listening association.
Definition: SctpAssociationUtil.cc:304
tags
* tags
Definition: IUdp-gates.txt:3
inet::sctp::SctpQueue::removeMsg
void removeMsg(const uint32_t key)
Definition: SctpQueue.cc:145
inet::sctp::SctpStateVariables::localAddresses
AddressVector localAddresses
Definition: SctpAssociation.h:597
inet::sctp::COOKIE_ECHO
@ COOKIE_ECHO
Definition: SctpAssociation.h:112
inet::sctp::SCTP_E_SEND_ASCONF
@ SCTP_E_SEND_ASCONF
Definition: SctpAssociation.h:94
inet::sctp::Sctp::sackNow
bool sackNow
Definition: Sctp.h:203
inet::sctp::SctpStateVariables::cmtUseFRC
bool cmtUseFRC
Definition: SctpAssociation.h:730
inet::sctp::SctpStateVariables::peerStreamsToReset
std::list< uint16_t > peerStreamsToReset
Definition: SctpAssociation.h:794
inet::sctp::SctpGapList::forwardCumAckTsn
void forwardCumAckTsn(const uint32_t cumAckTsn)
Definition: SctpGapList.cc:328
inet::sctp::SctpAssociation::sendOutgoingResetRequest
void sendOutgoingResetRequest(SctpIncomingSsnResetRequestParameter *requestParam)
Definition: SctpAssociationStreamReset.cc:116
inet::SctpResetReq::dup
virtual SctpResetReq * dup() const override
Definition: SctpCommand_m.h:760
inet::sctp::SctpStateVariables::GLOV_Shrunken
@ GLOV_Shrunken
Definition: SctpAssociation.h:672
inet::sctp::SctpAssociation::tsnLe
static bool tsnLe(const uint32_t tsn1, const uint32_t tsn2)
Definition: SctpAssociation.h:1077
inet::sctp::HighSpeedCwndAdjustmentEntry::decreaseFactor
double decreaseFactor
Definition: SctpCcFunctions.cc:34
inet::sctp::SctpStateVariables::blockingTsnsMoved
unsigned int blockingTsnsMoved
Definition: SctpAssociation.h:733
inet::sctp::Sctp::updateSockPair
void updateSockPair(SctpAssociation *assoc, L3Address localAddr, L3Address remoteAddr, int32_t localPort, int32_t remotePort)
To be called from SctpAssociation when socket pair changes.
Definition: Sctp.cc:642
inet::sctp::SctpAssociation::renegablyAckChunk
void renegablyAckChunk(SctpDataVariables *chunk, SctpPathVariables *sackPath)
Definition: SctpAssociationRcvMessage.cc:1953
inet::sctp::Sctp::removeLocalAddressFromAllRemoteAddresses
void removeLocalAddressFromAllRemoteAddresses(SctpAssociation *assoc, L3Address address, std::vector< L3Address > remAddresses)
Definition: Sctp.cc:735
inet::sctp::SctpAssociation::process_TIMEOUT_HEARTBEAT
void process_TIMEOUT_HEARTBEAT(SctpPathVariables *path)
Definition: SctpAssociationRcvMessage.cc:3613
inet::sctp::SctpAssociation::processInitAckArrived
bool processInitAckArrived(SctpInitAckChunk *initAckChunk)
Definition: SctpAssociationRcvMessage.cc:730
inet::sctp::SCTP_E_ADD_STREAMS
@ SCTP_E_ADD_STREAMS
Definition: SctpAssociation.h:93
inet::sctp::SctpStateVariables::msgNum
uint32_t msgNum
Definition: SctpAssociation.h:619
inet::sctp::SctpAssociation::getFragInProgressOfStream
bool getFragInProgressOfStream(uint16_t sid)
Definition: SctpAssociationUtil.cc:97
inet::sctp::SctpAssociation::streamSchedulerRandom
int32_t streamSchedulerRandom(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:220
inet::SCTP_I_ABANDONED
@ SCTP_I_ABANDONED
Definition: SctpCommand_m.h:212
inet::sctp::SctpStateVariables::errorCount
uint32_t errorCount
Definition: SctpAssociation.h:599
inet::sctp::SctpStateVariables::active
bool active
Definition: SctpAssociation.h:562
inet::sctp::SctpStateVariables::localTieTag
uint8_t localTieTag[32]
Definition: SctpAssociation.h:626
SACK_DELAY
#define SACK_DELAY
Definition: SctpAssociation.h:239
inet::sctp::SctpAssociation::process_TIMEOUT_RESET
void process_TIMEOUT_RESET(SctpPathVariables *path)
Definition: SctpAssociationRcvMessage.cc:3682
inet::sctp::SctpStateVariables::shutdownAckChunk
SctpShutdownAckChunk * shutdownAckChunk
Definition: SctpAssociation.h:647
inet::sctp::SctpStateVariables::lastDataSourcePath
SctpPathVariables * lastDataSourcePath
Definition: SctpAssociation.h:596
inet::L3Address::toIpv4
Ipv4Address toIpv4() const
Definition: L3Address.h:70
inet::sctp::SctpAssociation::makeOutgoingStreamResetParameter
SctpParameter * makeOutgoingStreamResetParameter(uint32_t srsn, SctpResetReq *info)
Definition: SctpAssociationStreamReset.cc:322
inet::sctp::SctpStateVariables::peerTsnAfterReset
uint32_t peerTsnAfterReset
Definition: SctpAssociation.h:786
inet::sctp::SctpAssociation::assocCollectedPaths
SctpPathCollection assocCollectedPaths
Definition: SctpAssociation.h:893
inet::sctp::SctpAssociation::T1_InitTimer
cMessage * T1_InitTimer
Definition: SctpAssociation.h:910
inet::sctp::SctpStateVariables::numResetRequests
uint16_t numResetRequests
Definition: SctpAssociation.h:634
inet::sctp::SctpDataVariables::tsn
uint32_t tsn
Definition: SctpAssociation.h:479
inet::sctp::SctpStateVariables::initialPeerRwnd
uint64_t initialPeerRwnd
Definition: SctpAssociation.h:601
inet::sctp::SctpAssociation::SSFunctions::ssInitStreams
void(SctpAssociation::* ssInitStreams)(uint32_t inStreams, uint32_t outStreams)
Definition: SctpAssociation.h:1289
inet::sctp::RESET_OUTGOING
@ RESET_OUTGOING
Definition: SctpAssociation.h:141
inet::sctp::SctpAssociation::pmStartPathManagement
void pmStartPathManagement()
Flow control.
Definition: SctpAssociationUtil.cc:2749
inet::sctp::SctpAssociation::process_TIMEOUT_SHUTDOWN
void process_TIMEOUT_SHUTDOWN(SctpEventCode &event)
Definition: SctpAssociationRcvMessage.cc:3573
inet::sctp::SctpAssociation::statisticsQueuedSentBytes
cOutVector * statisticsQueuedSentBytes
Definition: SctpAssociation.h:966
inet::sctp::SctpAssociation::StartTesting
cMessage * StartTesting
Definition: SctpAssociation.h:914
inet::sctp::SctpStateVariables::getPrimaryPath
SctpPathVariables * getPrimaryPath() const
Definition: SctpAssociation.h:549
SCTP_COOKIE_ACK_LENGTH
#define SCTP_COOKIE_ACK_LENGTH
Definition: SctpAssociation.h:210
inet::sctp::SctpStateVariables::findRequestNum
bool findRequestNum(uint32_t num)
Definition: SctpAssociationBase.cc:500
SCTP_SACK_CHUNK_LENGTH
#define SCTP_SACK_CHUNK_LENGTH
Definition: SctpAssociation.h:206
inet::sctp::SctpAssociation::updateHighSpeedCCThresholdIdx
void updateHighSpeedCCThresholdIdx(SctpPathVariables *path)
Definition: SctpCcFunctions.cc:113
inet::sctp::SctpStateVariables::peerRequests
std::map< uint32_t, RequestData > peerRequests
Definition: SctpAssociation.h:796
inet::sctp::AddressVector
std::vector< L3Address > AddressVector
Definition: SctpAssociation.h:42
inet::sctp::SctpGapList::getCumAckTsn
uint32_t getCumAckTsn() const
Definition: SctpGapList.h:79
SHA_LENGTH
#define SHA_LENGTH
Definition: SctpAssociation.h:226
inet::sctp::SctpStateVariables::CUCV_PseudoCumAckV2
@ CUCV_PseudoCumAckV2
Definition: SctpAssociation.h:701
inet::sctp::Sctp::assocList
std::list< SctpAssociation * > assocList
Definition: Sctp.h:169
inet::sctp::SctpStateVariables::highestTsnAcked
uint32_t highestTsnAcked
Definition: SctpAssociation.h:605
inet::IInterfaceTable::getInterface
virtual NetworkInterface * getInterface(int pos) const =0
Returns the NetworkInterface specified by an index 0..numInterfaces-1.
SCTP_INCOMING_RESET_REQUEST_PARAMETER_LENGTH
#define SCTP_INCOMING_RESET_REQUEST_PARAMETER_LENGTH
Definition: SctpAssociation.h:217
inet::sctp::HEARTBEAT
@ HEARTBEAT
Definition: SctpAssociation.h:106
inet::sctp::Sctp::setSocketOptions
void setSocketOptions(SocketOptions *options)
Definition: Sctp.h:254
inet::sctp::SctpAssociation::resetSsn
void resetSsn(uint16_t id)
Definition: SctpAssociationStreamReset.cc:922
inet::sctp::SctpAssociation::sendHMacError
void sendHMacError(const uint16_t id)
Definition: SctpAssociationUtil.cc:1897
inet::sctp::SctpAssociation::scheduleTimeout
void scheduleTimeout(cMessage *msg, const simtime_t &timeout)
Utility: start a timer.
Definition: SctpAssociation.h:1185
inet::sctp::SctpAssociation::retransmitInit
void retransmitInit()
Retransmitting chunks.
Definition: SctpAssociationUtil.cc:756
inet::sctp::Sctp::getAssocMaxRtx
int getAssocMaxRtx()
Definition: Sctp.h:267
inet::sctp::SctpStateVariables::shutdownChunk
SctpShutdownChunk * shutdownChunk
pointer to the resetChunk (for retransmission)
Definition: SctpAssociation.h:646
inet::sctp::SctpAssociation::cwndUpdateAfterRtxTimeout
void cwndUpdateAfterRtxTimeout(SctpPathVariables *path)
Definition: SctpCcFunctions.cc:830
inet::sctp::INIT_ACK
@ INIT_ACK
Definition: SctpAssociation.h:104
inet::sctp::SctpStateVariables::incomingRequest
SctpParameter * incomingRequest
Definition: SctpAssociation.h:789
inet::sctp::SCTP_E_DUP_RECEIVED
@ SCTP_E_DUP_RECEIVED
Definition: SctpAssociation.h:83
inet::Ipv4Address::TEST_NET
@ TEST_NET
Definition: Ipv4Address.h:80
inet::sctp::SCTP_E_SET_STREAM_PRIO
@ SCTP_E_SET_STREAM_PRIO
Definition: SctpAssociation.h:95
inet::sctp::SctpAssociation::addAuthChunkIfNecessary
bool addAuthChunkIfNecessary(Ptr< SctpHeader > sctpMsg, uint16_t chunkType, bool authAdded)
Definition: SctpAssociation.h:1485
inet::sctp::SctpAssociation::createSuccessIndication
SctpSuccessIndication * createSuccessIndication(uint32_t correlationId)
Definition: SctpAssociationAddIp.cc:297
inet::sctp::SctpAssociation::sendAsconf
void sendAsconf(const char *type, bool remote=false)
Methods for Add-IP and AUTH.
Definition: SctpAssociationAddIp.cc:15
inet::sctp::SctpAssociation::dacPacketsRcvd
uint8_t dacPacketsRcvd
Definition: SctpAssociation.h:924
inet::sctp::SCTP_E_SEND_SHUTDOWN_ACK
@ SCTP_E_SEND_SHUTDOWN_ACK
Definition: SctpAssociation.h:89
inet::sctp::SctpStateVariables::outstandingBytes
uint64_t outstandingBytes
Definition: SctpAssociation.h:612
inet::sctp::SCTP_E_ACCEPT
@ SCTP_E_ACCEPT
Definition: SctpAssociation.h:96
inet::sctp::SctpStateVariables::CCCV_CMT
@ CCCV_CMT
Definition: SctpAssociation.h:748
SCTP_NRSACK_CHUNK_LENGTH
#define SCTP_NRSACK_CHUNK_LENGTH
Definition: SctpAssociation.h:207
inet::sctp::SctpAssociation::statisticsArwndInLastSACK
cOutVector * statisticsArwndInLastSACK
Definition: SctpAssociation.h:973
inet::uint
unsigned int uint
Definition: INETDefs.h:55
inet::sctp::SACK
@ SACK
Definition: SctpAssociation.h:105
inet::sctp::SctpAssociation::processCookieEchoArrived
bool processCookieEchoArrived(SctpCookieEchoChunk *cookieEcho, L3Address addr)
Definition: SctpAssociationRcvMessage.cc:814
inet::sctp::SCTP_E_OPEN_PASSIVE
@ SCTP_E_OPEN_PASSIVE
Definition: SctpAssociation.h:63
inet::sctp::SctpStateVariables::queuedMessages
uint64_t queuedMessages
Definition: SctpAssociation.h:628
inet::sctp::SctpAssociation::numUsableStreams
int32_t numUsableStreams()
Definition: SctpSsFunctions.cc:163
inet::sctp::FCFS
@ FCFS
Definition: SctpAssociation.h:198
inet::sctp::SctpStateVariables::localRequestType
uint16_t localRequestType
Definition: SctpAssociation.h:799
inet::sctp::SctpStateVariables::sendQueueLimit
uint64_t sendQueueLimit
Definition: SctpAssociation.h:648
SCTP_SHUTDOWN_ACK_LENGTH
#define SCTP_SHUTDOWN_ACK_LENGTH
Definition: SctpAssociation.h:213
inet::sctp::SctpStateVariables::setPrimaryPath
void setPrimaryPath(SctpPathVariables *path)
Definition: SctpAssociation.h:536
inet::sctp::SctpStateVariables::CCCV_CMTRP_Test2
@ CCCV_CMTRP_Test2
Definition: SctpAssociation.h:754
inet::sctp::Sctp::addLocalAddress
void addLocalAddress(SctpAssociation *assoc, L3Address address)
Definition: Sctp.cc:677
inet::sctp::SctpStateVariables::resetDeferred
bool resetDeferred
Definition: SctpAssociation.h:776
inet::sctp::SctpStateVariables::peerStreamReset
bool peerStreamReset
Definition: SctpAssociation.h:775
inet::sctp::SctpAssociation::addPath
void addPath(const L3Address &addr)
Definition: SctpAssociationUtil.cc:2113
inet::sctp::SctpAssociation::makeAddStreamsRequestParameter
SctpParameter * makeAddStreamsRequestParameter(uint32_t srsn, SctpResetReq *info)
Definition: SctpAssociationStreamReset.cc:376
inet::sctp::SctpStateVariables::numRequests
uint32_t numRequests
Definition: SctpAssociation.h:621
inet::sctp::SCTP_E_IGNORE
@ SCTP_E_IGNORE
Definition: SctpAssociation.h:81
inet::sctp::SctpStateVariables::chunkList
std::vector< uint16_t > chunkList
Definition: SctpAssociation.h:812
inet::SCTP_C_ACCEPT
@ SCTP_C_ACCEPT
Definition: SctpCommand_m.h:151
inet::L3Address::getType
AddressType getType() const
Definition: L3Address.cc:51
inet::sctp::SctpStateVariables::numMsgsReq
std::vector< int32_t > numMsgsReq
Definition: SctpAssociation.h:636
SCTP_PKTDROP_CHUNK_LENGTH
#define SCTP_PKTDROP_CHUNK_LENGTH
Definition: SctpAssociation.h:225
inet::sctp::SctpAssociation::sendStreamPresent
bool sendStreamPresent(uint32_t sid)
Definition: SctpAssociationStreamReset.cc:929
inet::sctp::SCTP_E_SEND
@ SCTP_E_SEND
Definition: SctpAssociation.h:67
inet::sctp::SctpStateVariables::throughputInterval
double throughputInterval
Definition: SctpAssociation.h:841
inet::sctp::SctpAssociation::processIncomingResetRequestArrived
void processIncomingResetRequestArrived(SctpIncomingSsnResetRequestParameter *requestParam)
Definition: SctpAssociationRcvMessage.cc:2391
inet::sctp::SctpAssociation::printAssocBrief
void printAssocBrief()
Utility: prints local/remote addr/port and app gate index/assocId.
Definition: SctpAssociationUtil.cc:287
inet::sctp::SctpAsconfChunk::dup
virtual SctpAsconfChunk * dup() const override
Definition: SctpHeader.h:177
inet::sctp::SctpStateVariables::incomingRequestSet
bool incomingRequestSet
Definition: SctpAssociation.h:592
inet::sctp::SctpStateVariables::peerRequestSn
uint32_t peerRequestSn
Definition: SctpAssociation.h:784
inet::sctp::SctpStateVariables::CSP_RoundRobin
@ CSP_RoundRobin
Definition: SctpAssociation.h:738
inet::sctp::SctpAssociation::initStreams
void initStreams(uint32_t inStreams, uint32_t outStreams)
Definition: SctpSsFunctions.cc:58
inet::sctp::IFORWARD_TSN
@ IFORWARD_TSN
Definition: SctpAssociation.h:122
inet::sctp::SctpAssociation::getNextPath
SctpPathVariables * getNextPath(const SctpPathVariables *oldPath) const
Definition: SctpAssociationUtil.cc:2671
inet::sctp::SctpAssociation::sendSACKviaSelectedPath
void sendSACKviaSelectedPath(const Ptr< SctpHeader > &sctpMsg)
Definition: SctpAssociationSendAll.cc:499
inet::sctp::SctpAssociation::disposeOf
void disposeOf(SctpHeader *sctpmsg)
Definition: SctpAssociationUtil.cc:2880
inet::sctp::SctpStateVariables::swsMsgInvoked
bool swsMsgInvoked
Definition: SctpAssociation.h:836
inet::sctp::SctpStateVariables::CCCV_CMT_LIA
@ CCCV_CMT_LIA
Definition: SctpAssociation.h:751
inet::sctp::SctpAssociation::createAsconfAckChunk
SctpAsconfAckChunk * createAsconfAckChunk(uint32_t serialNumber)
Definition: SctpAssociationAddIp.cc:201
inet::Ipv6Address::GLOBAL
@ GLOBAL
Definition: Ipv6Address.h:48
inet::sctp::SctpStateVariables::resetRequested
bool resetRequested
Definition: SctpAssociation.h:580
inet::sctp::SctpStateVariables::reactivatePrimaryPath
bool reactivatePrimaryPath
Definition: SctpAssociation.h:578
inet::sctp::SctpQueue::getQueueSize
uint32_t getQueueSize() const
Definition: SctpQueue.cc:49
inet::sctp::SctpStateVariables::MBV_UseItOrLoseItTempCwnd
@ MBV_UseItOrLoseItTempCwnd
Definition: SctpAssociation.h:685
inet::SctpResetReq::getRequestType
virtual unsigned short getRequestType() const
inet::sctp::SctpAssociation::sendAddInAndOutStreamsRequest
void sendAddInAndOutStreamsRequest(SctpResetReq *info)
Definition: SctpAssociationStreamReset.cc:697
inet::sctp::SctpStateVariables::ackPointAdvanced
bool ackPointAdvanced
Definition: SctpAssociation.h:564
inet::Ipv4Address::PRIVATE_NETWORK
@ PRIVATE_NETWORK
Definition: Ipv4Address.h:85
inet::SCTP_C_CLOSE
@ SCTP_C_CLOSE
Definition: SctpCommand_m.h:133
SCTP_TSN_GT
#define SCTP_TSN_GT(a, b)
Definition: SctpAssociation.h:1071
inet::sctp::SctpAssociation::getSsnOfStream
uint32_t getSsnOfStream(uint16_t id)
Definition: SctpAssociationStreamReset.cc:908
inet::sctp::SctpAssociation::sendAbort
void sendAbort(uint16_t tBit=0)
Definition: SctpAssociationUtil.cc:1153
inet::SCTP_I_ADDRESS_ADDED
@ SCTP_I_ADDRESS_ADDED
Definition: SctpCommand_m.h:216
inet::sctp::SctpAssociation::processDataArrived
SctpEventCode processDataArrived(SctpDataChunk *dataChunk)
Definition: SctpAssociationRcvMessage.cc:2109
inet::sctp::SctpStateVariables::bytesToAddPerPeerChunk
uint32_t bytesToAddPerPeerChunk
Definition: SctpAssociation.h:834
inet::sctp::Sctp::getSackFrequency
int getSackFrequency()
Definition: Sctp.h:260
inet::sctp::SctpAssociation::state
SctpStateVariables * state
Definition: SctpAssociation.h:951
SCTP_STREAM_RESET_CHUNK_LENGTH
#define SCTP_STREAM_RESET_CHUNK_LENGTH
Definition: SctpAssociation.h:215
inet::sctp::SctpAssociation::stopTimer
void stopTimer(cMessage *timer)
Definition: SctpAssociationRcvMessage.cc:3667
inet::sctp::SctpAssociation::SSFunctions::ssAddOutStreams
void(SctpAssociation::* ssAddOutStreams)(uint32_t outStreams)
Definition: SctpAssociation.h:1291
inet::sctp::RESET_BOTH
@ RESET_BOTH
Definition: SctpAssociation.h:143
inet::sctp::SctpAssociation::putInTransmissionQ
void putInTransmissionQ(uint32_t tsn, SctpDataVariables *chunk)
Definition: SctpAssociationUtil.cc:2951
inet::sctp::SctpAssociation::advancePeerTsn
void advancePeerTsn()
Definition: SctpAssociationUtil.cc:2279
inet::sctp::SctpStateVariables::CBSV_BothSides
@ CBSV_BothSides
Definition: SctpAssociation.h:709
inet::sctp::SctpInitChunk::dup
virtual SctpInitChunk * dup() const override
Definition: SctpHeader_m.h:318
inet::sctp::SctpStateVariables::fork
bool fork
Definition: SctpAssociation.h:563
inet::Ipv4Address::IPv6_TO_IPv4_RELAY
@ IPv6_TO_IPv4_RELAY
Definition: Ipv4Address.h:81
inet::sctp::SctpAssociation::statisticsNumDuplicatesSent
cOutVector * statisticsNumDuplicatesSent
Definition: SctpAssociation.h:982
inet::sctp::SCTP_E_SET_RTO_INFO
@ SCTP_E_SET_RTO_INFO
Definition: SctpAssociation.h:97
inet::sctp::SctpStateVariables::numAddedInStreams
uint16_t numAddedInStreams
Definition: SctpAssociation.h:662
inet::sctp::SctpStateVariables::peerChunkList
std::vector< uint16_t > peerChunkList
Definition: SctpAssociation.h:813
inet::sctp::SctpAssociation::ccFunctions
CCFunctions ccFunctions
Definition: SctpAssociation.h:942
inet::sctp::SctpStateVariables::bytesToAddPerRcvdChunk
uint32_t bytesToAddPerRcvdChunk
Definition: SctpAssociation.h:833
inet::sctp::SctpAssociation::sendAvailableIndicationToApp
void sendAvailableIndicationToApp()
Definition: SctpAssociationUtil.cc:452
inet::sctp::SctpAssociation::process_TIMEOUT_RTX
void process_TIMEOUT_RTX(SctpPathVariables *path)
Definition: SctpAssociationRcvMessage.cc:3757
inet::sctp::SctpAssociation::unackChunk
void unackChunk(SctpDataVariables *chunk)
Definition: SctpAssociation.h:1445
inet::sctp::SHUTDOWN_COMPLETE
@ SHUTDOWN_COMPLETE
Definition: SctpAssociation.h:114
inet::sctp::SctpAssociation::cwndUpdateMaxBurst
void cwndUpdateMaxBurst(SctpPathVariables *path)
Definition: SctpCcFunctions.cc:922
inet::sctp::SctpAssociation::inboundStreams
uint32_t inboundStreams
Definition: SctpAssociation.h:933
inet::sctp::SctpStateVariables::prMethod
uint32_t prMethod
Definition: SctpAssociation.h:826
inet::sctp::SctpStateVariables::cmtSackPath
CSackPath cmtSackPath
Definition: SctpAssociation.h:741
inet::sctp::SCTP_E_ASSOCIATE
@ SCTP_E_ASSOCIATE
Definition: SctpAssociation.h:62
inet::sctp::RFC4960
@ RFC4960
Definition: SctpAssociation.h:187
inet::sctp::SctpAssociation::setFragInProgressOfStream
void setFragInProgressOfStream(uint16_t sid, bool frag)
Definition: SctpAssociationUtil.cc:104
inet::sctp::Sctp::getMaxBurst
int getMaxBurst()
Definition: Sctp.h:262
inet::sctp::SctpAssociation::cucProcessGapReports
void cucProcessGapReports(const SctpDataVariables *chunk, SctpPathVariables *path, const bool isAcked)
Definition: SctpAssociationRcvMessage.cc:935
inet::sctp::SctpStateVariables::waitForResponse
bool waitForResponse
Definition: SctpAssociation.h:778
inet::sctp::SctpAssociation::transmissionQ
SctpQueue * transmissionQ
Definition: SctpAssociation.h:957
inet::sctp::SctpAssociation::initPeerTsn
uint32_t initPeerTsn
Definition: SctpAssociation.h:939
inet::sctp::SctpParameter::dup
virtual SctpParameter * dup() const override
Definition: SctpHeader_m.h:1503
inet::sctp::PERFORMED
@ PERFORMED
Definition: SctpAssociation.h:135
inet::containsKey
bool containsKey(const std::map< K, V, _C > &m, const Tk &a)
Definition: stlutils.h:80
inet::sctp::SctpAssociation::timeForSack
void timeForSack(bool &sackOnly, bool &sackWithData)
Definition: SctpAssociationSendAll.cc:247
inet::SCTP_I_AVAILABLE
@ SCTP_I_AVAILABLE
Definition: SctpCommand_m.h:218
inet::sctp::SctpAssociation::chunkMustBeAbandoned
bool chunkMustBeAbandoned(SctpDataVariables *chunk, SctpPathVariables *sackPath)
Definition: SctpAssociationUtil.cc:2343
inet::sctp::SctpAssociation::decreaseOutstandingBytes
void decreaseOutstandingBytes(SctpDataVariables *chunk)
Definition: SctpAssociationRcvMessage.cc:34
inet::sctp::SctpStateVariables::queueLimit
uint32_t queueLimit
Definition: SctpAssociation.h:630
inet::sctp::SctpStateVariables::asconfSn
uint32_t asconfSn
Definition: SctpAssociation.h:767
inet::sctp::SctpAssociation::processHeartbeatAckArrived
SctpEventCode processHeartbeatAckArrived(SctpHeartbeatAckChunk *heartbeatack, SctpPathVariables *path)
Definition: SctpAssociationRcvMessage.cc:2271
inet::utils::for
for(int index=0;index< array->size();index++)
Definition: NedFunctions.cc:229
inet::sctp::SctpStateVariables::CSP_Primary
@ CSP_Primary
Definition: SctpAssociation.h:737
inet::sctp::SctpAssociation::getOutboundDataChunk
SctpDataVariables * getOutboundDataChunk(const SctpPathVariables *path, int32_t availableSpace, int32_t availableCwnd)
Definition: SctpAssociationUtil.cc:2301
inet::sctp::SctpAssociation::streamSchedulerFairBandwidth
int32_t streamSchedulerFairBandwidth(SctpPathVariables *path, bool peek)
Definition: SctpSsFunctions.cc:318
inet::sctp::SctpAssociation::cwndUpdateAfterSack
void cwndUpdateAfterSack()
Definition: SctpCcFunctions.cc:433
inet::sctp::SctpStateVariables::cmtCCVariant
CCCVariant cmtCCVariant
Definition: SctpAssociation.h:756
inet::sctp::SctpStateVariables::cmtSendAllComparisonFunction
bool(* cmtSendAllComparisonFunction)(const SctpPathVariables *left, const SctpPathVariables *right)
Definition: SctpAssociation.h:695
inet::sctp::SctpGapList::getHighestTsnReceived
uint32_t getHighestTsnReceived() const
Definition: SctpGapList.h:84
inet::SCTP_C_ADD_STREAMS
@ SCTP_C_ADD_STREAMS
Definition: SctpCommand_m.h:146
inet::sctp::SctpStateVariables::peerWindowFull
bool peerWindowFull
Definition: SctpAssociation.h:585
inet::sctp::SctpStateVariables::assocPmtu
uint32_t assocPmtu
Definition: SctpAssociation.h:617
inet::sctp::SctpAssociation::checkStreamsToReset
void checkStreamsToReset()
Definition: SctpAssociationStreamReset.cc:53
inet::sctp::Sctp::getEphemeralPort
uint16_t getEphemeralPort()
To be called from SctpAssociation: reserves an ephemeral port for the connection.
Definition: Sctp.cc:634
inet::sctp::SctpAssociation::sendDoubleStreamResetResponse
void sendDoubleStreamResetResponse(uint32_t insrrsn, uint16_t inresult, uint32_t outsrrsn, uint16_t outresult)
Definition: SctpAssociationStreamReset.cc:842
inet::Ipv4Address::THIS_NETWORK
@ THIS_NETWORK
Definition: Ipv4Address.h:75
inet::sctp::SctpAssociation::recordCwndUpdate
void recordCwndUpdate(SctpPathVariables *path)
Definition: SctpCcFunctions.cc:354
inet::sctp::RANDOM_SCHEDULE_PACKET
@ RANDOM_SCHEDULE_PACKET
Definition: SctpAssociation.h:194
inet::sctp::SctpAssociation::getOutstandingBytes
int32_t getOutstandingBytes() const
Definition: SctpAssociationUtil.cc:2799
inet::sctp::SctpAssociation::sendEstabIndicationToApp
void sendEstabIndicationToApp()
Utility: sends SCTP_I_ESTABLISHED indication with SctpConnectInfo to application.
Definition: SctpAssociationUtil.cc:472
inet::sctp::DENIED
@ DENIED
Definition: SctpAssociation.h:136
inet::sctp::SctpAssociation::scheduleSack
void scheduleSack()
Definition: SctpAssociationUtil.cc:1324
inet::sctp::SctpAssociation::dequeueAckedChunks
void dequeueAckedChunks(const uint32_t tsna, SctpPathVariables *path, simtime_t &rttEstimation)
Definition: SctpAssociationRcvMessage.cc:2028
inet::sctp::SCTP_E_STOP_SENDING
@ SCTP_E_STOP_SENDING
Definition: SctpAssociation.h:90
inet::sctp::SctpAssociation::tsnLt
static bool tsnLt(const uint32_t tsn1, const uint32_t tsn2)
Definition: SctpAssociation.h:1078
inet::sctp::SctpAssociation::removePath
void removePath()
Definition: SctpAssociationBase.cc:1801