INET Framework for OMNeT++/OMNEST
AnsaEtherMACBase.cc
Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Levente Meszaros
00003 // Copyright (C) 2004 Andras Varga
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018 //
00019 
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <omnetpp.h>
00023 #include "AnsaEtherMACBase.h"
00024 #include "IPassiveQueue.h"
00025 #include "IInterfaceTable.h"
00026 #include "InterfaceTableAccess.h"
00027 #include "InterfaceStateManager.h"
00028 
00029 static const double SPEED_OF_LIGHT = 200000000.0;
00030 
00031 AnsaEtherMACBase::AnsaEtherMACBase()
00032 {
00033     nb = NULL;
00034     queueModule = NULL;
00035     interfaceEntry = NULL;
00036     endTxMsg = endIFGMsg = endPauseMsg = NULL;
00037 }
00038 
00039 AnsaEtherMACBase::~AnsaEtherMACBase()
00040 {
00041     cancelAndDelete(endTxMsg);
00042     cancelAndDelete(endIFGMsg);
00043     cancelAndDelete(endPauseMsg);
00044 }
00045 
00046 void AnsaEtherMACBase::initialize()
00047 {
00048     physOutGate = gate("phys$o");
00049 
00050     initializeFlags();
00051 
00052     initializeTxrate();
00053     WATCH(txrate);
00054 
00055     initializeMACAddress();
00056     initializeQueueModule();
00057     initializeNotificationBoard();
00058     initializeStatistics();
00059 
00060     registerInterface(txrate); // needs MAC address
00061 
00062     // initialize queue
00063     txQueue.setName("txQueue");
00064 
00065     // initialize self messages
00066     endTxMsg = new cMessage("EndTransmission", ENDTRANSMISSION);
00067     endIFGMsg = new cMessage("EndIFG", ENDIFG);
00068     endPauseMsg = new cMessage("EndPause", ENDPAUSE);
00069 
00070     // initialize states
00071     transmitState = TX_IDLE_STATE;
00072     receiveState = RX_IDLE_STATE;
00073     WATCH(transmitState);
00074     WATCH(receiveState);
00075 
00076     // initalize pause
00077     pauseUnitsRequested = 0;
00078     WATCH(pauseUnitsRequested);
00079 
00080     // initialize queue limit
00081     txQueueLimit = par("txQueueLimit");
00082     WATCH(txQueueLimit);
00083 }
00084 
00085 void AnsaEtherMACBase::initializeQueueModule()
00086 {
00087     if (par("queueModule").stringValue()[0])
00088     {
00089         cModule *module = getParentModule()->getSubmodule(par("queueModule").stringValue());
00090         queueModule = check_and_cast<IPassiveQueue *>(module);
00091         EV << "Requesting first frame from queue module\n";
00092         queueModule->requestPacket();
00093     }
00094 }
00095 
00096 void AnsaEtherMACBase::initializeMACAddress()
00097 {
00098     const char *addrstr = par("address");
00099 
00100     if (!strcmp(addrstr,"auto"))
00101     {
00102         // assign automatic address
00103         address = MACAddress::generateAutoAddress();
00104 
00105         // change module parameter from "auto" to concrete address
00106         par("address").setStringValue(address.str().c_str());
00107     }
00108     else
00109     {
00110         address.setAddress(addrstr);
00111     }
00112 }
00113 
00114 void AnsaEtherMACBase::initializeNotificationBoard()
00115 {
00116     hasSubscribers = false;
00117     
00118     nb = NotificationBoardAccess().get();
00119     if(nb != NULL)
00120     {
00121       // subscribe interface change notifications
00122       nb->subscribe(this, NF_INTERFACE_STATE_CHANGED);
00123       if (interfaceEntry) {
00124           notifDetails.setInterfaceEntry(interfaceEntry);
00125           nb->subscribe(this, NF_SUBSCRIBERLIST_CHANGED);
00126           updateHasSubcribers();
00127       }
00128     }
00129 }
00130 
00131 void AnsaEtherMACBase::initializeFlags()
00132 {
00133     // initialize connected flag
00134     connected = physOutGate->getPathEndGate()->isConnected();
00135     if (!connected)
00136         EV << "MAC not connected to a network.\n";
00137     WATCH(connected);
00138 
00139     // TODO: this should be settable from the gui
00140     // initialize disabled flag
00141     // Note: it is currently not supported to enable a disabled MAC at runtime.
00142     // Difficulties: (1) autoconfig (2) how to pick up channel state (free, tx, collision etc)
00143     disabled = false;
00144     WATCH(disabled);
00145 
00146     // initialize promiscuous flag
00147     promiscuous = par("promiscuous");
00148     WATCH(promiscuous);
00149 }
00150 
00151 void AnsaEtherMACBase::initializeStatistics()
00152 {
00153     framesSentInBurst = 0;
00154     bytesSentInBurst = 0;
00155 
00156     numFramesSent = numFramesReceivedOK = numBytesSent = numBytesReceivedOK = 0;
00157     numFramesPassedToHL = numDroppedBitError = numDroppedNotForUs = 0;
00158     numFramesFromHL = numDroppedIfaceDown = 0;
00159     numPauseFramesRcvd = numPauseFramesSent = 0;
00160 
00161     WATCH(framesSentInBurst);
00162     WATCH(bytesSentInBurst);
00163 
00164     WATCH(numFramesSent);
00165     WATCH(numFramesReceivedOK);
00166     WATCH(numBytesSent);
00167     WATCH(numBytesReceivedOK);
00168     WATCH(numFramesFromHL);
00169     WATCH(numDroppedIfaceDown);
00170     WATCH(numDroppedBitError);
00171     WATCH(numDroppedNotForUs);
00172     WATCH(numFramesPassedToHL);
00173     WATCH(numPauseFramesRcvd);
00174     WATCH(numPauseFramesSent);
00175 
00176     numFramesSentVector.setName("framesSent");
00177     numFramesReceivedOKVector.setName("framesReceivedOK");
00178     numBytesSentVector.setName("bytesSent");
00179     numBytesReceivedOKVector.setName("bytesReceivedOK");
00180     numDroppedIfaceDownVector.setName("framesDroppedIfaceDown");
00181     numDroppedBitErrorVector.setName("framesDroppedBitError");
00182     numDroppedNotForUsVector.setName("framesDroppedNotForUs");
00183     numFramesPassedToHLVector.setName("framesPassedToHL");
00184     numPauseFramesRcvdVector.setName("pauseFramesRcvd");
00185     numPauseFramesSentVector.setName("pauseFramesSent");
00186 }
00187 
00188 void AnsaEtherMACBase::registerInterface(double txrate)
00189 {
00190     IInterfaceTable *ift = InterfaceTableAccess().getIfExists();
00191     if (!ift)
00192         return;
00193 
00194     interfaceEntry = new InterfaceEntry();
00195 
00196     // interface name: our module name without special characters ([])
00197     char *interfaceName = new char[strlen(getParentModule()->getFullName())+1];
00198     char *d=interfaceName;
00199     for (const char *s=getParentModule()->getFullName(); *s; s++)
00200         if (isalnum(*s))
00201             *d++ = *s;
00202     *d = '\0';
00203 
00204     interfaceEntry->setName(interfaceName);
00205     delete [] interfaceName;
00206 
00207     // data rate
00208     interfaceEntry->setDatarate(txrate);
00209 
00210     // generate a link-layer address to be used as interface token for IPv6
00211     interfaceEntry->setMACAddress(address);
00212     interfaceEntry->setInterfaceToken(address.formInterfaceIdentifier());
00213     //InterfaceToken token(0, simulation.getUniqueNumber(), 64);
00214     //interfaceEntry->setInterfaceToken(token);
00215 
00216     // MTU: typical values are 576 (Internet de facto), 1500 (Ethernet-friendly),
00217     // 4000 (on some point-to-point links), 4470 (Cisco routers default, FDDI compatible)
00218     interfaceEntry->setMtu(1500);
00219 
00220     // capabilities
00221     interfaceEntry->setMulticast(true);
00222     interfaceEntry->setBroadcast(true);
00223 
00224     // add
00225     ift->addInterface(interfaceEntry, this);
00226 }
00227 
00228 
00229 bool AnsaEtherMACBase::checkDestinationAddress(EtherFrame *frame)
00230 {
00231     // If not set to promiscuous = on, then checks if received frame contains destination MAC address
00232     // matching port's MAC address, also checks if broadcast bit is set
00233     if (!promiscuous && !frame->getDest().isBroadcast() && !frame->getDest().equals(address))
00234     {
00235         EV << "Frame `" << frame->getName() <<"' not destined to us, discarding\n";
00236         numDroppedNotForUs++;
00237         numDroppedNotForUsVector.record(numDroppedNotForUs);
00238         delete frame;
00239 
00240         return false;
00241     }
00242 
00243     return true;
00244 }
00245 
00246 void AnsaEtherMACBase::calculateParameters()
00247 {
00248     if (disabled || !connected)
00249     {
00250         bitTime = slotTime = interFrameGap = jamDuration = shortestFrameDuration = 0;
00251         carrierExtension = frameBursting = false;
00252         return;
00253     }
00254 
00255     if (txrate != ETHERNET_TXRATE && txrate != FAST_ETHERNET_TXRATE &&
00256         txrate != GIGABIT_ETHERNET_TXRATE && txrate != FAST_GIGABIT_ETHERNET_TXRATE)
00257     {
00258         error("nonstandard transmission rate %g, must be %g, %g, %g or %g bit/sec",
00259             txrate, ETHERNET_TXRATE, FAST_ETHERNET_TXRATE, GIGABIT_ETHERNET_TXRATE, FAST_GIGABIT_ETHERNET_TXRATE);
00260     }
00261 
00262     bitTime = 1/(double)txrate;
00263 
00264     // set slot time
00265     if (txrate==ETHERNET_TXRATE || txrate==FAST_ETHERNET_TXRATE)
00266         slotTime = SLOT_TIME;
00267     else
00268         slotTime = GIGABIT_SLOT_TIME;
00269 
00270     // only if Gigabit Ethernet
00271     frameBursting = (txrate==GIGABIT_ETHERNET_TXRATE || txrate==FAST_GIGABIT_ETHERNET_TXRATE);
00272     carrierExtension = (slotTime == GIGABIT_SLOT_TIME && !duplexMode);
00273 
00274     interFrameGap = INTERFRAME_GAP_BITS/(double)txrate;
00275     jamDuration = 8*JAM_SIGNAL_BYTES*bitTime;
00276     shortestFrameDuration = carrierExtension ? GIGABIT_MIN_FRAME_WITH_EXT : MIN_ETHERNET_FRAME;
00277 }
00278 
00279 void AnsaEtherMACBase::printParameters()
00280 {
00281     // Dump parameters
00282     EV << "MAC address: " << address << (promiscuous ? ", promiscuous mode" : "") << endl;
00283     EV << "txrate: " << txrate << ", " << (duplexMode ? "duplex" : "half-duplex") << endl;
00284 #if 0
00285     EV << "bitTime: " << bitTime << endl;
00286     EV << "carrierExtension: " << carrierExtension << endl;
00287     EV << "frameBursting: " << frameBursting << endl;
00288     EV << "slotTime: " << slotTime << endl;
00289     EV << "interFrameGap: " << interFrameGap << endl;
00290     EV << endl;
00291 #endif
00292 }
00293 
00294 void AnsaEtherMACBase::processFrameFromUpperLayer(EtherFrame *frame)
00295 {
00296     EV << "Received frame from upper layer: " << frame << endl;
00297 
00298     if (frame->getDest().equals(address))
00299     {
00300         error("logic error: frame %s from higher layer has local MAC address as dest (%s)",
00301               frame->getFullName(), frame->getDest().str().c_str());
00302     }
00303 
00304     if (frame->getByteLength() > MAX_ETHERNET_FRAME)
00305         error("packet from higher layer (%d bytes) exceeds maximum Ethernet frame size (%d)", frame->getByteLength(), MAX_ETHERNET_FRAME);
00306 
00307     // must be EtherFrame (or EtherPauseFrame) from upper layer
00308     bool isPauseFrame = (dynamic_cast<EtherPauseFrame*>(frame)!=NULL);
00309     if (!isPauseFrame)
00310     {
00311         numFramesFromHL++;
00312 
00313         if (txQueueLimit && txQueue.length()>txQueueLimit)
00314             error("txQueue length exceeds %d -- this is probably due to "
00315                   "a bogus app model generating excessive traffic "
00316                   "(or if this is normal, increase txQueueLimit!)",
00317                   txQueueLimit);
00318 
00319         // fill in src address if not set
00320         if (frame->getSrc().isUnspecified())
00321             frame->setSrc(address);
00322 
00323         // store frame and possibly begin transmitting
00324         EV << "Packet " << frame << " arrived from higher layers, enqueueing\n";
00325         txQueue.insert(frame);
00326     }
00327     else
00328     {
00329         EV << "PAUSE received from higher layer\n";
00330 
00331         // PAUSE frames enjoy priority -- they're transmitted before all other frames queued up
00332         if (!txQueue.empty())
00333             txQueue.insertBefore(txQueue.front(), frame);  // front() frame is probably being transmitted
00334         else
00335             txQueue.insert(frame);
00336     }
00337 
00338 }
00339 
00340 void AnsaEtherMACBase::processMsgFromNetwork(cPacket *frame)
00341 {
00342     EV << "Received frame from network: " << frame << endl;
00343 
00344     // frame must be EtherFrame or EtherJam
00345     if (dynamic_cast<EtherFrame*>(frame)==NULL && dynamic_cast<EtherJam*>(frame)==NULL)
00346         error("message with unexpected message class '%s' arrived from network (name='%s')",
00347                         frame->getClassName(), frame->getFullName());
00348 
00349     // detect cable length violation in half-duplex mode
00350     if (!duplexMode && simTime()-frame->getSendingTime()>=shortestFrameDuration)
00351         error("very long frame propagation time detected, maybe cable exceeds maximum allowed length? "
00352               "(%lgs corresponds to an approx. %lgm cable)",
00353               SIMTIME_STR(simTime() - frame->getSendingTime()),
00354               SIMTIME_STR((simTime() - frame->getSendingTime())*SPEED_OF_LIGHT));
00355 }
00356 
00357 void AnsaEtherMACBase::frameReceptionComplete(EtherFrame *frame)
00358 {
00359     int pauseUnits;
00360     EtherPauseFrame *pauseFrame;
00361 
00362     if ((pauseFrame=dynamic_cast<EtherPauseFrame*>(frame))!=NULL)
00363     {
00364         pauseUnits = pauseFrame->getPauseTime();
00365         delete frame;
00366         numPauseFramesRcvd++;
00367         numPauseFramesRcvdVector.record(numPauseFramesRcvd);
00368         processPauseCommand(pauseUnits);
00369     }
00370     else
00371     {
00372         processReceivedDataFrame((EtherFrame *)frame);
00373     }
00374 }
00375 
00376 void AnsaEtherMACBase::processReceivedDataFrame(EtherFrame *frame)
00377 {
00378     // bit errors
00379     if (frame->hasBitError())
00380     {
00381         numDroppedBitError++;
00382         numDroppedBitErrorVector.record(numDroppedBitError);
00383         delete frame;
00384         return;
00385     }
00386 
00387     // strip preamble and SFD
00388     frame->addByteLength(-PREAMBLE_BYTES-SFD_BYTES);
00389 
00390     // statistics
00391     numFramesReceivedOK++;
00392     numBytesReceivedOK += frame->getByteLength();
00393     numFramesReceivedOKVector.record(numFramesReceivedOK);
00394     numBytesReceivedOKVector.record(numBytesReceivedOK);
00395 
00396     if (!checkDestinationAddress(frame))
00397         return;
00398 
00399     numFramesPassedToHL++;
00400     numFramesPassedToHLVector.record(numFramesPassedToHL);
00401 
00402     // pass up to upper layer
00403     send(frame, "upperLayerOut");
00404 }
00405 
00406 void AnsaEtherMACBase::processPauseCommand(int pauseUnits)
00407 {
00408     if (transmitState==TX_IDLE_STATE)
00409     {
00410         EV << "PAUSE frame received, pausing for " << pauseUnitsRequested << " time units\n";
00411         if (pauseUnits>0)
00412             scheduleEndPausePeriod(pauseUnits);
00413     }
00414     else if (transmitState==PAUSE_STATE)
00415     {
00416         EV << "PAUSE frame received, pausing for " << pauseUnitsRequested << " more time units from now\n";
00417         cancelEvent(endPauseMsg);
00418         if (pauseUnits>0)
00419             scheduleEndPausePeriod(pauseUnits);
00420     }
00421     else
00422     {
00423         // transmitter busy -- wait until it finishes with current frame (endTx)
00424         // and then it'll go to PAUSE state
00425         EV << "PAUSE frame received, storing pause request\n";
00426         pauseUnitsRequested = pauseUnits;
00427     }
00428 }
00429 
00430 void AnsaEtherMACBase::handleEndIFGPeriod()
00431 {
00432     if (transmitState!=WAIT_IFG_STATE)
00433         error("Not in WAIT_IFG_STATE at the end of IFG period");
00434 
00435     if (txQueue.empty())
00436         error("End of IFG and no frame to transmit");
00437 
00438     // End of IFG period, okay to transmit, if Rx idle OR duplexMode
00439     cPacket *frame = (cPacket *)txQueue.front();
00440     EV << "IFG elapsed, now begin transmission of frame " << frame << endl;
00441 
00442     // Perform carrier extension if in Gigabit Ethernet
00443     if (carrierExtension && frame->getByteLength() < GIGABIT_MIN_FRAME_WITH_EXT)
00444     {
00445         EV << "Performing carrier extension of small frame\n";
00446         frame->setByteLength(GIGABIT_MIN_FRAME_WITH_EXT);
00447     }
00448 
00449     // start frame burst, if enabled
00450     if (frameBursting)
00451     {
00452         EV << "Starting frame burst\n";
00453         framesSentInBurst = 0;
00454         bytesSentInBurst = 0;
00455     }
00456 }
00457 
00458 void AnsaEtherMACBase::handleEndTxPeriod()
00459 {
00460     // we only get here if transmission has finished successfully, without collision
00461     if (transmitState!=TRANSMITTING_STATE || (!duplexMode && receiveState!=RX_IDLE_STATE))
00462         error("End of transmission, and incorrect state detected");
00463 
00464     if (txQueue.empty())
00465         error("Frame under transmission cannot be found");
00466 
00467     // get frame from buffer
00468     cPacket *frame = (cPacket *)txQueue.pop();
00469 
00470     numFramesSent++;
00471     numBytesSent += frame->getByteLength();
00472     numFramesSentVector.record(numFramesSent);
00473     numBytesSentVector.record(numBytesSent);
00474 
00475     if (dynamic_cast<EtherPauseFrame*>(frame)!=NULL)
00476     {
00477         numPauseFramesSent++;
00478         numPauseFramesSentVector.record(numPauseFramesSent);
00479     }
00480 
00481     EV << "Transmission of " << frame << " successfully completed\n";
00482     delete frame;
00483 }
00484 
00485 void AnsaEtherMACBase::handleEndPausePeriod()
00486 {
00487     if (transmitState != PAUSE_STATE)
00488         error("At end of PAUSE not in PAUSE_STATE!");
00489     EV << "Pause finished, resuming transmissions\n";
00490     beginSendFrames();
00491 }
00492 
00493 void AnsaEtherMACBase::processMessageWhenNotConnected(cMessage *msg)
00494 {
00495     EV << "Interface is not connected -- dropping packet " << msg << endl;
00496     delete msg;
00497     numDroppedIfaceDown++;
00498 }
00499 
00500 void AnsaEtherMACBase::processMessageWhenDisabled(cMessage *msg)
00501 {
00502     EV << "MAC is disabled -- dropping message " << msg << endl;
00503     delete msg;
00504 }
00505 
00506 void AnsaEtherMACBase::scheduleEndIFGPeriod()
00507 {
00508     scheduleAt(simTime()+interFrameGap, endIFGMsg);
00509     transmitState = WAIT_IFG_STATE;
00510 }
00511 
00512 void AnsaEtherMACBase::scheduleEndTxPeriod(cPacket *frame)
00513 {
00514     scheduleAt(simTime()+frame->getBitLength()*bitTime, endTxMsg);
00515     transmitState = TRANSMITTING_STATE;
00516 }
00517 
00518 void AnsaEtherMACBase::scheduleEndPausePeriod(int pauseUnits)
00519 {
00520     // length is interpreted as 512-bit-time units
00521     simtime_t pausePeriod = pauseUnits*PAUSE_BITTIME*bitTime;
00522     scheduleAt(simTime()+pausePeriod, endPauseMsg);
00523     transmitState = PAUSE_STATE;
00524 }
00525 
00526 bool AnsaEtherMACBase::checkAndScheduleEndPausePeriod()
00527 {
00528     if (pauseUnitsRequested>0)
00529     {
00530         // if we received a PAUSE frame recently, go into PAUSE state
00531         EV << "Going to PAUSE mode for " << pauseUnitsRequested << " time units\n";
00532 
00533         scheduleEndPausePeriod(pauseUnitsRequested);
00534         pauseUnitsRequested = 0;
00535         return true;
00536     }
00537 
00538     return false;
00539 }
00540 
00541 void AnsaEtherMACBase::beginSendFrames()
00542 {
00543     if (!txQueue.empty())
00544     {
00545         // Other frames are queued, therefore wait IFG period and transmit next frame
00546         EV << "Transmit next frame in output queue, after IFG period\n";
00547         scheduleEndIFGPeriod();
00548     }
00549     else
00550     {
00551         transmitState = TX_IDLE_STATE;
00552         if (queueModule)
00553         {
00554             // tell queue module that we've become idle
00555             EV << "Requesting another frame from queue module\n";
00556             queueModule->requestPacket();
00557         }
00558         else
00559         {
00560             // No more frames set transmitter to idle
00561             EV << "No more frames to send, transmitter set to idle\n";
00562         }
00563     }
00564 }
00565 
00566 void AnsaEtherMACBase::fireChangeNotification(int type, cPacket *msg)
00567 {
00568     if (nb) {
00569         notifDetails.setPacket(msg);
00570         nb->fireChangeNotification(type, &notifDetails);
00571     }
00572 }
00573 
00574 void AnsaEtherMACBase::finish()
00575 {
00576     if (!disabled)
00577     {
00578         simtime_t t = simTime();
00579         recordScalar("simulated time", t);
00580         recordScalar("txrate (Mb)", txrate/1000000);
00581         recordScalar("full duplex", duplexMode);
00582         recordScalar("frames sent",    numFramesSent);
00583         recordScalar("frames rcvd",    numFramesReceivedOK);
00584         recordScalar("bytes sent",     numBytesSent);
00585         recordScalar("bytes rcvd",     numBytesReceivedOK);
00586         recordScalar("frames from higher layer", numFramesFromHL);
00587         recordScalar("frames from higher layer dropped (iface down)", numDroppedIfaceDown);
00588         recordScalar("frames dropped (bit error)",  numDroppedBitError);
00589         recordScalar("frames dropped (not for us)", numDroppedNotForUs);
00590         recordScalar("frames passed up to HL", numFramesPassedToHL);
00591         recordScalar("PAUSE frames sent",  numPauseFramesSent);
00592         recordScalar("PAUSE frames rcvd",  numPauseFramesRcvd);
00593 
00594         if (t>0)
00595         {
00596             recordScalar("frames/sec sent", numFramesSent/t);
00597             recordScalar("frames/sec rcvd", numFramesReceivedOK/t);
00598             recordScalar("bits/sec sent",   8*numBytesSent/t);
00599             recordScalar("bits/sec rcvd",   8*numBytesReceivedOK/t);
00600         }
00601     }
00602 }
00603 
00604 void AnsaEtherMACBase::updateDisplayString()
00605 {
00606     // icon coloring
00607     const char *color;
00608     if (receiveState==RX_COLLISION_STATE)
00609         color = "red";
00610     else if (transmitState==TRANSMITTING_STATE)
00611         color = "yellow";
00612     else if (transmitState==JAMMING_STATE)
00613         color = "red";
00614     else if (receiveState==RECEIVING_STATE)
00615         color = "#4040ff";
00616     else if (transmitState==BACKOFF_STATE)
00617         color = "white";
00618     else if (transmitState==PAUSE_STATE)
00619         color = "gray";
00620     else
00621         color = "";
00622     getDisplayString().setTagArg("i",1,color);
00623     if (!strcmp(getParentModule()->getClassName(),"EthernetInterface"))
00624         getParentModule()->getDisplayString().setTagArg("i",1,color);
00625 
00626     // connection coloring
00627     updateConnectionColor(transmitState);
00628 
00629 #if 0
00630     // this code works but didn't turn out to be very useful
00631     const char *txStateName;
00632     switch (transmitState) {
00633         case TX_IDLE_STATE:      txStateName="IDLE"; break;
00634         case WAIT_IFG_STATE:     txStateName="WAIT_IFG"; break;
00635         case TRANSMITTING_STATE: txStateName="TX"; break;
00636         case JAMMING_STATE:      txStateName="JAM"; break;
00637         case BACKOFF_STATE:      txStateName="BACKOFF"; break;
00638         case PAUSE_STATE:        txStateName="PAUSE"; break;
00639         default: error("wrong tx state");
00640     }
00641     const char *rxStateName;
00642     switch (receiveState) {
00643         case RX_IDLE_STATE:      rxStateName="IDLE"; break;
00644         case RECEIVING_STATE:    rxStateName="RX"; break;
00645         case RX_COLLISION_STATE: rxStateName="COLL"; break;
00646         default: error("wrong rx state");
00647     }
00648 
00649     char buf[80];
00650     sprintf(buf, "tx:%s rx: %s\n#boff:%d #cTx:%d",
00651                  txStateName, rxStateName, backoffs, numConcurrentTransmissions);
00652     getDisplayString().setTagArg("t",0,buf);
00653 #endif
00654 }
00655 
00656 void AnsaEtherMACBase::updateConnectionColor(int txState)
00657 {
00658     const char *color;
00659     if (txState==TRANSMITTING_STATE)
00660         color = "yellow";
00661     else if (txState==JAMMING_STATE || txState==BACKOFF_STATE)
00662         color = "red";
00663     else
00664         color = "";
00665 
00666     cGate *g = physOutGate;
00667     while (g && g->getType()==cGate::OUTPUT)
00668     {
00669         g->getDisplayString().setTagArg("o",0,color);
00670         g->getDisplayString().setTagArg("o",1, color[0] ? "3" : "1");
00671         g = g->getNextGate();
00672     }
00673 }
00674 
00675 void AnsaEtherMACBase::receiveChangeNotification(int category, const cPolymorphic *details)
00676 {
00677     Enter_Method_Silent();
00678 
00679     if (category==NF_SUBSCRIBERLIST_CHANGED)
00680         updateHasSubcribers();
00681         
00682     if (category==NF_INTERFACE_STATE_CHANGED) // change state of notified interface
00683     {        
00684         InterfaceEntry *entry = check_and_cast<InterfaceEntry*>(details);
00685         
00686         if(interfaceEntry == entry && entry->isDown() != isDisabled())
00687         {
00688           setDisabled(entry->isDown());
00689           
00690           if(connected)
00691           {
00692            AnsaEtherMACBase *neighInt = dynamic_cast<AnsaEtherMACBase*>(physOutGate->getPathEndGate()->getOwnerModule());
00693            
00694            if((neighInt != NULL) && (neighInt->isDisabled() != isDisabled()))
00695            {
00696               InterfaceStateManager *stMng = check_and_cast<InterfaceStateManager*>(neighInt->getParentModule()->getParentModule()->getSubmodule("interfaceStateManager"));
00697               
00698               if(stMng != NULL)
00699               {
00700                 EV << "Changing state of the interface on the other site of link" << endl;
00701                 stMng->changeInterfaceState(neighInt->getInterfaceEntry(), isDisabled());
00702               }
00703            }
00704           }
00705         }
00706     }
00707 }
00708 
00709