ICMPSerializer.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005 Christian Dankbar, Irene Ruengeler, Michael Tuexen, Andras Varga
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #include <platdep/sockets.h>
00019 #include "headers/defs.h"
00020 namespace INETFw // load headers into a namespace, to avoid conflicts with platform definitions of the same stuff
00021 {
00022 #include "headers/bsdint.h"
00023 #include "headers/in.h"
00024 #include "headers/in_systm.h"
00025 #include "headers/ip.h"
00026 #include "headers/ip_icmp.h"
00027 };
00028 #include "IPSerializer.h"
00029 #include "ICMPSerializer.h"
00030 #include "PingPayload_m.h"
00031 #include "TCPIPchecksum.h"
00032 
00033 #if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) && !defined(__CYGWIN__) && !defined(_WIN64)
00034 #include <netinet/in.h>  // htonl, ntohl, ...
00035 #endif
00036 
00037 
00038 using namespace INETFw;
00039 
00040 
00041 int ICMPSerializer::serialize(const ICMPMessage *pkt, unsigned char *buf, unsigned int bufsize)
00042 {
00043     struct icmp *icmp = (struct icmp *) (buf);
00044     int packetLength;
00045 
00046     packetLength = ICMP_MINLEN;
00047 
00048     switch(pkt->getType())
00049     {
00050         case ICMP_ECHO_REQUEST:
00051         {
00052             PingPayload *pp = check_and_cast<PingPayload* >(pkt->getEncapsulatedMsg());
00053             icmp->icmp_type = ICMP_ECHO;
00054             icmp->icmp_code = 0;
00055             icmp->icmp_id   = htons(pp->getOriginatorId());
00056             icmp->icmp_seq  = htons(pp->getSeqNo());
00057             unsigned int datalen = (pp->getByteLength() - 4);
00058             for (unsigned int i=0; i < datalen; i++)
00059                 if (i < pp->getDataArraySize()) {
00060                     icmp->icmp_data[i] = pp->getData(i);
00061                 } else {
00062                     icmp->icmp_data[i] = 'a';
00063                 }
00064             packetLength += datalen;
00065             break;
00066         }
00067         case ICMP_ECHO_REPLY:
00068         {
00069             PingPayload *pp = check_and_cast<PingPayload* >(pkt->getEncapsulatedMsg());
00070             icmp->icmp_type = ICMP_ECHOREPLY;
00071             icmp->icmp_code = 0;
00072             icmp->icmp_id   = htons(pp->getOriginatorId());
00073             icmp->icmp_seq  = htons(pp->getSeqNo());
00074             unsigned int datalen = pp->getDataArraySize();
00075             for(unsigned int i=0; i < datalen; i++)
00076                 icmp->icmp_data[i] = pp->getData(i);
00077             packetLength += datalen;
00078             break;
00079         }
00080         case ICMP_DESTINATION_UNREACHABLE:
00081         {
00082             IPDatagram *ip = check_and_cast<IPDatagram* >(pkt->getEncapsulatedMsg());
00083             icmp->icmp_type = ICMP_UNREACH;
00084             icmp->icmp_code = pkt->getCode();
00085             packetLength += IPSerializer().serialize(ip, (unsigned char *)icmp->icmp_data, bufsize - ICMP_MINLEN);
00086             break;
00087         }
00088         case ICMP_TIME_EXCEEDED:
00089         {
00090             IPDatagram *ip = check_and_cast<IPDatagram* >(pkt->getEncapsulatedMsg());
00091             icmp->icmp_type = ICMP_TIMXCEED;
00092             icmp->icmp_code = ICMP_TIMXCEED_INTRANS;
00093             packetLength += IPSerializer().serialize(ip, (unsigned char *)icmp->icmp_data, bufsize - ICMP_MINLEN);
00094             break;
00095         }
00096         default:
00097         {
00098             packetLength = 0;
00099             EV << "Can not serialize ICMP packet: type " << pkt->getType() << " not supported.";
00100             break;
00101         }
00102     }
00103     icmp->icmp_cksum = TCPIPchecksum::checksum(buf, packetLength);
00104     return packetLength;
00105 }
00106 
00107 void ICMPSerializer::parse(const unsigned char *buf, unsigned int bufsize, ICMPMessage *pkt)
00108 {
00109     struct icmp *icmp = (struct icmp*) buf;
00110 
00111     switch(icmp->icmp_type)
00112     {
00113         case ICMP_ECHO:
00114         {
00115             PingPayload *pp;
00116             char name[32];
00117 
00118             pkt->setType(ICMP_ECHO_REQUEST);
00119             pkt->setCode(0);
00120             pkt->setByteLength(4);
00121             sprintf(name,"ping%d", ntohs(icmp->icmp_seq));
00122             pp = new PingPayload(name);
00123             pp->setOriginatorId(ntohs(icmp->icmp_id));
00124             pp->setSeqNo(ntohs(icmp->icmp_seq));
00125             pp->setByteLength(bufsize - 4);
00126             pp->setDataArraySize(bufsize - ICMP_MINLEN);
00127             for(unsigned int i=0; i<bufsize - ICMP_MINLEN; i++)
00128                 pp->setData(i, icmp->icmp_data[i]);
00129             pkt->encapsulate(pp);
00130             pkt->setName(pp->getName());
00131             break;
00132         }
00133         case ICMP_ECHOREPLY:
00134         {
00135             PingPayload *pp;
00136             char name[32];
00137 
00138             pkt->setType(ICMP_ECHO_REPLY);
00139             pkt->setCode(0);
00140             pkt->setByteLength(4);
00141             sprintf(name,"ping%d-reply", ntohs(icmp->icmp_seq));
00142             pp = new PingPayload(name);
00143             pp->setOriginatorId(ntohs(icmp->icmp_id));
00144             pp->setSeqNo(ntohs(icmp->icmp_seq));
00145             pp->setByteLength(bufsize - 4);
00146             pp->setDataArraySize(bufsize - ICMP_MINLEN);
00147             for (unsigned int i=0; i<bufsize - ICMP_MINLEN; i++)
00148                 pp->setData(i, icmp->icmp_data[i]);
00149             pkt->encapsulate(pp);
00150             pkt->setName(pp->getName());
00151             break;
00152         }
00153         default:
00154         {
00155             EV << "Can not create ICMP packet: type " << icmp->icmp_type << " not supported.";
00156             break;
00157         }
00158     }
00159 }