Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

EtherMAC.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003 CTIE, Monash University
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 #ifdef _MSC_VER
00020 #pragma warning(disable:4786)
00021 #endif
00022 
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <omnetpp.h>
00026 
00027 #include "EtherMAC.h"
00028 #include "utils.h"
00029 #include "cmessage30.h"
00030 
00031 
00032 
00033 static cEnvir& operator<< (cEnvir& ev, cMessage *msg)
00034 {
00035     ev.printf("(%s)%s",msg->className(),msg->fullName());
00036     return ev;
00037 }
00038 
00039 
00040 #ifndef OPP3
00041 static cEnvir& operator<< (cEnvir& ev, const MACAddress& addr)
00042 {
00043     char buf[20];
00044     ev << addr.toHexString(buf);
00045     return ev;
00046 }
00047 #endif
00048 
00049 static std::ostream& operator<< (std::ostream& ev, const MACAddress& addr)
00050 {
00051     char buf[20];
00052     ev << addr.toHexString(buf);
00053     return ev;
00054 }
00055 
00056 
00057 Define_Module( EtherMAC );
00058 
00059 unsigned int EtherMAC::autoAddressCtr = 0;
00060 
00061 void EtherMAC::initialize()
00062 {
00063     outputbuffer.setName("outputBuffer");
00064 
00065     frameBeingReceived = NULL;
00066     endTxMsg = new cMessage("EndTransmission", ENDTRANSMISSION);
00067     endJammingMsg = new cMessage("EndJamming", ENDJAMMING);
00068     endRxMsg = new cMessage("EndReception", ENDRECEPTION);
00069     endIFGMsg = new cMessage("EndIFG", ENDIFG);
00070     endBackoffMsg = new cMessage("EndBackoff", ENDBACKOFF);
00071     endPauseMsg = new cMessage("EndPause", ENDPAUSE);
00072 
00073     const char *addrstr = par("address");
00074     if (!strcmp(addrstr,"auto"))
00075     {
00076         // assign automatic address
00077         ++autoAddressCtr;
00078         unsigned char addrbytes[6];
00079         addrbytes[0] = 0x0A;
00080         addrbytes[1] = 0xAA;
00081         addrbytes[2] = (autoAddressCtr>>24)&0xff;
00082         addrbytes[3] = (autoAddressCtr>>16)&0xff;
00083         addrbytes[4] = (autoAddressCtr>>8)&0xff;
00084         addrbytes[5] = (autoAddressCtr)&0xff;
00085         myaddress.setAddressBytes(addrbytes);
00086 
00087         // change module parameter from "auto" to concrete address
00088         char buf[20];
00089         par("address").setStringValue(myaddress.toHexString(buf));
00090     }
00091     else
00092     {
00093         myaddress.setAddress(addrstr);
00094     }
00095     promiscuous = par("promiscuous");
00096     maxQueueSize = par("maxQueueSize");
00097 
00098     disabled = !gate("physicalOut")->destinationGate()->isConnected();
00099     if (disabled)
00100         EV << "MAC not connected to a network, disabling.\n";
00101     // Note: it is currently not supported to enable a disabled MAC at runtime.
00102     // Difficulties: (1) autoconfig (2) how to pick up channel state (free, tx, collision etc)
00103     WATCH(disabled);
00104 
00105     // launch autoconfig process
00106     bool performAutoconfig = true;
00107     if (!disabled && performAutoconfig)
00108     {
00109         startAutoconfig();
00110     }
00111     else
00112     {
00113         autoconfigInProgress = false;
00114         txrate = par("txrate");
00115         duplexMode = par("duplexEnabled");
00116         calculateParameters();
00117     }
00118     WATCH(autoconfigInProgress);
00119 
00120     // initialize state info
00121     transmitState = TX_IDLE_STATE;
00122     receiveState = RX_IDLE_STATE;
00123     backoffs = 0;
00124     numConcurrentTransmissions = 0;
00125     framesSentInBurst = 0;
00126     bytesSentInBurst = 0;
00127     pauseUnitsRequested = 0;
00128 
00129     WATCH(transmitState);
00130     WATCH(receiveState);
00131     WATCH(backoffs);
00132     WATCH(numConcurrentTransmissions);
00133     WATCH(framesSentInBurst);
00134     WATCH(bytesSentInBurst);
00135     WATCH(pauseUnitsRequested);
00136 
00137     // init statistics
00138     totalCollisionTime = 0.0;
00139     totalSuccessfulRxTxTime = 0.0;
00140     numFramesSent = numFramesReceivedOK = numBytesSent = numBytesReceivedOK = 0;
00141     numFramesPassedToHL = numDroppedBitError = numDroppedNotForUs = 0;
00142     numFramesFromHL = numFramesFromHLDropped = 0;
00143     numPauseFramesRcvd = numPauseFramesSent = numCollisions = numBackoffs = 0;
00144 
00145     WATCH(numFramesSent);
00146     WATCH(numFramesReceivedOK);
00147     WATCH(numBytesSent);
00148     WATCH(numBytesReceivedOK);
00149     WATCH(numFramesFromHL);
00150     WATCH(numFramesFromHLDropped);
00151     WATCH(numDroppedBitError);
00152     WATCH(numDroppedNotForUs);
00153     WATCH(numFramesPassedToHL);
00154     WATCH(numPauseFramesRcvd);
00155     WATCH(numPauseFramesSent);
00156     WATCH(numCollisions);
00157     WATCH(numBackoffs);
00158 
00159     numFramesSentVector.setName("framesSent");
00160     numFramesReceivedOKVector.setName("framesReceivedOK");
00161     numBytesSentVector.setName("bytesSent");
00162     numBytesReceivedOKVector.setName("bytesReceivedOK");
00163     numFramesFromHLDroppedVector.setName("framesFromHLDropped");
00164     numDroppedBitErrorVector.setName("framesDroppedBitError");
00165     numDroppedNotForUsVector.setName("framesDroppedNotForUs");
00166     numFramesPassedToHLVector.setName("framesPassedToHL");
00167     numPauseFramesRcvdVector.setName("pauseFramesRcvd");
00168     numPauseFramesSentVector.setName("pauseFramesSent");
00169     numCollisionsVector.setName("collisions");
00170     numBackoffsVector.setName("backoffs");
00171 }
00172 
00173 void EtherMAC::printParameters()
00174 {
00175     // Dump parameters
00176     EV << "MAC address: " << myaddress << (promiscuous ? ", promiscuous mode" : "") << endl;
00177     EV << "txrate: " << txrate << ", " << (duplexMode ? "duplex" : "half-duplex") << endl;
00178 #if 0
00179     EV << "bitTime: " << bitTime << endl;
00180     EV << "carrierExtension: " << carrierExtension << endl;
00181     EV << "frameBursting: " << frameBursting << endl;
00182     EV << "slotTime: " << slotTime << endl;
00183     EV << "interFrameGap: " << interFrameGap << endl;
00184     EV << "\n";
00185 #endif
00186 }
00187 
00188 void EtherMAC::calculateParameters()
00189 {
00190     if (disabled)
00191     {
00192         bitTime = slotTime = interFrameGap = jamDuration = shortestFrameDuration = 0;
00193         carrierExtension = frameBursting = false;
00194         return;
00195     }
00196 
00197     // calculate other parameters from txrate and duplexMode
00198     if (txrate!=ETHERNET_TXRATE && txrate!=FAST_ETHERNET_TXRATE && txrate!=GIGABIT_ETHERNET_TXRATE)
00199     {
00200         error("nonstandard txrate, must be %ld, %ld or %ld bit/sec", ETHERNET_TXRATE,
00201               FAST_ETHERNET_TXRATE, GIGABIT_ETHERNET_TXRATE);
00202     }
00203     bitTime = 1/(double)txrate;
00204 
00205     // Only if Gigabit Ethernet
00206     carrierExtension = (txrate==GIGABIT_ETHERNET_TXRATE && !duplexMode);
00207     frameBursting = (txrate==GIGABIT_ETHERNET_TXRATE);
00208 
00209     // set slot time
00210     if (txrate==ETHERNET_TXRATE || txrate==FAST_ETHERNET_TXRATE)
00211         slotTime = SLOT_TIME;
00212     else
00213         slotTime = GIGABIT_SLOT_TIME;
00214 
00215     interFrameGap = INTERFRAME_GAP_BITS/(double)txrate;
00216     jamDuration = 8*JAM_SIGNAL_BYTES*bitTime;
00217     shortestFrameDuration = carrierExtension ? GIGABIT_MIN_FRAME_WITH_EXT : MIN_ETHERNET_FRAME;
00218 }
00219 
00220 void EtherMAC::startAutoconfig()
00221 {
00222     autoconfigInProgress = true;
00223     lowestTxrateSuggested = 0;  // none suggested
00224     duplexVetoed = false;
00225 
00226     double initialTxrate = par("txrate");
00227     bool duplexEnabled = par("duplexEnabled");
00228     txrate = 0;
00229     duplexMode = duplexEnabled;
00230     if (!duplexEnabled || initialTxrate>0)
00231     {
00232         EV << "Autoconfig: advertising our settings: " << initialTxrate/1000000 << "Mb, "
00233            << (duplexMode ? "duplex" : "half-duplex") << endl;
00234 
00235         EtherAutoconfig *autoconf = new EtherAutoconfig("autoconf");
00236         if (!duplexEnabled)
00237             autoconf->setHalfDuplex(true);
00238         if (initialTxrate>0)
00239             autoconf->setTxrate(initialTxrate);
00240         send(autoconf, "physicalOut");
00241     }
00242     scheduleAt(simTime()+AUTOCONFIG_PERIOD, new cMessage("EndAutoconfig",ENDAUTOCONFIG));
00243 }
00244 
00245 void EtherMAC::handleAutoconfigMessage(cMessage *msg)
00246 {
00247     if (!msg->isSelfMessage())
00248     {
00249         if (msg->arrivalGate() == gate("upperLayerIn"))
00250         {
00251             // from upper layer
00252             EV << "Received frame from upper layer during autoconfig period: " << msg << endl;
00253             processFrameFromUpperLayer(check_and_cast<EtherFrame *>(msg));
00254         }
00255         else
00256         {
00257             // from network: must be autoconfig message
00258             EV << "Message from network during autoconfig period: " << msg << endl;
00259             EtherAutoconfig *autoconf = check_and_cast<EtherAutoconfig *>(msg);
00260             double acTxrate = autoconf->getTxrate();
00261 
00262             EV << "Autoconfig message: ";
00263             if (acTxrate>0)
00264                 EV << acTxrate/1000000 << "Mb ";
00265             if (autoconf->getHalfDuplex())
00266                 EV << "non-duplex";
00267             EV << "\n";
00268 
00269             if (acTxrate>0 && (acTxrate<lowestTxrateSuggested || lowestTxrateSuggested==0))
00270                 lowestTxrateSuggested = acTxrate;
00271             if (!duplexVetoed && autoconf->getHalfDuplex())
00272                 duplexVetoed = true;
00273             delete msg;
00274         }
00275     }
00276     else
00277     {
00278         // self-message signals end of autoconfig period
00279         EV << "Self-message during autoconfig period: " << msg << endl;
00280 
00281         delete msg;
00282         autoconfigInProgress = false;
00283 
00284         double initialTxrate = par("txrate");
00285         bool duplexEnabled = par("duplexEnabled");
00286 
00287         txrate = (initialTxrate==0 && lowestTxrateSuggested==0) ? 100000000 /* 100 Mb */:
00288                  (initialTxrate==0) ? lowestTxrateSuggested :
00289                  (lowestTxrateSuggested==0) ? initialTxrate :
00290                  (lowestTxrateSuggested<initialTxrate) ? lowestTxrateSuggested : initialTxrate;
00291         duplexMode = (duplexEnabled && !duplexVetoed);
00292         calculateParameters();
00293 
00294         EV << "Parameters after autoconfig: txrate=" << txrate/1000000 << "Mb, " << (duplexMode ? "duplex" : "half-duplex") << endl;
00295 
00296 #ifdef OPP3
00297         if (ev.isGUI())
00298         {
00299             char modestr[64];
00300             sprintf(modestr, "%dMb\n%s", int(txrate/1000000), (duplexMode ? "full duplex" : "half duplex"));
00301             displayString().setTagArg("t",0,modestr);
00302             displayString().setTagArg("t",1,"r");
00303             sprintf(modestr, "%s: %dMb %s", fullName(), int(txrate/1000000), (duplexMode ? "duplex" : "half duplex"));
00304             parentModule()->bubble(modestr);
00305         }
00306 #endif
00307 
00308         if (!outputbuffer.empty())
00309         {
00310             EV << "Autoconfig period over, starting to send frames\n";
00311             scheduleEndIFGPeriod();
00312         }
00313     }
00314 }
00315 
00316 void EtherMAC::handleMessage (cMessage *msg)
00317 {
00318     if (disabled)
00319     {
00320         EV << "MAC is disabled -- dropping message " << msg << "\n";
00321         delete msg;
00322         return;
00323     }
00324     if (autoconfigInProgress)
00325     {
00326         handleAutoconfigMessage(msg);
00327         return;
00328     }
00329 
00330     printState();
00331     // some consistency check
00332     if (!duplexMode && transmitState==TRANSMITTING_STATE && receiveState!=RX_IDLE_STATE)
00333         error("Inconsistent state -- transmitting and receiving at the same time");
00334 
00335     if (!msg->isSelfMessage())
00336     {
00337         // either frame from upper layer, or frame/jam signal from the network
00338         if (msg->arrivalGate() == gate("upperLayerIn"))
00339         {
00340             EV << "Received frame from upper layer: " << msg << endl;
00341             processFrameFromUpperLayer(check_and_cast<EtherFrame *>(msg));
00342         }
00343         else
00344         {
00345             EV << "Received frame from network: " << msg << endl;
00346             processMsgFromNetwork(msg);
00347         }
00348     }
00349     else
00350     {
00351         // Process different self-messages (timer signals)
00352         EV << "Self-message " << msg << " received\n";
00353         switch (msg->kind())
00354         {
00355             case ENDIFG:
00356                 handleEndIFGPeriod();
00357                 break;
00358 
00359             case ENDTRANSMISSION:
00360                 handleEndTxPeriod();
00361                 break;
00362 
00363             case ENDRECEPTION:
00364                 handleEndRxPeriod();
00365                 break;
00366 
00367             case ENDBACKOFF:
00368                 handleEndBackoffPeriod();
00369                 break;
00370 
00371             case ENDJAMMING:
00372                 handleEndJammingPeriod();
00373                 break;
00374 
00375             case ENDPAUSE:
00376                 handleEndPausePeriod();
00377                 break;
00378 
00379             default:
00380                 error("self-message with unexpected message kind %d", msg->kind());
00381         }
00382     }
00383     printState();
00384 }
00385 
00386 
00387 void EtherMAC::processFrameFromUpperLayer(EtherFrame *frame)
00388 {
00389     // note: this method may be called durig autoconfig period too, but we really
00390     // shouldn't start transmission at that time, only queue up the frame.
00391 
00392     // check message kind
00393     if (frame->kind()!=ETH_FRAME && frame->kind()!=ETH_PAUSE)
00394         error("message with unexpected message kind %d arrived from higher layer", frame->kind());
00395 
00396     // pause frames must be EtherPauseFrame AND kind==ETH_PAUSE
00397     ASSERT((frame->kind()==ETH_PAUSE) == (dynamic_cast<EtherPauseFrame *>(frame)!=NULL));
00398 
00399     if (frame->getDest().equals(myaddress))
00400     {
00401         char buf[20];
00402         error("logic error: frame %s from higher layer has local MAC address as dest (%s)",
00403               frame->fullName(), frame->getDest().toHexString(buf));
00404     }
00405 
00406     if (frame->length()>8*MAX_ETHERNET_FRAME)
00407         error("packet from higher layer (%d bytes) exceeds maximum Ethernet frame size (%d)", frame->length()/8, MAX_ETHERNET_FRAME);
00408 
00409     // must be ETH_FRAME (or ETH_PAUSE) from upper layer
00410     bool isPauseFrame = (frame->kind()==ETH_PAUSE);
00411     if (!isPauseFrame)
00412     {
00413         numFramesFromHL++;
00414 
00415         if (outputbuffer.length()>=maxQueueSize)
00416         {
00417             EV << "Packet " << frame << " arrived from higher layers but queue full, dropping\n";
00418             numFramesFromHLDropped++;
00419             numFramesFromHLDroppedVector.record(numFramesFromHLDropped);
00420             delete frame;
00421             return;
00422         }
00423 
00424         // fill in src address if not set
00425         if (frame->getSrc().isEmpty())
00426             frame->setSrc(myaddress);
00427 
00428         // store frame and possibly begin transmitting
00429         EV << "Packet " << frame << " arrived from higher layers, enqueueing\n";
00430         outputbuffer.insert(frame);
00431     }
00432     else
00433     {
00434         EV << "PAUSE received from higher layer\n";
00435 
00436         // PAUSE frames enjoy priority -- they're transmitted before all other frames queued up
00437         if (!outputbuffer.empty())
00438             outputbuffer.insertBefore(outputbuffer.tail(), frame);  // tail() frame is probably being transmitted
00439         else
00440             outputbuffer.insert(frame);
00441     }
00442 
00443     if (!autoconfigInProgress && (duplexMode || receiveState==RX_IDLE_STATE) && transmitState==TX_IDLE_STATE)
00444     {
00445         EV << "No incoming carrier signals detected, frame clear to send, wait IFG first\n";
00446         scheduleEndIFGPeriod();
00447     }
00448 }
00449 
00450 
00451 void EtherMAC::processMsgFromNetwork(cMessage *msg)
00452 {
00453     // msg must be ETH_FRAME, ETH_PAUSE or JAM_SIGNAL
00454     if (msg->kind()!=ETH_FRAME && msg->kind()!=ETH_PAUSE && msg->kind()!=JAM_SIGNAL)
00455         error("message with unexpected message kind %d arrived from network", msg->kind());
00456 
00457     // detect cable length violation in half-duplex mode
00458     if (!duplexMode && simTime()-msg->sendingTime()>=shortestFrameDuration)
00459         error("very long frame propagation time detected, maybe cable exceeds maximum allowed length? "
00460               "(%lgs corresponds to an approx. %lgm cable)",
00461               simTime()-msg->sendingTime(),
00462               (simTime()-msg->sendingTime())*200000000.0);
00463 
00464     simtime_t endRxTime = simTime() + msg->length()*bitTime;
00465 
00466     if (!duplexMode && transmitState==TRANSMITTING_STATE)
00467     {
00468         // since we're halfduplex, receiveState must be RX_IDLE_STATE (asserted at top of handleMessage)
00469         if (msg->kind()==JAM_SIGNAL)
00470             error("Stray jam signal arrived while transmitting (usual cause is cable length exceeding allowed maximum)");
00471 
00472         EV << "Transmission interrupted by incoming frame, handling collision\n";
00473         cancelEvent(endTxMsg);
00474 
00475         EV << "Transmitting jam signal\n";
00476         sendJamSignal(); // backoff will be executed when jamming finished
00477 
00478         // set receive state and schedule end of reception
00479         receiveState = RX_COLLISION_STATE;
00480         numConcurrentTransmissions++;
00481         simtime_t endJamTime = simTime()+jamDuration;
00482         scheduleAt(endRxTime<endJamTime ? endJamTime : endRxTime, endRxMsg);
00483         delete msg;
00484 
00485         numCollisions++;
00486         numCollisionsVector.record(numCollisions);
00487     }
00488     else if (receiveState==RX_IDLE_STATE)
00489     {
00490         if (msg->kind()==JAM_SIGNAL)
00491             error("Stray jam signal arrived (usual cause is cable length exceeding allowed maximum)");
00492 
00493         EV << "Start reception of frame\n";
00494         numConcurrentTransmissions++;
00495         if (frameBeingReceived)
00496             error("frameBeingReceived!=0 in RX_IDLE_STATE");
00497         frameBeingReceived = (EtherFrame *)msg;
00498         scheduleEndRxPeriod(msg);
00499         channelBusySince = simTime();
00500     }
00501     else if (receiveState==RECEIVING_STATE && msg->kind()!=JAM_SIGNAL && endRxMsg->arrivalTime()-simTime()<bitTime)
00502     {
00503         // With the above condition we filter out "false" collisions that may occur with
00504         // back-to-back frames. That is: when "beginning of frame" message (this one) occurs
00505         // BEFORE "end of previous frame" event (endRxMsg) -- same simulation time,
00506         // only wrong order.
00507 
00508         EV << "Back-to-back frames: completing reception of current frame, starting reception of next one\n";
00509 
00510         // complete reception of previous frame
00511         cancelEvent(endRxMsg);
00512         EtherFrame *frame = frameBeingReceived;
00513         frameBeingReceived = NULL;
00514         frameReceptionComplete(frame);
00515 
00516         // start receiving next frame
00517         frameBeingReceived = (EtherFrame *)msg;
00518         scheduleEndRxPeriod(msg);
00519     }
00520     else // (receiveState==RECEIVING_STATE || receiveState==RX_COLLISION_STATE)
00521     {
00522         // handle overlapping receptions
00523         if (msg->kind()==JAM_SIGNAL)
00524         {
00525             if (numConcurrentTransmissions<=0)
00526                 error("numConcurrentTransmissions=%d on jam arrival (stray jam?)",numConcurrentTransmissions);
00527 
00528             numConcurrentTransmissions--;
00529             EV << "Jam signal received, this marks end of one transmission\n";
00530 
00531             // by the time jamming ends, all transmissions will have been aborted
00532             if (numConcurrentTransmissions==0)
00533             {
00534                 EV << "Last jam signal received, collision will ends when jam ends\n";
00535                 cancelEvent(endRxMsg);
00536                 scheduleAt(endRxTime, endRxMsg);
00537             }
00538         }
00539         else // ETH_FRAME or ETH_PAUSE
00540         {
00541             numConcurrentTransmissions++;
00542             if (endRxMsg->arrivalTime() < endRxTime)
00543             {
00544                 // otherwise just wait until the end of the longest transmission
00545                 EV << "Overlapping receptions -- setting collision state and extending collision period\n";
00546                 cancelEvent(endRxMsg);
00547                 scheduleAt(endRxTime, endRxMsg);
00548             }
00549             else
00550             {
00551                 EV << "Overlapping receptions -- setting collision state\n";
00552             }
00553         }
00554 
00555         // delete collided frames: arrived frame as well as the one we're currently receiving
00556         delete msg;
00557         if (receiveState==RECEIVING_STATE)
00558         {
00559             delete frameBeingReceived;
00560             frameBeingReceived = NULL;
00561 
00562             numCollisions++;
00563             numCollisionsVector.record(numCollisions);
00564         }
00565 
00566         // go to collision state
00567         receiveState = RX_COLLISION_STATE;
00568     }
00569 }
00570 
00571 
00572 void EtherMAC::handleEndIFGPeriod()
00573 {
00574     if (transmitState!=WAIT_IFG_STATE)
00575         error("Not in WAIT_IFG_STATE at the end of IFG period");
00576 
00577     if (outputbuffer.empty())
00578         error("End of IFG and no frame to transmit");
00579 
00580     // End of IFG period, okay to transmit, if Rx idle OR duplexMode
00581     cMessage *frame = (cMessage *)outputbuffer.tail();
00582     EV << "IFG elapsed, now begin transmission of frame " << frame << endl;
00583 
00584     // Perform carrier extension if in Gigabit Ethernet
00585     if (carrierExtension && frame->length() < 8*GIGABIT_MIN_FRAME_WITH_EXT)
00586     {
00587         EV << "Performing carrier extension of small frame\n";
00588         frame->setLength(8*GIGABIT_MIN_FRAME_WITH_EXT);
00589     }
00590 
00591     // start frame burst, if enabled
00592     if (frameBursting)
00593     {
00594         EV << "Starting frame burst\n";
00595         framesSentInBurst = 0;
00596         bytesSentInBurst = 0;
00597     }
00598 
00599     // send frame to network
00600     startFrameTransmission();
00601 }
00602 
00603 void EtherMAC::startFrameTransmission()
00604 {
00605     cMessage *origFrame = (cMessage *)outputbuffer.tail();
00606     EV << "Transmitting a copy of frame " << origFrame << endl;
00607     cMessage *frame = (cMessage *) origFrame->dup();
00608 
00609     // add preamble and SFD (Starting Frame Delimiter), then send out
00610     frame->setLength(frame->length()+8*PREAMBLE_BYTES+8*SFD_BYTES);
00611     send(frame, "physicalOut");
00612 
00613     // update burst variables
00614     if (frameBursting)
00615     {
00616         bytesSentInBurst = frame->length()/8;
00617         framesSentInBurst++;
00618     }
00619 
00620     // check for collisions (there might be an ongoing reception which we don't know about, see below)
00621     if (!duplexMode && receiveState!=RX_IDLE_STATE)
00622     {
00623         // During the IFG period the hardware cannot listen to the channel,
00624         // so it might happen that receptions have begun during the IFG,
00625         // and even collisions might be in progress.
00626         //
00627         // But we don't know of any ongoing transmission so we blindly
00628         // start transmitting, immediately collide and send a jam signal.
00629         //
00630         sendJamSignal();
00631         // numConcurrentTransmissions stays the same: +1 transmission, -1 jam
00632 
00633         if (receiveState==RECEIVING_STATE)
00634         {
00635             delete frameBeingReceived;
00636             frameBeingReceived = NULL;
00637 
00638             numCollisions++;
00639             numCollisionsVector.record(numCollisions);
00640         }
00641         // go to collision state
00642         receiveState = RX_COLLISION_STATE;
00643     }
00644     else
00645     {
00646         // no collision
00647         scheduleEndTxPeriod(frame);
00648 
00649         // only count transmissions in totalSuccessfulRxTxTime if channel is half-duplex
00650         if (!duplexMode)
00651             channelBusySince = simTime();
00652     }
00653 }
00654 
00655 void EtherMAC::handleEndTxPeriod()
00656 {
00657     // we only get here if transmission has finished successfully, without collision
00658     if (transmitState!=TRANSMITTING_STATE || (!duplexMode && receiveState!=RX_IDLE_STATE))
00659         error("End of transmission, and incorrect state detected");
00660 
00661     if (outputbuffer.empty())
00662         error("Frame under transmission cannot be found");
00663 
00664     // get frame from buffer
00665     cMessage *frame = (cMessage*)outputbuffer.pop();
00666 
00667     numFramesSent++;
00668     numBytesSent += frame->length()/8;
00669     numFramesSentVector.record(numFramesSent);
00670     numBytesSentVector.record(numBytesSent);
00671 
00672     if (frame->kind()==ETH_PAUSE)
00673     {
00674         numPauseFramesSent++;
00675         numPauseFramesSentVector.record(numPauseFramesSent);
00676     }
00677 
00678     // only count transmissions in totalSuccessfulRxTxTime if channel is half-duplex
00679     if (!duplexMode)
00680     {
00681         simtime_t dt = simTime()-channelBusySince;
00682         totalSuccessfulRxTxTime += dt;
00683     }
00684 
00685     EV << "Transmission of " << frame << " successfully completed\n";
00686     delete frame;
00687     backoffs = 0;
00688 
00689     // check for and obey received PAUSE frames after each transmission
00690     if (pauseUnitsRequested>0)
00691     {
00692         // if we received a PAUSE frame recently, go into PAUSE state
00693         EV << "Going to PAUSE mode for " << pauseUnitsRequested << " time units\n";
00694         scheduleEndPausePeriod(pauseUnitsRequested);
00695         pauseUnitsRequested = 0;
00696         return;
00697     }
00698 
00699     // Gigabit Ethernet: now decide if we transmit next frame right away (burst) or wait IFG
00700     // this is not entirely correct, there must be IFG between burst frames too
00701     bool burstFrame=false;
00702     if (frameBursting && !outputbuffer.empty())
00703     {
00704         // check if max bytes for burst not exceeded
00705         if (bytesSentInBurst<GIGABIT_MAX_BURST_BYTES)
00706         {
00707              burstFrame=true;
00708              EV << "Transmitting next frame in current burst\n";
00709         }
00710         else
00711         {
00712              EV << "Next frame does not fit in current burst\n";
00713         }
00714     }
00715 
00716     if (burstFrame)
00717         startFrameTransmission();
00718     else
00719         beginSendFrames();
00720 }
00721 
00722 void EtherMAC::handleEndRxPeriod()
00723 {
00724     EV << "Frame reception complete\n";
00725     simtime_t dt = simTime()-channelBusySince;
00726     if (receiveState==RECEIVING_STATE) // i.e. not RX_COLLISION_STATE
00727     {
00728         EtherFrame *frame = frameBeingReceived;
00729         frameBeingReceived = NULL;
00730         frameReceptionComplete(frame);
00731         totalSuccessfulRxTxTime += dt;
00732     }
00733     else
00734     {
00735         totalCollisionTime += dt;
00736     }
00737 
00738     receiveState = RX_IDLE_STATE;
00739     numConcurrentTransmissions = 0;
00740 
00741     if (transmitState==TX_IDLE_STATE && !outputbuffer.empty())
00742     {
00743         EV << "Receiver now idle, can transmit frames in output buffer after IFG period\n";
00744         scheduleEndIFGPeriod();
00745     }
00746 }
00747 
00748 void EtherMAC::handleEndBackoffPeriod()
00749 {
00750     if (transmitState != BACKOFF_STATE)
00751         error("At end of BACKOFF not in BACKOFF_STATE!");
00752     if (outputbuffer.empty())
00753         error("At end of BACKOFF and buffer empty!");
00754 
00755     if (receiveState==RX_IDLE_STATE)
00756     {
00757         EV << "Backoff period ended, wait IFG\n";
00758         scheduleEndIFGPeriod();
00759     }
00760     else
00761     {
00762         EV << "Backoff period ended but channel not free, idling\n";
00763         transmitState = TX_IDLE_STATE;
00764     }
00765 }
00766 
00767 void EtherMAC::handleEndJammingPeriod()
00768 {
00769     if (transmitState != JAMMING_STATE)
00770         error("At end of JAMMING not in JAMMING_STATE!");
00771     EV << "Jamming finished, executing backoff\n";
00772     handleRetransmission();
00773 }
00774 
00775 void EtherMAC::handleEndPausePeriod()
00776 {
00777     if (transmitState != PAUSE_STATE)
00778         error("At end of PAUSE not in PAUSE_STATE!");
00779     EV << "Pause finished, resuming transmissions\n";
00780     beginSendFrames();
00781 }
00782 
00783 void EtherMAC::sendJamSignal()
00784 {
00785     cMessage *jam = new cMessage("JAM_SIGNAL", JAM_SIGNAL);
00786     jam->setLength(8*JAM_SIGNAL_BYTES);
00787     send(jam, "physicalOut");
00788 
00789     scheduleAt(simTime()+jamDuration, endJammingMsg);
00790     transmitState = JAMMING_STATE;
00791 }
00792 
00793 void EtherMAC::scheduleEndIFGPeriod()
00794 {
00795     scheduleAt(simTime()+interFrameGap, endIFGMsg);
00796     transmitState = WAIT_IFG_STATE;
00797 }
00798 
00799 void EtherMAC::scheduleEndTxPeriod(cMessage *frame)
00800 {
00801     scheduleAt(simTime()+frame->length()*bitTime, endTxMsg);
00802     transmitState = TRANSMITTING_STATE;
00803 }
00804 
00805 void EtherMAC::scheduleEndRxPeriod(cMessage *frame)
00806 {
00807     scheduleAt(simTime()+frame->length()*bitTime, endRxMsg);
00808     receiveState = RECEIVING_STATE;
00809 }
00810 
00811 void EtherMAC::scheduleEndPausePeriod(int pauseUnits)
00812 {
00813     // length is interpreted as 512-bit-time units
00814     double pausePeriod = pauseUnits*PAUSE_BITTIME*bitTime;
00815     scheduleAt(simTime()+pausePeriod, endPauseMsg);
00816     transmitState = PAUSE_STATE;
00817 }
00818 
00819 void EtherMAC::frameReceptionComplete(EtherFrame *frame)
00820 {
00821     int pauseUnits;
00822 
00823     switch (frame->kind())
00824     {
00825       case ETH_FRAME:
00826         processReceivedDataFrame((EtherFrame *)frame);
00827         break;
00828 
00829       case ETH_PAUSE:
00830         pauseUnits = ((EtherPauseFrame *)frame)->getPauseTime();
00831         delete frame;
00832         numPauseFramesRcvd++;
00833         numPauseFramesRcvdVector.record(numPauseFramesRcvd);
00834         processPauseCommand(pauseUnits);
00835         break;
00836 
00837       default:
00838         error("Invalid message kind %d",frame->kind());
00839     }
00840 }
00841 
00842 void EtherMAC::processReceivedDataFrame(EtherFrame *frame)
00843 {
00844     // bit errors
00845     if (frame->hasBitError())
00846     {
00847         numDroppedBitError++;
00848         numDroppedBitErrorVector.record(numDroppedBitError);
00849         delete frame;
00850         return;
00851     }
00852 
00853     // strip preamble and SFD
00854     frame->setLength(frame->length() - 8*PREAMBLE_BYTES - 8*SFD_BYTES);
00855 
00856     // statistics
00857     numFramesReceivedOK++;
00858     numBytesReceivedOK += frame->length()/8;
00859     numFramesReceivedOKVector.record(numFramesReceivedOK);
00860     numBytesReceivedOKVector.record(numBytesReceivedOK);
00861 
00862     // If not set to promiscuous = on, then checks if received frame contains destination MAC address
00863     // matching port's MAC address, also checks if broadcast bit is set
00864     if (!promiscuous && !frame->getDest().isBroadcast() && !frame->getDest().equals(myaddress))
00865     {
00866         EV << "Frame `" << frame->name() <<"' not destined to us, discarding\n";
00867         numDroppedNotForUs++;
00868         numDroppedNotForUsVector.record(numDroppedNotForUs);
00869         delete frame;
00870         return;
00871     }
00872 
00873     numFramesPassedToHL++;
00874     numFramesPassedToHLVector.record(numFramesPassedToHL);
00875 
00876     // pass up to upper layer
00877     send(frame, "upperLayerOut");
00878 }
00879 
00880 void EtherMAC::processPauseCommand(int pauseUnits)
00881 {
00882     if (transmitState==TX_IDLE_STATE)
00883     {
00884         EV << "PAUSE frame received, pausing for " << pauseUnitsRequested << " time units\n";
00885         if (pauseUnits>0)
00886             scheduleEndPausePeriod(pauseUnits);
00887     }
00888     else if (transmitState==PAUSE_STATE)
00889     {
00890         EV << "PAUSE frame received, pausing for " << pauseUnitsRequested << " more time units from now\n";
00891         cancelEvent(endPauseMsg);
00892         if (pauseUnits>0)
00893             scheduleEndPausePeriod(pauseUnits);
00894     }
00895     else
00896     {
00897         // transmitter busy -- wait until it finishes with current frame (endTx)
00898         // and then it'll go to PAUSE state
00899         EV << "PAUSE frame received, storing pause request\n";
00900         pauseUnitsRequested = pauseUnits;
00901     }
00902 }
00903 
00904 void EtherMAC::handleRetransmission()
00905 {
00906     if (++backoffs > MAX_ATTEMPTS)
00907     {
00908         EV << "Number of retransmit attempts of frame exceeds maximum, cancelling transmission of frame\n";
00909         delete outputbuffer.pop();
00910 
00911         transmitState = TX_IDLE_STATE;
00912         backoffs = 0;
00913         // no beginSendFrames(), because end of jam signal sending will trigger it automatically
00914         return;
00915     }
00916 
00917     EV << "Executing backoff procedure\n";
00918     int backoffrange = (backoffs>=BACKOFF_RANGE_LIMIT) ? 1024 : (1 << backoffs);
00919     int slotNumber = intuniform(0,backoffrange-1);
00920     simtime_t backofftime = slotNumber*slotTime;
00921 
00922     scheduleAt(simTime()+backofftime, endBackoffMsg);
00923     transmitState = BACKOFF_STATE;
00924 
00925     numBackoffs++;
00926     numBackoffsVector.record(numBackoffs);
00927 }
00928 
00929 void EtherMAC::printState()
00930 {
00931 #define CASE(x) case x: EV << #x; break
00932     EV << "transmitState: ";
00933     switch (transmitState) {
00934         CASE(TX_IDLE_STATE);
00935         CASE(WAIT_IFG_STATE);
00936         CASE(TRANSMITTING_STATE);
00937         CASE(JAMMING_STATE);
00938         CASE(BACKOFF_STATE);
00939         CASE(PAUSE_STATE);
00940     }
00941     EV << ",  receiveState: ";
00942     switch (receiveState) {
00943         CASE(RX_IDLE_STATE);
00944         CASE(RECEIVING_STATE);
00945         CASE(RX_COLLISION_STATE);
00946     }
00947     EV << ",  backoffs: " << backoffs;
00948     EV << ",  numConcurrentTransmissions: " << numConcurrentTransmissions;
00949     EV << ",  queueLength: " << outputbuffer.length() << endl;
00950 #undef CASE
00951 }
00952 
00953 void EtherMAC::beginSendFrames()
00954 {
00955     if (!outputbuffer.empty())
00956     {
00957         // Other frames are queued, therefore wait IFG period and transmit next frame
00958         EV << "Transmit next frame in output queue, after IFG period\n";
00959         scheduleEndIFGPeriod();
00960     }
00961     else
00962     {
00963         // No more frames set transmitter to idle
00964         EV << "No more frames to send, transmitter set to idle\n";
00965         transmitState = TX_IDLE_STATE;
00966     }
00967 }
00968 
00969 void EtherMAC::finish()
00970 {
00971     if (!disabled && par("writeScalars").boolValue())
00972     {
00973         double t = simTime();
00974         simtime_t totalChannelIdleTime = t - totalSuccessfulRxTxTime - totalCollisionTime;
00975         recordScalar("simulated time", t);
00976         recordScalar("txrate (Mb)", txrate/1000000);
00977         recordScalar("full duplex", duplexMode);
00978         recordScalar("rx channel idle (%)", 100*totalChannelIdleTime/t);
00979         recordScalar("rx channel utilization (%)", 100*totalSuccessfulRxTxTime/t);
00980         recordScalar("rx channel collision (%)", 100*totalCollisionTime);
00981         recordScalar("frames sent",    numFramesSent);
00982         recordScalar("frames rcvd",    numFramesReceivedOK);
00983         recordScalar("bytes sent",     numBytesSent);
00984         recordScalar("bytes rcvd",     numBytesReceivedOK);
00985         recordScalar("frames from higher layer", numFramesFromHL);
00986         recordScalar("frames from higher layer dropped (queue full)", numFramesFromHLDropped);
00987         recordScalar("frames dropped (bit error)",  numDroppedBitError);
00988         recordScalar("frames dropped (not for us)", numDroppedNotForUs);
00989         recordScalar("frames passed up to HL", numFramesPassedToHL);
00990         recordScalar("PAUSE frames sent",  numPauseFramesSent);
00991         recordScalar("PAUSE frames rcvd",  numPauseFramesRcvd);
00992         recordScalar("collisions",     numCollisions);
00993         recordScalar("backoffs",       numBackoffs);
00994 
00995         if (t>0)
00996         {
00997             recordScalar("frames/sec sent", numFramesSent/t);
00998             recordScalar("frames/sec rcvd", numFramesReceivedOK/t);
00999             recordScalar("bits/sec sent",   8*numBytesSent/t);
01000             recordScalar("bits/sec rcvd",   8*numBytesReceivedOK/t);
01001         }
01002     }
01003 }
01004 
01005 

Generated on Sat May 15 20:30:43 2004 for Ethernet by doxygen1.2.17