/* * 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 "macngenhanced.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" #include "timer-handler.h" #define negotiatebased #define espectedSINR 0.1 static class MacngenhancedClass : public TclClass { public: MacngenhancedClass() : TclClass("Mac/Macngenhanced") {} TclObject* create(int, const char*const*) { return new Macngenhanced(); } } class_Macngenhanced; // Added by Sushmita to support event tracing (singal@nunki.usc.edu). void Macngenhanced::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(); } Macngenhanced::Macngenhanced() : Mac() { rx_state_ = tx_state_ = MAC_IDLE; tx_active_ = 0; waitTimer = new MacngenhancedWaitTimer(this); sendTimer = new MacngenhancedSendTimer(this); recvTimer = new MacngenhancedRecvTimer(this); //C.A.R.MEN broadcastTimer = new MacngenhancedBroadCastTimer(this); PrimaryUser_Timer_= new PrimaryUser_Timer(this); // Added by Sushmita to support event tracing (singal@nunki.usc.edu) et_ = new EventTrace(); busy_ = 0; bind("fullduplex_mode_", &fullduplex_mode_); broadcastTimer->start(0.5); for(int i=0;i<100;i++){ ChannelUsage[i]=65535; } txpower=0.4; PrimaryUser_Timer_->start(0.01); } /* int Macngenhanced::hdr_dst(char* hdr, int dst ) { struct hdr_mac_tdma *dh = (struct hdr_mac_tdma*) hdr; if(dst > -2) STORE4BYTE(&dst, (dh->dh_da)); return ETHER_ADDR(dh->dh_da); } */ // Added by Sushmita to support event tracing (singal@nunki.usc.edu) int Macngenhanced::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 Macngenhanced::recv(Packet *p, Handler *h) { struct hdr_cmn *hdr = HDR_CMN(p); hdr_ip *iph = hdr_ip::access(p); if (hdr->fromprimaryuser == 1) { printf("node %d receive a packet from primary user. \n", index_); Packet::free(p); return; } /* if this packet is not towards me, free it if(iph->daddr()!=index_ && iph->daddr()!=-1){ Packet::free(p); return; } */ 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; } /* let Macngenhanced::send handle the outgoing packets */ /* 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 Macngenhanced::txtime(Packet *p) { struct hdr_cmn *ch = HDR_CMN(p); double t = ch->txtime(); if (t < 0.0) t = 0.0; return t; } void Macngenhanced::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()%20) * 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+ HDR_CMN(pktRx_)->txtime()); //sendTimer->restart(jitter + ch->txtime() // + HDR_CMN(pktRx_)->txtime()); } } void Macngenhanced::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; hdr_ip *iph = hdr_ip::access(p); // 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; //caculating the SINR information double interference=((MobileNode*)(netif_->node()))->PacketPr_.getInterference(sh->channel); if(interference){ temp.recvSINR=20*p->txinfo_.RxPr/interference; } ((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 Macngenhanced::waitHandler() { if (rx_state_ != MAC_IDLE ) { // we're currently receiving, so schedule it after // we finish receiving double jitter = (Random::random()%40) * 100/bandwidth_; waitTimer->restart(jitter+ HDR_CMN(pktRx_)->txtime()); //sendTimer->restart(jitter + ch->txtime() // + HDR_CMN(pktRx_)->txtime()); return; } hdr_cmn* ch=HDR_CMN(pktTx_); tx_state_ = MAC_SEND; tx_active_ = 1; int chan=0; if(chan==-1){ chan=0;//using common channel } hdr_ip *iph = hdr_ip::access(pktTx_); txpower=((MobileNode*)(netif_->node()))->PacketPr_.DecidePr(iph->daddr()); //set the tx power of outgoing packet //this filed will be read in the wirelessphy.c module ch->txPr=txpower; //if it is a strategy packet restart the timer hdr_mac* dh = HDR_MAC(pktTx_); ch->channelindex_=chan; ch->direction() = hdr_cmn::DOWN; downtarget_->recv(pktTx_, txHandler_); if (dh->strategy_ == 1) { //restart the broadcast timer broadcastTimer->restart(0.6); } //restart the send timer sendTimer->restart(ch->txtime()); } void Macngenhanced::sendHandler() { Handler *h = txHandler_; Packet *p = pktTx_; pktTx_ = 0; txHandler_ = 0; tx_state_ = MAC_IDLE; tx_active_ = 0; if(h){ //handler exists h->handle(p); return; } else { return; } } //C.A.R.MEN void Macngenhanced::sendStrategy(){ /* 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() double jitter = (Random::random()%2) * 100/bandwidth_; broadcastTimer->restart(HDR_CMN(pktTx_)->txtime()); return; } if (rx_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() double jitter = (Random::random()%2) * 100/bandwidth_; broadcastTimer->restart(HDR_CMN(pktRx_)->txtime()); return; } int dst=-1; 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_STRATEGY; //ch->size() = phymib_.getRTSlen(); ch->iface() = -2; ch->error() = 0; ch->direction() = hdr_cmn::DOWN; /* 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(); //recvchan=sh->channel; recvchan=0; // Added by Sushmita to support event tracing (singal@nunki.usc.edu) trace_event("SENSING_CARRIER",p); pktTx_ = p; txHandler_ = this; // rather than sending packets out immediately, add in some // jitter to reduce chance of unnecessary collisions double jitter = (Random::random()%2)/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 + HDR_CMN(pktRx_)->txtime()); //sendTimer->restart(jitter + ch->txtime() // + HDR_CMN(pktRx_)->txtime()); } } //C.A.R.MEN void Macngenhanced::sendPrimaryUserPacket(){ //if it is primary user, send the packet. otherwise, do nothing if(((MobileNode*)(netif_->node()))->IsPrimaryUser()){ /* 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() double jitter = (Random::random()%2) * 100/bandwidth_; PrimaryUser_Timer_->restart(HDR_CMN(pktTx_)->txtime()); return; } if (rx_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() double jitter = (Random::random()%2) * 100/bandwidth_; PrimaryUser_Timer_->restart(HDR_CMN(pktRx_)->txtime()); return; } int dst=-1; Packet *p = Packet::alloc(); hdr_cmn* ch = HDR_CMN(p); hdr_mac* dh = HDR_MAC(p); //set the primary user field ch->fromprimaryuser=1; ch->uid() = 0; ch->ptype() = PT_STRATEGY; //ch->size() = phymib_.getRTSlen(); ch->iface() = -2; ch->error() = 0; ch->direction() = hdr_cmn::DOWN; /* store data tx time */ ch->txtime() = Mac::txtime(ch->size())+0.001; //set recv channel to be 0 .. recvchan=0; // Added by Sushmita to support event tracing (singal@nunki.usc.edu) trace_event("SENSING_CARRIER",p); pktTx_ = p; txHandler_ = this; // rather than sending packets out immediately, add in some // jitter to reduce chance of unnecessary collisions double jitter = (Random::random()%2)/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 + HDR_CMN(pktRx_)->txtime()); //sendTimer->restart(jitter + ch->txtime() // + HDR_CMN(pktRx_)->txtime()); } } } // Timers void MacngenhancedTimer::restart(double time) { if (busy_) stop(); start(time); } void MacngenhancedTimer::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 MacngenhancedTimer::stop(void) { Scheduler &s = Scheduler::instance(); assert(busy_); s.cancel(&intr); busy_ = 0; stime = rtime = 0.0; } void MacngenhancedWaitTimer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; mac->waitHandler(); } void MacngenhancedSendTimer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; mac->sendHandler(); } void MacngenhancedRecvTimer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; mac->recvHandler(); } //C.A.R.MEN void MacngenhancedBroadCastTimer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; #ifdef negotiatebased mac->sendStrategy(); #endif } void PrimaryUser_Timer::handle(Event *e) { busy_ = 0; stime = rtime = 0.0; printf("sendPrimaryUserPacket\n"); mac->sendPrimaryUserPacket(); }