INET Framework for OMNeT++/OMNEST
Mac80211 Class Reference

An implementation of the 802.11b MAC. More...

#include <Mac80211.h>

Inheritance diagram for Mac80211:
WirelessMacBase INotifiable

List of all members.

Public Member Functions

 Mac80211 ()
virtual ~Mac80211 ()

Protected Member Functions

virtual int numInitStages () const
 Initialization of the module and some variables.
virtual void initialize (int)
 Initialization of the module and some variables.
virtual void registerInterface ()
 Register the interface in IInterfaceTable.
virtual void receiveChangeNotification (int category, const cPolymorphic *details)
 Called by the NotificationBoard whenever a change occurs we're interested in.
virtual void handleSelfMsg (cMessage *)
 Handle self messages such as timer...
virtual void handleUpperMsg (cPacket *)
 Handle packets from upper layer.
virtual void handleCommand (cMessage *)
 Handle commands from upper layer.
virtual void handleLowerMsg (cPacket *)
 Handle packets from lower layer.
virtual void handleEndContentionTimer ()
 handle end of contention
virtual void handleMsgNotForMe (Mac80211Pkt *)
 handle a message that is not for me or errornous
virtual void handleMsgForMe (Mac80211Pkt *)
 handle a message that was meant for me
virtual void handleBroadcastMsg (Mac80211Pkt *)
virtual void handleEndTransmissionTimer ()
 handle the end of a transmission...
virtual void handleEndSifsTimer ()
 handle end of SIFS
virtual void handleTimeoutTimer ()
 handle time out
virtual void handleNavTimer ()
 NAV timer expired, the exchange of messages of other stations is done.
virtual void handleRTSframe (Mac80211Pkt *)
virtual void handleDATAframe (Mac80211Pkt *)
virtual void handleACKframe (Mac80211Pkt *)
virtual void handleCTSframe (Mac80211Pkt *)
virtual void sendDATAframe ()
 send data frame
virtual void sendACKframe (Mac80211Pkt *)
 send Acknoledgement
virtual void sendCTSframe (Mac80211Pkt *)
 send CTS frame
virtual void sendRTSframe ()
 send RTS frame
virtual void sendBROADCASTframe ()
 send broadcast frame
virtual Mac80211Pkt * encapsMsg (cPacket *netw)
 encapsulate packet
virtual void decapsulateAndSendUp (Mac80211Pkt *frame)
 decapsulate packet and send to higher layer
virtual Mac80211Pkt * buildDATAframe ()
 build a data frame
virtual Mac80211Pkt * buildACKframe (Mac80211Pkt *)
 build an ACK
virtual Mac80211Pkt * buildCTSframe (Mac80211Pkt *)
 build a CTS frame
virtual Mac80211Pkt * buildRTSframe ()
 build an RTS frame
virtual Mac80211Pkt * buildBROADCASTframe ()
 build a broadcast frame
virtual void beginNewCycle ()
 start a new contention period
virtual simtime_t computeBackoff ()
 Compute a backoff value.
virtual int computeContentionWindow ()
 Compute a new contention window.
virtual void testMaxAttempts ()
 Test if maximum number of retries to transmit is exceeded.
virtual simtime_t computeTimeout (_802_11frameType type, simtime_t last_frame_duration)
 return a timeOut value for a certain type of frame
virtual simtime_t computePacketDuration (int bits)
 computes the duration of a transmission over the physical channel
virtual void setState (State state)
 Sets the state, and produces a log message in between.

Static Protected Member Functions

static const char * stateName (State state)
 Produce a readable name of the given state.
static const char * timerTypeName (int type)
 Produce a readable name of the given timer type.
static const char * pktTypeName (int type)
 Produce a readable name of the given packet type.

Protected Attributes

MACAddress myMacAddr
 mac address
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.
cMessage * contention
 Timer used for contention periods.
cMessage * endTransmission
 Timer used to indicate the end of the transmission of an ACK or a BROADCAST packet.
cMessage * endSifs
 Timer used to indicate the end of a SIFS.
simtime_t EIFS
 extended interframe space
simtime_t BW
 Variable to store the current backoff value.
State state
 Current state of the MAC.
RadioState::State radioState
 Current state of the radio (kept updated by receiveChangeNotification())
int maxQueueSize
 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.
int retryCounter
 Number of frame transmission attempt.
bool tryWithoutBackoff
 If there's a new packet to send and the channel is free, no backoff is needed.
bool rtsCts
 true if Rts/Cts is used, false if not; can be set in omnetpp.ini
simtime_t delta
 Very small value used in timer scheduling in order to avoid multiple changements of state in the same simulation time.
