TCPDump.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005 Michael Tuexen
00003 // Copyright (C) 2008 Irene Ruengeler
00004 // Copyright (C) 2009 Thomas Dreibholz
00005 // Copyright (C) 2009 Thomas Reschka
00006 //
00007 // This program is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU Lesser General Public License
00009 // as published by the Free Software Foundation; either version 2
00010 // of the License, or (at your option) any later version.
00011 //
00012 // This program is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015 // GNU Lesser General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU Lesser General Public License
00018 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00019 //
00020 
00021 
00022 #include "TCPDump.h"
00023 #include "IPControlInfo_m.h"
00024 #include "SCTPMessage.h"
00025 #include "SCTPAssociation.h"
00026 #include "IPSerializer.h"
00027 #include "ICMPMessage.h"
00028 #include "UDPPacket_m.h"
00029 
00030 #if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) && !defined(__CYGWIN__) && !defined(_WIN64)
00031 #include <netinet/in.h>  // htonl, ntohl, ...
00032 #endif
00033 
00034 #define MAXBUFLENGTH 65536
00035 
00036 TCPDumper::TCPDumper(std::ostream& out)
00037 {
00038      outp = &out;
00039 }
00040 
00041 TCPDumper::~TCPDumper()
00042 {
00043 }
00044 
00045 void TCPDumper::ipDump(const char *label, IPDatagram *dgram, const char *comment)
00046 {
00047      if (dynamic_cast<SCTPMessage *>(dgram->getEncapsulatedMsg()))
00048      {
00049           SCTPMessage *sctpmsg = check_and_cast<SCTPMessage *>(dgram->getEncapsulatedMsg());
00050           if (dgram->hasBitError())
00051                 sctpmsg->setBitError(true);
00052           sctpDump(label, sctpmsg, dgram->getSrcAddress().str(), dgram->getDestAddress().str(), comment);
00053      }
00054      else
00055           delete dgram;
00056 }
00057 
00058 void TCPDumper::sctpDump(const char *label, SCTPMessage *sctpmsg, const std::string& srcAddr, const std::string& destAddr, const char *comment)
00059 {
00060      std::ostream& out = *outp;
00061      uint32 numberOfChunks;
00062      SCTPChunk* chunk;
00063      uint8 type;
00064      // seq and time (not part of the tcpdump format)
00065      char buf[30];
00066      sprintf(buf,"[%.3f%s] ", simulation.getSimTime().dbl(), label);
00067      out << buf;
00068 
00069      // src/dest
00070      out << srcAddr  << "." << sctpmsg->getSrcPort()  << " > ";
00071 
00072      out << destAddr << "." << sctpmsg->getDestPort() << ": ";
00073      if (sctpmsg->hasBitError())
00074      {
00075           sctpmsg->setChecksumOk(false);
00076      }
00077      numberOfChunks = sctpmsg->getChunksArraySize();
00078      out << "numberOfChunks="<<numberOfChunks<<" VTag="<<sctpmsg->getTag()<<"\n";
00079      if (sctpmsg->hasBitError())
00080           out << "Packet has bit error!!\n";
00081      for (uint32 i=0; i<numberOfChunks; i++)
00082      {
00083           chunk = (SCTPChunk*)sctpmsg->getChunks(i);
00084           type  = chunk->getChunkType();
00085           switch (type)
00086           {
00087                 case INIT:
00088                      out << "INIT ";
00089                      break;
00090                 case INIT_ACK:
00091                      out << "INIT_ACK ";
00092                      break;
00093                 case COOKIE_ECHO:
00094                      out << "COOKIE_ECHO ";
00095                      break;
00096                 case COOKIE_ACK:
00097                      out << "COOKIE_ACK ";
00098                      break;
00099                 case DATA:
00100                      out << "DATA ";
00101                      break;
00102                 case SACK:
00103                      out << "SACK ";
00104                      break;
00105                 case HEARTBEAT:
00106                      out << "HEARTBEAT ";
00107                      break;
00108                 case HEARTBEAT_ACK:
00109                      out << "HEARTBEAT_ACK ";
00110                      break;
00111                 case ABORT:
00112                      out << "ABORT ";
00113                      break;
00114                 case SHUTDOWN:
00115                      out << "SHUTDOWN ";
00116                      break;
00117                 case SHUTDOWN_ACK:
00118                      out << "SHUTDOWN_ACK ";
00119                      break;
00120                 case SHUTDOWN_COMPLETE:
00121                      out << "SHUTDOWN_COMPLETE ";
00122                      break;
00123                 case ERRORTYPE:
00124                      out << "ERROR";
00125                      break;
00126 
00127           }
00128      }
00129 
00130      if (verbosity >= 1)
00131      {
00132           out << endl;
00133           for (uint32 i=0; i<numberOfChunks; i++)
00134           {
00135                 chunk = (SCTPChunk*)sctpmsg->getChunks(i);
00136                 type    = chunk->getChunkType();
00137 
00138                 sprintf(buf,  "   %3u: ", i + 1);
00139                 out << buf;
00140                 switch (type)
00141                 {
00142                      case INIT:
00143                      {
00144                           SCTPInitChunk* initChunk;
00145                           initChunk = check_and_cast<SCTPInitChunk *>(chunk);
00146                           out << "INIT[InitiateTag=";
00147                           out << initChunk->getInitTag();
00148                           out << "; a_rwnd=";
00149                           out << initChunk->getA_rwnd();
00150                           out << "; OS=";
00151                           out << initChunk->getNoOutStreams();
00152                           out << "; IS=";
00153                           out << initChunk->getNoInStreams();
00154                           out << "; InitialTSN=";
00155                           out << initChunk->getInitTSN();
00156                           if (initChunk->getAddressesArraySize() > 0)
00157                           {
00158                                 out <<"; Addresses=";
00159                                 for (uint32 i = 0; i < initChunk->getAddressesArraySize(); i++)
00160                                 {
00161                                      if (i > 0)
00162                                           out << ",";
00163                                      if (initChunk->getAddresses(i).isIPv6())
00164                                           out << initChunk->getAddresses(i).str();
00165                                      else
00166                                           out << initChunk->getAddresses(i);
00167                                 }
00168                           }
00169 
00170                           out <<"]";
00171                           break;
00172                      }
00173                      case INIT_ACK:
00174                      {
00175                           SCTPInitAckChunk* initackChunk;
00176                           initackChunk = check_and_cast<SCTPInitAckChunk *>(chunk);
00177                           out << "INIT_ACK[InitiateTag=";
00178                           out << initackChunk->getInitTag();
00179                           out << "; a_rwnd=";
00180                           out << initackChunk->getA_rwnd();
00181                           out << "; OS=";
00182                           out << initackChunk->getNoOutStreams();
00183                           out << "; IS=";
00184                           out << initackChunk->getNoInStreams();
00185                           out << "; InitialTSN=";
00186                           out << initackChunk->getInitTSN();
00187                           out << "; CookieLength=";
00188                           out << initackChunk->getCookieArraySize();
00189                           if (initackChunk->getAddressesArraySize() > 0)
00190                           {
00191                                 out <<"; Addresses=";
00192                                 for (uint32 i = 0; i < initackChunk->getAddressesArraySize(); i++)
00193                                 {
00194                                      if (i > 0)
00195                                           out << ",";
00196                                      out << initackChunk->getAddresses(i);
00197                                 }
00198                           }
00199                           out <<"]";
00200                           break;
00201                      }
00202                      case COOKIE_ECHO:
00203                           out << "COOKIE_ECHO[CookieLength=";
00204                           out <<     chunk->getBitLength()/8 - 4;
00205                           out <<"]";
00206                           break;
00207                      case COOKIE_ACK:
00208                           out << "COOKIE_ACK ";
00209                           break;
00210                      case DATA:
00211                      {
00212                           SCTPDataChunk* dataChunk;
00213                           dataChunk = check_and_cast<SCTPDataChunk *>(chunk);
00214                           out << "DATA[TSN=";
00215                           out << dataChunk->getTsn();
00216                           out << "; SID=";
00217                           out << dataChunk->getSid();
00218                           out << "; SSN=";
00219                           out << dataChunk->getSsn();
00220                           out << "; PPID=";
00221                           out << dataChunk->getPpid();
00222                           out << "; PayloadLength=";
00223                           out << dataChunk->getBitLength()/8 - 16;
00224                           out <<"]";
00225                           break;
00226                      }
00227                      case SACK:
00228                      {
00229                           SCTPSackChunk* sackChunk;
00230                           sackChunk = check_and_cast<SCTPSackChunk *>(chunk);
00231                           out << "SACK[CumTSNAck=";
00232                           out << sackChunk->getCumTsnAck();
00233                           out << "; a_rwnd=";
00234                           out << sackChunk->getA_rwnd();
00235                           if (sackChunk->getGapStartArraySize() > 0)
00236                           {
00237                                 out <<"; Gaps=";
00238                                 for (uint32 i = 0; i < sackChunk->getGapStartArraySize(); i++)
00239                                 {
00240                                      if (i > 0)
00241                                           out << ", ";
00242                                      out << sackChunk->getGapStart(i) << "-" << sackChunk->getGapStop(i);
00243                                 }
00244                           }
00245                           if (sackChunk->getDupTsnsArraySize() > 0)
00246                           {
00247                                 out <<"; Dups=";
00248                                 for (uint32 i = 0; i < sackChunk->getDupTsnsArraySize(); i++)
00249                                 {
00250                                      if (i > 0)
00251                                           out << ", ";
00252                                      out << sackChunk->getDupTsns(i);
00253                                 }
00254                           }
00255                           out <<"]";
00256                           break;
00257                      }
00258                      case HEARTBEAT:
00259                           SCTPHeartbeatChunk* heartbeatChunk;
00260                           heartbeatChunk = check_and_cast<SCTPHeartbeatChunk *>(chunk);
00261                           out << "HEARTBEAT[InfoLength=";
00262                           out <<     chunk->getBitLength()/8 - 4;
00263                           out << "; time=";
00264                           out << heartbeatChunk->getTimeField();
00265                           out <<"]";
00266                           break;
00267                      case HEARTBEAT_ACK:
00268                           out << "HEARTBEAT_ACK[InfoLength=";
00269                           out <<     chunk->getBitLength()/8 - 4;
00270                           out <<"]";
00271                           break;
00272                      case ABORT:
00273                           SCTPAbortChunk* abortChunk;
00274                           abortChunk = check_and_cast<SCTPAbortChunk *>(chunk);
00275                           out << "ABORT[T-Bit=";
00276                           out << abortChunk->getT_Bit();
00277                           out << "]";
00278                           break;
00279                      case SHUTDOWN:
00280                           SCTPShutdownChunk* shutdown;
00281                           shutdown = check_and_cast<SCTPShutdownChunk *>(chunk);
00282                           out << "SHUTDOWN[CumTSNAck=";
00283                           out << shutdown->getCumTsnAck();
00284                           out << "]";
00285                           break;
00286                      case SHUTDOWN_ACK:
00287                           out << "SHUTDOWN_ACK ";
00288                           break;
00289                      case SHUTDOWN_COMPLETE:
00290                           out << "SHUTDOWN_COMPLETE ";
00291                           break;
00292                      case ERRORTYPE:
00293                      {
00294                           SCTPErrorChunk* errorChunk;
00295                           errorChunk = check_and_cast<SCTPErrorChunk*>(chunk);
00296                           uint32 numberOfParameters = errorChunk->getParametersArraySize();
00297                           uint32 parameterType;
00298                           for (uint32 i=0; i<numberOfParameters; i++)
00299                           {
00300                                 SCTPParameter* param = (SCTPParameter*)errorChunk->getParameters(i);
00301                                 parameterType   = param->getParameterType();
00302                           }
00303 
00304                           break;
00305                      }
00306 
00307                 }
00308                 out << endl;
00309           }
00310      }
00311      // comment
00312      if (comment)
00313           out << "# " << comment;
00314 
00315      out << endl;
00316 }
00317 
00318 TCPDump::~TCPDump()
00319 {
00320 }
00321 
00322 const char *TCPDumper::intToChunk(int32 type)
00323 {
00324      switch (type)
00325      {
00326           case 0: return "DATA";
00327           case 1: return "INIT";
00328           case 2: return "INIT_ACK";
00329           case 3: return "SACK";
00330           case 4: return "HEARTBEAT";
00331           case 5: return "HEARTBEAT_ACK";
00332           case 6: return "ABORT";
00333           case 7: return "SHUTDOWN";
00334           case 8: return "SHUTDOWN_ACK";
00335           case 9: return "ERRORTYPE";
00336           case 10: return "COOKIE_ECHO";
00337           case 11: return "COOKIE_ACK";
00338           case 14: return "SHUTDOWN_COMPLETE";
00339      }
00340      return "";
00341 }
00342 
00343 void TCPDumper::dump(const char *label, const char *msg)
00344 {
00345      std::ostream& out = *outp;
00346 
00347      // seq and time (not part of the tcpdump format)
00348      char buf[30];
00349      sprintf(buf,"[%.3f%s] ", simulation.getSimTime().dbl(), label);
00350      out << buf;
00351 
00352      out << msg << "\n";
00353 }
00354 
00355 //----
00356 
00357 Define_Module(TCPDump);
00358 
00359 TCPDump::TCPDump() : cSimpleModule(), tcpdump(ev.getOStream())
00360 {
00361 
00362 
00363 }
00364 
00365 void TCPDumper::udpDump(bool l2r, const char *label, IPDatagram *dgram, const char *comment)
00366 {
00367     cMessage *encapmsg = dgram->getEncapsulatedMsg();
00368     if (dynamic_cast<UDPPacket *>(encapmsg))
00369     {
00370         std::ostream& out = *outp;
00371 
00372         // seq and time (not part of the tcpdump format)
00373         char buf[30];
00374         sprintf(buf,"[%.3f%s] ", simulation.getSimTime().dbl(), label);
00375         out << buf;
00376         UDPPacket* udppkt = check_and_cast<UDPPacket*>(encapmsg);
00377 
00378         // src/dest
00379         if (l2r)
00380         {
00381             out << dgram->getSrcAddress().str() << "." << udppkt->getSourcePort() << " > ";
00382             out << dgram->getDestAddress().str() << "." << udppkt->getDestinationPort() << ": ";
00383         }
00384         else
00385         {
00386             out << dgram->getDestAddress().str() << "." << udppkt->getDestinationPort() << " < ";
00387             out << dgram->getSrcAddress().str() << "." << udppkt->getSourcePort() << ": ";
00388         }
00389 
00390         //out << endl;
00391         out << "UDP: Payload length=" << udppkt->getByteLength()-8 << endl;
00392         if (udppkt->getSourcePort()==9899 || udppkt->getDestinationPort() == 9899)
00393         {
00394             if (dynamic_cast<SCTPMessage *>(udppkt->getEncapsulatedMsg()))
00395                 sctpDump("", (SCTPMessage *)(udppkt->getEncapsulatedMsg()), std::string(l2r?"A":"B"),std::string(l2r?"B":"A"));
00396         }
00397     }
00398 }
00399 
00400 void TCPDumper::tcpDump(bool l2r, const char *label, IPDatagram *dgram, const char *comment)
00401 {
00402      cMessage *encapmsg = dgram->getEncapsulatedMsg();
00403      if (dynamic_cast<TCPSegment *>(encapmsg))
00404      {
00405           // if TCP, dump as TCP
00406           tcpDump(l2r, label, (TCPSegment *)encapmsg, dgram->getSrcAddress().str(), dgram->getDestAddress().str(), comment);
00407      }
00408      else
00409      {
00410           // some other packet, dump what we can
00411           std::ostream& out = *outp;
00412 
00413           // seq and time (not part of the tcpdump format)
00414           char buf[30];
00415           sprintf(buf,"[%.3f%s] ", SIMTIME_DBL(simTime()), label);
00416           out << buf;
00417 
00418           // packet class and name
00419           out << "? " << encapmsg->getClassName() << " \"" << encapmsg->getName() << "\"\n";
00420      }
00421 }
00422 
00423 //FIXME: Temporary hack for Ipv6 support
00424 void TCPDumper::dumpIPv6(bool l2r, const char *label, IPv6Datagram_Base *dgram, const char *comment)
00425 {
00426      cMessage *encapmsg = dgram->getEncapsulatedMsg();
00427      if (dynamic_cast<TCPSegment *>(encapmsg))
00428      {
00429           // if TCP, dump as TCP
00430           tcpDump(l2r, label, (TCPSegment *)encapmsg, dgram->getSrcAddress().str(), dgram->getDestAddress().str(), comment);
00431      }
00432      else
00433      {
00434           // some other packet, dump what we can
00435           std::ostream& out = *outp;
00436 
00437           // seq and time (not part of the tcpdump format)
00438           char buf[30];
00439           sprintf(buf,"[%.3f%s] ", SIMTIME_DBL(simTime()), label);
00440           out << buf;
00441 
00442           // packet class and name
00443           out << "? " << encapmsg->getClassName() << " \"" << encapmsg->getName() << "\"\n";
00444      }
00445 }
00446 
00447 void TCPDumper::tcpDump(bool l2r, const char *label, TCPSegment *tcpseg, const std::string& srcAddr, const std::string& destAddr, const char *comment)
00448 {
00449      std::ostream& out = *outp;
00450 
00451     // seq and time (not part of the tcpdump format)
00452     char buf[30];
00453     sprintf(buf,"[%.3f%s] ", SIMTIME_DBL(simTime()), label);
00454     out << buf;
00455     // src/dest ports
00456     if (l2r)
00457     {
00458         out << srcAddr << "." << tcpseg->getSrcPort() << " > ";
00459         out << destAddr << "." << tcpseg->getDestPort() << ": ";
00460     }
00461     else
00462     {
00463         out << destAddr << "." << tcpseg->getDestPort() << " < ";
00464         out << srcAddr << "." << tcpseg->getSrcPort() << ": ";
00465     }
00466 
00467     // flags
00468     bool flags = false;
00469     if (tcpseg->getUrgBit()) {flags=true; out << "U ";}
00470     if (tcpseg->getAckBit()) {flags=true; out << "A ";}
00471     if (tcpseg->getPshBit()) {flags=true; out << "P ";}
00472     if (tcpseg->getRstBit()) {flags=true; out << "R ";}
00473     if (tcpseg->getSynBit()) {flags=true; out << "S ";}
00474     if (tcpseg->getFinBit()) {flags=true; out << "F ";}
00475     if (!flags) {out << ". ";}
00476 
00477     // data-seqno
00478     if (tcpseg->getPayloadLength()>0 || tcpseg->getSynBit())
00479     {
00480         out << tcpseg->getSequenceNo() << ":" << tcpseg->getSequenceNo()+tcpseg->getPayloadLength();
00481         out << "(" << tcpseg->getPayloadLength() << ") ";
00482     }
00483 
00484     // ack
00485     if (tcpseg->getAckBit())
00486         out << "ack " << tcpseg->getAckNo() << " ";
00487 
00488     // window
00489     out << "win " << tcpseg->getWindow() << " ";
00490 
00491     // urgent
00492     if (tcpseg->getUrgBit())
00493         out << "urg " << tcpseg->getUrgentPointer() << " ";
00494 
00495     // options present?
00496     if (tcpseg->getHeaderLength() > 20)
00497         {
00498         std::string direction = "sent";
00499         if (l2r) // change direction
00500             {direction = "received";}
00501 
00502         unsigned short numOptions = tcpseg->getOptionsArraySize();
00503         out << "\nTCP Header Option(s) " << direction << ":\n";
00504         for (int i=0; i<numOptions; i++)
00505         {
00506             TCPOption option = tcpseg->getOptions(i);
00507             unsigned short kind = option.getKind();
00508             unsigned short length = option.getLength();
00509             out << (i+1) << ". option kind=" << kind << " length=" << length << "\n";
00510         }
00511     }
00512 
00513     // comment
00514     if (comment)
00515         out << "# " << comment;
00516 
00517      out << endl;
00518 }
00519 
00520 void TCPDump::initialize()
00521 {
00522     struct pcap_hdr fh;
00523     const char* file = this->par("dumpFile");
00524     snaplen = this->par("snaplen");
00525     tcpdump.setVerbosity(par("verbosity"));
00526 
00527 
00528     if (strcmp(file,"")!=0)
00529     {
00530         tcpdump.dumpfile = fopen(file, "wb");
00531         if (!tcpdump.dumpfile)
00532         {
00533             fprintf(stderr, "Cannot open file [%s] for writing: %s\n", file, strerror(errno));
00534             exit(-1);
00535         }
00536 
00537         fh.magic = PCAP_MAGIC;
00538         fh.version_major = 2;
00539         fh.version_minor = 4;
00540         fh.thiszone = 0;
00541         fh.sigfigs = 0;
00542         fh.snaplen = snaplen;
00543         fh.network = 0;
00544         fwrite(&fh, sizeof(fh), 1, tcpdump.dumpfile);
00545     }
00546     else
00547         tcpdump.dumpfile = NULL;
00548 }
00549 
00550 void TCPDump::handleMessage(cMessage *msg)
00551 {
00552 
00553     if (!ev.disable_tracing)
00554     {
00555         bool l2r;
00556 
00557         if (dynamic_cast<IPDatagram *>(msg))
00558         {
00559             if (((IPDatagram *)msg)->getTransportProtocol()==132)
00560             {
00561                 tcpdump.ipDump("", (IPDatagram *)msg);
00562             }
00563             else
00564             {
00565                 if (PK(msg)->hasBitError())
00566                 {
00567                     delete msg;
00568                     return;
00569                 }
00570                 l2r = msg->arrivedOn("in1");
00571                 if (((IPDatagram *)msg)->getTransportProtocol()==6)
00572                 {
00573                     tcpdump.tcpDump(l2r, "", (IPDatagram *)msg, "");
00574                 }
00575                 else if (((IPDatagram *)msg)->getTransportProtocol()==17)
00576                     tcpdump.udpDump(l2r, "", (IPDatagram *)msg, "");
00577             }
00578         }
00579         else if (dynamic_cast<SCTPMessage *>(msg))
00580         {
00581             l2r = msg->arrivedOn("in1");
00582             tcpdump.sctpDump("", (SCTPMessage *)msg, std::string(l2r?"A":"B"),std::string(l2r?"B":"A"));
00583         }
00584         else if (dynamic_cast<TCPSegment *>(msg))
00585         {
00586             if (PK(msg)->hasBitError())
00587             {
00588                 delete msg;
00589                 return;
00590             }
00591             l2r = msg->arrivedOn("in1");
00592             tcpdump.tcpDump(l2r, "", (TCPSegment *)msg, std::string(l2r?"A":"B"),std::string(l2r?"B":"A"));
00593         }
00594         else if (dynamic_cast<ICMPMessage *>(msg))
00595         {
00596             if (PK(msg)->hasBitError())
00597             {
00598                 delete msg;
00599                 return;
00600             }
00601             std::cout<<"ICMPMessage\n";
00602         }
00603         else
00604         {
00605             // search for encapsulated IP[v6]Datagram in it
00606             cPacket *encapmsg = PK(msg);
00607             while (encapmsg && dynamic_cast<IPDatagram *>(encapmsg)==NULL && dynamic_cast<IPv6Datagram_Base *>(encapmsg)==NULL)
00608                 encapmsg = encapmsg->getEncapsulatedMsg();
00609                 l2r = msg->arrivedOn("in1");
00610             if (!encapmsg)
00611             {
00612                 //We do not want this to end in an error if EtherAutoconf messages
00613                 //are passed, so just print a warning. -WEI
00614                 EV << "CANNOT DECODE: packet " << msg->getName() << " doesn't contain either IP or IPv6 Datagram\n";
00615             }
00616             else
00617             {
00618                 if (dynamic_cast<IPDatagram *>(encapmsg))
00619                     tcpdump.tcpDump(l2r, "", (IPDatagram *)encapmsg);
00620                 else if (dynamic_cast<IPv6Datagram_Base *>(encapmsg))
00621                     tcpdump.dumpIPv6(l2r, "", (IPv6Datagram_Base *)encapmsg);
00622                 else
00623                 ASSERT(0); // cannot get here
00624             }
00625         }
00626     }
00627 
00628 
00629     if (tcpdump.dumpfile!=NULL && dynamic_cast<IPDatagram *>(msg))
00630     {
00631         uint8 buf[MAXBUFLENGTH];
00632         memset((void*)&buf, 0, sizeof(buf));
00633 
00634         const simtime_t stime = simulation.getSimTime();
00635         // Write PCap header
00636 
00637         struct pcaprec_hdr ph;
00638         ph.ts_sec = (int32)stime.dbl();
00639         ph.ts_usec = (uint32)((stime.dbl() - ph.ts_sec)*1000000);
00640          // Write Ethernet header
00641         uint32 hdr = 2; //AF_INET
00642                      //We do not want this to end in an error if EtherAutoconf messages
00643         IPDatagram *ipPacket = check_and_cast<IPDatagram *>(msg);
00644         // IP header:
00645         //struct sockaddr_in *to = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
00646         //int32 tosize = sizeof(struct sockaddr_in);
00647         int32 serialized_ip = IPSerializer().serialize(ipPacket, buf, sizeof(buf));
00648         ph.incl_len = serialized_ip + sizeof(uint32);
00649 
00650         ph.orig_len = ph.incl_len;
00651         fwrite(&ph, sizeof(ph), 1, tcpdump.dumpfile);
00652         fwrite(&hdr, sizeof(uint32), 1, tcpdump.dumpfile);
00653         fwrite(buf, serialized_ip, 1, tcpdump.dumpfile);
00654     }
00655 
00656 
00657     // forward
00658     int32 index = msg->getArrivalGate()->getIndex();
00659     int32 id;
00660     if (msg->getArrivalGate()->isName("ifIn"))
00661         id = findGate("out2",index);
00662     else
00663         id = findGate("ifOut",index);
00664 
00665     send(msg, id);
00666 }
00667 
00668 void TCPDump::finish()
00669 {
00670      tcpdump.dump("", "tcpdump finished");
00671      if (strcmp(this->par("dumpFile"),"")!=0)
00672           fclose(tcpdump.dumpfile);
00673 }
00674