|
INET Framework for OMNeT++/OMNEST
|
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, ¬ifDetails); 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, ¬ifDetails); 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, ¬ifDetails); 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