📄 mac-802_11e.cc
字号:
#undef NDEBUG#include <assert.h>#include "delay.h"#include "connector.h"#include "packet.h"#include "random.h"#include "mobilenode.h"#include "stream.h"#include "arp.h"#include "ll.h"#include "mac.h"#include "mac-timers_802_11e.h"#include "mac-802_11e.h"#include "cmu-trace.h"#include "priq.h"//include the following line when using Akaroa//#include "akaroa.H"#define AKAROA 0 #define INTERVAL 0.01 // XXX Can't we make these macros inline methods? Otherwise why should we have// inline methods at all??#define CHECK_BACKOFF_TIMER() \{ \ if(is_idle() && mhBackoff_.paused()) { \ mhBackoff_.resume(); \ } \ if(! is_idle() && mhBackoff_.busy() && ! mhBackoff_.paused()){ \ mhBackoff_.pause(); \ } \ if(!is_idle() && mhDefer_.busy()) mhDefer_.stop(); \}inline voidMac802_11e::transmit(Packet *p, double t){ /* * If I'm transmitting without doing CS, such as when * sending an ACK, any incoming packet will be "missed" * and hence, must be discarded. */ if(rx_state_ != MAC_IDLE) { struct hdr_mac802_11 *dh = HDR_MAC802_11(p); assert(dh->dh_fc.fc_type == MAC_Type_Control); assert(dh->dh_fc.fc_subtype == MAC_Subtype_ACK); assert(pktRx_); struct hdr_cmn *ch = HDR_CMN(pktRx_); ch->error() = 1; /* force packet discard */ } /* * pass the packet on the "interface" which will in turn * place the packet on the channel. * * NOTE: a handler is passed along so that the Network * Interface can distinguish between incoming and * outgoing packets. */ struct hdr_cmn *sd = HDR_CMN(p); int prio = LEVEL(p); tx_active_ = 1; sending = 1; CHECK_BACKOFF_TIMER(); downtarget_->recv(p->copy(), this); if(sd->ptype() == PT_CBR || sd->ptype() == PT_EXP) { if(!rtx_[prio]){ numbytes_[prio] += sd->size() - ETHER_HDR_LEN11; } } mhIF_.start(txtime(p)); mhSend_.start(t); } #define SET_RX_STATE(x) \{ \ rx_state_ = x; \ CHECK_BACKOFF_TIMER(); \}#define SET_TX_STATE(pri, x) \{ \ tx_state_[pri] = x; \}/* ====================================================================== Global Variables ====================================================================== */static EDCF_PHY_MIB EDCF_PMIB ={ DSSS_EDCF_SlotTime, DSSS_EDCF_CCATime, DSSS_EDCF_RxTxTurnaroundTime, DSSS_EDCF_SIFSTime, DSSS_EDCF_PreambleLength, DSSS_EDCF_PLCPHeaderLength, DSSS_EDCF_PLCPDataRate}; static MAC_MIB EDCF_MMIB ={ MAC_EDCF_RTSThreshold, MAC_EDCF_ShortRetryLimit, MAC_EDCF_LongRetryLimit, MAC_EDCF_FragmentationThreshold, MAC_EDCF_MaxTransmitMSDULifetime, MAC_EDCF_MaxReceiveLifetime, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};/* ====================================================================== TCL Hooks for the simulator ====================================================================== */static class Mac802_11eClass : public TclClass {public: Mac802_11eClass() : TclClass("Mac/802_11e") {} TclObject* create(int, const char*const*) { return (new Mac802_11e(&EDCF_PMIB, &EDCF_MMIB)); }} class_mac802_11e;/* ====================================================================== Mac Class Functions ====================================================================== */Mac802_11e::Mac802_11e(EDCF_PHY_MIB *p, MAC_MIB *m) : Mac(), mhIF_(this), mhNav_(this), mhRecv_(this), mhSend_(this), mhDefer_(this, p->SlotTime), mhSifs_(this, p->SlotTime), mhBackoff_(this, p->SlotTime), AK(this){ // Pointer to PriQ, Cast in priq.cc queue_ = 0; //flags to control if PriQ Parameters have already been adopted AIFSset = 0; CWset = 0; for(int i=0; i < MAX_PRI; i++){ packets_[i] = 0; pktRTS_[i] = 0; pktCTRL_[i] = 0; pktTx_[i] = 0; tx_state_[i] = MAC_IDLE; ssrc_[i] = slrc_[i] = 0; callback_[i] = 0; numbytes_[i] = 0; rtx_[i] = 0; cw_[i] = 0; cwmin_[i] = 0; cwmax_[i] = 0; aifs_[i] = 0; txop_limit_[i] = 0; } jitter = 1000; //jitter = 0; throughput = 0; interval_ = INTERVAL; if(AKAROA) AK.start(); macmib_ = m; phymib_ = p; nav_ = 0.0; rx_state_ = MAC_IDLE; tx_active_ = 0; idle_time = 0; sending = 0; cfb_dur = 0; cfb_active = 0; cfb_broadcast = 0; levels = 0; slotnum = 0; pf = 0; cw_old = 0; sifs_ = phymib_->SIFSTime; pifs_ = sifs_ + phymib_->SlotTime; difs_ = sifs_ + 2*phymib_->SlotTime; // see (802.11-1999, 9.2.10) eifs_ = sifs_ + (8 * ETHER_ACK_LEN / phymib_->PLCPDataRate);// eifs_ = sifs_ + (8 * ETHER_ACK_LEN / phymib_->PLCPDataRate) + difs_; eifs_nav_ = 0; //tx_sifs_ = sifs_ - phymib_->RxTxTurnaroundTime; //tx_pifs_ = tx_sifs_ + phymib_->SlotTime; //tx_difs_ = tx_sifs_ + 2 * phymib_->SlotTime; sta_seqno_ = 1; cache_ = 0; cache_node_count_ = 0; // chk if basic/data rates are set // otherwise use bandwidth_ as default; Tcl& tcl = Tcl::instance(); tcl.evalf("Mac/802_11e set basicRate_"); if (strcmp(tcl.result(), "0") != 0) bind_bw("basicRate_", &basicRate_); else basicRate_ = bandwidth_; tcl.evalf("Mac/802_11e set dataRate_"); if (strcmp(tcl.result(), "0") != 0) bind_bw("dataRate_", &dataRate_); else dataRate_ = bandwidth_; tcl.evalf("Mac/802_11e set rst_cw_mode_"); if (strcmp(tcl.result(), "0") != 0) bind("rst_cw_mode_", &rst_cw_mode_); else rst_cw_mode_=0; bind("cfb_", &cfb_);}intMac802_11e::command(int argc, const char*const* argv){ if (argc == 3) { if (strcmp(argv[1], "log-target") == 0) { logtarget_ = (NsObject*) TclObject::lookup(argv[2]); if(logtarget_ == 0) return TCL_ERROR; return TCL_OK; } else if(strcmp(argv[1], "nodes") == 0) { if(cache_) return TCL_ERROR; cache_node_count_ = atoi(argv[2]); cache_ = new Host[cache_node_count_ + 1]; assert(cache_); bzero(cache_, sizeof(Host) * (cache_node_count_+1 )); return TCL_OK; } } // wiethoelter, 28.07.03 // VOIP-Projekt // Zugriff auf das RetryLimit des MAC-Layers vom RTPData-Agent aus Tcl& tcl = Tcl::instance(); if ( argc == 2 ) { if ( strcmp( argv[1], "set_RetryLimit" ) == 0 ) { tcl.resultf( "%d", macmib_->ShortRetryLimit ); return TCL_OK; } } if ( argc == 3 ) { if ( strcmp( argv[1], "set_RetryLimit" ) == 0 ) { macmib_->ShortRetryLimit = atoi( argv[2] );; return TCL_OK; } } return Mac::command(argc, argv);}/* ====================================================================== Debugging Routines ====================================================================== *//* * dump and packet trace are not adopted to 802.11e yet! */voidMac802_11e::trace_pkt(Packet *p) { struct hdr_cmn *ch = HDR_CMN(p); struct hdr_mac802_11* dh = HDR_MAC802_11(p); u_int16_t *t = (u_int16_t*) &dh->dh_fc; fprintf(stderr, "\t[ %2x %2x %2x %2x ] %x %s %d\n", *t, dh->dh_duration, ETHER_ADDR(dh->dh_da), ETHER_ADDR(dh->dh_sa), index_, packet_info.name(ch->ptype()), ch->size());}voidMac802_11e::dump(char *fname){ fprintf(stderr, "\n%s --- (INDEX: %d, time: %2.9f)\n", fname, index_, Scheduler::instance().clock()); fprintf(stderr, "\ttx_state_: %x, rx_state_: %x, nav: %2.9f, idle: %d\n", tx_state_, rx_state_, nav_, is_idle()); fprintf(stderr, "\tpktTx_: %x, pktRx_: %x, pktRTS_: %x, pktCTRL_: %x, callback: %x\n", (int) pktTx_, (int) pktRx_, (int) pktRTS_, (int) pktCTRL_, (int) callback_); fprintf(stderr, "\tDefer: %d, Backoff: %d (%d), Recv: %d, Timer: %d Nav: %d\n", mhDefer_.busy(), mhBackoff_.busy(), mhBackoff_.paused(), mhRecv_.busy(), mhSend_.busy(), mhNav_.busy()); fprintf(stderr, "\tBackoff Expire: %f\n", mhBackoff_.expire());}/* ====================================================================== Packet Headers Routines ====================================================================== */inline intMac802_11e::hdr_dst(char* hdr, int dst ){ struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr; //dst = (u_int32_t)(dst); if(dst > -2) STORE4BYTE(&dst, (dh->dh_da)); return ETHER_ADDR(dh->dh_da);}inline int Mac802_11e::hdr_src(char* hdr, int src ){ struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr; if(src > -2) STORE4BYTE(&src, (dh->dh_sa)); return ETHER_ADDR(dh->dh_sa);}inline int Mac802_11e::hdr_type(char* hdr, u_int16_t type){ struct hdr_mac802_11 *dh = (struct hdr_mac802_11*) hdr; if(type) STORE2BYTE(&type,(dh->dh_body)); return GET2BYTE(dh->dh_body);}/* ====================================================================== Misc Routines ====================================================================== */inline intMac802_11e::is_idle(){ if(rx_state_ != MAC_IDLE){ idle_time = 0; return 0; } if(sending) { idle_time = 0; return 0; } if(nav_ > Scheduler::instance().clock()){ idle_time = 0; return 0; } idle_time = Scheduler::instance().clock(); return 1;}voidMac802_11e::discard(Packet *p, const char* why){ hdr_mac802_11* mh = HDR_MAC802_11(p); hdr_cmn *ch = HDR_CMN(p);#if 0 /* old logic 8/8/98 -dam */ /* * If received below the RXThreshold, then just free. */ if(p->txinfo_.Pr < p->txinfo_.ant.RXThresh) { Packet::free(p); //p = 0; return; }#endif // 0 /* if the rcvd pkt contains errors, a real MAC layer couldn't necessarily read any data from it, so we just toss it now */ if(ch->error() != 0) { Packet::free(p); //p = 0; return; } switch(mh->dh_fc.fc_type) { case MAC_Type_Management: drop(p, why); return; case MAC_Type_Control: switch(mh->dh_fc.fc_subtype) { case MAC_Subtype_RTS: if((u_int32_t)ETHER_ADDR(mh->dh_sa) == \ (u_int32_t)index_) { drop(p, why); return; } /* fall through - if necessary */ case MAC_Subtype_CTS: case MAC_Subtype_ACK: if((u_int32_t)ETHER_ADDR(mh->dh_da) == \ (u_int32_t)index_) { drop(p, why); return; } break; default: fprintf(stderr, "invalid MAC Control subtype\n"); exit(1); } break; case MAC_Type_Data: switch(mh->dh_fc.fc_subtype) { case MAC_Subtype_Data: if((u_int32_t)ETHER_ADDR(mh->dh_da) == \ (u_int32_t)index_ || (u_int32_t)ETHER_ADDR(mh->dh_sa) == \ (u_int32_t)index_ || (u_int32_t)ETHER_ADDR(mh->dh_da) == MAC_BROADCAST) { drop(p); return; } break; default: fprintf(stderr, "invalid MAC Data subtype\n"); exit(1); } break; default: fprintf(stderr, "invalid MAC type (%x)\n", mh->dh_fc.fc_type); trace_pkt(p); exit(1); } Packet::free(p);}voidMac802_11e::capture(Packet *p){ /* * Update the NAV so that this does not screw * up carrier sense. */ set_nav(usec(eifs_ + txtime(p))); Packet::free(p);}voidMac802_11e::collision(Packet *p){ switch(rx_state_) { case MAC_RECV: SET_RX_STATE(MAC_COLL); /* fall through */ case MAC_COLL: assert(pktRx_); assert(mhRecv_.busy()); /* * Since a collision has occurred, figure out * which packet that caused the collision will * "last" the longest. Make this packet, * pktRx_ and reset the Recv Timer if necessary. */ if(txtime(p) > mhRecv_.expire()) { mhRecv_.stop(); discard(pktRx_, DROP_MAC_COLLISION); pktRx_ = p; mhRecv_.start(txtime(pktRx_)); } else { discard(p, DROP_MAC_COLLISION); } break; default: assert(0); }}voidMac802_11e::tx_resume(){ double rTime; assert(mhSend_.busy() == 0); for(int pri = 0; pri < MAX_PRI; pri++){ //assert(mhDefer_.defer(pri) == 0); if(!mhDefer_.defer(pri)) { if(pktCTRL_[pri]) { /* * Need to send a CTS or ACK. */ mhSifs_.start(pri, sifs_); } else if(pktRTS_[pri]) { if(mhBackoff_.backoff(pri) == 0) { rTime = (Random::random() % getCW(LEVEL(pktRTS_[pri]))) * phymib_->SlotTime; mhDefer_.start(pri, getAIFS(LEVEL(pktRTS_[pri]))); } } else if(pktTx_[pri]) { if(mhBackoff_.backoff(pri) == 0) { hdr_cmn *ch = HDR_CMN(pktTx_[pri]); struct hdr_mac802_11 *mh = HDR_MAC802_11(pktTx_[pri]); if ((u_int32_t) ch->size() < macmib_->RTSThreshold || (u_int32_t) ETHER_ADDR(mh->dh_da) == MAC_BROADCAST) { if((u_int32_t) ETHER_ADDR(mh->dh_da) == MAC_BROADCAST) rTime = (Random::random() % (getCW(pri) + 1)) * phymib_->SlotTime; else rTime = 0; mhDefer_.start(pri, getAIFS(pri) + rTime); } else { mhSifs_.start(pri, sifs_); } } } else if(callback_[pri] != 0) { rtx_[pri] = 0; Handler *h = callback_[pri]; callback_[pri] = 0; h->handle((Event*) 0); } SET_TX_STATE(pri, MAC_IDLE); } }}voidMac802_11e::rx_resume(){ assert(pktRx_ == 0); assert(mhRecv_.busy() == 0); SET_RX_STATE(MAC_IDLE);}/* ====================================================================== Timer Handler Routines ====================================================================== */voidMac802_11e::backoffHandler(int pri){ if(pktCTRL_[pri]) { assert(mhSend_.busy() || mhDefer_.defer(pri)); return; } if(check_pktRTS(pri) == 0) return; if(check_pktTx(pri) == 0) return;}voidMac802_11e::deferHandler(int pri){ assert(pktCTRL_[pri] || pktRTS_[pri] || pktTx_[pri]); if(check_pktCTRL(pri) == 0) return; assert(mhBackoff_.backoff(pri) == 0); //if (mhBackoff_.busy() != 0) //{ // printf("deferHandler:mhBackoff_ busy!\n"); // return; //} if(check_pktRTS(pri) == 0) return; if(check_pktTx(pri) == 0) return;}voidMac802_11e::navHandler(){ eifs_nav_ = 0.0; if(is_idle() && mhBackoff_.paused()) { mhBackoff_.resume(); }}voidMac802_11e::recvHandler(){ recv_timer();}voidMac802_11e::sendHandler(){ Scheduler &s = Scheduler::instance(); sending = 0; CHECK_BACKOFF_TIMER(); send_timer();}void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -