/* * mac-simple.cc * Copyright (C) 2003 by the University of Southern California * $Id: mac-simple.cc,v 1.7 2005/09/21 20:52:46 haldar Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * * The copyright of this module includes the following * linking-with-specific-other-licenses addition: * * In addition, as a special exception, the copyright holders of * this module give you permission to combine (via static or * dynamic linking) this module with free software programs or * libraries that are released under the GNU LGPL and with code * included in the standard release of ns-2 under the Apache 2.0 * license or under otherwise-compatible licenses with advertising * requirements (or modified versions of such code, with unchanged * license). You may copy and distribute such a system following the * terms of the GNU GPL for this module and the licenses of the * other code concerned, provided that you include the source code of * that other code when and as the GNU GPL requires distribution of * source code. * * Note that people who make modified versions of this module * are not obligated to grant this special exception for their * modified versions; it is their choice whether to do so. The GNU * General Public License gives permission to release a modified * version without this exception; this exception also makes it * possible to release a modified version which carries forward this * exception. * */ #include "ll.h" #include "mac.h" #include "macng.h" #include "random.h" // Added by Sushmita to support event tracing (singal@nunki.usc.edu) #include "agent.h" #include "basetrace.h" #include "cmu-trace.h" //carmen #include "mobilenode.h" #include "packet.h" #define negotiatebased static class MacngClass : public TclClass { public: MacngClass() : TclClass("Mac/Macng") {} TclObject* create(int, const char*const*) { return new Macng(); } } class_Macng; // Added by Sushmita to support event tracing (singal@nunki.usc.edu). void Macng::trace_event(char *eventtype, Packet *p) { if (et_ == NULL) return; char *wrk = et_->buffer(); char *nwrk = et_->nbuffer(); hdr_ip *iph = hdr_ip::access(p); char *src_nodeaddr = Address::instance().print_nodeaddr(iph->saddr()); char *dst_nodeaddr = Address::instance().print_nodeaddr(iph->daddr()); if (wrk != 0) { sprintf(wrk, "E -t "TIME_FORMAT" %s %s %s", et_->round(Scheduler::instance().clock()), eventtype, src_nodeaddr, dst_nodeaddr); } if (nwrk != 0) { sprintf(nwrk, "E -t "TIME_FORMAT" %s %s %s", et_->round(Scheduler::instance().clock()), eventtype, src_nodeaddr, dst_nodeaddr); } et_->dump(); } Macng::Macng() : Mac() { rx_state_ = tx_state_ = MAC_IDLE; tx_active_ = 0; waitTimer = new MacngWaitTimer(this); sendTimer = new MacngSendTimer(this); recvTimer = new MacngRecvTimer(this); //C.A.R.MEN broadcastTimer = new MacngBroadCastTimer(this); // Added by Sushmita to support event tracing (singal@nunki.usc.edu) et_ = new EventTrace(); busy_ = 0; bind("fullduplex_mode_", &fullduplex_mode_); broadcastTimer->start(Random::uniform()); for(int i=0;i<100;i++){ ChannelUsage[i]=65535; } } // Added by Sushmita to support event tracing (singal@nunki.usc.edu) int Macng::command(int argc, const char*const* argv) { if (argc == 3) { if(strcmp(argv[1], "eventtrace") == 0) { et_ = (EventTrace *)TclObject::lookup(argv[2]); return (TCL_OK); } } return Mac::command(argc, argv); } void Macng::recv(Packet *p, Handler *h) { struct hdr_cmn *hdr = HDR_CMN(p); int dst = (hdr_dst((char*)HDR_MAC(p))); /* let Macng::send handle the outgoing packets */ if (hdr->direction() == hdr_cmn::DOWN) { send(p,h); return; } //if packet is not in my channel or common channel if(hdr->localif()!=0 && hdr->localif()!=recvchan){ Packet::free(p); return; } /* handle an incoming packet */ /* * If we are transmitting, then set the error bit in the packet * so that it will be thrown away */ // in full duplex mode it can recv and send at the same time if (!fullduplex_mode_ && tx_active_) { hdr->error() = 1; } /* * check to see if we're already receiving a different packet */ if (rx_state_ == MAC_IDLE) { /* * We aren't already receiving any packets, so go ahead * and try to receive this one. */ rx_state_ = MAC_RECV; pktRx_ = p; /* schedule reception of the packet */ recvTimer->start(txtime(p)); } else { /* * We are receiving a different packet, so decide whether * the new packet's power is high enough to notice it. */ if (pktRx_->txinfo_.RxPr / p->txinfo_.RxPr >= p->txinfo_.CPThresh) { /* power too low, ignore the packet */ Packet::free(p); } else { /* power is high enough to result in collision */ rx_state_ = MAC_COLL; /* * look at the length of each packet and update the * timer if necessary */ if (txtime(p) > recvTimer->expire()) { recvTimer->stop(); Packet::free(pktRx_); pktRx_ = p; recvTimer->start(txtime(pktRx_)); } else { Packet::free(p); } } } } double Macng::txtime(Packet *p) { struct hdr_cmn *ch = HDR_CMN(p); double t = ch->txtime(); if (t < 0.0) t = 0.0; return t; } void Macng::send(Packet *p, Handler *h) { hdr_cmn* ch = HDR_CMN(p); /* store data tx time */ ch->txtime() = Mac::txtime(ch->size()); // Added by Sushmita to support event tracing (singal@nunki.usc.edu) trace_event("SENSING_CARRIER",p); /* check whether we're idle */ if (tx_state_ != MAC_IDLE) { // already transmitting another packet .. drop this one // Note that this normally won't happen due to the queue // between the LL and the MAC .. the queue won't send us // another packet until we call its handler in sendHandler() Packet::free(p); return; } pktTx_ = p; txHandler_ = h; // rather than sending packets out immediately, add in some // jitter to reduce chance of unnecessary collisions double jitter = Random::random()%40 * 100/bandwidth_; if(rx_state_ != MAC_IDLE) { trace_event("BACKING_OFF",p); } if (rx_state_ == MAC_IDLE ) { // we're idle, so start sending now waitTimer->restart(jitter); sendTimer->restart(jitter + ch->txtime()); } else { // we're currently receiving, so schedule it after // we finish receiving waitTimer->restart(jitter); sendTimer->restart(jitter + ch->txtime() + HDR_CMN(pktRx_)->txtime()); } } void Macng::recvHandler() { hdr_cmn *ch = HDR_CMN(pktRx_); Packet* p = pktRx_; MacState state = rx_state_; pktRx_ = 0; int dst = hdr_dst((char*)HDR_MAC(p)); // JL hdr_mac *mh = HDR_MAC(p); //busy_ = 0; rx_state_ = MAC_IDLE; // in full duplex mode we can send and recv at the same time // as different chanels are used for tx and rx'ing if (!fullduplex_mode_ && tx_active_) { // we are currently sending, so discard packet Packet::free(p); } else if (state == MAC_COLL) { // recv collision, so discard the packet drop(p, DROP_MAC_COLLISION); //Packet::free(p); } else if (mh->strategy_ == 1) { //it is a strategy packet, let's record its information hdr_strategy *sh = HDR_STRATEGY(p); Strategy temp; temp.nodeinfo=sh->nodeID; temp.x=sh->x; temp.y=sh->y; temp.channel=sh->channel; ((MobileNode*)(netif_->node()))->PacketPr_.InsertStrategy(&temp); Packet::free(p); } else if (dst != index_ && (u_int32_t)dst != MAC_BROADCAST) { /* address filtering * We don't want to log this event, so we just free * the packet instead of calling the drop routine. */ Packet::free(p); } else if (ch->error()) { // packet has errors, so discard it //Packet::free(p); drop(p, DROP_MAC_PACKET_ERROR); } else { uptarget_->recv(p, (Handler*) 0); } } void Macng::waitHandler() { tx_state_ = MAC_SEND; tx_active_ = 1; int dst = (hdr_dst((char*)HDR_MAC(pktTx_))); int chan=((MobileNode*)(netif_->node()))->PacketPr_.Searchnode(dst); if(chan==-1){ chan=0;//using common channel } hdr_cmn* ch=HDR_CMN(pktTx_); ch->channelindex_=chan; downtarget_->recv(pktTx_, txHandler_); } void Macng::sendHandler() { Handler *h = txHandler_; Packet *p = pktTx_; pktTx_ = 0; txHandler_ = 0; tx_state_ = MAC_IDLE; tx_active_ = 0; int dst = (hdr_dst((char*)HDR_MAC(p))); //busy_ = 1; //busy_ = 0; // I have to let the guy above me know I'm done with the packet hdr_mac* dh = HDR_MAC(p); if (dh->strategy_ == 1) { Packet::free(p); return; } else { h->handle(p); } } //C.A.R.MEN void Macng::sendStrategy(){ Packet *p = Packet::alloc(); hdr_cmn* ch = HDR_CMN(p); hdr_mac* dh = HDR_MAC(p); hdr_strategy* sh = HDR_STRATEGY(p); ch->uid() = 0; ch->ptype() = PT_MAC; //ch->size() = phymib_.getRTSlen(); ch->iface() = -2; ch->error() = 0; ch->direction()=hdr_cmn::DOWN; dh->macDA_= -1; /* store data tx time */ ch->txtime() = Mac::txtime(ch->size())+0.001; dh->strategy_ = 1; sh->nodeID=index_; sh->x = ((MobileNode*)(netif_->node()))->X(); sh->y=((MobileNode*)(netif_->node()))->Y(); sh->channel=((MobileNode*)(netif_->node()))->PacketPr_.DecideStrategy(); recvchan=sh->channel; // Added by Sushmita to support event tracing (singal@nunki.usc.edu) trace_event("SENSING_CARRIER",p); /* check whether we're idle */ if (tx_state_ != MAC_IDLE) { // already transmitting another packet .. drop this one // Note that this normally won't happen due to the queue // between the LL and the MAC .. the queue won't send us // another packet until we call its handler in sendHandler() Packet::free(p); return; } pktTx_ = p; txHandler_ = this; // rather than sending packets out immediately, add in some // jitter to reduce chance of unnecessary collisions double jitter = Random::random()%40 * 100/bandwidth_; if(rx_state_ != MAC_IDLE) { trace_event("BACKING_OFF",p); } if (rx_state_ == MAC_IDLE ) { // we're idle, so start sending now waitTimer->restart(jitter); sendTimer->restart(jitter + ch->txtime()); } else { // we're currently receiving, so schedule it after // we finish receiving waitTimer->restart(jitter); sendTimer->restart(jitter + ch->txtime() + HDR_CMN(pktRx_)->txtime()); } } // Timers void MacngTimer::restart(double time) { if (busy_) stop(); start(time); } void MacngTimer::start(double time) { Scheduler &s = Scheduler::instance(); assert(busy_ == 0); busy_ = 1; stime = s.clock(); rtime = time; assert(rtime >= 0.0); s.schedule(this, &intr, rtime); } void MacngTimer::stop(void) { Scheduler &s = Scheduler::instance(); assert(busy_); s.cancel(&intr); busy_ = 0; stime = rtime = 0.0; } void MacngWaitTimer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; mac->waitHandler(); } void MacngSendTimer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; mac->sendHandler(); } void MacngRecvTimer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; mac->recvHandler(); } //C.A.R.MEN void MacngBroadCastTimer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; #ifdef negotiatebased mac->sendStrategy(); #endif }