|
INET Framework for OMNeT++/OMNEST
|
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