MiXiM
2.3
|
An implementation of the 802.11b MAC. More...
#include <Mac80211.h>
Classes | |
struct | NeighborEntry |
Data about a neighbor host. More... | |
Public Types | |
enum | Mac80211MessageKinds { RTS = LAST_BASE_MAC_MESSAGE_KIND, CTS, ACK, DATA, BROADCAST, LAST_MAC_80211_MESSAGE_KIND } |
frame kinds | |
Public Member Functions | |
virtual void | initialize (int) |
Initialization of the module and some variables. | |
virtual void | finish () |
Called when the simulation has finished. | |
Protected Types | |
enum | timerType { TIMEOUT, NAV } |
enum | State { WFDATA = 0, QUIET = 1, IDLE = 2, CONTEND = 3, WFCTS = 4, WFACK = 5, BUSY = 6 } |
typedef std::list< Mac80211Pkt * > | MacPktList |
Type for a queue of Mac80211Pkts. | |
typedef std::list< NeighborEntry > | NeighborList |
Type for a list of NeighborEntries. | |
Protected Member Functions | |
virtual void | handleSelfMsg (cMessage *) |
Handle self messages such as timer... | |
virtual void | handleUpperMsg (cMessage *msg) |
Handle messages from upper layer. | |
virtual void | handleLowerMsg (cMessage *) |
Handle messages from lower layer. | |
virtual void | handleLowerControl (cMessage *) |
Handle messages from lower layer. | |
virtual void | handleEndContentionTimer () |
handle end of contention | |
void | handleMsgNotForMe (cMessage *af, simtime_t_cref duration) |
handle a message that is not for me or errornous | |
void | handleMsgForMe (Mac80211Pkt *) |
handle a message that was meant for me | |
void | handleBroadcastMsg (Mac80211Pkt *) |
void | handleEndTransmission () |
handle the end of a transmission... | |
void | handleEndSifsTimer () |
handle end of SIFS | |
void | handleTimeoutTimer () |
handle time out | |
void | handleNavTimer () |
NAV timer expired, the exchange of messages of other stations is done. | |
void | handleRTSframe (Mac80211Pkt *) |
void | handleDATAframe (Mac80211Pkt *) |
void | handleACKframe (Mac80211Pkt *) |
void | handleCTSframe (Mac80211Pkt *) |
void | dataTransmissionFailed () |
void | rtsTransmissionFailed () |
virtual void | sendDATAframe (Mac80211Pkt *) |
send data frame | |
void | sendACKframe (Mac80211Pkt *) |
send Acknoledgement | |
void | sendCTSframe (Mac80211Pkt *) |
send CTS frame | |
virtual void | sendRTSframe () |
send RTS frame | |
void | sendBROADCASTframe () |
send broadcast frame | |
virtual macpkt_ptr_t | encapsMsg (cPacket *netw) |
encapsulate packet | |
virtual cPacket * | decapsMsg (macpkt_ptr_t frame) |
decapsulate packet | |
virtual void | beginNewCycle () |
start a new contention period | |
simtime_t | backoff (bool rtscts=true) |
Compute a backoff value. | |
void | testMaxAttempts () |
Test if maximum number of retries to transmit is exceeded. | |
simtime_t | timeOut (Mac80211MessageKinds type, double br) |
return a timeOut value for a certain type of frame | |
simtime_t | packetDuration (double bits, double br) |
computes the duration of a transmission over the physical channel, given a certain bitrate | |
const char * | stateName (State state) |
Produce a readable name of the given state. | |
void | setState (State state) |
Sets the state, and produces a log message in between. | |
bool | rtsCts (Mac80211Pkt *m) |
Check whether the next packet should be send with RTS/CTS. | |
void | suspendContention () |
suspend an ongoing contention, pick it up again when the channel becomes idle | |
double | retrieveBitrate (const LAddress::L2Type &destAddress) |
figure out at which bitrate to send to this particular destination | |
void | addNeighbor (Mac80211Pkt *af) |
add a new entry to the neighbor list | |
NeighborList::iterator | findNeighbor (const LAddress::L2Type &address) |
find a neighbor based on his address | |
NeighborList::iterator | findOldestNeighbor () |
find the oldest neighbor -- usually in order to overwrite this entry | |
void | senseChannelWhileIdle (simtime_t_cref duration) |
Starts a channel sense request which sense the channel for the passed duration or until the channel is busy. | |
Signal * | createSignal (simtime_t_cref start, simtime_t_cref length, double power, double bitrate) |
Creates the signal to be used for a packet to be sent. | |
Protected Attributes | |
cMessage * | timeout |
Timer used for time-outs after the transmission of a RTS, a CTS, or a DATA packet. | |
cMessage * | nav |
Timer used for the defer time of a node. Also called NAV : networks allocation vector. | |
ChannelSenseRequest * | contention |
Used to sense if the channel is idle for contention periods. | |
ChannelSenseRequest * | endSifs |
Timer used to indicate the end of a SIFS. | |
simtime_t | chSenseStart |
Stores the the time a channel sensing started. Used to calculate the quiet-time of the channel if the sensing was aborted. | |
State | state |
Current state of the MAC. | |
double | defaultBitrate |
Default bitrate. | |
double | txPower |
The power at which data is transmitted. | |
double | centerFreq |
Stores the center frequency the Mac uses. | |
double | bitrate |
Current bit rate at which data is transmitted. | |
bool | autoBitrate |
Auto bit rate adaptation -- switch. | |
std::vector< double > | snrThresholds |
Hold RSSI thresholds at which to change the bitrates. | |
unsigned | queueLength |
Maximal number of packets in the queue; should be set in the omnetpp.ini. | |
bool | nextIsBroadcast |
Boolean used to know if the next packet is a broadcast packet. | |
MacPktList | fromUpperLayer |
Buffering of messages from upper layer. | |
unsigned | longRetryCounter |
Number of frame transmission attempt. | |
unsigned | shortRetryCounter |
Number of frame transmission attempt. | |
simtime_t | remainingBackoff |
remaining backoff time. If the backoff timer is interrupted, this variable holds the remaining backoff time. | |
simtime_t | currentIFS |
current IFS value (DIFS or EIFS) If an error has been detected, the next backoff requires EIFS, once a valid frame has been received, resets to DIFS. | |
int | rtsCtsThreshold |
Number of bits in a packet before RTS/CTS is used. | |
simtime_t | delta |
Very small value used in timer scheduling in order to avoid multiple changements of state in the same simulation time. | |
unsigned | neighborhoodCacheSize |
Keep information for this many neighbors. | |
simtime_t | neighborhoodCacheMaxAge |
Consider information in cache outdate if it is older than this. | |
NeighborList | neighbors |
A list of this hosts neighbors. | |
bool | switching |
int | fsc |
Private Member Functions | |
Mac80211 (const Mac80211 &) | |
Copy constructor is not allowed. | |
Mac80211 & | operator= (const Mac80211 &) |
Assignment operator is not allowed. |
An implementation of the 802.11b MAC.
For more info, see the NED file.
enum Mac80211::State [protected] |
Definition of the states
{ WFDATA = 0, // waiting for data packet QUIET = 1, // waiting for the communication between two other nodes to end IDLE = 2, // no packet to send, no packet receiving CONTEND = 3,// contention state (battle for the channel) WFCTS = 4, // RTS sent, waiting for CTS WFACK = 5, // DATA packet sent, waiting for ACK BUSY = 6 // during transmission of an ACK or a BROADCAST packet };
enum Mac80211::timerType [protected] |
Definition of the timer types
{ TIMEOUT, NAV };
simtime_t Mac80211::backoff | ( | bool | rtscts = true | ) | [protected] |
Compute a backoff value.
Compute the backoff value.
References longRetryCounter, and shortRetryCounter.
Referenced by beginNewCycle(), handleACKframe(), handleEndTransmission(), and initialize().
{ unsigned rc = (rtscts) ? longRetryCounter : shortRetryCounter; unsigned cw = ((CW_MIN + 1) << rc) - 1; if(cw > CW_MAX) cw = CW_MAX; simtime_t value = ((double) intrand(cw + 1)) * ST; debugEV << simTime() << " random backoff = " << value << endl; return value; }
void Mac80211::beginNewCycle | ( | ) | [protected, virtual] |
start a new contention period
Start a new contention period if the channel is free and if there's a packet to send. Called at the end of a deferring period, a busy period, or after a failure. Called by the HandleMsgForMe(), HandleTimer() HandleUpperMsg(), and, without RTS/CTS, by handleMsgNotForMe().
References backoff(), contention, currentIFS, fromUpperLayer, MacToPhyInterface::getChannelState(), ChannelState::info(), ChannelState::isIdle(), LAddress::isL2Broadcast(), nav, nextIsBroadcast, BaseMacLayer::phy, remainingBackoff, senseChannelWhileIdle(), setState(), and testMaxAttempts().
Referenced by handleACKframe(), handleBroadcastMsg(), handleEndTransmission(), handleMsgNotForMe(), handleNavTimer(), handleTimeoutTimer(), and handleUpperMsg().
{ // before trying to send one more time a packet, test if the // maximum retry limit is reached. If it is the case, then // delete the packet and send the next packet. testMaxAttempts(); if (nav->isScheduled()) { debugEV << "cannot beginNewCycle until NAV expires at t " << nav->getArrivalTime() << endl; return; } /* if(timeout->isScheduled()) { cancelEvent(timeout); } */ if (!fromUpperLayer.empty()) { // look if the next packet is unicast or broadcast nextIsBroadcast = LAddress::isL2Broadcast(fromUpperLayer.front()->getDestAddr()); setState(CONTEND); if(!contention->isScheduled()) { ChannelState channel = phy->getChannelState(); debugEV << simTime() << " do contention: medium = " << channel.info() << ", backoff = " << remainingBackoff << endl; if(channel.isIdle()) { senseChannelWhileIdle(currentIFS + remainingBackoff); //scheduleAt(simTime() + currentIFS + remainingBackoff, contention); } else { /* Mac80211 in MiXiM uses the same mechanism for backoff and post-backoff, a senseChannelWhileIdle which schedules a timer for a duration of IFS + remainingBackoff (i.e. The inter-frame spacing and the present state of the backoff counter). If Host A were doing post-backoff when the frame from Host B arrived, the remainingBackoff would have been > 0 and backoff would have resumed after the frame from Host B finishes. However, Host A has already completed its post-backoff (remainingBackoff was 0) so it essentially was IDLE when the beacon was generated (actually, it was receiving Host B’s frame). So what happens now is that all nodes which have an arrival during Host B’s frame AND have completed their post-backoff, will wait one IFS and then transmit, resulting in synchronised collisions one IFS after a transmission (or an EIFS after a collision). The correct behaviour here is for Host A’s MAC to note that post-backoff has completed (remainingBackoff has reached 0) and the medium is busy, so the MAC must draw a new backoff from the contention window. http://www.freeminded.org/?p=801 */ //channel is busy if(remainingBackoff==0) { remainingBackoff = backoff(); } } } } else { // post-xmit backoff (minor nit: if random backoff=0, we punt) if(remainingBackoff > 0 && !contention->isScheduled()) { ChannelState channel = phy->getChannelState(); debugEV << simTime() << " do contention: medium = " << channel.info() << ", backoff = " << remainingBackoff << endl; if(channel.isIdle()) { senseChannelWhileIdle(currentIFS + remainingBackoff); //scheduleAt(simTime() + currentIFS + remainingBackoff, contention); } } setState(IDLE); } }
Mac80211::macpkt_ptr_t Mac80211::encapsMsg | ( | cPacket * | netw | ) | [protected, virtual] |
encapsulate packet
Encapsulates the received network-layer packet into a MacPkt and set all needed header fields.
Reimplemented from BaseMacLayer.
References fsc, BaseMacLayer::getUpperDestinationFromControlInfo(), and BaseMacLayer::myMacAddr.
Referenced by handleUpperMsg().
{ Mac80211Pkt *pkt = new Mac80211Pkt(netw->getName()); // headerLength, including final CRC-field AND the phy header length! pkt->setBitLength(MAC80211_HEADER_LENGTH); pkt->setRetry(false); // this is not a retry pkt->setSequenceControl(fsc++); // add a unique fsc to it if(fsc <= 0) fsc = 1; // copy dest address from the Control Info attached to the network // mesage by the network layer cObject *const cInfo = netw->removeControlInfo(); debugEV << "CInfo removed, mac addr=" << getUpperDestinationFromControlInfo(cInfo) << endl; pkt->setDestAddr(getUpperDestinationFromControlInfo(cInfo)); //delete the control info delete cInfo; //set the src address to own mac address (nic module id()) pkt->setSrcAddr(myMacAddr); //encapsulate the network packet pkt->encapsulate(netw); debugEV <<"pkt encapsulated, length: " << pkt->getBitLength() << "\n"; return pkt; }
void Mac80211::handleACKframe | ( | Mac80211Pkt * | ) | [protected] |
Handle ACK and delete corresponding packet from queue
References backoff(), beginNewCycle(), fromUpperLayer, longRetryCounter, remainingBackoff, shortRetryCounter, and timeout.
Referenced by handleMsgForMe().
{ // cancel time-out event cancelEvent(timeout); // the transmission is acknowledged : initialize long_retry_counter longRetryCounter = 0; shortRetryCounter = 0; // post transmit backoff remainingBackoff = backoff(); // removes the acknowledged packet from the queue Mac80211Pkt *temp = fromUpperLayer.front(); fromUpperLayer.pop_front(); delete temp; // if thre's a packet to send and if the channel is free then start a new contention period beginNewCycle(); }
void Mac80211::handleBroadcastMsg | ( | Mac80211Pkt * | af | ) | [protected] |
Handle a broadcast packet. This packet is simply passed to the upper layer. No acknowledgement is needed. Called by handleLowerMsg(Mac80211Pkt *af)
References beginNewCycle(), contention, decapsMsg(), BaseLayer::sendUp(), state, and switching.
Referenced by handleLowerMsg().
{ debugEV << "handle broadcast\n"; if((state == BUSY) && (!switching)) { error("logic error: node is currently transmitting, can not receive " "(does the physical layer do its job correctly?)"); } sendUp(decapsMsg(af)); delete af; if (state == CONTEND) { assert(!contention->isScheduled()); //suspendContention(); beginNewCycle(); } }
void Mac80211::handleCTSframe | ( | Mac80211Pkt * | af | ) | [protected] |
Handle a CTS frame. Called by HandleMsgForMe(Mac80211Pkt* af)
References endSifs, BaseLayer::sendControlDown(), shortRetryCounter, and timeout.
Referenced by handleMsgForMe().
{ // cancel time-out event cancelEvent(timeout); shortRetryCounter = 0; // wait a short interframe space if(endSifs->isScheduled()) error("Mac80211::handleCTSframe when SIFS scheduled"); endSifs->setContextPointer(af); sendControlDown(endSifs); //scheduleAt(simTime() + SIFS, endSifs); }
void Mac80211::handleDATAframe | ( | Mac80211Pkt * | af | ) | [protected] |
Handle a frame which expected to be a DATA frame. Called by HandleMsgForMe()
References decapsMsg(), endSifs, findNeighbor(), neighbors, rtsCts(), BaseLayer::sendControlDown(), BaseLayer::sendUp(), and timeout.
Referenced by handleMsgForMe().
{ NeighborList::iterator it; if (rtsCts(af)) cancelEvent(timeout); // cancel time-out event it = findNeighbor(af->getSrcAddr()); if(it == neighbors.end()) error("Mac80211::handleDATAframe: neighbor not registered"); if(af->getRetry() && (it->fsc == af->getSequenceControl())) { debugEV << "Mac80211::handleDATAframe suppressed duplicate message " << af << " fsc: " << it->fsc << "\n"; } else { it->fsc = af->getSequenceControl(); // pass the packet to the upper layer sendUp(decapsMsg(af)); } // wait a short interframe space if(endSifs->isScheduled()) error("Mac80211::handleDATAframe when SIFS scheduled"); endSifs->setContextPointer(af); sendControlDown(endSifs); //scheduleAt(simTime() + SIFS, endSifs); }
void Mac80211::handleEndContentionTimer | ( | ) | [protected, virtual] |
handle end of contention
The node has won the contention, and is now allowed to send an RTS/DATA or Broadcast packet. The backoff value is deleted and will be newly computed in the next contention period
References contention, currentIFS, fromUpperLayer, nextIsBroadcast, BaseMacLayer::phy, remainingBackoff, rtsCts(), sendBROADCASTframe(), sendDATAframe(), sendRTSframe(), MacToPhyInterface::setRadioState(), state, suspendContention(), and MiximRadio::TX.
Referenced by handleLowerControl().
{ if(!contention->getResult().isIdle()) { suspendContention(); return; } if(state == IDLE) { remainingBackoff = 0; // bug: ID: 3460932 /* In Mac80211, currentIFS is set to DIFS upon successful reception and EIFS upon reception of a corrupted frame. This is correct. However, currentIFS remains unchanged while performing post-backoff. As a result, the EIFS related to reception of a corrupted frame (and subsequent post-backoff) is used again in the minimum duration of idle time before a transmission is performed (i.e. the mandatory IFS during which a station decides whether to transmit directly or go do backoff). This results in incorrect behaviour, as this is a new opportunity. A fix is simple: in handleEndContentionTimer(), add "currentIFS = DIFS;" inside the state==IDLE if-clause. This is where post-backoff completes and not only remainingBackoff but also currentIFS should be reset. See also: http://www.freeminded.org/?p=811 */ currentIFS = DIFS; } else if(state == CONTEND) { // the node has won the channel, the backoff window is deleted and // will be new calculated in the next contention period remainingBackoff = 0; // unicast packet phy->setRadioState(MiximRadio::TX); if (!nextIsBroadcast) { if(rtsCts(fromUpperLayer.front())) { // send a RTS sendRTSframe(); } else { sendDATAframe(0); } }// broadcast packet else { sendBROADCASTframe(); // removes the packet from the queue without waiting for an acknowledgement Mac80211Pkt *temp = fromUpperLayer.front(); fromUpperLayer.pop_front(); delete(temp); } } else { error("logic error: expiration of the contention timer outside of CONTEND/IDLE state, should not happen"); } }
void Mac80211::handleEndSifsTimer | ( | ) | [protected] |
handle end of SIFS
Handle the end sifs timer. Then sends a CTS, a DATA, or an ACK frame
References endSifs, fromUpperLayer, BaseMacLayer::phy, sendACKframe(), sendCTSframe(), sendDATAframe(), MacToPhyInterface::setRadioState(), setState(), and MiximRadio::TX.
Referenced by handleLowerControl().
{ if(!endSifs->getResult().isIdle()){ // delete the previously received frame delete static_cast<Mac80211Pkt *>(endSifs->getContextPointer()); // state in now IDLE or CONTEND if (fromUpperLayer.empty()) setState(IDLE); else setState(CONTEND); return; } Mac80211Pkt *frame = static_cast<Mac80211Pkt *>(endSifs->getContextPointer()); phy->setRadioState(MiximRadio::TX); switch (frame->getKind()) { case RTS: sendCTSframe(frame); break; case CTS: sendDATAframe(frame); break; case DATA: sendACKframe(frame); break; default: error("logic error: end sifs timer when previously received packet is not RTS/CTS/DATA"); break; } // don't need previous frame any more delete frame; }
void Mac80211::handleEndTransmission | ( | ) | [protected] |
handle the end of a transmission...
Handle the end of transmission timer (end of the transmission of an ACK or a broadcast packet). Called by HandleTimer(cMessage* msg)
References backoff(), beginNewCycle(), longRetryCounter, nextIsBroadcast, remainingBackoff, shortRetryCounter, and state.
Referenced by handleLowerControl().
{ debugEV << "transmission of packet is over\n"; if(state == BUSY) { if(nextIsBroadcast) { shortRetryCounter = 0; longRetryCounter = 0; remainingBackoff = backoff(); } beginNewCycle(); } else if(state == WFDATA) { beginNewCycle(); } }
void Mac80211::handleLowerMsg | ( | cMessage * | msg | ) | [protected, virtual] |
Handle messages from lower layer.
Handle all messages from lower layer. Checks the destination MAC adress of the packet. Then calls one of the three functions : handleMsgNotForMe(), handleBroadcastMsg(), or handleMsgForMe(). Called by handleMessage().
Reimplemented from BaseMacLayer.
References addNeighbor(), contention, currentIFS, MacToPhyInterface::getRadioState(), handleBroadcastMsg(), handleMsgForMe(), handleMsgNotForMe(), LAddress::isL2Broadcast(), BaseMacLayer::myMacAddr, BaseMacLayer::phy, and MiximRadio::RX.
{ Mac80211Pkt *af = static_cast<Mac80211Pkt *>(msg); int radioState = phy->getRadioState(); if(radioState == MiximRadio::RX) { // end of the reception debugEV << " handleLowerMsg frame " << af << " received from " << af->getSrcAddr() << " addressed to " << af->getDestAddr() << "\n"; addNeighbor(af); if (contention->isScheduled()) { error("Gaack! I am changing the IFS on an ongoing contention"); } currentIFS = DIFS; if(af->getDestAddr() == myMacAddr) { handleMsgForMe(af); } else if(LAddress::isL2Broadcast(af->getDestAddr())) { handleBroadcastMsg(af); } else { handleMsgNotForMe(af, af->getDuration()); } } else { debugEV << " handleLowerMsg frame " << af << " deleted, strange race condition\n"; delete af; } }
void Mac80211::handleMsgForMe | ( | Mac80211Pkt * | af | ) | [protected] |
handle a message that was meant for me
Handle a packet for the node. The result of this reception is a function of the type of the received message (RTS,CTS,DATA, or ACK), and of the current state of the MAC (WFDATA, CONTEND, IDLE, WFCTS, or WFACK). Called by handleLowerMsg()
References contention, handleACKframe(), handleCTSframe(), handleDATAframe(), handleRTSframe(), state, stateName(), and switching.
Referenced by handleLowerMsg().
{ debugEV << "handle msg for me " << af->getName() << " in " << stateName(state) << "\n"; switch (state) { case IDLE: // waiting for the end of the contention period case CONTEND: // or waiting for RTS // RTS or DATA accepted if (af->getKind() == RTS) { assert(!contention->isScheduled()); //suspendContention(); handleRTSframe(af); } else if (af->getKind() == DATA) { assert(!contention->isScheduled()); //suspendContention(); handleDATAframe(af); } else { error("in handleMsgForMe() IDLE/CONTEND, strange message %s", af->getName()); } break; case WFDATA: // waiting for DATA if (af->getKind() == DATA) { handleDATAframe(af); } else { EV << "unexpected message -- probably a collision of RTSs\n"; delete af; } break; case WFACK: // waiting for ACK if (af->getKind() == ACK) { handleACKframe(af); } else { error("in handleMsgForMe() WFACK, strange message %s", af->getName()); } delete af; break; case WFCTS: // The MAC is waiting for CTS if (af->getKind() == CTS) { handleCTSframe(af); } else { EV << "unexpected msg -- deleted \n"; delete af; } break; case QUIET: // the node is currently deferring. // cannot handle any packet with its MAC adress delete af; break; case BUSY: // currently transmitting an ACK or a BROADCAST packet if(switching) { EV << "message received during radio state switchover\n"; delete af; } else { error("logic error: node is currently transmitting, can not receive " "(does the physical layer do its job correctly?)"); } break; default: error("unknown state %d", state); break; } }
void Mac80211::handleMsgNotForMe | ( | cMessage * | af, |
simtime_t_cref | duration | ||
) | [protected] |
handle a message that is not for me or errornous
Handle all ACKs,RTS, CTS, or DATA not for the node. If RTS/CTS is used the node must stay quiet until the current handshake between the two communicating nodes is over. This is done by scheduling the timer message nav (Network Allocation Vector). Without RTS/CTS a new contention is started. If an error occured the node must defer for EIFS. Called by handleLowerMsg()
References beginNewCycle(), Decider80211::COLLISION, contention, currentIFS, fromUpperLayer, longRetryCounter, nav, BaseMacLayer::PACKET_DROPPED, rtsCts(), setState(), shortRetryCounter, state, and timeout.
Referenced by handleLowerControl(), and handleLowerMsg().
{ debugEV << "handle msg not for me " << af->getName() << "\n"; // if the duration of the packet is null, then do nothing (to avoid // the unuseful scheduling of a self message) if(duration != 0) { // the node is already deferring if (state == QUIET) { // the current value of the NAV is not sufficient if (nav->getArrivalTime() < simTime() + duration) { cancelEvent(nav); scheduleAt(simTime() + duration, nav); debugEV << "NAV timer started for: " << duration << " State QUIET\n"; } } // other states else { // if the MAC wait for another frame, it can delete its time out // (exchange is aborted) if (timeout->isScheduled()) { cancelEvent(timeout); if(state == WFACK) { fromUpperLayer.front()->setRetry(true); } if((state == WFACK) || (state == WFCTS)) { if(rtsCts(fromUpperLayer.front())) { longRetryCounter++; } else { shortRetryCounter++; } } } // the node must defer for the time of the transmission scheduleAt(simTime() + duration, nav); debugEV << "NAV timer started, not QUIET: " << duration << endl; assert(!contention->isScheduled()); //suspendContention(); setState(QUIET); } } if((af->getKind() == BaseDecider::PACKET_DROPPED) || (af->getKind() == Decider80211::COLLISION)) { assert(!contention->isScheduled()); //suspendContention(); //if (contention->isScheduled()) { // error("Gaack! I am changing the IFS on an ongoing contention"); //} //handle broken cts and ACK frames if(state == WFCTS) { assert(timeout->isScheduled()); cancelEvent(timeout); rtsTransmissionFailed(); } else if(state == WFACK) { assert(timeout->isScheduled()); cancelEvent(timeout); dataTransmissionFailed(); } currentIFS = EIFS; } beginNewCycle(); delete af; }
void Mac80211::handleNavTimer | ( | ) | [protected] |
NAV timer expired, the exchange of messages of other stations is done.
Handle the NAV timer (end of a defering period). Called by HandleTimer(cMessage* msg)
References beginNewCycle(), and state.
Referenced by handleSelfMsg().
{ if (state != QUIET) error("logic error: expiration of the NAV timer outside of the state QUIET, should not happen"); // if there's a packet to send and if the channel is free, then start a new contention period // lmf - Potential race condition: If nav expires at same time // medium becomes IDLE (usual case), but the navTimeout comes // before the mediumIndication, then the medium is still BUSY when // beginNewCycle() is called, so the backoff doesn't resume. // Usually it doesn't matter, since there is also an arriving // frame and so beginNewCycle() will be called again by the // handleMsgXXX. But if there is no frame (mobility, exposed // terminal, etc) there's a potential problem. beginNewCycle(); }
void Mac80211::handleRTSframe | ( | Mac80211Pkt * | af | ) | [protected] |
Handle aframe wich is expected to be an RTS. Called by HandleMsgForMe()
References endSifs, and BaseLayer::sendControlDown().
Referenced by handleMsgForMe().
{ if(endSifs->isScheduled()) error("Mac80211::handleRTSframe when SIFS scheduled"); // wait a short interframe space endSifs->setContextPointer(af); sendControlDown(endSifs); //scheduleAt(simTime() + SIFS, endSifs); }
void Mac80211::handleSelfMsg | ( | cMessage * | msg | ) | [protected, virtual] |
Handle self messages such as timer...
handle timers
Reimplemented from BaseMacLayer.
References handleNavTimer(), and handleTimeoutTimer().
{ debugEV << simTime() << " handleSelfMsg " << msg->getName() << "\n"; switch (msg->getKind()) { // the MAC was waiting for a CTS, a DATA, or an ACK packet but the timer has expired. case TIMEOUT: handleTimeoutTimer(); // noch zu betrachten.. break; // the MAC was waiting because an other communication had won the channel. This communication is now over case NAV: handleNavTimer(); // noch zu betrachten... break; default: error("unknown timer type"); break; } }
void Mac80211::handleTimeoutTimer | ( | ) | [protected] |
handle time out
Handle the time out timer. Called by handleTimer(cMessage* msg)
References beginNewCycle(), state, and stateName().
Referenced by handleSelfMsg().
{ debugEV << simTime() << " handleTimeoutTimer " << stateName(state) << "\n"; if(state == WFCTS) { rtsTransmissionFailed(); } else if(state == WFACK) { dataTransmissionFailed(); } // if there's a packet to send and if the channel is free then // start a new contention period if (state != QUIET) beginNewCycle(); }
void Mac80211::handleUpperMsg | ( | cMessage * | msg | ) | [protected, virtual] |
Handle messages from upper layer.
This implementation does not support fragmentation, so it is tested if the maximum length of the MPDU is exceeded.
Reimplemented from BaseMacLayer.
References beginNewCycle(), encapsMsg(), endSifs, fromUpperLayer, BaseMacLayer::PACKET_DROPPED, queueLength, BaseLayer::sendControlUp(), and state.
{ cPacket* pkt = static_cast<cPacket*>(msg); debugEV << "Mac80211::handleUpperMsg " << msg->getName() << "\n"; if (pkt->getBitLength() > 18496){ error("packet from higher layer (%s)%s is too long for 802.11b, %d bytes (fragmentation is not supported yet)", pkt->getClassName(), pkt->getName(), pkt->getByteLength()); } if(fromUpperLayer.size() == queueLength) { //TODO: CSMAMacLayer does create a new mac packet and sends it up. Maybe settle on a consistent solution here msg->setName("MAC ERROR"); msg->setKind(PACKET_DROPPED); sendControlUp(msg); debugEV << "packet " << msg << " received from higher layer but MAC queue is full, signalling error\n"; return; } Mac80211Pkt *mac = static_cast<Mac80211Pkt*>(encapsMsg(pkt)); debugEV << "packet " << pkt << " received from higher layer, dest=" << mac->getDestAddr() << ", encapsulated\n"; fromUpperLayer.push_back(mac); // If the MAC is in the IDLE state, then start a new contention period if (state == IDLE && !endSifs->isScheduled()) { beginNewCycle(); } else { debugEV << "enqueued, will be transmitted later\n"; } }
void Mac80211::initialize | ( | int | stage | ) | [virtual] |
Initialization of the module and some variables.
First we have to initialize the module from which we derived ours, in this case BaseLayer.
Reimplemented from BaseMacLayer.
Reimplemented in Mac80211MultiChannel.
References autoBitrate, backoff(), bitrate, centerFreq, MacToPhyInterface::CHANNEL_SENSE_REQUEST, contention, currentIFS, FWMath::dBm2mW(), defaultBitrate, delta, endSifs, fsc, BaseMacLayer::getConnectionManager(), MacToPhyInterface::getCurrentRadioChannel(), longRetryCounter, BaseMacLayer::myMacAddr, nav, neighborhoodCacheMaxAge, neighborhoodCacheSize, BaseMacLayer::phy, queueLength, remainingBackoff, rtsCtsThreshold, senseChannelWhileIdle(), shortRetryCounter, snrThresholds, state, switching, timeout, and txPower.
{ BaseMacLayer::initialize(stage); if (stage == 0) { debugEV << "Initializing stage 0\n"; switching = false; fsc = intrand(0x7FFFFFFF); if(fsc == 0) fsc = 1; debugEV << " fsc: " << fsc << "\n"; queueLength = hasPar("queueLength") ? par("queueLength").longValue() : 10; // timers timeout = new cMessage("timeout", TIMEOUT); nav = new cMessage("NAV", NAV); contention = new ChannelSenseRequest("contention", MacToPhyInterface::CHANNEL_SENSE_REQUEST); contention->setSenseMode(UNTIL_BUSY); endSifs = new ChannelSenseRequest("end SIFS", MacToPhyInterface::CHANNEL_SENSE_REQUEST); endSifs->setSenseMode(UNTIL_BUSY); endSifs->setSenseTimeout(SIFS); state = IDLE; longRetryCounter = 0; shortRetryCounter = 0; rtsCtsThreshold = hasPar("rtsCtsThreshold") ? par("rtsCtsThreshold").longValue() : 1; currentIFS = EIFS; autoBitrate = hasPar("autoBitrate") ? par("autoBitrate").boolValue() : false; txPower = hasPar("txPower") ? par("txPower").doubleValue() : 110.11; delta = 1E-9; debugEV << "SIFS: " << SIFS << " DIFS: " << DIFS << " EIFS: " << EIFS << endl; } else if(stage == 1) { BaseConnectionManager* cc = getConnectionManager(); if(cc->hasPar("pMax") && txPower > cc->par("pMax").doubleValue()) opp_error("TranmitterPower can't be bigger than pMax in ConnectionManager! " "Please adjust your omnetpp.ini file accordingly."); int channel = phy->getCurrentRadioChannel(); if(!(1<=channel && channel<=14)) { opp_error("MiximRadio set to invalid channel %d. Please make sure the" " phy modules parameter \"initialRadioChannel\" is set to" " a valid 802.11 channel (1 to 14)!", channel); } centerFreq = CENTER_FREQUENCIES[channel]; bool found = false; bitrate = hasPar("bitrate") ? par("bitrate").doubleValue() : BITRATES_80211[0]; for(int i = 0; i < 4; i++) { if(bitrate == BITRATES_80211[i]) { found = true; break; } } if(!found) bitrate = BITRATES_80211[0]; defaultBitrate = bitrate; snrThresholds.push_back(hasPar("snr2Mbit") ? par("snr2Mbit").doubleValue() : 100); snrThresholds.push_back(hasPar("snr5Mbit") ? par("snr5Mbit").doubleValue() : 100); snrThresholds.push_back(hasPar("snr11Mbit") ? par("snr11Mbit").doubleValue() : 100); snrThresholds.push_back(111111111); // sentinel neighborhoodCacheSize = hasPar("neighborhoodCacheSize") ? par("neighborhoodCacheSize").longValue() : 0; neighborhoodCacheMaxAge = hasPar("neighborhoodCacheMaxAge") ? par("neighborhoodCacheMaxAge").longValue() : 10000; debugEV << " MAC Address: " << myMacAddr << " rtsCtsThreshold: " << rtsCtsThreshold << " bitrate: " << bitrate << " channel: " << channel << " autoBitrate: " << autoBitrate << " 2MBit: " << snrThresholds[0] << " 5.5MBit: " <<snrThresholds[1] << " 11MBit: " << snrThresholds[2] << " neighborhoodCacheSize " << neighborhoodCacheSize << " neighborhoodCacheMaxAge " << neighborhoodCacheMaxAge << endl; for(int i = 0; i < 3; i++) { snrThresholds[i] = FWMath::dBm2mW(snrThresholds[i]); } remainingBackoff = backoff(); senseChannelWhileIdle(remainingBackoff + currentIFS); } }
simtime_t Mac80211::packetDuration | ( | double | bits, |
double | br | ||
) | [protected] |
computes the duration of a transmission over the physical channel, given a certain bitrate
Computes the duration of the transmission of a frame over the physical channel. 'bits' should be the total length of the mac packet in bits excluding the phy header length.
References BaseMacLayer::phyHeaderLength.
Referenced by sendACKframe(), sendBROADCASTframe(), sendCTSframe(), sendDATAframe(), sendRTSframe(), and timeOut().
{ return bits / br + phyHeaderLength / BITRATE_HEADER; }
void Mac80211::sendACKframe | ( | Mac80211Pkt * | af | ) | [protected] |
send Acknoledgement
Send an ACK frame.Called by HandleEndSifsTimer()
References createSignal(), PhyToMacControlInfo::getDeciderResult(), BaseMacLayer::myMacAddr, packetDuration(), BaseLayer::sendDown(), BaseMacLayer::setDownControlInfo(), setState(), and txPower.
Referenced by handleEndSifsTimer().
{ Mac80211Pkt *frame = new Mac80211Pkt("wlan-ack"); double br = static_cast<const DeciderResult80211*>(PhyToMacControlInfo::getDeciderResult(af))->getBitrate(); delete af->removeControlInfo(); setDownControlInfo(frame, createSignal(simTime(), packetDuration(LENGTH_ACK, br), txPower, br)); frame->setKind(ACK); frame->setBitLength((int)LENGTH_ACK); // the dest address must be the src adress of the RTS or the DATA // packet received. The src adress is the adress of the node frame->setSrcAddr(myMacAddr); frame->setDestAddr(af->getSrcAddr()); frame->setDuration(0); sendDown(frame); debugEV << "sent ACK frame!\n"; // update state and display setState(BUSY); }
void Mac80211::sendBROADCASTframe | ( | ) | [protected] |
send broadcast frame
Send a BROADCAST frame.Called by handleContentionTimer()
References createSignal(), fromUpperLayer, packetDuration(), retrieveBitrate(), BaseLayer::sendDown(), BaseMacLayer::setDownControlInfo(), setState(), and txPower.
Referenced by handleEndContentionTimer().
{ // send a copy of the frame in front of the queue Mac80211Pkt *frame = static_cast<Mac80211Pkt *>(fromUpperLayer.front()->dup()); double br = retrieveBitrate(frame->getDestAddr()); simtime_t duration = packetDuration(frame->getBitLength(), br); setDownControlInfo(frame, createSignal(simTime(), duration, txPower, br)); frame->setKind(BROADCAST); sendDown(frame); // update state and display setState(BUSY); }
void Mac80211::sendCTSframe | ( | Mac80211Pkt * | af | ) | [protected] |
send CTS frame
Send a CTS frame.Called by HandleEndSifsTimer()
References createSignal(), PhyToMacControlInfo::getDeciderResult(), BaseMacLayer::myMacAddr, packetDuration(), BaseLayer::sendDown(), BaseMacLayer::setDownControlInfo(), setState(), and txPower.
Referenced by handleEndSifsTimer().
{ Mac80211Pkt *frame = new Mac80211Pkt("wlan-cts"); double br = static_cast<const DeciderResult80211*>(PhyToMacControlInfo::getDeciderResult(af))->getBitrate(); delete af->removeControlInfo(); setDownControlInfo(frame, createSignal(simTime(), packetDuration(LENGTH_CTS, br), txPower, br)); frame->setKind(CTS); frame->setBitLength((int)LENGTH_CTS); // the dest adress must be the src adress of the RTS received. The // src adress is the adress of the node frame->setSrcAddr(myMacAddr); frame->setDestAddr(af->getSrcAddr()); frame->setDuration(af->getDuration() - SIFS - packetDuration(LENGTH_CTS, br)); //scheduleAt(simTime() + af->getDuration() - packetDuration(LENGTH_ACK, br) - 2 * SIFS + delta, timeout); debugEV << " Mac80211::sendCTSframe duration: " << packetDuration(LENGTH_CTS, br) << " br: " << br << "\n"; // send CTS frame sendDown(frame); // update state and display setState(WFDATA); }
void Mac80211::sendDATAframe | ( | Mac80211Pkt * | af | ) | [protected, virtual] |
send data frame
Send a DATA frame. Called by HandleEndSifsTimer() or handleEndContentionTimer()
References createSignal(), fromUpperLayer, PhyToMacControlInfo::getDeciderResult(), BaseMacLayer::myMacAddr, packetDuration(), retrieveBitrate(), BaseLayer::sendDown(), BaseMacLayer::setDownControlInfo(), setState(), shortRetryCounter, timeOut(), timeout, and txPower.
Referenced by handleEndContentionTimer(), and handleEndSifsTimer().
{ Mac80211Pkt *frame = static_cast<Mac80211Pkt *>(fromUpperLayer.front()->dup()); double br; if(af) { br = static_cast<const DeciderResult80211*>(PhyToMacControlInfo::getDeciderResult(af))->getBitrate(); delete af->removeControlInfo(); } else { br = retrieveBitrate(frame->getDestAddr()); if(shortRetryCounter) frame->setRetry(true); } simtime_t duration = packetDuration(frame->getBitLength(), br); setDownControlInfo(frame, createSignal(simTime(), duration, txPower, br)); // build a copy of the frame in front of the queue' frame->setSrcAddr(myMacAddr); frame->setKind(DATA); frame->setDuration(SIFS + packetDuration(LENGTH_ACK, br)); // schedule time out scheduleAt(simTime() + timeOut(DATA, br), timeout); debugEV << "sending DATA to " << frame->getDestAddr() << " with bitrate " << br << endl; // send DATA frame sendDown(frame); // update state and display setState(WFACK); }
void Mac80211::sendRTSframe | ( | ) | [protected, virtual] |
send RTS frame
Send a RTS frame.Called by handleContentionTimer()
References createSignal(), fromUpperLayer, packetDuration(), retrieveBitrate(), BaseLayer::sendDown(), BaseMacLayer::setDownControlInfo(), setState(), timeOut(), timeout, and txPower.
Referenced by handleEndContentionTimer().
{ Mac80211Pkt *frame = new Mac80211Pkt("wlan-rts"); const Mac80211Pkt* frameToSend = fromUpperLayer.front(); double br = retrieveBitrate(frameToSend->getDestAddr()); setDownControlInfo(frame, createSignal(simTime(),packetDuration(LENGTH_RTS, br), txPower, br)); frame->setKind(RTS); frame->setBitLength((int)LENGTH_RTS); // the src adress and dest address are copied in the frame in the queue (frame to be sent) frame->setSrcAddr(frameToSend->getSrcAddr()); frame->setDestAddr(frameToSend->getDestAddr()); double packetSize = frameToSend->getBitLength(); frame->setDuration(3 * SIFS + packetDuration(LENGTH_CTS, br) + packetDuration(packetSize, br) + packetDuration(LENGTH_ACK, br)); debugEV << " Mac80211::sendRTSframe duration: " << packetDuration(LENGTH_RTS, br) << " br: " << br << "\n"; // schedule time-out scheduleAt(simTime() + timeOut(RTS, br), timeout); // send RTS frame sendDown(frame); // update state and display setState(WFCTS); }
void Mac80211::senseChannelWhileIdle | ( | simtime_t_cref | duration | ) | [protected] |
Starts a channel sense request which sense the channel for the passed duration or until the channel is busy.
Used during contend state to check if the channel is free.
References chSenseStart, contention, and BaseLayer::sendControlDown().
Referenced by beginNewCycle(), and initialize().
{ if(contention->isScheduled()) { error("Cannot start a new channel sense request because already sensing the channel!"); } chSenseStart = simTime(); contention->setSenseTimeout(duration); sendControlDown(contention); }
void Mac80211::testMaxAttempts | ( | ) | [protected] |
Test if maximum number of retries to transmit is exceeded.
Test if the maximal retry limit is reached, and delete the frame to send in this case.
References fromUpperLayer, longRetryCounter, BaseMacLayer::PACKET_DROPPED, BaseLayer::sendControlUp(), and shortRetryCounter.
Referenced by beginNewCycle().
{ if ((longRetryCounter >= LONG_RETRY_LIMIT) || (shortRetryCounter >= SHORT_RETRY_LIMIT)) { debugEV << "retry limit reached src: "<< shortRetryCounter << " lrc: " << longRetryCounter << endl; // initialize counter longRetryCounter = 0; shortRetryCounter = 0; // delete the frame to transmit Mac80211Pkt *temp = fromUpperLayer.front(); fromUpperLayer.pop_front(); temp->setName("MAC ERROR"); temp->setKind(PACKET_DROPPED); sendControlUp(temp); } }
simtime_t Mac80211::timeOut | ( | Mac80211MessageKinds | type, |
double | br | ||
) | [protected] |
return a timeOut value for a certain type of frame
Return a time-out value for a type of frame. Called by SendRTSframe, sendCTSframe, etc.
References delta, fromUpperLayer, and packetDuration().
Referenced by sendDATAframe(), and sendRTSframe().
{ simtime_t time_out = 0; switch (type) { case RTS: time_out = SIFS + packetDuration(LENGTH_RTS, br) + ST + packetDuration(LENGTH_CTS, br) + delta; debugEV << " Mac80211::timeOut RTS " << time_out << "\n"; break; case DATA: time_out = SIFS + packetDuration(fromUpperLayer.front()->getBitLength(), br) + ST + packetDuration(LENGTH_ACK, br) + delta; debugEV << " Mac80211::timeOut DATA " << time_out << "\n"; break; default: EV << "Unused frame type was given when calling timeOut(), this should not happen!\n"; break; } return time_out; }
double Mac80211::defaultBitrate [protected] |
Default bitrate.
The default bitrate must be set in the omnetpp.ini. It is used whenever an auto bitrate is not appropriate, like broadcasts.
Referenced by initialize(), and retrieveBitrate().
int Mac80211::fsc [protected] |
sequence control -- to detect duplicates
Referenced by encapsMsg(), and initialize().
unsigned Mac80211::longRetryCounter [protected] |
Number of frame transmission attempt.
Incremented when the SHORT_RETRY_LIMIT is hit, or when an ACK or CTS is missing.
Referenced by backoff(), handleACKframe(), handleEndTransmission(), handleMsgNotForMe(), initialize(), retrieveBitrate(), and testMaxAttempts().
bool Mac80211::switching [protected] |
take care of switchover times
Referenced by handleBroadcastMsg(), handleMsgForMe(), and initialize().