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