/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ /* * mac-802_3.cc * $Id: mac-802_3.cc,v 1.16 2002/06/14 23:15:03 yuri Exp $ */ #include #include #include #include #include //#define MAC_DEBUG #ifndef MAC_DEBUG #define FPRINTF(s, f, t, index, func) do {} while (0) #else static double xtime= 0.0; # define FPRINTF(s, f, t, index, func) \ do { fprintf(s, f, t, index, func); xtime= t; } while (0) #endif //MAC_DEBUG #define PRNT_MAC_FUNCS(mac) \ FPRINTF(stderr, "%.15f : %d : %s\n", \ Scheduler::instance().clock(), (mac)->index_, __PRETTY_FUNCTION__) inline void MacHandler::cancel() { PRNT_MAC_FUNCS(mac); Scheduler& s = Scheduler::instance(); assert(busy_); s.cancel(&intr); // No need to free the event intr since it's statically allocated. busy_ = 0; } inline void Mac8023HandlerSend::cancel() { PRNT_MAC_FUNCS(mac); assert(busy_); Scheduler &s= Scheduler::instance(); s.cancel(&intr); busy_= 0; p_= 0; } inline void MacHandlerRecv::cancel() { PRNT_MAC_FUNCS(mac); Scheduler& s = Scheduler::instance(); assert(busy_ && p_); s.cancel(&intr); busy_ = 0; Packet::free(p_); p_= 0; } inline void MacHandlerRetx::cancel() { PRNT_MAC_FUNCS(mac); Scheduler& s = Scheduler::instance(); assert(busy_ && p_); s.cancel(&intr); } inline void MacHandlerIFS::cancel() { PRNT_MAC_FUNCS(mac); //fprintf (stderr, "cancelled dtime= %.15f\n", intr.time_- Scheduler::instance().clock()); MacHandler::cancel(); } static class Mac802_3Class : public TclClass { public: Mac802_3Class() : TclClass("Mac/802_3") {} TclObject* create(int, const char*const*) { return (new Mac802_3); } } class_mac802_3; void Mac8023HandlerSend::handle(Event*) { PRNT_MAC_FUNCS(mac); assert(p_); /* Transmission completed successfully */ busy_ = 0; p_= 0; mac->mhRetx_.free(); mac->mhRetx_.reset(); mac->mhIFS_.schedule(mac->netif_->txtime(int(IEEE_8023_IFS_BITS/8.0))); } void Mac8023HandlerSend::schedule(const Packet *p, double t) { PRNT_MAC_FUNCS(mac); Scheduler& s = Scheduler::instance(); assert(!busy_); s.schedule(this, &intr, t); busy_ = 1; p_= p; } void MacHandlerRecv::handle(Event* ) { /* Reception Successful */ PRNT_MAC_FUNCS(mac); busy_ = 0; mac->recv_complete(p_); p_= 0; } void MacHandlerRecv::schedule(Packet *p, double t) { PRNT_MAC_FUNCS(mac); Scheduler& s = Scheduler::instance(); assert(p && !busy_); s.schedule(this, &intr, t); busy_ = 1; p_ = p; } bool MacHandlerRetx::schedule(double delta) { PRNT_MAC_FUNCS(mac); Scheduler& s = Scheduler::instance(); assert(p_ && !busy_); int k, r; if(try_ < IEEE_8023_ALIMIT) { k = min(try_, IEEE_8023_BLIMIT); r = Random::integer(1 << k); s.schedule(this, &intr, r * mac->netif_->txtime((int)(IEEE_8023_SLOT_BITS/8.0)) + delta); busy_ = 1; return true; } return false; } void MacHandlerRetx::handle(Event *) { PRNT_MAC_FUNCS(mac); assert(p_); busy_= 0; ++try_; mac->transmit(p_); } inline void MacHandlerIFS::schedule(double t) { PRNT_MAC_FUNCS(mac); assert(!busy_); Scheduler &s= Scheduler::instance(); s.schedule(this, &intr, t); busy_= 1; } inline void MacHandlerIFS::handle(Event*) { PRNT_MAC_FUNCS(mac); busy_= 0; mac->resume(); } Mac802_3::Mac802_3() : trace_(0), mhRecv_(this), mhRetx_(this), mhIFS_(this), mhSend_(this) { // Bind mac trace variable bind_bool("trace_",&trace_); } void Mac802_3::sendUp(Packet *p, Handler *) { PRNT_MAC_FUNCS(this); /* just received the 1st bit of a packet */ if (state_ != MAC_IDLE && mhIFS_.busy()) { #define EPS 1.0e-15 /* can be considered controller clock resolution */ if (mhIFS_.expire() - Scheduler::instance().clock() > EPS) { // This can happen when 3 nodes TX: // 1 was TX, then IFS, then TX again; // 2,3 were in RX (from 1), then IFS, then TX, then collision with 1 and IFS // while 3 in IFS it RX from 2 and vice versa. // We ignore it and let the ifs timer take care of things. Packet::free(p); return; } else { // This means that mhIFS_ is about to expire now. We assume that IFS is over // and resume, because we want to give this guy a chance - otherwise the guy // who TX before will TX again (fairness); if we have anything to // TX, this forces a collision. mhIFS_.cancel(); resume(); } #undef EPS } if(state_ == MAC_IDLE) { state_ = MAC_RECV; assert(!mhRecv_.busy()); /* the last bit will arrive in txtime seconds */ mhRecv_.schedule(p, netif_->txtime(p)); } else { collision(p); //received packet while sending or receiving } } void Mac802_3::sendDown(Packet *p, Handler *h) { PRNT_MAC_FUNCS(this); assert(initialized()); assert(h); assert(netif_->txtime(IEEE_8023_MINFRAME) > 2*netif_->channel()->maxdelay()); /* max prop. delay is limited by specs: about 25us for 10Mbps and 2.5us for 100Mbps */ int size= (HDR_CMN(p)->size() += ETHER_HDR_LEN); //XXX also preamble? hdr_mac *mh= HDR_MAC(p); mh->padding_= 0; if (size > IEEE_8023_MAXFRAME) { static bool warnedMAX= false; if (!warnedMAX) { fprintf(stderr, "Mac802_3: frame is too big: %d\n", size); warnedMAX= true; } } else if (size < IEEE_8023_MINFRAME) { // pad it to fit MINFRAME mh->padding_= IEEE_8023_MINFRAME - size; HDR_CMN(p)->size() += mh->padding_; } callback_ = h; mhRetx_.packet(p); //packet's buffered by mhRetx in case of retransmissions transmit(p); } void Mac802_3::transmit(Packet *p) { PRNT_MAC_FUNCS(this); assert(callback_); if(mhSend_.packet()) { fprintf(stderr, "index: %d\n", index_); fprintf(stderr, "Retx Timer: %d\n", mhRetx_.busy()); fprintf(stderr, "IFS Timer: %d\n", mhIFS_.busy()); fprintf(stderr, "Recv Timer: %d\n", mhRecv_.busy()); fprintf(stderr, "Send Timer: %d\n", mhSend_.busy()); exit(1); } /* Perform carrier sense - if we were sending before, never mind state_ */ if (mhIFS_.busy() || (state_ != MAC_IDLE)) { /* we'll try again when IDLE. It'll happen either when reception completes, or if collision. Either way, we call resume() */ return; } double txtime = netif_->txtime(p); /* Schedule transmission of the packet's last bit */ mhSend_.schedule(p, txtime); // pass the packet to the PHY: need to send a copy, // because there may be collision and it may be freed Packet *newp = p->copy(); HDR_CMN(newp)->direction()= hdr_cmn::DOWN; //down downtarget_->recv(newp); state_= MAC_SEND; } void Mac802_3::collision(Packet *p) { PRNT_MAC_FUNCS(this); if (mhIFS_.busy()) mhIFS_.cancel(); double ifstime= netif_->txtime(int((IEEE_8023_JAMSIZE+IEEE_8023_IFS_BITS)/8.0)); //jam time + ifs mhIFS_.schedule(ifstime); switch(state_) { case MAC_SEND: // If mac trace feature is on generate a collision trace for this packet. if (trace_) drop(p); else Packet::free(p); if (mhSend_.busy()) mhSend_.cancel(); if (!mhRetx_.busy()) { /* schedule retransmissions */ if (!mhRetx_.schedule(ifstime)) { p= mhRetx_.packet(); hdr_cmn *th = hdr_cmn::access(p); HDR_CMN(p)->size() -= (ETHER_HDR_LEN + HDR_MAC(p)->padding_); fprintf(stderr,"BEB limit exceeded:Dropping packet %d\n",th->uid()); fflush(stderr); drop(p); // drop if backed off far enough mhRetx_.reset(); } } break; case MAC_RECV: Packet::free(p); // more than 2 packets collisions possible if (mhRecv_.busy()) mhRecv_.cancel(); break; default: assert("SHOULD NEVER HAPPEN" == 0); } } void Mac802_3::recv_complete(Packet *p) { PRNT_MAC_FUNCS(this); assert(!mhRecv_.busy()); assert(!mhSend_.busy()); hdr_cmn *ch= HDR_CMN(p); /* Address Filtering */ hdr_mac *mh= HDR_MAC(p); int dst= mh->macDA(); if ((dst != BCAST_ADDR) && (dst != index_)) { Packet::free(p); goto done; } /* Strip off the mac header and padding if any */ ch->size() -= (ETHER_HDR_LEN + mh->padding_); /* xxx FEC here */ if( ch->error() ) { fprintf(stderr,"\nChecksum error\nDropping packet"); fflush(stderr); // drop(p); Packet::free(p); goto done; } /* we could schedule an event to account for mac-delay */ if ((p->ref_count() > 0) /* so the channel is using ref-copying */ && (dst == BCAST_ADDR)) { /* make a real copy only if broadcasting, otherwise * all nodes except the receiver are going to free * this packet */ uptarget_->recv(p->copy(), (Handler*) 0); Packet::free(p); // this will decrement ref counter } else { uptarget_->recv(p, (Handler*) 0); } done: mhIFS_.schedule(netif_->txtime(int(IEEE_8023_IFS_BITS/8.0)));// wait for one IFS, then resume } /* we call resume() in these cases: - successful transmission - whole packet's received - collision and backoffLimit's exceeded - collision while receiving */ void Mac802_3::resume() { PRNT_MAC_FUNCS(this); assert(!mhRecv_.busy()); assert(!mhSend_.busy()); assert(!mhIFS_.busy()); state_= MAC_IDLE; if (mhRetx_.packet()) { if (!mhRetx_.busy()) { // we're not backing off and not sensing carrier right now: send transmit(mhRetx_.packet()); } } else { if (callback_ && !mhRetx_.busy()) { //WARNING: calling callback_->handle may change the value of callback_ Handler* h= callback_; callback_= 0; h->handle(0); } } }