PPP.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2004 Andras Varga
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 <string.h>
00020 #include <omnetpp.h>
00021 #include "IInterfaceTable.h"
00022 #include "InterfaceTableAccess.h"
00023 #include "PPP.h"
00024 #include "IPassiveQueue.h"
00025 #include "NotificationBoard.h"
00026 #include "NotifierConsts.h"
00027 
00028 
00029 
00030 Define_Module(PPP);
00031 
00032 PPP::PPP()
00033 {
00034     endTransmissionEvent = NULL;
00035     nb = NULL;
00036 }
00037 
00038 PPP::~PPP()
00039 {
00040     // kludgy way to check that nb is not deleted yet
00041     if (nb && nb == findModuleWhereverInNode("notificationBoard", this))
00042         nb->unsubscribe(this, NF_SUBSCRIBERLIST_CHANGED);
00043     cancelAndDelete(endTransmissionEvent);
00044 }
00045 
00046 void PPP::initialize(int stage)
00047 {
00048     // all initialization is done in the first stage
00049     if (stage==0)
00050     {
00051         txQueue.setName("txQueue");
00052         endTransmissionEvent = new cMessage("pppEndTxEvent");
00053 
00054         txQueueLimit = par("txQueueLimit");
00055 
00056         interfaceEntry = NULL;
00057 
00058         numSent = numRcvdOK = numBitErr = numDroppedIfaceDown = 0;
00059         WATCH(numSent);
00060         WATCH(numRcvdOK);
00061         WATCH(numBitErr);
00062         WATCH(numDroppedIfaceDown);
00063 
00064         // find queueModule
00065         queueModule = NULL;
00066         if (par("queueModule").stringValue()[0])
00067         {
00068             cModule *mod = getParentModule()->getSubmodule(par("queueModule").stringValue());
00069             queueModule = check_and_cast<IPassiveQueue *>(mod);
00070         }
00071 
00072         // remember the output gate now, to speed up send()
00073         physOutGate = gate("phys$o");
00074 
00075         // we're connected if other end of connection path is an input gate
00076         bool connected = physOutGate->getPathEndGate()->getType()==cGate::INPUT;
00077 
00078         // if we're connected, get the gate with transmission rate
00079         datarateChannel = connected ? physOutGate->getTransmissionChannel() : NULL;
00080         double datarate = connected ? datarateChannel->par("datarate").doubleValue() : 0;
00081 
00082         // register our interface entry in IInterfaceTable
00083         interfaceEntry = registerInterface(datarate);
00084 
00085         // prepare to fire notifications
00086         nb = NotificationBoardAccess().get();
00087         notifDetails.setInterfaceEntry(interfaceEntry);
00088         nb->subscribe(this, NF_SUBSCRIBERLIST_CHANGED);
00089         updateHasSubcribers();
00090 
00091         // display string stuff
00092         if (ev.isGUI())
00093         {
00094             if (connected) {
00095                 oldConnColor = datarateChannel->getDisplayString().getTagArg("ls",0);
00096             }
00097             else {
00098                 // we are not connected: gray out our icon
00099                 getDisplayString().setTagArg("i",1,"#707070");
00100                 getDisplayString().setTagArg("i",2,"100");
00101             }
00102         }
00103 
00104         // request first frame to send
00105         if (queueModule)
00106         {
00107             EV << "Requesting first frame from queue module\n";
00108             queueModule->requestPacket();
00109         }
00110     }
00111 
00112     // update display string when addresses have been autoconfigured etc.
00113     if (stage==3)
00114     {
00115         updateDisplayString();
00116     }
00117 }
00118 
00119 InterfaceEntry *PPP::registerInterface(double datarate)
00120 {
00121     InterfaceEntry *e = new InterfaceEntry();
00122 
00123     // interface name: our module name without special characters ([])
00124     char *interfaceName = new char[strlen(getParentModule()->getFullName())+1];
00125     char *d=interfaceName;
00126     for (const char *s=getParentModule()->getFullName(); *s; s++)
00127         if (isalnum(*s))
00128             *d++ = *s;
00129     *d = '\0';
00130 
00131     e->setName(interfaceName);
00132     delete [] interfaceName;
00133 
00134     // data rate
00135     e->setDatarate(datarate);
00136 
00137     // generate a link-layer address to be used as interface token for IPv6
00138     InterfaceToken token(0, simulation.getUniqueNumber(), 64);
00139     e->setInterfaceToken(token);
00140 
00141     // MTU: typical values are 576 (Internet de facto), 1500 (Ethernet-friendly),
00142     // 4000 (on some point-to-point links), 4470 (Cisco routers default, FDDI compatible)
00143     e->setMtu(par("mtu"));
00144 
00145     // capabilities
00146     e->setMulticast(true);
00147     e->setPointToPoint(true);
00148 
00149     // add
00150     IInterfaceTable *ift = InterfaceTableAccess().get();
00151     ift->addInterface(e, this);
00152 
00153     return e;
00154 }
00155 
00156 
00157 void PPP::startTransmitting(cPacket *msg)
00158 {
00159     // if there's any control info, remove it; then encapsulate the packet
00160     delete msg->removeControlInfo();
00161     PPPFrame *pppFrame = encapsulate(msg);
00162     if (ev.isGUI()) displayBusy();
00163 
00164     if (hasSubscribers)
00165     {
00166         // fire notification
00167         notifDetails.setPacket(pppFrame);
00168         nb->fireChangeNotification(NF_PP_TX_BEGIN, &notifDetails);
00169     }
00170 
00171     // send
00172     EV << "Starting transmission of " << pppFrame << endl;
00173     send(pppFrame, physOutGate);
00174 
00175     // schedule an event for the time when last bit will leave the gate.
00176     simtime_t endTransmissionTime = datarateChannel->getTransmissionFinishTime();
00177     scheduleAt(endTransmissionTime, endTransmissionEvent);
00178 }
00179 
00180 void PPP::handleMessage(cMessage *msg)
00181 {
00182     if (datarateChannel==NULL)
00183     {
00184         EV << "Interface is not connected, dropping packet " << msg << endl;
00185         delete msg;
00186         numDroppedIfaceDown++;
00187     }
00188     else if (msg==endTransmissionEvent)
00189     {
00190         // Transmission finished, we can start next one.
00191         EV << "Transmission finished.\n";
00192         if (ev.isGUI()) displayIdle();
00193 
00194         if (hasSubscribers)
00195         {
00196             // fire notification
00197             notifDetails.setPacket(NULL);
00198             nb->fireChangeNotification(NF_PP_TX_END, &notifDetails);
00199         }
00200 
00201         if (!txQueue.empty())
00202         {
00203             cPacket *pk = (cPacket *) txQueue.pop();
00204             startTransmitting(pk);
00205             numSent++;
00206         }
00207         else if (queueModule)
00208         {
00209             // tell queue module that we've become idle
00210             queueModule->requestPacket();
00211         }
00212     }
00213     else if (msg->arrivedOn("phys$i"))
00214     {
00215         if (hasSubscribers)
00216         {
00217             // fire notification
00218             notifDetails.setPacket(PK(msg));
00219             nb->fireChangeNotification(NF_PP_RX_END, &notifDetails);
00220         }
00221 
00222         // check for bit errors
00223         if (PK(msg)->hasBitError())
00224         {
00225             EV << "Bit error in " << msg << endl;
00226             numBitErr++;
00227             delete msg;
00228         }
00229         else
00230         {
00231             // pass up payload
00232             cPacket *payload = decapsulate(check_and_cast<PPPFrame *>(msg));
00233             numRcvdOK++;
00234             send(payload,"netwOut");
00235         }
00236     }
00237     else // arrived on gate "netwIn"
00238     {
00239         if (endTransmissionEvent->isScheduled())
00240         {
00241             // We are currently busy, so just queue up the packet.
00242             EV << "Received " << msg << " for transmission but transmitter busy, queueing.\n";
00243             if (ev.isGUI() && txQueue.length()>=3) getDisplayString().setTagArg("i",1,"red");
00244 
00245             if (txQueueLimit && txQueue.length()>txQueueLimit)
00246                 error("txQueue length exceeds %d -- this is probably due to "
00247                       "a bogus app model generating excessive traffic "
00248                       "(or if this is normal, increase txQueueLimit!)",
00249                       txQueueLimit);
00250 
00251             txQueue.insert(msg);
00252         }
00253         else
00254         {
00255             // We are idle, so we can start transmitting right away.
00256             EV << "Received " << msg << " for transmission\n";
00257             startTransmitting(PK(msg));
00258             numSent++;
00259         }
00260     }
00261 
00262     if (ev.isGUI())
00263         updateDisplayString();
00264 
00265 }
00266 
00267 void PPP::displayBusy()
00268 {
00269     getDisplayString().setTagArg("i",1, txQueue.length()>=3 ? "red" : "yellow");
00270     datarateChannel->getDisplayString().setTagArg("ls",0,"yellow");
00271     datarateChannel->getDisplayString().setTagArg("ls",1,"3");
00272 }
00273 
00274 void PPP::displayIdle()
00275 {
00276     getDisplayString().setTagArg("i",1,"");
00277     datarateChannel->getDisplayString().setTagArg("ls",0,oldConnColor.c_str());
00278     datarateChannel->getDisplayString().setTagArg("ls",1,"1");
00279 }
00280 
00281 void PPP::updateDisplayString()
00282 {
00283     if (ev.isDisabled())
00284     {
00285         // speed up things
00286         getDisplayString().setTagArg("t",0,"");
00287     }
00288     else if (datarateChannel!=NULL)
00289     {
00290         double datarate = datarateChannel->par("datarate").doubleValue();
00291         char datarateText[40];
00292         if (datarate>=1e9) sprintf(datarateText,"%gG", datarate/1e9);
00293         else if (datarate>=1e6) sprintf(datarateText,"%gM", datarate/1e6);
00294         else if (datarate>=1e3) sprintf(datarateText,"%gK", datarate/1e3);
00295         else sprintf(datarateText,"%gbps", datarate);
00296 
00297 /* TBD find solution for displaying IP address without dependence on IPv6 or IPv6
00298         IPAddress addr = interfaceEntry->ipv4Data()->getIPAddress();
00299         sprintf(buf, "%s / %s\nrcv:%ld snt:%ld", addr.isUnspecified()?"-":addr.str().c_str(), datarateText, numRcvdOK, numSent);
00300 */
00301 
00302         char buf[80];
00303         sprintf(buf, "%s\nrcv:%ld snt:%ld", datarateText, numRcvdOK, numSent);
00304 
00305         if (numBitErr>0)
00306             sprintf(buf+strlen(buf), "\nerr:%ld", numBitErr);
00307 
00308         getDisplayString().setTagArg("t",0,buf);
00309     }
00310     else
00311     {
00312         char buf[80];
00313         sprintf(buf, "not connected\ndropped:%ld", numDroppedIfaceDown);
00314         getDisplayString().setTagArg("t",0,buf);
00315     }
00316 }
00317 
00318 void PPP::updateHasSubcribers()
00319 {
00320     hasSubscribers = nb->hasSubscribers(NF_PP_TX_BEGIN) ||
00321                      nb->hasSubscribers(NF_PP_TX_END) ||
00322                      nb->hasSubscribers(NF_PP_RX_END);
00323 }
00324 
00325 void PPP::receiveChangeNotification(int category, const cPolymorphic *)
00326 {
00327     if (category==NF_SUBSCRIBERLIST_CHANGED)
00328         updateHasSubcribers();
00329 }
00330 
00331 PPPFrame *PPP::encapsulate(cPacket *msg)
00332 {
00333     PPPFrame *pppFrame = new PPPFrame(msg->getName());
00334     pppFrame->setByteLength(PPP_OVERHEAD_BYTES);
00335     pppFrame->encapsulate(msg);
00336     return pppFrame;
00337 }
00338 
00339 cPacket *PPP::decapsulate(PPPFrame *pppFrame)
00340 {
00341     cPacket *msg = pppFrame->decapsulate();
00342     delete pppFrame;
00343     return msg;
00344 }
00345 
00346