|
INET Framework for OMNeT++/OMNEST
|
#include <UDPSerializer.h>
Public Member Functions | |
| UDPSerializer () | |
| int | serialize (const UDPPacket *pkt, unsigned char *buf, unsigned int bufsize) |
| void | parse (const unsigned char *buf, unsigned int bufsize, UDPPacket *pkt) |
Converts between UDPPacket and binary (network byte order) UDP header.
| UDPSerializer::UDPSerializer | ( | ) | [inline] |
{}
| void UDPSerializer::parse | ( | const unsigned char * | buf, |
| unsigned int | bufsize, | ||
| UDPPacket * | pkt | ||
| ) |
Puts a packet sniffed from the wire into an UDPPacket.
Referenced by IPSerializer::parse().
{
int32 size_common_header = sizeof(struct common_header);
int32 size_init_chunk = sizeof(struct init_chunk);
int32 size_init_ack_chunk = sizeof(struct init_ack_chunk);
int32 size_data_chunk = sizeof(struct data_chunk);
int32 size_sack_chunk = sizeof(struct sack_chunk);
int32 size_heartbeat_chunk = sizeof(struct heartbeat_chunk);
int32 size_heartbeat_ack_chunk = sizeof(struct heartbeat_ack_chunk);
int32 size_abort_chunk = sizeof(struct abort_chunk);
int32 size_cookie_echo_chunk = sizeof(struct cookie_echo_chunk);
uint16 paramType;
int32 parptr, chunklen, cLen, woPadding;
struct common_header *common_header = (struct common_header*) (buf);
int32 tempChecksum = common_header->checksum;
common_header->checksum = 0;
int32 chksum = checksum((unsigned char*)common_header, bufsize);
common_header->checksum = tempChecksum;
const unsigned char *chunks = (unsigned char*) (buf + size_common_header);
sctpEV3<<"SCTPSerializer::parse SCTPMessage\n";
if (tempChecksum == chksum)
dest->setChecksumOk(true);
else
dest->setChecksumOk(false);
sctpEV3<<"checksumOK="<<dest->getChecksumOk()<<"\n";
dest->setSrcPort(ntohs(common_header->source_port));
dest->setDestPort(ntohs(common_header->destination_port));
dest->setTag(ntohl(common_header->verification_tag));
dest->setBitLength(SCTP_COMMON_HEADER*8);
// chunks
uint32 chunkPtr = 0;
// catch ALL chunks - when a chunk is taken, the chunkPtr is set to the next chunk
while(chunkPtr < (bufsize - size_common_header))
{
const struct chunk * chunk = (struct chunk*)(chunks + chunkPtr);
int32 chunkType = chunk->type;
sctpEV3<<"chunkType="<<chunkType<<"\n";
woPadding = ntohs(chunk->length);
sctpEV3<<"chunk->length="<<ntohs(chunk->length)<<"\n";
cLen = ADD_PADDING(woPadding);
switch(chunkType)
{
case DATA:
{
ev<<"Data received\n";
const struct data_chunk *dc = (struct data_chunk*) (chunks + chunkPtr);
sctpEV3<<"cLen="<<cLen<<"\n";
if(cLen == 0)
throw new cRuntimeError("Incoming SCTP packet contains data chunk with length==0");
SCTPDataChunk *chunk = new SCTPDataChunk("DATA");
chunk->setChunkType(chunkType);
chunk->setUBit(dc->flags & UNORDERED_BIT);
chunk->setBBit(dc->flags & BEGIN_BIT);
chunk->setEBit(dc->flags & END_BIT);
chunk->setTsn(ntohl(dc->tsn));
chunk->setSid(ntohs(dc->sid));
chunk->setSsn(ntohs(dc->ssn));
chunk->setPpid(ntohl(dc->ppi));
chunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8);
sctpEV3<<"parse data: woPadding="<<woPadding<<" size_data_chunk="<<size_data_chunk<<"\n";
if(woPadding > size_data_chunk)
{
SCTPSimpleMessage* msg=new SCTPSimpleMessage("data");
int32 datalen = (woPadding - size_data_chunk);
msg->setBitLength(datalen*8);
msg->setDataLen(datalen);
msg->setDataArraySize(datalen);
for(int32 i=0; i<datalen; i++)
msg->setData(i, dc->user_data[i]);
chunk->encapsulate(msg);
}
sctpEV3<<"datachunkLength="<<chunk->getBitLength()<<"\n";
dest->addChunk(chunk);
break;
}
case INIT:
{
ev<<"parse INIT\n";
const struct init_chunk *init_chunk = (struct init_chunk*) (chunks + chunkPtr); // (recvBuffer + size_ip + size_common_header);
chunklen = SCTP_INIT_CHUNK_LENGTH;
SCTPInitChunk *chunk = new SCTPInitChunk("INIT");
chunk->setChunkType(chunkType);
chunk->setName("INIT");
chunk->setInitTag(ntohl(init_chunk->initiate_tag));
chunk->setA_rwnd(ntohl(init_chunk->a_rwnd));
chunk->setNoOutStreams(ntohs(init_chunk->mos));
chunk->setNoInStreams(ntohs(init_chunk->mis));
chunk->setInitTSN(ntohl(init_chunk->initial_tsn));
chunk->setAddressesArraySize(0);
chunk->setUnrecognizedParametersArraySize(0);
//sctpEV3<<"INIT arrived from wire\n";
if(cLen > size_init_chunk)
{
int32 parcounter = 0, addrcounter = 0;
parptr = 0;
bool stopProcessing = false;
while(cLen > size_init_chunk+parptr && !stopProcessing)
{
sctpEV3<<"Process INIT parameters\n";
const struct tlv *parameter = (struct tlv*)(((unsigned char*)init_chunk) + size_init_chunk + parptr);
paramType = ntohs(parameter->type);
sctpEV3<<"search for param "<<paramType<<"\n";
switch (paramType)
{
case SUPPORTED_ADDRESS_TYPES:
{
break;
}
case INIT_PARAM_IPV4:
{
// we supppose an ipv4 address parameter
sctpEV3<<"IPv4\n";
const struct init_ipv4_address_parameter *v4addr;
v4addr = (struct init_ipv4_address_parameter*) (((unsigned char*)init_chunk) + size_init_chunk + parptr);
chunk->setAddressesArraySize(++addrcounter);
IPvXAddress *localv4Addr;
localv4Addr = new IPvXAddress("0.0.0.0");
localv4Addr->set(ntohl(v4addr->address));
chunk->setAddresses(addrcounter-1, *localv4Addr);
chunklen += 8;
break;
}
case INIT_PARAM_IPV6:
{
sctpEV3<<"IPv6\n";
const struct init_ipv6_address_parameter *ipv6addr;
ipv6addr = (struct init_ipv6_address_parameter*) (((unsigned char*)init_chunk) + size_init_chunk + parptr);
IPv6Address ipv6Addr = IPv6Address(ipv6addr->address[0], ipv6addr->address[1],
ipv6addr->address[2], ipv6addr->address[3]);
IPvXAddress *localv6Addr;
localv6Addr = new IPvXAddress("0:0:0:0:0:0:0:0");
sctpEV3<<"address"<<ipv6Addr<<"\n";
localv6Addr->set(ipv6Addr);
chunk->setAddressesArraySize(++addrcounter);
chunk->setAddresses(addrcounter-1, *localv6Addr);
chunklen += 20;
break;
}
default:
{
sctpEV3 << "ExtInterface: Unknown SCTP INIT parameter type " << paramType<<"\n";
uint16 skip = (paramType & 0x8000) >> 15;
if (skip == 0)
stopProcessing = true;
uint16 report = (paramType & 0x4000) >> 14;
if (report != 0)
{
const struct tlv *unknown;
unknown = (struct tlv*) (((unsigned char*)init_chunk) + size_init_chunk + parptr);
uint32 unknownLen=chunk->getUnrecognizedParametersArraySize();
chunk->setUnrecognizedParametersArraySize(unknownLen+ADD_PADDING(ntohs(unknown->length)));
struct data_vector* dv = (struct data_vector*) (((unsigned char*)init_chunk) + size_init_chunk + parptr);
for (uint32 i=unknownLen; i<unknownLen+ADD_PADDING(ntohs(unknown->length)); i++)
chunk->setUnrecognizedParameters(i,dv->data[i-unknownLen]);
}
sctpEV3<<"stopProcessing="<<stopProcessing<<" report="<<report<<"\n";
break;
}
}
parptr += ADD_PADDING(ntohs(parameter->length));
parcounter++;
}
}
chunk->setBitLength(chunklen*8);
dest->addChunk(chunk);
//chunkPtr += cLen;
break;
}
case INIT_ACK:
{
const struct init_ack_chunk *iac = (struct init_ack_chunk*) (chunks + chunkPtr);
chunklen = SCTP_INIT_CHUNK_LENGTH;
SCTPInitAckChunk *chunk = new SCTPInitAckChunk("INIT_ACK");
chunk->setChunkType(chunkType);
chunk->setInitTag(ntohl(iac->initiate_tag));
chunk->setA_rwnd(ntohl(iac->a_rwnd));
chunk->setNoOutStreams(ntohs(iac->mos));
chunk->setNoInStreams(ntohs(iac->mis));
chunk->setInitTSN(ntohl(iac->initial_tsn));
chunk->setUnrecognizedParametersArraySize(0);
if(cLen > size_init_ack_chunk)
{
int32 parcounter = 0, addrcounter = 0;
parptr = 0;
bool stopProcessing = false;
//sctpEV3<<"cLen="<<cLen<<"\n";
while(cLen > size_init_ack_chunk+parptr && !stopProcessing)
{
const struct tlv *parameter = (struct tlv*)(((unsigned char*)iac) + size_init_ack_chunk + parptr);
paramType = ntohs(parameter->type);
//sctpEV3<<"ParamType = "<<paramType<<" parameterLength="<<ntohs(parameter->length)<<"\n";
switch (paramType)
{
case SUPPORTED_ADDRESS_TYPES:
{
break;
}
case INIT_PARAM_IPV4:
{
sctpEV3<<"parse IPv4\n";
const struct init_ipv4_address_parameter *v4addr;
v4addr = (struct init_ipv4_address_parameter*) (((unsigned char*)iac) + size_init_ack_chunk + parptr);
chunk->setAddressesArraySize(++addrcounter);
IPvXAddress *localv4Addr;
localv4Addr = new IPvXAddress("0.0.0.0");
localv4Addr->set(ntohl(v4addr->address));
chunk->setAddresses(addrcounter-1, *localv4Addr);
chunklen += 8;
break;
}
case INIT_PARAM_IPV6:
{
sctpEV3<<"IPv6\n";
const struct init_ipv6_address_parameter *ipv6addr;
ipv6addr = (struct init_ipv6_address_parameter*) (((unsigned char*)iac) + size_init_chunk + parptr);
IPv6Address ipv6Addr = IPv6Address(ipv6addr->address[0], ipv6addr->address[1],
ipv6addr->address[2], ipv6addr->address[3]);
IPvXAddress *localv6Addr;
localv6Addr = new IPvXAddress("0:0:0:0:0:0:0:0");
sctpEV3<<"address"<<ipv6Addr<<"\n";
localv6Addr->set(ipv6Addr);
chunk->setAddressesArraySize(++addrcounter);
chunk->setAddresses(addrcounter-1, *localv6Addr);
chunklen += 20;
break;
}
case INIT_PARAM_COOKIE:
{
const struct tlv *cookie = (struct tlv*) (((unsigned char*)iac) + size_init_ack_chunk + parptr);
int32 cookieLen = ntohs(cookie->length) - 4;
// put cookie data into chunk (char array cookie)
chunk->setCookieArraySize(cookieLen);
for(int32 i=0; i<cookieLen; i++)
chunk->setCookie(i, cookie->value[i]);
chunklen+=cookieLen+4;
break;
}
default:
{
sctpEV3 << "ExtInterface: Unknown SCTP INIT-ACK parameter type " << paramType<<"\n";
uint16 skip = (paramType & 0x8000) >> 15;
if (skip == 0)
stopProcessing = true;
uint16 report = (paramType & 0x4000) >> 14;
if (report != 0)
{
const struct tlv *unknown;
unknown = (struct tlv*) (((unsigned char*)iac) + size_init_ack_chunk + parptr);
uint32 unknownLen=chunk->getUnrecognizedParametersArraySize();
chunk->setUnrecognizedParametersArraySize(unknownLen+ADD_PADDING(ntohs(unknown->length)));
struct data_vector* dv = (struct data_vector*) (((unsigned char*)iac) + size_init_ack_chunk + parptr);
for (uint32 i=unknownLen; i<unknownLen+ADD_PADDING(ntohs(unknown->length)); i++)
chunk->setUnrecognizedParameters(i,dv->data[i-unknownLen]);
}
sctpEV3<<"stopProcessing="<<stopProcessing<<" report="<<report<<"\n";
break;
}
}
parptr += ADD_PADDING(ntohs(parameter->length));
//sctpEV3<<"parptr="<<parptr<<"\n";
parcounter++;
}
}
chunk->setBitLength(chunklen*8);
dest->addChunk(chunk);
break;
}
case SACK:
{
ev<<"SCTPMessage: SACK received\n";
const struct sack_chunk *sac = (struct sack_chunk*) (chunks + chunkPtr);
SCTPSackChunk *chunk = new SCTPSackChunk("SACK");
chunk->setChunkType(chunkType);
uint32 cumtsnack = ntohl(sac->cum_tsn_ack);
chunk->setCumTsnAck(cumtsnack);
chunk->setA_rwnd(ntohl(sac->a_rwnd));
int32 ngaps = ntohs(sac->nr_of_gaps);
int32 ndups = ntohs(sac->nr_of_dups);
chunk->setNumGaps(ngaps);
chunk->setNumDupTsns(ndups);
chunk->setGapStartArraySize(ngaps);
chunk->setGapStopArraySize(ngaps);
chunk->setDupTsnsArraySize(ndups);
for(int32 i=0; i<ngaps; i++)
{
const struct sack_gap *gap = (struct sack_gap*) (((unsigned char*)sac) + size_sack_chunk + i*sizeof(sack_gap));
chunk->setGapStart(i, ntohs(gap->start) + cumtsnack);
chunk->setGapStop(i, ntohs(gap->stop) + cumtsnack);
}
for(int32 i=0; i<ndups; i++)
{
const struct sack_duptsn *dup = (struct sack_duptsn*) (((unsigned char*)sac) + size_sack_chunk + ngaps*sizeof(sack_gap) + i*sizeof(sack_duptsn));
chunk->setDupTsns(i, ntohl(dup->tsn));
}
chunk->setBitLength(cLen*8);
dest->addChunk(chunk);
break;
}
case HEARTBEAT:
{
//sctpEV3<<"SCTPMessage: Heartbeat received\n";
const struct heartbeat_chunk *hbc = (struct heartbeat_chunk*) (chunks + chunkPtr);
SCTPHeartbeatChunk *chunk = new SCTPHeartbeatChunk("HEARTBEAT");
chunk->setChunkType(chunkType);
if(cLen > size_heartbeat_chunk)
{
int32 parcounter = 0;
parptr = 0;
while(cLen > size_heartbeat_chunk+parptr)
{
// we supppose type 1 here
//sctpEV3<<"HB-chunk+parptr="<<size_heartbeat_chunk+parptr<<"\n";
const struct heartbeat_info *hbi = (struct heartbeat_info*) (((unsigned char*)hbc) + size_heartbeat_chunk + parptr);
if(ntohs(hbi->type) == 1) // sender specific hb info
{
//sctpEV3<<"HBInfo\n";
int32 infoLen = ntohs(hbi->length) - 4;
parptr += ADD_PADDING(infoLen) + 4;
parcounter++;
chunk->setInfoArraySize(infoLen);
for(int32 i=0; i<infoLen; i++)
chunk->setInfo(i, HBI_INFO(hbi)[i]);
}
else
{
parptr += ADD_PADDING(ntohs(hbi->length)); // set pointer forwards with count of bytes in length field of TLV
parcounter++;
continue;
}
}
}
chunk->setBitLength(cLen*8);
dest->addChunk(chunk);
break;
}
case HEARTBEAT_ACK:
{
ev<<"SCTPMessage: Heartbeat_Ack received\n";
const struct heartbeat_ack_chunk *hbac = (struct heartbeat_ack_chunk*) (chunks + chunkPtr);
SCTPHeartbeatAckChunk *chunk = new SCTPHeartbeatAckChunk("HEARTBEAT_ACK");
chunk->setChunkType(chunkType);
if(cLen>size_heartbeat_ack_chunk)
{
int32 parcounter = 0;
parptr = 0;
while(cLen > size_heartbeat_ack_chunk+parptr)
{
// we supppose type 1 here, the same provided in heartbeat chunks
const struct heartbeat_info *hbi = (struct heartbeat_info*) (((unsigned char*)hbac) + size_heartbeat_ack_chunk + parptr);
if(ntohs(hbi->type) == 1) // sender specific hb info
{
parptr += sizeof(struct heartbeat_info);
parcounter++;
chunk->setRemoteAddr(IPvXAddress(ntohl(HBI_ADDR(hbi))));
chunk->setTimeField(ntohl((uint32)HBI_TIME(hbi)));
}
else
{
parptr += ntohs(hbi->length); // set pointer forwards with count of bytes in length field of TLV
parcounter++;
continue;
}
}
}
chunk->setBitLength(cLen*8);
dest->addChunk(chunk);
break;
}
case ABORT:
{
ev<<"SCTPMessage: Abort received\n";
const struct abort_chunk *ac = (struct abort_chunk*) (chunks + chunkPtr);
cLen = ntohs(ac->length);
SCTPAbortChunk *chunk = new SCTPAbortChunk("ABORT");
chunk->setChunkType(chunkType);
chunk->setT_Bit(ac->flags & T_BIT);
if(cLen>size_abort_chunk)
{
// TODO: handle attached error causes
}
chunk->setBitLength(cLen*8);
dest->addChunk(chunk);
break;
}
case COOKIE_ECHO:
{
SCTPCookieEchoChunk *chunk = new SCTPCookieEchoChunk("COOKIE_ECHO");
chunk->setChunkType(chunkType);
sctpEV3<<"Parse Cookie-Echo\n";
if(cLen>size_cookie_echo_chunk)
{
int32 cookieSize = woPadding-size_cookie_echo_chunk;
sctpEV3<<"cookieSize="<<cookieSize<<"\n";
const struct cookie_parameter *cookie = (struct cookie_parameter*)(chunks+chunkPtr+4);
SCTPCookie* stateCookie = new SCTPCookie();
stateCookie->setCreationTime(ntohl(cookie->creationTime));
stateCookie->setLocalTag(ntohl(cookie->localTag));
stateCookie->setPeerTag(ntohl(cookie->peerTag));
stateCookie->setLocalTieTagArraySize(32);
stateCookie->setPeerTieTagArraySize(32);
for(int32 i=0; i<32; i++)
{
stateCookie->setLocalTieTag(i, cookie->localTieTag[i]);
stateCookie->setPeerTieTag(i, cookie->peerTieTag[i]);
}
stateCookie->setBitLength(SCTP_COOKIE_LENGTH*8);
chunk->setStateCookie(stateCookie);
}
chunk->setBitLength(woPadding*8);
dest->addChunk(chunk);
break;
}
case COOKIE_ACK:
{
ev<<"SCTPMessage: Cookie_Ack received\n";
SCTPCookieAckChunk *chunk = new SCTPCookieAckChunk("COOKIE_ACK");
chunk->setChunkType(chunkType);
chunk->setBitLength(cLen*8);
dest->addChunk(chunk);
break;
}
case SHUTDOWN:
{
ev<<"SCTPMessage: Shutdown received\n";
const struct shutdown_chunk *sc = (struct shutdown_chunk*) (chunks + chunkPtr);
SCTPShutdownChunk *chunk = new SCTPShutdownChunk("SHUTDOWN");
chunk->setChunkType(chunkType);
uint32 cumtsnack = ntohl(sc->cumulative_tsn_ack);
chunk->setCumTsnAck(cumtsnack);
chunk->setBitLength(cLen*8);
dest->addChunk(chunk);
break;
}
case SHUTDOWN_ACK:
{
ev<<"SCTPMessage: ShutdownAck received\n";
SCTPShutdownAckChunk *chunk = new SCTPShutdownAckChunk("SHUTDOWN_ACK");
chunk->setChunkType(chunkType);
chunk->setBitLength(cLen*8);
dest->addChunk(chunk);
break;
}
case SHUTDOWN_COMPLETE:
{
ev<<"SCTPMessage: ShutdownComplete received\n";
const struct shutdown_complete_chunk *scc = (struct shutdown_complete_chunk*) (chunks + chunkPtr);
SCTPShutdownCompleteChunk *chunk = new SCTPShutdownCompleteChunk("SHUTDOWN_COMPLETE");
chunk->setChunkType(chunkType);
chunk->setTBit(scc->flags & T_BIT);
chunk->setBitLength(cLen*8);
dest->addChunk(chunk);
break;
}
case ERRORTYPE:
{
const struct error_chunk *error;
error = (struct error_chunk*) (chunks + chunkPtr);
SCTPErrorChunk *errorchunk;
errorchunk = new SCTPErrorChunk("ERROR");
errorchunk->setChunkType(chunkType);
errorchunk->setBitLength(SCTP_ERROR_CHUNK_LENGTH*8);
parptr = 0;
dest->addChunk(errorchunk);
break;
}
default:
//printf("TODO: Implement chunk type %d, found in chunk array on %d!\n", chunkType, ct);
sctpEV3 << "Parser: Unknown SCTP chunk type " << chunkType;
/*throw new cRuntimeError("TODO: unknown chunktype in incoming packet from external interface! Implement it!");*/
break;
} // end of switch(chunkType)
chunkPtr += cLen;
} // end of while()
}
| int UDPSerializer::serialize | ( | const UDPPacket * | pkt, |
| unsigned char * | buf, | ||
| unsigned int | bufsize | ||
| ) |
Serializes an UDPPacket for transmission on the wire. Returns the length of data written into buffer.
Referenced by IPSerializer::serialize().
{
int32 size_init_chunk = sizeof(struct init_chunk);
int32 size_sack_chunk = sizeof(struct sack_chunk);
int32 size_heartbeat_chunk = sizeof(struct heartbeat_chunk);
int32 size_heartbeat_ack_chunk = sizeof(struct heartbeat_ack_chunk);
int32 size_chunk = sizeof(struct chunk);
struct common_header *ch = (struct common_header*) (buf);
uint32 writtenbytes = sizeof(struct common_header);
// fill SCTP common header structure
ch->source_port = htons(msg->getSrcPort());
ch->destination_port = htons(msg->getDestPort());
ch->verification_tag = htonl(msg->getTag());
// SCTP chunks:
int32 noChunks = msg->getChunksArraySize();
for(int32 cc = 0; cc < noChunks; cc++)
{
const SCTPChunk *chunk = check_and_cast<SCTPChunk *>(((SCTPMessage *)msg)->getChunks(cc));
unsigned char chunkType = chunk->getChunkType();
switch(chunkType)
{
case DATA:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: Data sent \n";
SCTPDataChunk *dataChunk = check_and_cast<SCTPDataChunk *>(chunk);
struct data_chunk *dc = (struct data_chunk*) (buf + writtenbytes); // append data to buffer
unsigned char flags = 0;
// fill buffer with data from SCTP data chunk structure
dc->type = dataChunk->getChunkType();
if (dataChunk->getUBit())
flags |= UNORDERED_BIT;
if (dataChunk->getBBit())
flags |= BEGIN_BIT;
if (dataChunk->getEBit())
flags |= END_BIT;
dc->flags = flags;
dc->length = htons(dataChunk->getByteLength());
dc->tsn = htonl(dataChunk->getTsn());
dc->sid = htons(dataChunk->getSid());
dc->ssn = htons(dataChunk->getSsn());
dc->ppi = htonl(dataChunk->getPpid());
writtenbytes += SCTP_DATA_CHUNK_LENGTH;
SCTPSimpleMessage *smsg = check_and_cast<SCTPSimpleMessage *>(dataChunk->getEncapsulatedPacket());
// T.D. 09.02.2010: Only copy data when there is something to copy!
const uint32 datalen = smsg->getDataLen();
if( smsg->getDataArraySize() >= datalen) {
for (uint32 i = 0; i < datalen; i++) {
dc->user_data[i] = smsg->getData(i);
}
}
writtenbytes += ADD_PADDING(datalen);
break;
}
case INIT:
{
//sctpEV3<<"serialize INIT sizeKeyVector="<<sizeKeyVector<<"\n";
// source data from internal struct:
SCTPInitChunk *initChunk = check_and_cast<SCTPInitChunk *>(chunk);
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: Init sent \n";
// destination is send buffer:
struct init_chunk *ic = (struct init_chunk*) (buf + writtenbytes); // append data to buffer
//buflen += (initChunk->getBitLength() / 8);
// fill buffer with data from SCTP init chunk structure
ic->type = initChunk->getChunkType();
ic->flags = 0; // no flags available in this type of SCTPChunk
ic->initiate_tag = htonl(initChunk->getInitTag());
ic->a_rwnd = htonl(initChunk->getA_rwnd());
ic->mos = htons(initChunk->getNoOutStreams());
ic->mis = htons(initChunk->getNoInStreams());
ic->initial_tsn = htonl(initChunk->getInitTSN());
int32 parPtr = 0;
// Var.-Len. Parameters
struct supported_address_types_parameter* sup_addr = (struct supported_address_types_parameter*) (((unsigned char *)ic) + size_init_chunk + parPtr);
sup_addr->type = htons(INIT_SUPPORTED_ADDRESS);
sup_addr->length = htons(6);
sup_addr->address_type = htons(INIT_PARAM_IPV4);
parPtr += 8;
int32 numaddr = initChunk->getAddressesArraySize();
for(int32 i=0; i<numaddr; i++)
{
struct init_ipv4_address_parameter *ipv4addr = (struct init_ipv4_address_parameter*) (((unsigned char *)ic) + size_init_chunk + parPtr);
ipv4addr->type = htons(INIT_PARAM_IPV4);
ipv4addr->length = htons(8);
ipv4addr->address = htonl(initChunk->getAddresses(i).get4().getInt());
parPtr += sizeof(struct init_ipv4_address_parameter);
}
ic->length = htons(SCTP_INIT_CHUNK_LENGTH+parPtr);
writtenbytes += SCTP_INIT_CHUNK_LENGTH+parPtr;
break;
}
case INIT_ACK:
{
//sctpEV3<<"serialize INIT_ACK sizeKeyVector="<<sizeKeyVector<<"\n";
SCTPInitAckChunk *initAckChunk = check_and_cast<SCTPInitAckChunk *>(chunk);
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: InitAck sent \n";
// destination is send buffer:
struct init_ack_chunk *iac = (struct init_ack_chunk*) (buf + writtenbytes); // append data to buffer
// fill buffer with data from SCTP init ack chunk structure
iac->type = initAckChunk->getChunkType();
// iac->flags = initAckChunk->getFlags(); // no flags available in this type of SCTPChunk
iac->initiate_tag = htonl(initAckChunk->getInitTag());
iac->a_rwnd = htonl(initAckChunk->getA_rwnd());
iac->mos = htons(initAckChunk->getNoOutStreams());
iac->mis = htons(initAckChunk->getNoInStreams());
iac->initial_tsn = htonl(initAckChunk->getInitTSN());
// Var.-Len. Parameters
int32 parPtr=0;
struct supported_address_types_parameter* sup_addr = (struct supported_address_types_parameter*) (((unsigned char *)iac) + size_init_chunk + parPtr);
sup_addr->type = htons(INIT_SUPPORTED_ADDRESS);
sup_addr->length = htons(6);
sup_addr->address_type = htons(INIT_PARAM_IPV4);
parPtr += 8;
int32 numaddr = initAckChunk->getAddressesArraySize();
for(int32 i=0; i<numaddr; i++)
{
struct init_ipv4_address_parameter *ipv4addr = (struct init_ipv4_address_parameter*) (((unsigned char *)iac) + size_init_chunk + parPtr);
ipv4addr->type = htons(INIT_PARAM_IPV4);
ipv4addr->length = htons(8);
ipv4addr->address = htonl(initAckChunk->getAddresses(i).get4().getInt());
parPtr += 8;
}
uint32 uLen = initAckChunk->getUnrecognizedParametersArraySize();
if (uLen>0)
{
//sctpEV3<<"uLen="<<uLen<<"\n";
int32 k=0;
uint32 pLen=0;
while (uLen>0)
{
struct tlv* unknown = (struct tlv*) (((unsigned char *)iac) + size_init_chunk + parPtr);
unknown->type = htons(UNRECOGNIZED_PARAMETER);
pLen = initAckChunk->getUnrecognizedParameters(k+2)*16+initAckChunk->getUnrecognizedParameters(k+3);
unknown->length = htons(pLen+4);
//sctpEV3<<"unknown->length="<<pLen<<"\n";
for (uint32 i=0; i<ADD_PADDING(pLen); i++,k++)
unknown->value[i] = initAckChunk->getUnrecognizedParameters(k);
parPtr += ADD_PADDING(pLen+4);
uLen-=ADD_PADDING(pLen);
}
}
/*if(cookielen == 0)
{
cookielen = 4;
initAckChunk->setCookieArraySize(cookielen);
initAckChunk->setCookie(0, '1');
initAckChunk->setCookie(1, '3');
initAckChunk->setCookie(2, '3');
initAckChunk->setCookie(3, '7');
iac->length = htons(ntohs(iac->length) + 8);
}*/
int32 cookielen = initAckChunk->getCookieArraySize();
if (cookielen == 0)
{
SCTPCookie* stateCookie = check_and_cast<SCTPCookie*>(initAckChunk->getStateCookie());
struct init_cookie_parameter *cookie = (struct init_cookie_parameter*) (((unsigned char *)iac) + size_init_chunk + parPtr);
cookie->type = htons(INIT_PARAM_COOKIE);
cookie->length = htons(SCTP_COOKIE_LENGTH + 4);
cookie->creationTime = htonl((uint32)stateCookie->getCreationTime().dbl());
cookie->localTag = htonl(stateCookie->getLocalTag());
cookie->peerTag = htonl(stateCookie->getPeerTag());
for(int32 i=0; i<32; i++)
{
cookie->localTieTag[i] = stateCookie->getLocalTieTag(i);
cookie->peerTieTag[i] = stateCookie->getPeerTieTag(i);
}
parPtr += (SCTP_COOKIE_LENGTH + 4);
}
else
{
struct tlv *cookie = (struct tlv*) (((unsigned char *)iac) + size_init_chunk + parPtr);
cookie->type = htons(INIT_PARAM_COOKIE);
cookie->length = htons(cookielen+4);
for(int32 i=0; i<cookielen; i++)
cookie->value[i] = initAckChunk->getCookie(i);
parPtr += cookielen + 4;
}
iac->length = htons(SCTP_INIT_CHUNK_LENGTH+parPtr);
writtenbytes += SCTP_INIT_CHUNK_LENGTH+parPtr;
break;
}
case SACK:
{
SCTPSackChunk *sackChunk = check_and_cast<SCTPSackChunk *>(chunk);
// destination is send buffer:
struct sack_chunk *sac = (struct sack_chunk*) (buf + writtenbytes); // append data to buffer
writtenbytes += (sackChunk->getBitLength() / 8);
// fill buffer with data from SCTP init ack chunk structure
sac->type = sackChunk->getChunkType();
// sac->flags = sackChunk->getFlags(); // no flags available in this type of SCTPChunk
sac->length = htons(sackChunk->getBitLength() / 8);
uint32 cumtsnack = sackChunk->getCumTsnAck();
sac->cum_tsn_ack = htonl(cumtsnack);
sac->a_rwnd = htonl(sackChunk->getA_rwnd());
sac->nr_of_gaps = htons(sackChunk->getNumGaps());
sac->nr_of_dups = htons(sackChunk->getNumDupTsns());
// GAPs and Dup. TSNs:
int32 numgaps = sackChunk->getNumGaps();
int32 numdups = sackChunk->getNumDupTsns();
for(int32 i=0; i<numgaps; i++)
{
struct sack_gap *gap = (struct sack_gap*) (((unsigned char *)sac) + size_sack_chunk + i*sizeof(struct sack_gap));
gap->start = htons(sackChunk->getGapStart(i) - cumtsnack);
gap->stop = htons(sackChunk->getGapStop(i) - cumtsnack);
}
for(int32 i=0; i<numdups; i++)
{
struct sack_duptsn *dup = (struct sack_duptsn*) (((unsigned char *)sac) + size_sack_chunk + numgaps*sizeof(struct sack_gap) + i*sizeof(sack_duptsn));
dup->tsn = htonl(sackChunk->getDupTsns(i));
}
break;
}
case HEARTBEAT:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: Heartbeat sent \n";
SCTPHeartbeatChunk *heartbeatChunk = check_and_cast<SCTPHeartbeatChunk *>(chunk);
// destination is send buffer:
struct heartbeat_chunk *hbc = (struct heartbeat_chunk*) (buf + writtenbytes); // append data to buffer
writtenbytes += (heartbeatChunk->getBitLength() / 8);
// fill buffer with data from SCTP init ack chunk structure
hbc->type = heartbeatChunk->getChunkType();
// hbc->flags = heartbeatChunk->getFlags(); // no flags available in this type of SCTPChunk
hbc->length = htons(heartbeatChunk->getBitLength() / 8);
// deliver info:
struct heartbeat_info *hbi = (struct heartbeat_info*) (((unsigned char*)hbc) + size_heartbeat_chunk);
IPvXAddress addr = heartbeatChunk->getRemoteAddr();
simtime_t time = heartbeatChunk->getTimeField();
int32 infolen = sizeof(addr.get4().getInt()) + sizeof(uint32);
hbi->type = htons(1); // mandatory
hbi->length = htons(infolen+4);
HBI_ADDR(hbi) = htonl(addr.get4().getInt());
HBI_TIME(hbi) = htonl((uint32)time.dbl());
break;
}
case HEARTBEAT_ACK:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: HeartbeatAck sent \n";
SCTPHeartbeatAckChunk *heartbeatAckChunk = check_and_cast<SCTPHeartbeatAckChunk *>(chunk);
// destination is send buffer:
struct heartbeat_ack_chunk *hbac = (struct heartbeat_ack_chunk*) (buf + writtenbytes); // append data to buffer
writtenbytes += (heartbeatAckChunk->getBitLength() / 8);
// fill buffer with data from SCTP init ack chunk structure
hbac->type = heartbeatAckChunk->getChunkType();
// hbac->flags = heartbeatAckChunk->getFlags(); // no flags available in this type of SCTPChunk
hbac->length = htons(heartbeatAckChunk->getBitLength() / 8);
// deliver info:
struct heartbeat_info *hbi = (struct heartbeat_info*) (((unsigned char*)hbac) + size_heartbeat_ack_chunk);
int32 infolen = heartbeatAckChunk->getInfoArraySize();
hbi->type = htons(1); //mandatory
if (infolen > 0)
{
hbi->length = htons(infolen+4);
for(int32 i=0; i<infolen; i++)
{
HBI_INFO(hbi)[i] = heartbeatAckChunk->getInfo(i);
}
}
else
{
IPvXAddress addr = heartbeatAckChunk->getRemoteAddr();
infolen = sizeof(addr.get4().getInt()) + sizeof(uint32);
hbi->type = htons(1); // mandatory
hbi->length = htons(infolen+4);
simtime_t time = heartbeatAckChunk->getTimeField();
HBI_ADDR(hbi) = htonl(addr.get4().getInt());
HBI_TIME(hbi) = htonl((uint32)time.dbl());
}
break;
}
case ABORT:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: Abort sent \n";
SCTPAbortChunk *abortChunk = check_and_cast<SCTPAbortChunk *>(chunk);
// destination is send buffer:
struct abort_chunk *ac = (struct abort_chunk*) (buf + writtenbytes); // append data to buffer
writtenbytes += (abortChunk->getBitLength() / 8);
// fill buffer with data from SCTP init ack chunk structure
ac->type = abortChunk->getChunkType();
unsigned char flags = 0;
if(abortChunk->getT_Bit())
flags |= T_BIT;
ac->flags = flags;
ac->length = htons(abortChunk->getBitLength() / 8);
break;
}
case COOKIE_ECHO:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: CookieEcho sent \n";
SCTPCookieEchoChunk *cookieChunk = check_and_cast<SCTPCookieEchoChunk *>(chunk);
struct cookie_echo_chunk *cec = (struct cookie_echo_chunk*) (buf + writtenbytes);
cec->type = cookieChunk->getChunkType();
cec->length = htons(cookieChunk->getBitLength() / 8);
int32 cookielen = cookieChunk->getCookieArraySize();
if (cookielen>0)
{
for(int32 i=0; i<cookielen; i++)
cec->state_cookie[i] = cookieChunk->getCookie(i);
}
else
{
SCTPCookie* stateCookie = check_and_cast<SCTPCookie*>(cookieChunk->getStateCookie());
struct cookie_parameter *cookie = (struct cookie_parameter*) (buf + writtenbytes+4);
cookie->creationTime = htonl((uint32)stateCookie->getCreationTime().dbl());
cookie->localTag = htonl(stateCookie->getLocalTag());
cookie->peerTag = htonl(stateCookie->getPeerTag());
for(int32 i=0; i<32; i++)
{
cookie->localTieTag[i] = stateCookie->getLocalTieTag(i);
cookie->peerTieTag[i] = stateCookie->getPeerTieTag(i);
}
}
writtenbytes += (ADD_PADDING(cookieChunk->getBitLength() / 8));
//sctpEV3<<"buflen cookie_echo="<<buflen<<"\n";
uint32 uLen = cookieChunk->getUnrecognizedParametersArraySize();
if (uLen>0)
{
//sctpEV3<<"uLen="<<uLen<<"\n";
struct error_chunk* error = (struct error_chunk*)(buf + writtenbytes);
error->type = ERRORTYPE;
error->flags = 0;
int32 k=0;
uint32 pLen=0;
uint32 ecLen = SCTP_ERROR_CHUNK_LENGTH;
uint32 ecParPtr = 0;
while (uLen>0)
{
struct tlv* unknown = (struct tlv*) (((unsigned char *)error) + sizeof(struct error_chunk) + ecParPtr);
unknown->type = htons(UNRECOGNIZED_PARAMETER);
pLen = cookieChunk->getUnrecognizedParameters(k+2)*16+cookieChunk->getUnrecognizedParameters(k+3);
unknown->length = htons(pLen+4);
ecLen += pLen+4;
//sctpEV3<<"plength="<<pLen<<" ecLen="<<ecLen<<"\n";
for (uint32 i=0; i<ADD_PADDING(pLen); i++,k++)
unknown->value[i] = cookieChunk->getUnrecognizedParameters(k);
ecParPtr += ADD_PADDING(pLen+4);
//sctpEV3<<"ecParPtr="<<ecParPtr<<"\n";
uLen-=ADD_PADDING(pLen);
}
error->length = htons(ecLen);
writtenbytes += SCTP_ERROR_CHUNK_LENGTH+ecParPtr;
}
break;
}
case COOKIE_ACK:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: CookieAck sent \n";
SCTPCookieAckChunk *cookieAckChunk = check_and_cast<SCTPCookieAckChunk *>(chunk);
struct cookie_ack_chunk *cac = (struct cookie_ack_chunk*) (buf + writtenbytes);
writtenbytes += (cookieAckChunk->getBitLength() / 8);
cac->type = cookieAckChunk->getChunkType();
cac->length = htons(cookieAckChunk->getBitLength() / 8);
break;
}
case SHUTDOWN:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: ShutdownAck sent \n";
SCTPShutdownChunk *shutdownChunk = check_and_cast<SCTPShutdownChunk *>(chunk);
struct shutdown_chunk *sac = (struct shutdown_chunk*) (buf + writtenbytes);
writtenbytes += (shutdownChunk->getBitLength() / 8);
sac->type = shutdownChunk->getChunkType();
sac->cumulative_tsn_ack = htonl(shutdownChunk->getCumTsnAck());
sac->length = htons(shutdownChunk->getBitLength() / 8);
break;
}
case SHUTDOWN_ACK:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: ShutdownAck sent \n";
SCTPShutdownAckChunk *shutdownAckChunk = check_and_cast<SCTPShutdownAckChunk *>(chunk);
struct shutdown_ack_chunk *sac = (struct shutdown_ack_chunk*) (buf + writtenbytes);
writtenbytes += (shutdownAckChunk->getBitLength() / 8);
sac->type = shutdownAckChunk->getChunkType();
sac->length = htons(shutdownAckChunk->getBitLength() / 8);
break;
}
case SHUTDOWN_COMPLETE:
{
//sctpEV3<<simulation.simTime()<<" SCTPAssociation:: ShutdownAck sent \n";
SCTPShutdownCompleteChunk *shutdownCompleteChunk = check_and_cast<SCTPShutdownCompleteChunk *>(chunk);
struct shutdown_complete_chunk *sac = (struct shutdown_complete_chunk*) (buf + writtenbytes);
writtenbytes += (shutdownCompleteChunk->getBitLength() / 8);
sac->type = shutdownCompleteChunk->getChunkType();
sac->length = htons(shutdownCompleteChunk->getBitLength() / 8);
unsigned char flags = 0;
if(shutdownCompleteChunk->getTBit())
flags |= T_BIT;
sac->flags = flags;
break;
}
case ERRORTYPE:
{
SCTPErrorChunk* errorchunk = check_and_cast<SCTPErrorChunk*>(chunk);
struct error_chunk* error = (struct error_chunk*)(buf + writtenbytes);
error->type = errorchunk->getChunkType();
error->flags = 0;
if (errorchunk->getParametersArraySize()>0)
{
writtenbytes += size_chunk;
}
else
writtenbytes += ADD_PADDING(error->length);
break;
}
default:
printf("Serialize TODO: Implement for outgoing chunk type %d!\n", chunkType);
throw new cRuntimeError("TODO: unknown chunktype in outgoing packet on external interface! Implement it!");
// break;
}
/*drop(chunk);
delete chunk;*/
}
// finally, set the CRC32 checksum field in the SCTP common header
/*sctpEV3<<"srcport="<<msg->getSrcPort() <<"destport="<<msg->getDestPort() <<"writtenbytes vor checksum="<<writtenbytes<<"\n";*/
ch->checksum = checksum((unsigned char*)ch, writtenbytes);
return writtenbytes;
}