00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <stdio.h>
00019 #include <string.h>
00020 #include <omnetpp.h>
00021 #include "EtherMAC.h"
00022 #include "Ieee802Ctrl_m.h"
00023 #include "IPassiveQueue.h"
00024
00025
00026
00027 static std::ostream& operator<< (std::ostream& out, cMessage *msg)
00028 {
00029 out << "(" << msg->getClassName() << ")" << msg->getFullName();
00030 return out;
00031 }
00032
00033
00034 Define_Module( EtherMAC );
00035
00036 EtherMAC::EtherMAC()
00037 {
00038 frameBeingReceived = NULL;
00039 endJammingMsg = endRxMsg = endBackoffMsg = NULL;
00040 }
00041
00042 EtherMAC::~EtherMAC()
00043 {
00044 delete frameBeingReceived;
00045 cancelAndDelete(endRxMsg);
00046 cancelAndDelete(endBackoffMsg);
00047 cancelAndDelete(endJammingMsg);
00048 }
00049
00050 void EtherMAC::initialize()
00051 {
00052 EtherMACBase::initialize();
00053
00054 endRxMsg = new cMessage("EndReception", ENDRECEPTION);
00055 endBackoffMsg = new cMessage("EndBackoff", ENDBACKOFF);
00056 endJammingMsg = new cMessage("EndJamming", ENDJAMMING);
00057
00058
00059 cGate *g = physOutGate;
00060 while (g)
00061 {
00062 cDatarateChannel *chan = dynamic_cast<cDatarateChannel*>(g->getChannel());
00063 if (chan && chan->par("datarate").doubleValue()>0)
00064 error("connection on gate %s has data rate set: using data rate with EtherMAC "
00065 "is forbidden, module's txrate parameter must be used instead",
00066 g->getFullPath().c_str());
00067 g = g->getNextGate();
00068 }
00069
00070
00071 bool performAutoconfig = true;
00072 if (!disabled && connected && performAutoconfig)
00073 {
00074 startAutoconfig();
00075 }
00076 else
00077 {
00078 autoconfigInProgress = false;
00079 duplexMode = par("duplexEnabled");
00080 calculateParameters();
00081 }
00082 WATCH(autoconfigInProgress);
00083
00084
00085 backoffs = 0;
00086 numConcurrentTransmissions = 0;
00087
00088 WATCH(backoffs);
00089 WATCH(numConcurrentTransmissions);
00090
00091
00092 totalCollisionTime = 0.0;
00093 totalSuccessfulRxTxTime = 0.0;
00094 numCollisions = numBackoffs = 0;
00095
00096 WATCH(numCollisions);
00097 WATCH(numBackoffs);
00098
00099 numCollisionsVector.setName("collisions");
00100 numBackoffsVector.setName("backoffs");
00101 }
00102
00103 void EtherMAC::initializeTxrate()
00104 {
00105 txrate = par("txrate");
00106 }
00107
00108 void EtherMAC::startAutoconfig()
00109 {
00110 autoconfigInProgress = true;
00111 lowestTxrateSuggested = 0;
00112 duplexVetoed = false;
00113
00114 double initialTxrate = par("txrate");
00115 bool duplexEnabled = par("duplexEnabled");
00116 txrate = 0;
00117 duplexMode = duplexEnabled;
00118 if (!duplexEnabled || initialTxrate>0)
00119 {
00120 EV << "Autoconfig: advertising our settings: " << initialTxrate/1000000 << "Mb, "
00121 << (duplexMode ? "duplex" : "half-duplex") << endl;
00122
00123 EtherAutoconfig *autoconf = new EtherAutoconfig("autoconf");
00124 if (!duplexEnabled)
00125 autoconf->setHalfDuplex(true);
00126 if (initialTxrate>0)
00127 autoconf->setTxrate(initialTxrate);
00128 send(autoconf, physOutGate);
00129 }
00130 scheduleAt(simTime()+AUTOCONFIG_PERIOD, new cMessage("EndAutoconfig",ENDAUTOCONFIG));
00131 }
00132
00133 void EtherMAC::handleAutoconfigMessage(cMessage *msg)
00134 {
00135 if (!msg->isSelfMessage())
00136 {
00137 if (msg->getArrivalGate() == gate("upperLayerIn"))
00138 {
00139
00140 EV << "Received frame from upper layer during autoconfig period: " << msg << endl;
00141 processFrameFromUpperLayer(check_and_cast<EtherFrame *>(msg));
00142 }
00143 else
00144 {
00145
00146 EV << "Message from network during autoconfig period: " << msg << endl;
00147 EtherAutoconfig *autoconf = check_and_cast<EtherAutoconfig *>(msg);
00148 double acTxrate = autoconf->getTxrate();
00149
00150 EV << "Autoconfig message: ";
00151 if (acTxrate>0)
00152 EV << acTxrate/1000000 << "Mb ";
00153 if (autoconf->getHalfDuplex())
00154 EV << "non-duplex";
00155 EV << "\n";
00156
00157 if (acTxrate>0 && (acTxrate<lowestTxrateSuggested || lowestTxrateSuggested==0))
00158 lowestTxrateSuggested = acTxrate;
00159 if (!duplexVetoed && autoconf->getHalfDuplex())
00160 duplexVetoed = true;
00161 delete msg;
00162 }
00163 }
00164 else
00165 {
00166
00167 EV << "Self-message during autoconfig period: " << msg << endl;
00168
00169 delete msg;
00170 autoconfigInProgress = false;
00171
00172 double initialTxrate = par("txrate");
00173 bool duplexEnabled = par("duplexEnabled");
00174
00175 txrate = (initialTxrate==0 && lowestTxrateSuggested==0) ? 100000000 :
00176 (initialTxrate==0) ? lowestTxrateSuggested :
00177 (lowestTxrateSuggested==0) ? initialTxrate :
00178 (lowestTxrateSuggested<initialTxrate) ? lowestTxrateSuggested : initialTxrate;
00179 duplexMode = (duplexEnabled && !duplexVetoed);
00180 calculateParameters();
00181
00182 EV << "Parameters after autoconfig: txrate=" << txrate/1000000 << "Mb, " << (duplexMode ? "duplex" : "half-duplex") << endl;
00183
00184 if (ev.isGUI())
00185 {
00186 char modestr[64];
00187 sprintf(modestr, "%dMb\n%s", int(txrate/1000000), (duplexMode ? "full duplex" : "half duplex"));
00188 getDisplayString().setTagArg("t",0,modestr);
00189
00190 sprintf(modestr, "%s: %dMb %s", getFullName(), int(txrate/1000000), (duplexMode ? "duplex" : "half duplex"));
00191 getParentModule()->bubble(modestr);
00192 }
00193
00194 if (!txQueue.empty())
00195 {
00196 EV << "Autoconfig period over, starting to send frames\n";
00197 scheduleEndIFGPeriod();
00198 }
00199 }
00200 }
00201
00202 void EtherMAC::handleMessage (cMessage *msg)
00203 {
00204 if (disabled)
00205 {
00206 EV << "MAC is disabled -- dropping message " << msg << "\n";
00207 delete msg;
00208 return;
00209 }
00210 if (autoconfigInProgress)
00211 {
00212 handleAutoconfigMessage(msg);
00213 return;
00214 }
00215
00216 printState();
00217
00218 if (!duplexMode && transmitState==TRANSMITTING_STATE && receiveState!=RX_IDLE_STATE)
00219 error("Inconsistent state -- transmitting and receiving at the same time");
00220
00221 if (!msg->isSelfMessage())
00222 {
00223
00224 if (msg->getArrivalGate() == gate("upperLayerIn"))
00225 processFrameFromUpperLayer(check_and_cast<EtherFrame *>(msg));
00226 else
00227 processMsgFromNetwork(PK(msg));
00228 }
00229 else
00230 {
00231
00232 EV << "Self-message " << msg << " received\n";
00233 switch (msg->getKind())
00234 {
00235 case ENDIFG:
00236 handleEndIFGPeriod();
00237 break;
00238
00239 case ENDTRANSMISSION:
00240 handleEndTxPeriod();
00241 break;
00242
00243 case ENDRECEPTION:
00244 handleEndRxPeriod();
00245 break;
00246
00247 case ENDBACKOFF:
00248 handleEndBackoffPeriod();
00249 break;
00250
00251 case ENDJAMMING:
00252 handleEndJammingPeriod();
00253 break;
00254
00255 case ENDPAUSE:
00256 handleEndPausePeriod();
00257 break;
00258
00259 default:
00260 error("self-message with unexpected message kind %d", msg->getKind());
00261 }
00262 }
00263 printState();
00264
00265 if (ev.isGUI())
00266 updateDisplayString();
00267 }
00268
00269
00270 void EtherMAC::processFrameFromUpperLayer(EtherFrame *frame)
00271 {
00272 EtherMACBase::processFrameFromUpperLayer(frame);
00273
00274 if (!autoconfigInProgress && (duplexMode || receiveState==RX_IDLE_STATE) && transmitState==TX_IDLE_STATE)
00275 {
00276 EV << "No incoming carrier signals detected, frame clear to send, wait IFG first\n";
00277 scheduleEndIFGPeriod();
00278 }
00279 }
00280
00281
00282 void EtherMAC::processMsgFromNetwork(cPacket *msg)
00283 {
00284 EtherMACBase::processMsgFromNetwork(msg);
00285
00286 simtime_t endRxTime = simTime() + msg->getBitLength()*bitTime;
00287
00288 if (!duplexMode && transmitState==TRANSMITTING_STATE)
00289 {
00290
00291 if (dynamic_cast<EtherJam*>(msg) != NULL)
00292 error("Stray jam signal arrived while transmitting (usual cause is cable length exceeding allowed maximum)");
00293
00294 EV << "Transmission interrupted by incoming frame, handling collision\n";
00295 cancelEvent(endTxMsg);
00296
00297 EV << "Transmitting jam signal\n";
00298 sendJamSignal();
00299
00300
00301 receiveState = RX_COLLISION_STATE;
00302 numConcurrentTransmissions++;
00303 simtime_t endJamTime = simTime()+jamDuration;
00304 scheduleAt(endRxTime<endJamTime ? endJamTime : endRxTime, endRxMsg);
00305 delete msg;
00306
00307 numCollisions++;
00308 numCollisionsVector.record(numCollisions);
00309 }
00310 else if (receiveState==RX_IDLE_STATE)
00311 {
00312 if (dynamic_cast<EtherJam*>(msg) != NULL)
00313 error("Stray jam signal arrived (usual cause is cable length exceeding allowed maximum)");
00314
00315 EV << "Start reception of frame\n";
00316 numConcurrentTransmissions++;
00317 if (frameBeingReceived)
00318 error("frameBeingReceived!=0 in RX_IDLE_STATE");
00319 frameBeingReceived = (EtherFrame *)msg;
00320 scheduleEndRxPeriod(msg);
00321 channelBusySince = simTime();
00322 }
00323 else if (receiveState==RECEIVING_STATE && dynamic_cast<EtherJam*>(msg)==NULL && endRxMsg->getArrivalTime()-simTime()<bitTime)
00324 {
00325
00326
00327
00328
00329
00330 EV << "Back-to-back frames: completing reception of current frame, starting reception of next one\n";
00331
00332
00333 cancelEvent(endRxMsg);
00334 EtherFrame *frame = frameBeingReceived;
00335 frameBeingReceived = NULL;
00336 frameReceptionComplete(frame);
00337
00338
00339 frameBeingReceived = (EtherFrame *)msg;
00340 scheduleEndRxPeriod(msg);
00341 }
00342 else
00343 {
00344
00345 if (dynamic_cast<EtherJam*>(msg) != NULL)
00346 {
00347 if (numConcurrentTransmissions<=0)
00348 error("numConcurrentTransmissions=%d on jam arrival (stray jam?)",numConcurrentTransmissions);
00349
00350 numConcurrentTransmissions--;
00351 EV << "Jam signal received, this marks end of one transmission\n";
00352
00353
00354 if (numConcurrentTransmissions==0)
00355 {
00356 EV << "Last jam signal received, collision will ends when jam ends\n";
00357 cancelEvent(endRxMsg);
00358 scheduleAt(endRxTime, endRxMsg);
00359 }
00360 }
00361 else
00362 {
00363 numConcurrentTransmissions++;
00364 if (endRxMsg->getArrivalTime() < endRxTime)
00365 {
00366
00367 EV << "Overlapping receptions -- setting collision state and extending collision period\n";
00368 cancelEvent(endRxMsg);
00369 scheduleAt(endRxTime, endRxMsg);
00370 }
00371 else
00372 {
00373 EV << "Overlapping receptions -- setting collision state\n";
00374 }
00375 }
00376
00377
00378 delete msg;
00379 if (receiveState==RECEIVING_STATE)
00380 {
00381 delete frameBeingReceived;
00382 frameBeingReceived = NULL;
00383
00384 numCollisions++;
00385 numCollisionsVector.record(numCollisions);
00386 }
00387
00388
00389 receiveState = RX_COLLISION_STATE;
00390 }
00391 }
00392
00393
00394 void EtherMAC::handleEndIFGPeriod()
00395 {
00396 EtherMACBase::handleEndIFGPeriod();
00397
00398
00399 cPacket *frame = (cPacket *)txQueue.front();
00400
00401
00402 if (carrierExtension && frame->getByteLength() < GIGABIT_MIN_FRAME_WITH_EXT)
00403 {
00404 EV << "Performing carrier extension of small frame\n";
00405 frame->setByteLength(GIGABIT_MIN_FRAME_WITH_EXT);
00406 }
00407
00408
00409 startFrameTransmission();
00410 }
00411
00412 void EtherMAC::startFrameTransmission()
00413 {
00414 cPacket *origFrame = (cPacket *)txQueue.front();
00415 EV << "Transmitting a copy of frame " << origFrame << endl;
00416 cPacket *frame = origFrame->dup();
00417
00418
00419 frame->addByteLength(PREAMBLE_BYTES+SFD_BYTES);
00420 if (ev.isGUI()) updateConnectionColor(TRANSMITTING_STATE);
00421 send(frame, physOutGate);
00422
00423
00424 if (frameBursting)
00425 {
00426 bytesSentInBurst = frame->getByteLength();
00427 framesSentInBurst++;
00428 }
00429
00430
00431 if (!duplexMode && receiveState!=RX_IDLE_STATE)
00432 {
00433
00434
00435
00436
00437
00438
00439
00440 sendJamSignal();
00441
00442
00443 if (receiveState==RECEIVING_STATE)
00444 {
00445 delete frameBeingReceived;
00446 frameBeingReceived = NULL;
00447
00448 numCollisions++;
00449 numCollisionsVector.record(numCollisions);
00450 }
00451
00452 receiveState = RX_COLLISION_STATE;
00453 }
00454 else
00455 {
00456
00457 scheduleEndTxPeriod(frame);
00458
00459
00460 if (!duplexMode)
00461 channelBusySince = simTime();
00462 }
00463 }
00464
00465 void EtherMAC::handleEndTxPeriod()
00466 {
00467 EtherMACBase::handleEndTxPeriod();
00468
00469
00470 if (!duplexMode)
00471 {
00472 simtime_t dt = simTime()-channelBusySince;
00473 totalSuccessfulRxTxTime += dt;
00474 }
00475
00476 backoffs = 0;
00477
00478
00479 if (checkAndScheduleEndPausePeriod())
00480 return;
00481
00482
00483
00484 bool burstFrame=false;
00485 if (frameBursting && !txQueue.empty())
00486 {
00487
00488 if (bytesSentInBurst<GIGABIT_MAX_BURST_BYTES)
00489 {
00490 burstFrame=true;
00491 EV << "Transmitting next frame in current burst\n";
00492 }
00493 else
00494 {
00495 EV << "Next frame does not fit in current burst\n";
00496 }
00497 }
00498
00499 if (burstFrame)
00500 startFrameTransmission();
00501 else
00502 beginSendFrames();
00503 }
00504
00505 void EtherMAC::handleEndRxPeriod()
00506 {
00507 EV << "Frame reception complete\n";
00508 simtime_t dt = simTime()-channelBusySince;
00509 if (receiveState==RECEIVING_STATE)
00510 {
00511 EtherFrame *frame = frameBeingReceived;
00512 frameBeingReceived = NULL;
00513 frameReceptionComplete(frame);
00514 totalSuccessfulRxTxTime += dt;
00515 }
00516 else
00517 {
00518 totalCollisionTime += dt;
00519 }
00520
00521 receiveState = RX_IDLE_STATE;
00522 numConcurrentTransmissions = 0;
00523
00524 if (transmitState==TX_IDLE_STATE && !txQueue.empty())
00525 {
00526 EV << "Receiver now idle, can transmit frames in output buffer after IFG period\n";
00527 scheduleEndIFGPeriod();
00528 }
00529 }
00530
00531 void EtherMAC::handleEndBackoffPeriod()
00532 {
00533 if (transmitState != BACKOFF_STATE)
00534 error("At end of BACKOFF not in BACKOFF_STATE!");
00535 if (txQueue.empty())
00536 error("At end of BACKOFF and buffer empty!");
00537
00538 if (receiveState==RX_IDLE_STATE)
00539 {
00540 EV << "Backoff period ended, wait IFG\n";
00541 scheduleEndIFGPeriod();
00542 }
00543 else
00544 {
00545 EV << "Backoff period ended but channel not free, idling\n";
00546 transmitState = TX_IDLE_STATE;
00547 }
00548 }
00549
00550 void EtherMAC::handleEndJammingPeriod()
00551 {
00552 if (transmitState != JAMMING_STATE)
00553 error("At end of JAMMING not in JAMMING_STATE!");
00554 EV << "Jamming finished, executing backoff\n";
00555 handleRetransmission();
00556 }
00557
00558 void EtherMAC::sendJamSignal()
00559 {
00560 cPacket *jam = new EtherJam("JAM_SIGNAL");
00561 jam->setByteLength(JAM_SIGNAL_BYTES);
00562 if (ev.isGUI()) updateConnectionColor(JAMMING_STATE);
00563 send(jam, physOutGate);
00564
00565 scheduleAt(simTime()+jamDuration, endJammingMsg);
00566 transmitState = JAMMING_STATE;
00567 }
00568
00569 void EtherMAC::scheduleEndRxPeriod(cPacket *frame)
00570 {
00571 scheduleAt(simTime()+frame->getBitLength()*bitTime, endRxMsg);
00572 receiveState = RECEIVING_STATE;
00573 }
00574
00575 void EtherMAC::handleRetransmission()
00576 {
00577 if (++backoffs > MAX_ATTEMPTS)
00578 {
00579 EV << "Number of retransmit attempts of frame exceeds maximum, cancelling transmission of frame\n";
00580 delete txQueue.pop();
00581
00582 transmitState = TX_IDLE_STATE;
00583 backoffs = 0;
00584
00585 return;
00586 }
00587
00588 EV << "Executing backoff procedure\n";
00589 int backoffrange = (backoffs>=BACKOFF_RANGE_LIMIT) ? 1024 : (1 << backoffs);
00590 int slotNumber = intuniform(0,backoffrange-1);
00591 simtime_t backofftime = slotNumber*slotTime;
00592
00593 scheduleAt(simTime()+backofftime, endBackoffMsg);
00594 transmitState = BACKOFF_STATE;
00595
00596 numBackoffs++;
00597 numBackoffsVector.record(numBackoffs);
00598 }
00599
00600 void EtherMAC::printState()
00601 {
00602 #define CASE(x) case x: EV << #x; break
00603 EV << "transmitState: ";
00604 switch (transmitState) {
00605 CASE(TX_IDLE_STATE);
00606 CASE(WAIT_IFG_STATE);
00607 CASE(TRANSMITTING_STATE);
00608 CASE(JAMMING_STATE);
00609 CASE(BACKOFF_STATE);
00610 CASE(PAUSE_STATE);
00611 }
00612 EV << ", receiveState: ";
00613 switch (receiveState) {
00614 CASE(RX_IDLE_STATE);
00615 CASE(RECEIVING_STATE);
00616 CASE(RX_COLLISION_STATE);
00617 }
00618 EV << ", backoffs: " << backoffs;
00619 EV << ", numConcurrentTransmissions: " << numConcurrentTransmissions;
00620 EV << ", queueLength: " << txQueue.length() << endl;
00621 #undef CASE
00622 }
00623
00624 void EtherMAC::finish()
00625 {
00626 EtherMACBase::finish();
00627
00628 simtime_t t = simTime();
00629 simtime_t totalChannelIdleTime = t - totalSuccessfulRxTxTime - totalCollisionTime;
00630 recordScalar("rx channel idle (%)", 100*(totalChannelIdleTime/t));
00631 recordScalar("rx channel utilization (%)", 100*(totalSuccessfulRxTxTime/t));
00632 recordScalar("rx channel collision (%)", 100*(totalCollisionTime/t));
00633 recordScalar("collisions", numCollisions);
00634 recordScalar("backoffs", numBackoffs);
00635 }
00636
00637 void EtherMAC::updateHasSubcribers()
00638 {
00639 hasSubscribers = false;
00640 }
00641