double bitrate
 The bitrate should be set in omnetpp.ini; be sure to use a valid 802.11 bitrate.
int broadcastBackoff
 Should be set in the omnetpp.ini.

Private Types

enum  timerType {
  TIMEOUT, NAV, CONTENTION, END_TRANSMISSION,
  END_SIFS
}
enum  State {
  WFDATA = 0, QUIET = 1, IDLE = 2, CONTEND = 3,
  WFCTS = 4, WFACK = 5, BUSY = 6
}
typedef std::list< Mac80211Pkt * > MacPktList

Detailed Description

An implementation of the 802.11b MAC.

For more info, see the NED file.

Author:
David Raguin

Member Typedef Documentation

typedef std::list<Mac80211Pkt*> Mac80211::MacPktList [private]

Member Enumeration Documentation

enum Mac80211::State [private]

Definition of the states

Enumerator:
WFDATA 
QUIET 
IDLE 
CONTEND 
WFCTS 
WFACK 
BUSY 
               {
      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 [private]

Definition of the timer types

Enumerator:
TIMEOUT 
NAV 
CONTENTION 
END_TRANSMISSION 
END_SIFS 

Constructor & Destructor Documentation

Mac80211::Mac80211 ( )
Mac80211::~Mac80211 ( ) [virtual]
{
    cancelAndDelete(timeout);
    cancelAndDelete(nav);
    cancelAndDelete(contention);
    cancelAndDelete(endTransmission);
    cancelAndDelete(endSifs);
}

Member Function Documentation

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().

Referenced by handleACKframe(), handleBroadcastMsg(), handleEndTransmissionTimer(), handleLowerMsg(), handleMsgNotForMe(), handleNavTimer(), handleTimeoutTimer(), and handleUpperMsg().

{
    EV << "beginning new contention cycle\n";

    // 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 (!fromUpperLayer.empty())
    {

        // look if the next packet is unicast or broadcast
        nextIsBroadcast = (((Mac80211Pkt *) fromUpperLayer.front())->getDestAddr().isBroadcast());

        // print("next is broadcast = "<<nextIsBroadcast);

        // if the channel is free then wait a random time and transmit
        if (radioState == RadioState::IDLE)
        {
            // if channel is idle AND I was not the last one that transmitted
            // data: no backoff
            if (tryWithoutBackoff)
            {
                EV << "trying to send without backoff...\n";
                scheduleAt(simTime() + DIFS, contention);
            }
            else
            {
                // backoff!
                scheduleAt(simTime() + computeBackoff() + DIFS, contention);
            }
        }
        tryWithoutBackoff = false;

        // else wait until the channel gets free; the state is now contend
        setState(CONTEND);
    }
    else
    {
        tryWithoutBackoff = false;
        setState(IDLE);
    }
}
Mac80211Pkt * Mac80211::buildACKframe ( Mac80211Pkt *  af) [protected, virtual]

build an ACK

Build an ACK frame. Called by sendACKframe()

Referenced by sendACKframe().

{
    Mac80211Pkt *frame = new Mac80211Pkt("wlan-ack");
    frame->setKind(ACK);
    frame->setBitLength(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);

    return frame;
}
Mac80211Pkt * Mac80211::buildBROADCASTframe ( ) [protected, virtual]

build a broadcast frame

Build a BROADCAST frame. Called sendBROADCASTframe()

Referenced by sendBROADCASTframe().

{
    // send a copy of the frame in front of the queue
    Mac80211Pkt *frame = (Mac80211Pkt *) (fromUpperLayer.front())->dup();
    frame->setKind(BROADCAST);
    return frame;
}
Mac80211Pkt * Mac80211::buildCTSframe ( Mac80211Pkt *  af) [protected, virtual]

build a CTS frame

Build a CTS frame. Called by sendCTSframe()

Referenced by sendCTSframe().

{
    Mac80211Pkt *frame = new Mac80211Pkt("wlan-cts");
    frame->setKind(CTS);
    frame->setBitLength(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 - computePacketDuration(LENGTH_CTS));

    return frame;
}
Mac80211Pkt * Mac80211::buildDATAframe ( ) [protected, virtual]

build a data frame

Build a DATA frame. Called by sendDATAframe()

Referenced by sendDATAframe().

{
    // build a copy of the frame in front of the queue
    Mac80211Pkt *frame = (Mac80211Pkt *) (fromUpperLayer.front())->dup();
    frame->setSrcAddr(myMacAddr);
    frame->setKind(DATA);
    if (rtsCts)
        frame->setDuration(SIFS + computePacketDuration(LENGTH_ACK));
    else
        frame->setDuration(0);

    return frame;
}
Mac80211Pkt * Mac80211::buildRTSframe ( ) [protected, virtual]

build an RTS frame

Build a RTS frame. Called by sendRTSframe()

Referenced by sendRTSframe().

{
    Mac80211Pkt *frame = new Mac80211Pkt("wlan-rts");
    frame->setKind(RTS);
    frame->setBitLength(LENGTH_RTS);

    // the src adress and dest address are copied in the frame in the queue (frame to be sent)
    frame->setSrcAddr(((Mac80211Pkt *) fromUpperLayer.front())->getSrcAddr());
    frame->setDestAddr(((Mac80211Pkt *) fromUpperLayer.front())->getDestAddr());
    frame->setDuration(3 * SIFS + computePacketDuration(LENGTH_CTS) +
                       computePacketDuration(fromUpperLayer.front()->getBitLength()) +
                       computePacketDuration(LENGTH_ACK));

    return frame;
}
simtime_t Mac80211::computeBackoff ( ) [protected, virtual]

Compute a backoff value.

Compute the backoff value.

Referenced by beginNewCycle(), and handleMsgNotForMe().

{
    // the MAC has won the previous contention. We have to compute a new
    // backoff window
    if (BW == 0) {
        int CW = computeContentionWindow();
        EV << "generating backoff for CW: " << CW << endl;
        BW = intrand(CW + 1) * ST;
    }
    // CW is the contention window (see the function). ST is the
    // slot time.  else we take the old value of BW, in order to give a
    // bigger priority to a node which has lost a previous contention
    // period.
    EV << "backing off for: " << BW + DIFS << endl;
    return BW;
}
int Mac80211::computeContentionWindow ( ) [protected, virtual]

Compute a new contention window.

Compute the contention window with the binary backoff algorithm. Use the variable counter (attempts to transmit packet), the constant values CWmax (contention window maximum) and m (parameter for the initial backoff window, usally m=7). Called by computeBackoff()

Referenced by computeBackoff().

{
    // the next packet is an unicast packet
    if (!nextIsBroadcast)
    {
        int cw = (CW_MIN + 1) * (1 << (retryCounter - 1)) - 1;
        // return the calculated value or CWmax if the maximal value is reached
        if (cw <= CW_MAX)
            return cw;
        else
            return CW_MAX;
    }

    // the next packet is broadcast : the contention window must be maximal
    else
        return broadcastBackoff;
}
simtime_t Mac80211::computePacketDuration ( int  bits) [protected, virtual]

computes the duration of a transmission over the physical channel

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.

Referenced by buildCTSframe(), buildDATAframe(), buildRTSframe(), computeTimeout(), initialize(), sendACKframe(), and sendBROADCASTframe().

{
    return bits / bitrate + PHY_HEADER_LENGTH / BITRATE_HEADER;
}
simtime_t Mac80211::computeTimeout ( _802_11frameType  type,
simtime_t  last_frame_duration 
) [protected, virtual]

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.

Referenced by sendCTSframe(), sendDATAframe(), and sendRTSframe().

{
    simtime_t time_out = 0;
    switch (type)
    {
    case RTS:
        time_out = SIFS + computePacketDuration(LENGTH_RTS) + computePacketDuration(LENGTH_CTS) + delta;
        break;
    case CTS:
        time_out = last_frame_duration - computePacketDuration(LENGTH_ACK) - 2 * SIFS + delta;
        break;
    case DATA:
        time_out =
            SIFS + computePacketDuration(fromUpperLayer.front()->getBitLength()) + computePacketDuration(LENGTH_ACK) +
            delta + 0.1;
        //XXX: I have added some time here, because propagation delay of AirFrames caused problems
        // the timeout periods should be carefully revised with special care for the deltas?! --Levy
        break;
    default:
        EV << "Unused frame type was given when calling computeTimeout(), this should not happen!\n";
    }
    return time_out;
}
void Mac80211::decapsulateAndSendUp ( Mac80211Pkt *  frame) [protected, virtual]

decapsulate packet and send to higher layer

Referenced by handleBroadcastMsg(), and handleDATAframe().

{
    cPacket *msg = frame->decapsulate();
    // FIXME TBD set control info
    delete frame;
    sendUp(msg);
}
Mac80211Pkt * Mac80211::encapsMsg ( cPacket *  netw) [protected, virtual]

encapsulate packet

Encapsulates the received network-layer packet into a MacPkt and set all needed header fields.

Referenced by handleUpperMsg().

{
    Mac80211Pkt *pkt = new Mac80211Pkt(netw->getName());
    pkt->setBitLength(272);        // headerLength, including final CRC-field

    // copy dest address from the control info
    Ieee802Ctrl *ctrl = check_and_cast<Ieee802Ctrl *>(netw->removeControlInfo());
    pkt->setDestAddr(ctrl->getDest());
    delete ctrl;

    // set the src address to own mac address (nic module getId())
    pkt->setSrcAddr(myMacAddr);

    // encapsulate the network packet
    pkt->encapsulate(netw);

    return pkt;
}
void Mac80211::handleACKframe ( Mac80211Pkt *  af) [protected, virtual]

Handle a frame which is expected to be an ACK.Called by HandleMsgForMe(MAcawFrame* af)

Referenced by handleMsgForMe().

{
    EV << "handling Ack frame\n";

    // cancel time-out event
    cancelEvent(timeout);

    // the transmission is acknowledged : initialize long_retry_counter
    retryCounter = 1;

    // 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, virtual]

Handle a broadcast packet. This packet is simply passed to the upper layer. No acknowledgement is needed. Called by handleLowerMsg(Mac80211Pkt *af)

Referenced by handleLowerMsg().

{
    EV << "handle broadcast\n";
    if (state == BUSY)
        error("logic error: node is currently transmitting, can not receive "
              "(does the physical layer do its job correctly?)");

    decapsulateAndSendUp(af);
    if (state == CONTEND)
        beginNewCycle();
}
void Mac80211::handleCommand ( cMessage *  msg) [protected, virtual]

Handle commands from upper layer.

Implements WirelessMacBase.

{
    // no commands supported by Mac80211
    error("Non-packet message arrived from higher layer: (%s)%s", msg->getClassName(), msg->getName());
}
void Mac80211::handleCTSframe ( Mac80211Pkt *  af) [protected, virtual]

Handle a CTS frame. Called by HandleMsgForMe(Mac80211Pkt* af)

Referenced by handleMsgForMe().

{
    // cancel time-out event
    cancelEvent(timeout);

    // wait a short interframe space
    endSifs->setContextPointer(af);
    scheduleAt(simTime() + SIFS, endSifs);
}
void Mac80211::handleDATAframe ( Mac80211Pkt *  af) [protected, virtual]

Handle a frame which expected to be a DATA frame. Called by HandleMsgForMe()

Referenced by handleMsgForMe().

{
    if (rtsCts)
        cancelEvent(timeout);  // cancel time-out event

    // make a copy
    Mac80211Pkt *copy = (Mac80211Pkt *) af->dup();

    // pass the packet to the upper layer
    decapsulateAndSendUp(af);

    // wait a short interframe space
    endSifs->setContextPointer(copy);
    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

Referenced by handleSelfMsg().

{
    EV << "end contention period\n";

    if (state != CONTEND)
        error("logic error: expiration of the contention timer outside of CONTEND state, should not happen");

    // the node has won the channel, the backoff window is deleted and
    // will be new calculated in the next contention period
    BW = 0;
    // unicast packet
    if (!nextIsBroadcast)
    {
        if (rtsCts)
        {
            // send a RTS
            sendRTSframe();
            setState(WFCTS);
        }
        else
        {
            sendDATAframe();
            setState(WFACK);
        }

        // broadcast packet
    }
    else
    {
        sendBROADCASTframe();

        // removes the packet from the queue without waiting for an acknowledgement
        Mac80211Pkt *temp = fromUpperLayer.front();
        fromUpperLayer.pop_front();
        delete(temp);
    }
}
void Mac80211::handleEndSifsTimer ( ) [protected, virtual]

handle end of SIFS

Handle the end sifs timer. Then sends a CTS, a DATA, or an ACK frame

Referenced by handleSelfMsg().

{
    Mac80211Pkt *frame = (Mac80211Pkt *) endSifs->getContextPointer();

    switch (frame->getKind())
    {
    case RTS:
        sendCTSframe(frame);
        break;
    case CTS:
        sendDATAframe();
        break;
    case DATA:
        sendACKframe(frame);
        break;
    default:
        error("logic error: end sifs timer when previously received packet is not RTS/CTS/DATA");
    }

    // don't need previous frame any more
    delete frame;
}
void Mac80211::handleEndTransmissionTimer ( ) [protected, virtual]

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)

Referenced by handleSelfMsg().

{
    EV << "transmission of ACK/BROADCAST is over\n";
    if (state != BUSY)
        error("logic error: expiration of the end transmission timer outside the BUSY state, should not happen");

    // if there's a packet to send and if the channel is free, then start a new contention period
    beginNewCycle();
}
void Mac80211::handleLowerMsg ( cPacket *  msg) [protected, virtual]

Handle packets 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().

Implements WirelessMacBase.

{
    Mac80211Pkt *af = check_and_cast<Mac80211Pkt *>(msg);

    // end of the reception
    EV << "frame " << af << " received, kind = " << pktTypeName(af->getKind()) << "\n";

    switch (af->getKind())
    {
    case COLLISION: // packet lost or bit error
        delete af;
        if (state == CONTEND)
            beginNewCycle();
        break;

    case BITERROR:
        handleMsgNotForMe(af);
        break;

    case BROADCAST: // broadcast packet
        handleBroadcastMsg(af);
        break;

    default: // other packet
        if (af->getDestAddr() == myMacAddr)  // FIXME verify broadcast dest addr works!
            handleMsgForMe(af);
        else
            handleMsgNotForMe(af);
    }
}
void Mac80211::handleMsgForMe ( Mac80211Pkt *  af) [protected, virtual]

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()

Referenced by handleLowerMsg().

{
    EV << "handle msg for me in state = " << stateName(state) << " with type = " << pktTypeName(af->getKind()) << "\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)
            handleRTSframe(af);
        else if (af->getKind() == DATA)
            handleDATAframe(af);
        else
            // TODO: what if a late ACK has arrived?
            EV << "in handleMsgForMe() IDLE/CONTEND, strange message, darf das?\n";
        break;

    case WFDATA:  // waiting for DATA

        if (af->getKind() == DATA)
            handleDATAframe(af);
        else
            EV << "in handleMsgForMe() WFDATA, strange message, darf das?\n";
        break;

    case WFACK:  // waiting for ACK

        if (af->getKind() == ACK)
            handleACKframe(af);
        else
            EV << "in handleMsgForMe() WFACK, strange message, darf das?\n";
        delete af;
        break;

    case WFCTS:  // The MAC is waiting for CTS

        if (af->getKind() == CTS)
            handleCTSframe(af);
        else
            EV << "in handleMsgForMe() WFCTS, strange message, darf das?\n";
        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
        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);
    }
}
void Mac80211::handleMsgNotForMe ( Mac80211Pkt *  af) [protected, virtual]

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()

