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; }