INET Framework for OMNeT++/OMNEST
CSMAMacLayer.cc
Go to the documentation of this file.
00001 /* -*- mode:c++ -*- ********************************************************
00002  * file:        CSMAMacLayer.cc
00003  *
00004  * author:      Marc Loebbers, Yosia Hadisusanto
00005  *
00006  * copyright:   (C) 2004 Telecommunication Networks Group (TKN) at
00007  *              Technische Universitaet Berlin, Germany.
00008  *
00009  *              This program is free software; you can redistribute it
00010  *              and/or modify it under the terms of the GNU General Public
00011  *              License as published by the Free Software Foundation; either
00012  *              version 2 of the License, or (at your option) any later
00013  *              version.
00014  *              For further information see file COPYING
00015  *              in the top level directory
00016  ***************************************************************************
00017  * part of:     framework implementation developed by tkn
00018  ***************************************************************************/
00019 
00020 
00021 #include "CSMAMacLayer.h"
00022 #include "Ieee802Ctrl_m.h"
00023 #include "IInterfaceTable.h"
00024 #include "InterfaceTableAccess.h"
00025 
00026 
00027 Define_Module(CSMAMacLayer);
00028 
00029 
00030 CSMAMacLayer::CSMAMacLayer()
00031 {
00032     timer = NULL;
00033 }
00034 
00035 CSMAMacLayer::~CSMAMacLayer()
00036 {
00037     cancelAndDelete(timer);
00038 }
00039 
00040 void CSMAMacLayer::initialize(int stage)
00041 {
00042     WirelessMacBase::initialize(stage);
00043 
00044     if (stage == 0)
00045     {
00046         queueLength = hasPar("queueLength") ? (int)par("queueLength") : 0;
00047         EV << "queueLength = " << queueLength << endl;
00048 
00049         //subscribe for the information of the carrier sense
00050         nb->subscribe(this, NF_RADIOSTATE_CHANGED);
00051 
00052         // initialize the timer
00053         timer = new cMessage("backoff");
00054 
00055         radioState = RadioState::IDLE; // until 1st receiveChangeNotification()
00056 
00057         // get registered in IInterfaceTable
00058         registerInterface();
00059     }
00060 }
00061 
00062 void CSMAMacLayer::registerInterface()
00063 {
00064     InterfaceEntry *e = new InterfaceEntry();
00065 
00066     // interface name: NetworkInterface module's name without special characters ([])
00067     char *interfaceName = new char[strlen(getParentModule()->getFullName()) + 1];
00068     char *d = interfaceName;
00069     for (const char *s = getParentModule()->getFullName(); *s; s++)
00070         if (isalnum(*s))
00071             *d++ = *s;
00072     *d = '\0';
00073 
00074     e->setName(interfaceName);
00075     delete [] interfaceName;
00076 
00077     const char *addrstr = par("address");
00078     if (!strcmp(addrstr, "auto"))
00079     {
00080         // assign automatic address
00081         myMacAddr = MACAddress::generateAutoAddress();
00082 
00083         // change module parameter from "auto" to concrete address
00084         par("address").setStringValue(myMacAddr.str().c_str());
00085     }
00086     else
00087     {
00088         myMacAddr.setAddress(addrstr);
00089     }
00090     e->setMACAddress(myMacAddr);
00091 
00092     // generate interface identifier for IPv6
00093     e->setInterfaceToken(myMacAddr.formInterfaceIdentifier());
00094 
00095     // MTU on 802.11 = ?
00096     e->setMtu(1500);  // FIXME
00097 
00098     // capabilities
00099     e->setBroadcast(true);
00100     e->setMulticast(true);
00101     e->setPointToPoint(false);
00102 
00103     // add
00104     IInterfaceTable *ift = InterfaceTableAccess().get();
00105     ift->addInterface(e, this);
00106 }
00107 
00108 
00109 void CSMAMacLayer::finish()
00110 {
00111 }
00112 
00113 void CSMAMacLayer::handleCommand(cMessage *msg)
00114 {
00115     // no commands supported by CSMAMacLayer
00116     error("Non-packet message arrived from higher layer: (%s)%s", msg->getClassName(), msg->getName());
00117 }
00118 
00132 void CSMAMacLayer::handleUpperMsg(cPacket *msg)
00133 {
00134     MacPkt *mac = encapsMsg(msg);
00135 
00136     // message has to be queued if another message is waiting to be send
00137     // or if we are already trying to send another message
00138 
00139     // the comparison with sendTime is necessary so that concurrently
00140     // arriving messages are handled sequentially. As soon as one
00141     // message arrived at simTime() is passed to lower layers all other
00142     // messages arriving at the same time will be buffered.
00143     if (timer->isScheduled() || radioState == RadioState::TRANSMIT || sendTime == simTime())
00144     {
00145 
00146         // if there is no queue the message will be deleted
00147         if (queueLength == 0)
00148         {
00149             EV << "New packet arrived though another is still waiting for being sent, "
00150                 " and buffer size is zero. New packet is deleted.\n";
00151             // TODO: Signal this to upper layer!
00152             delete mac;
00153             return;
00154         }
00155 
00156         // the queue is not full yet so we can queue the message
00157         if (macQueue.length() < queueLength)
00158         {
00159             EV << "already transmitting, putting pkt into queue...\n";
00160             macQueue.insert(mac);
00161             return;
00162         }
00163         // queue is full, message has to be deleted
00164         else
00165         {
00166             EV << "New packet arrived, but queue is FULL, so new packet is deleted\n";
00167             // TODO: Signal this to upper layer!!
00168             delete mac;
00169             return;
00170         }
00171     }
00172 
00173     // no message is scheduled for sending or currently being sent
00174 
00175     // check the radio status and transmit the message if the channel is
00176     // idle. Otherwise backoff for a random time and try again
00177     if (radioState == RadioState::IDLE)
00178     {
00179         EV << "CHANNEL IDLE, send...\n";
00180         sendDown(mac);
00181         //store the sending time
00182         sendTime = simTime();
00183     }
00184     else
00185     {
00186         timer->setContextPointer(mac);
00187         simtime_t randomTime = intuniform(0, 10) / 100.0;
00188         scheduleAt(simTime() + randomTime, timer);
00189         EV << "CHANNEL BUSY, I will try to retransmit at " << simTime() + randomTime << ".\n";
00190     }
00191 
00192 }
00193 
00194 
00199 void CSMAMacLayer::handleSelfMsg(cMessage *msg)
00200 {
00201     EV << "timer expired, calling handleUpperMsg again.. time: " << simTime() << endl;
00202 
00203     // timer expired for a buffered frame, try to send again
00204     handleUpperMsg((MacPkt *) msg->getContextPointer());
00205 }
00206 
00207 
00213 void CSMAMacLayer::handleLowerMsg(cPacket *msg)
00214 {
00215     MacPkt *mac = check_and_cast<MacPkt *>(msg);
00216 
00217     //only foward to upper layer if message is for me or broadcast
00218     if (mac->getDestAddr() == myMacAddr || mac->getDestAddr().isBroadcast())
00219     {
00220         EV << "sending pkt to upper...\n";
00221         sendUp(mac);
00222     }
00223     else
00224     {
00225         EV << "packet not for me, deleting...\n";
00226         delete mac;
00227     }
00228 }
00229 
00234 MacPkt *CSMAMacLayer::encapsMsg(cPacket *netw)
00235 {
00236     MacPkt *pkt = new MacPkt(netw->getName());
00237     pkt->setBitLength(272);
00238 
00239     // copy dest address from the Control Info attached to the network
00240     // mesage by the network layer
00241     Ieee802Ctrl *ctrl = check_and_cast<Ieee802Ctrl *>(netw->removeControlInfo());
00242 
00243     EV << "ctrl removed, mac addr=" << ctrl->getDest() << endl;
00244     pkt->setDestAddr(ctrl->getDest());
00245 
00246     //delete the control info
00247     delete ctrl;
00248 
00249     //set the src address to own mac address
00250     pkt->setSrcAddr(myMacAddr);
00251 
00252     //encapsulate the network packet
00253     pkt->encapsulate(netw);
00254     EV << "pkt encapsulated\n";
00255 
00256     return pkt;
00257 }
00258 
00266 void CSMAMacLayer::receiveChangeNotification(int category, const cPolymorphic *details)
00267 {
00268     Enter_Method("receiveChangeNotification(%s, %s)", notificationCategoryName(category),
00269                  details?details->info().c_str() : "n/a");
00270     printNotificationBanner(category, details);
00271 
00272     if (category == NF_RADIOSTATE_CHANGED)
00273     {
00274         // update the local copy of the radio state
00275         radioState = check_and_cast<RadioState *>(details)->getState();
00276 
00277         // NOTE: we may be invoked during INIT STAGE 1 too, when SnrEval notifies us
00278         // about the initial radio state. This function has to work correctly
00279         // even when called during initialization phase!
00280 
00281         // if the channel is idle now, the queue is not empty and no timer
00282         // is scheduled, this means that sending the previous message is
00283         // complete and the next one can be taken out of the queue
00284         if (radioState == RadioState::IDLE && !macQueue.empty() && !timer->isScheduled())
00285         {
00286             timer->setContextPointer(macQueue.pop());
00287             simtime_t randomTime = intuniform(0, 10) / 100.0;
00288             scheduleAt(simTime() + randomTime, timer);
00289             EV << "taking next pkt out of queue, schedule at " << simTime() + randomTime << endl;
00290         }
00291     }
00292 }
00293 
00294