Referenced by handleLowerMsg().

{
    EV << "handle msg not for me\n";

    // if this packet  can not be correctly read
    if (af->getKind() == BITERROR)
        af->setDuration(EIFS);

    // if the duration of the packet is null, then do nothing (to avoid
    // the unuseful scheduling of a self message)
    if (af->getDuration() != 0)
    {

        // the node is already deferring
        if (state == QUIET)
        {
            // the current value of the NAV is not sufficient
            if (nav->getArrivalTime() < simTime() + af->getDuration())
            {
                cancelEvent(nav);
                scheduleAt(simTime() + af->getDuration(), nav);
                EV << "NAV timer started for: " << af->getDuration() << " 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);

            // is state == WFCTS or WFACK, the data transfer has failed ...

            // the node must defer for the time of the transmission
            scheduleAt(simTime() + af->getDuration(), nav);
            EV << "NAV timer started, not QUIET: " << af->getDuration() << endl;
            setState(QUIET);

        }
    }
    if (!rtsCts)
    {                           // todo: Nachgucken: was passiert bei Error ohne rtsCts!
        if (state == CONTEND)
        {
            if (af->getKind() == BITERROR)
            {
                if (contention->isScheduled())
                    cancelEvent(contention);
                scheduleAt(simTime() + computeBackoff() + EIFS, contention);
            }
            else
                beginNewCycle();
        }
    }
    delete af;
}
void Mac80211::handleNavTimer ( ) [protected, virtual]

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)

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
    beginNewCycle();
}
void Mac80211::handleRTSframe ( Mac80211Pkt *  af) [protected, virtual]

