EtherEncap.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003 Andras Varga; CTIE, Monash University, Australia
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public License
00015  * along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 */
00017 
00018 #include <stdio.h>
00019 #include "EtherEncap.h"
00020 #include "EtherFrame_m.h"
00021 #include "Ieee802Ctrl_m.h"
00022 #include "IInterfaceTable.h"
00023 #include "InterfaceTableAccess.h"
00024 #include "EtherMAC.h"
00025 
00026 
00027 Define_Module(EtherEncap);
00028 
00029 void EtherEncap::initialize()
00030 {
00031     seqNum = 0;
00032     WATCH(seqNum);
00033 
00034     totalFromHigherLayer = totalFromMAC = totalPauseSent = 0;
00035     WATCH(totalFromHigherLayer);
00036     WATCH(totalFromMAC);
00037     WATCH(totalPauseSent);
00038 }
00039 
00040 void EtherEncap::handleMessage(cMessage *msg)
00041 {
00042     if (msg->arrivedOn("lowerLayerIn"))
00043     {
00044         processFrameFromMAC(check_and_cast<EtherFrame *>(msg));
00045     }
00046     else
00047     {
00048         // from higher layer
00049         switch(msg->getKind())
00050         {
00051             case IEEE802CTRL_DATA:
00052             case 0: // default message kind (0) is also accepted
00053               processPacketFromHigherLayer(PK(msg));
00054               break;
00055 
00056             case IEEE802CTRL_SENDPAUSE:
00057               // higher layer want MAC to send PAUSE frame
00058               handleSendPause(msg);
00059               break;
00060 
00061             default:
00062               error("received message `%s' with unknown message kind %d", msg->getName(), msg->getKind());
00063         }
00064     }
00065 
00066     if (ev.isGUI())
00067         updateDisplayString();
00068 }
00069 
00070 void EtherEncap::updateDisplayString()
00071 {
00072     char buf[80];
00073     sprintf(buf, "passed up: %ld\nsent: %ld", totalFromMAC, totalFromHigherLayer);
00074     getDisplayString().setTagArg("t",0,buf);
00075 }
00076 
00077 void EtherEncap::processPacketFromHigherLayer(cPacket *msg)
00078 {
00079     if (msg->getByteLength() > MAX_ETHERNET_DATA)
00080         error("packet from higher layer (%d bytes) exceeds maximum Ethernet payload length (%d)", (int)msg->getByteLength(), MAX_ETHERNET_DATA);
00081 
00082     totalFromHigherLayer++;
00083 
00084     // Creates MAC header information and encapsulates received higher layer data
00085     // with this information and transmits resultant frame to lower layer
00086 
00087     // create Ethernet frame, fill it in from Ieee802Ctrl and encapsulate msg in it
00088     EV << "Encapsulating higher layer packet `" << msg->getName() <<"' for MAC\n";
00089 
00090     Ieee802Ctrl *etherctrl = check_and_cast<Ieee802Ctrl*>(msg->removeControlInfo());
00091     EthernetIIFrame *frame = new EthernetIIFrame(msg->getName());
00092 
00093     frame->setSrc(etherctrl->getSrc());  // if blank, will be filled in by MAC
00094     frame->setDest(etherctrl->getDest());
00095     frame->setEtherType(etherctrl->getEtherType());
00096     frame->setByteLength(ETHER_MAC_FRAME_BYTES);
00097     delete etherctrl;
00098 
00099     frame->encapsulate(msg);
00100     if (frame->getByteLength() < MIN_ETHERNET_FRAME)
00101         frame->setByteLength(MIN_ETHERNET_FRAME);  // "padding"
00102 
00103     send(frame, "lowerLayerOut");
00104 }
00105 
00106 void EtherEncap::processFrameFromMAC(EtherFrame *frame)
00107 {
00108     totalFromMAC++;
00109 
00110     // decapsulate and attach control info
00111     cPacket *higherlayermsg = frame->decapsulate();
00112 
00113     // add Ieee802Ctrl to packet
00114     Ieee802Ctrl *etherctrl = new Ieee802Ctrl();
00115     etherctrl->setSrc(frame->getSrc());
00116     etherctrl->setDest(frame->getDest());
00117     higherlayermsg->setControlInfo(etherctrl);
00118 
00119     EV << "Decapsulating frame `" << frame->getName() <<"', passing up contained "
00120           "packet `" << higherlayermsg->getName() << "' to higher layer\n";
00121 
00122     // pass up to higher layers.
00123     send(higherlayermsg, "upperLayerOut");
00124     delete frame;
00125 }
00126 
00127 void EtherEncap::handleSendPause(cMessage *msg)
00128 {
00129     Ieee802Ctrl *etherctrl = dynamic_cast<Ieee802Ctrl*>(msg->removeControlInfo());
00130     if (!etherctrl)
00131         error("PAUSE command `%s' from higher layer received without Ieee802Ctrl", msg->getName());
00132     int pauseUnits = etherctrl->getPauseUnits();
00133     delete etherctrl;
00134 
00135     EV << "Creating and sending PAUSE frame, with duration=" << pauseUnits << " units\n";
00136 
00137     // create Ethernet frame
00138     char framename[30];
00139     sprintf(framename, "pause-%d-%d", getId(), seqNum++);
00140     EtherPauseFrame *frame = new EtherPauseFrame(framename);
00141     frame->setPauseTime(pauseUnits);
00142 
00143     frame->setByteLength(ETHER_MAC_FRAME_BYTES+ETHER_PAUSE_COMMAND_BYTES);
00144     if (frame->getByteLength() < MIN_ETHERNET_FRAME)
00145         frame->setByteLength(MIN_ETHERNET_FRAME);
00146 
00147     send(frame, "lowerLayerOut");
00148     delete msg;
00149 
00150     totalPauseSent++;
00151 }
00152 
00153 void EtherEncap::finish()
00154 {
00155     recordScalar("packets from higher layer", totalFromHigherLayer);
00156     recordScalar("frames from MAC", totalFromMAC);
00157 }
00158 
00159