Handle aframe wich is expected to be an RTS. Called by HandleMsgForMe()

Referenced by handleMsgForMe().

{
    // wait a short interframe space
    endSifs->setContextPointer(af);
    scheduleAt(simTime() + SIFS, endSifs);
}
void Mac80211::handleSelfMsg ( cMessage *  msg) [protected, virtual]

Handle self messages such as timer...

handle timers

Implements WirelessMacBase.

{
    EV << "processing self message with type = " << timerTypeName(msg->getKind()) << endl;

    switch (msg->getKind())
    {
    case END_SIFS:
        handleEndSifsTimer();   // noch zu betrachten
        break;

    case END_TRANSMISSION:
        handleEndTransmissionTimer();   // noch zu betrachten
        break;

    case CONTENTION:
        handleEndContentionTimer();
        break;

        // 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");
    }
}
void Mac80211::handleTimeoutTimer ( ) [protected, virtual]

handle time out

Handle the time out timer. Called by handleTimer(cMessage* msg)

Referenced by handleSelfMsg().

{
    // if (state == WFCTS || state == WFACK)testMaxAttempts();

    // 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 ( cPacket *  msg) [protected, virtual]

Handle packets from upper layer.

This implementation does not support fragmentation, so it is tested if the maximum length of the MPDU is exceeded.

Implements WirelessMacBase.

{
    if (msg->getByteLength() > 2312)
        error("packet from higher layer (%s)%s is too long for 802.11b, %d bytes (fragmentation is not supported yet)",
              msg->getClassName(), msg->getName(), (int)(msg->getByteLength()));

    if (maxQueueSize && (int)fromUpperLayer.size() == maxQueueSize)
    {
        EV << "packet " << msg << " received from higher layer but MAC queue is full, deleting\n";
        delete msg;
        return;
    }

    Mac80211Pkt *mac = encapsMsg(msg);
    EV << "packet " << msg << " 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())
    {
        tryWithoutBackoff = true;
        beginNewCycle();
    }
    else
    {
        EV << "enqueued, will be transmitted later\n";
    }
}
void Mac80211::initialize ( int  stage) [protected, virtual]

Initialization of the module and some variables.

Reimplemented from WirelessMacBase.

{
    WirelessMacBase::initialize(stage);

    if (stage == 0)
    {
        EV << "Initializing stage 0\n";
        maxQueueSize = par("maxQueueSize");

        // subscribe for the information of the carrier sense
        nb->subscribe(this, NF_RADIOSTATE_CHANGED);

        // timers
        timeout = new cMessage("timeout", TIMEOUT);
        nav = new cMessage("NAV", NAV);
        contention = new cMessage("contention", CONTENTION);
        endTransmission = new cMessage("transmission", END_TRANSMISSION);
        endSifs = new cMessage("end SIFS", END_SIFS);

        BW = 0;
        state = IDLE;
        retryCounter = 1;
        broadcastBackoff = par("broadcastBackoff");
        rtsCts = par("rtsCts");
        bitrate = par("bitrate");
        delta = 1E-9; //XXX it's rather "epsilon", but this delta business looks a bit dodgy a solution anyway

        radioState = RadioState::IDLE; // until 1st receiveChangeNotification()

        EIFS = SIFS + DIFS + computePacketDuration(LENGTH_ACK);
        EV << "SIFS: " << SIFS << " DIFS: " << DIFS << " EIFS: " << EIFS << endl;

        // get registered in IInterfaceTable
        registerInterface();

        WATCH(state);
        WATCH(radioState);
    }
}
virtual int Mac80211::numInitStages ( ) const [inline, protected, virtual]

Initialization of the module and some variables.

{return 2;}
const char * Mac80211::pktTypeName ( int  type) [static, protected]

Produce a readable name of the given packet type.

Referenced by handleLowerMsg(), and handleMsgForMe().

{
#define CASE(x) case x: s=#x; break
    const char *s = "???";
    switch (type)
    {
        CASE(TIMEOUT);
        CASE(DATA);
        CASE(BROADCAST);
        CASE(RTS);
        CASE(CTS);
        CASE(ACK);
        CASE(ACKRTS);
        CASE(BEGIN_RECEPTION);
        CASE(BITERROR);
        CASE(COLLISION);
    }
    return s;
#undef CASE
}
void Mac80211::receiveChangeNotification ( int  category,
const cPolymorphic *  details 
) [protected, virtual]

Called by the NotificationBoard whenever a change occurs we're interested in.

Handle change nofitications. In this layer it is usually information about the radio channel, i.e. if it is IDLE etc.

Implements INotifiable.

{
    Enter_Method("receiveChangeNotification(%s, %s)", notificationCategoryName(category),
                 details?details->info().c_str() : "n/a");
    printNotificationBanner(category, details);

    if (category == NF_RADIOSTATE_CHANGED)
    {
        // update the local copy of the radio state
        radioState = check_and_cast<RadioState *>(details)->getState();

        // NOTE: we may be invoked during INIT STAGE 1 too, when SnrEval notifies us
        // about the initial radio state. This function has to work correctly
        // even when called during initialization phase!

        EV << "** Radio state update in " << getClassName() << ": " << details->info()
           << " (at T=" << simTime() << ")\n";

        // beginning of a reception
        if (radioState == RadioState::RECV)
        {
            // if there's a contention period
            if (contention->isScheduled())
            {
                // update the backoff window in order to give higher priority in
                // the next battle
                if (simTime() - contention->getSendingTime() >= DIFS)
                {
                    BW = contention->getArrivalTime() - simTime();
                    EV << "Backoff window made smaller, new BW: " << BW << endl;
                }
                cancelEvent(contention);
            }

            // if there's a SIFS period
            if (endSifs->isScheduled())
            {
                // delete the previously received frame
                delete (Mac80211Pkt *)endSifs->getContextPointer();

                // cancel the next transmission
                cancelEvent(endSifs);

                // state in now IDLE or CONTEND
                if (fromUpperLayer.empty())
                    setState(IDLE);
                else
                    setState(CONTEND);
            }
        }
    }
}
void Mac80211::registerInterface ( ) [protected, virtual]

Register the interface in IInterfaceTable.

Referenced by initialize().

{
    InterfaceEntry *e = new InterfaceEntry();

    // interface name: NetworkInterface module's name without special characters ([])
    char *interfaceName = new char[strlen(getParentModule()->getFullName()) + 1];
    char *d = interfaceName;
    for (const char *s = getParentModule()->getFullName(); *s; s++)
        if (isalnum(*s))
            *d++ = *s;
    *d = '\0';

    e->setName(interfaceName);
    delete [] interfaceName;

    const char *addrstr = par("address");
    if (!strcmp(addrstr, "auto"))
    {
        // assign automatic address
        myMacAddr = MACAddress::generateAutoAddress();

        // change module parameter from "auto" to concrete address
        par("address").setStringValue(myMacAddr.str().c_str());
    }
    else
    {
        myMacAddr.setAddress(addrstr);
    }
    e->setMACAddress(myMacAddr);

    // generate interface identifier for IPv6
    e->setInterfaceToken(myMacAddr.formInterfaceIdentifier());

    // MTU on 802.11 = ?
    e->setMtu(par("mtu"));            // FIXME

    // capabilities
    e->setBroadcast(true);
    e->setMulticast(true);
    e->setPointToPoint(false);

    // add
    IInterfaceTable *ift = InterfaceTableAccess().get();
    ift->addInterface(e, this);
}
void Mac80211::sendACKframe ( Mac80211Pkt *  af) [protected, virtual]

send Acknoledgement

Send an ACK frame.Called by HandleEndSifsTimer()

Referenced by handleEndSifsTimer().

{
    // the MAC must wait the end of the transmission before beginning an
    // other contention period
    scheduleAt(simTime() + computePacketDuration(LENGTH_ACK) + delta, endTransmission);

    // send ACK frame
    sendDown(buildACKframe(af));
    EV << "sent ACK frame!\n";

    // update state and display
    setState(BUSY);
}
void Mac80211::sendBROADCASTframe ( ) [protected, virtual]

send broadcast frame

Send a BROADCAST frame.Called by handleContentionTimer()

Referenced by handleEndContentionTimer().

{
    // the MAC must wait the end of the transmission before beginning any
    // other contention period
    scheduleAt(simTime() + computePacketDuration(fromUpperLayer.front()->getBitLength()), endTransmission);
    // send ACK frame
    sendDown(buildBROADCASTframe());

    // update state and display
    setState(BUSY);
}
void Mac80211::sendCTSframe ( Mac80211Pkt *  af) [protected, virtual]

send CTS frame

Send a CTS frame.Called by HandleEndSifsTimer()

Referenced by handleEndSifsTimer().

{
    // schedule time-out
    scheduleAt(simTime() + computeTimeout(CTS, af->getDuration()), timeout);

    // send CTS frame
    sendDown(buildCTSframe(af));

    // update state and display
    setState(WFDATA);
}
void Mac80211::sendDATAframe ( ) [protected, virtual]

send data frame

Send a DATA frame. Called by HandleEndSifsTimer() or handleEndContentionTimer()

Referenced by handleEndContentionTimer(), and handleEndSifsTimer().

{
    EV << "sending data frame\n";

    // schedule time out
    scheduleAt(simTime() + computeTimeout(DATA, 0), timeout);

    if (!rtsCts)
        // retryCounter incremented
        retryCounter++;

    // send DATA frame
    sendDown(buildDATAframe());

    // update state and display
    setState(WFACK);
}
void Mac80211::sendRTSframe ( ) [protected, virtual]

send RTS frame

Send a RTS frame.Called by handleContentionTimer()

Referenced by handleEndContentionTimer().

{
    // schedule time-out
    scheduleAt(simTime() + computeTimeout(RTS, 0), timeout);

    // long_retry_counter incremented
    retryCounter++;

    // send RTS frame
    sendDown(buildRTSframe());

    // update state and display
    setState(WFCTS);
}
void Mac80211::setState ( State  state) [protected, virtual]

Sets the state, and produces a log message in between.

Referenced by beginNewCycle(), handleEndContentionTimer(), handleMsgNotForMe(), receiveChangeNotification(), sendACKframe(), sendBROADCASTframe(), sendCTSframe(), sendDATAframe(), and sendRTSframe().

{
    if (state==newState)
        EV << "staying in state " << stateName(state) << "\n";
    else
        EV << "state " << stateName(state) << " --> " << stateName(newState) << "\n";
    state = newState;
}
const char * Mac80211::stateName ( State  state) [static, protected]

Produce a readable name of the given state.

Referenced by handleMsgForMe(), and setState().

{
#define CASE(x) case x: s=#x; break
    const char *s = "???";
    switch (state)
    {
        CASE(WFDATA);
        CASE(QUIET);
        CASE(IDLE);
        CASE(CONTEND);
        CASE(WFCTS);
        CASE(WFACK);
        CASE(BUSY);
    }
    return s;
#undef CASE
}
void Mac80211::testMaxAttempts ( ) [protected, virtual]

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.

Referenced by beginNewCycle().

{
    if (retryCounter > RETRY_LIMIT)
    {
        // initialize counter
        retryCounter = 1;
        // reportLost(fromUpperLayer.front());

        // delete the frame to transmit
        Mac80211Pkt *temp = fromUpperLayer.front();
        fromUpperLayer.pop_front();
        delete(temp);
    }
}
const char * Mac80211::timerTypeName ( int  type) [static, protected]

Produce a readable name of the given timer type.

Referenced by handleSelfMsg().

{
#define CASE(x) case x: s=#x; break
    const char *s = "???";
    switch (type)
    {
        CASE(TIMEOUT);
        CASE(NAV);
        CASE(CONTENTION);
        CASE(END_TRANSMISSION);
        CASE(END_SIFS);
    }
    return s;
#undef CASE
}

Member Data Documentation

double Mac80211::bitrate [protected]

The bitrate should be set in omnetpp.ini; be sure to use a valid 802.11 bitrate.

Referenced by computePacketDuration(), and initialize().

int Mac80211::broadcastBackoff [protected]

Should be set in the omnetpp.ini.

Referenced by computeContentionWindow(), and initialize().

simtime_t Mac80211::BW [protected]

Variable to store the current backoff value.

Referenced by computeBackoff(), handleEndContentionTimer(), initialize(), and receiveChangeNotification().

cMessage* Mac80211::contention [protected]

Timer used for contention periods.

Referenced by beginNewCycle(), handleMsgNotForMe(), initialize(), Mac80211(), receiveChangeNotification(), and ~Mac80211().

simtime_t Mac80211::delta [protected]

Very small value used in timer scheduling in order to avoid multiple changements of state in the same simulation time.

Referenced by computeTimeout(), initialize(), and sendACKframe().

simtime_t Mac80211::EIFS [protected]

extended interframe space

Referenced by handleMsgNotForMe(), and initialize().

cMessage* Mac80211::endTransmission [protected]

Timer used to indicate the end of the transmission of an ACK or a BROADCAST packet.

Referenced by initialize(), Mac80211(), sendACKframe(), sendBROADCASTframe(), and ~Mac80211().

int Mac80211::maxQueueSize [protected]

Maximal number of packets in the queue; should be set in the omnetpp.ini.

Referenced by handleUpperMsg(), and initialize().

cMessage* Mac80211::nav [protected]

Timer used for the defer time of a node. Also called NAV : networks allocation vector.

Referenced by handleMsgNotForMe(), initialize(), Mac80211(), and ~Mac80211().

bool Mac80211::nextIsBroadcast [protected]

Boolean used to know if the next packet is a broadcast packet.

Referenced by beginNewCycle(), computeContentionWindow(), and handleEndContentionTimer().

Current state of the radio (kept updated by receiveChangeNotification())

Referenced by beginNewCycle(), initialize(), and receiveChangeNotification().

int Mac80211::retryCounter [protected]

Number of frame transmission attempt.

Referenced by computeContentionWindow(), handleACKframe(), initialize(), sendDATAframe(), sendRTSframe(), and testMaxAttempts().

bool Mac80211::rtsCts [protected]

true if Rts/Cts is used, false if not; can be set in omnetpp.ini

Referenced by buildDATAframe(), handleDATAframe(), handleEndContentionTimer(), handleMsgNotForMe(), initialize(), and sendDATAframe().

cMessage* Mac80211::timeout [protected]

Timer used for time-outs after the transmission of a RTS, a CTS, or a DATA packet.

Referenced by handleACKframe(), handleCTSframe(), handleDATAframe(), handleMsgNotForMe(), initialize(), Mac80211(), sendCTSframe(), sendDATAframe(), sendRTSframe(), and ~Mac80211().

bool Mac80211::tryWithoutBackoff [protected]

If there's a new packet to send and the channel is free, no backoff is needed.

Referenced by beginNewCycle(), and handleUpperMsg().


The documentation for this class was generated from the following files: