ProcedureRoughly takes the following path (when no errors or congestion):recv() -> send() -> sendDATA() and sendRTS() -> start defer timer-> deferHandler() -> check_pktRTS() -> transmit()-> recv() -> receive timer started
-> recv_timer() -> recvCTS() -> tx_resume() -> start defer timer -> rx_resume() -> deferHandler() -> check_pktTx() -> transmit()-> recv() -> receive timer started-> recv_timer() -> recvACK() -> tx_resume() -> callback_ -> rx_resume() -> done!
recv ( )void Mac802_11::recv(Packet *p, Handler *h){
struct hdr_cmn *hdr = HDR_CMN(p);assert(initialized());
if( hdr->direction() == hdr_cmn::DOWN ) { send(p, h); return; } if(tx_active_ && hdr->error() == 0) {
hdr->error() = 1;}
if(rx_state_ == MAC_IDLE) {setRxState(MAC_RECV);pktRx_ = p;mhRecv_.start(txtime(p));
} else { ………………………………………………………………………………………
}}
back to procedure
send( )void Mac802_11::send(Packet *p, Handler *h){
double rTime;struct hdr_mac802_11* dh = HDR_MAC802_11(p);
EnergyModel *em = netif_->node()->energy_model();if (em && em->sleep()) {
em->set_node_sleep(0);em->set_node_state(EnergyModel::INROUTE);
}
callback_ = h;sendDATA(p);sendRTS(ETHER_ADDR(dh->dh_ra));
dh->dh_scontrol = sta_seqno_++;
if(mhBackoff_.busy() == 0) {if(is_idle()) {
if (mhDefer_.busy() == 0) {rTime = (Random::random() % cw_) * (phymib_.getSlotTime());mhDefer_.start(phymib_.getDIFS() + rTime);
}} else {
mhBackoff_.start(cw_, is_idle());}
}}
back to procedure
if((u_int32_t)ETHER_ADDR(dh->dh_ra) != MAC_BROADCAST) {
/* store data tx time for unicast packets */ch->txtime() = txtime(ch->size(), dataRate
_);
dh->dh_duration = usec(txtime(phymib_.getACKlen(), basicRate_)+ phymib_.getSIFS());
} else {/* store data tx time for broadcast packets (see 9.6) */
ch->txtime() = txtime(ch->size(), basicRate_ );
dh->dh_duration = 0;}pktTx_ = p;
}
sendDATA( )Mac802_11::sendDATA(Packet *p){
hdr_cmn* ch = HDR_CMN(p);struct hdr_mac802_11* dh = HDR_MAC802_11(p);
assert(pktTx_ == 0);
ch->size() += phymib_.getHdrLen11();
dh->dh_fc.fc_protocol_version = MAC_ProtocolVersion;dh->dh_fc.fc_type = MAC_Type_Data;dh->dh_fc.fc_subtype = MAC_Subtype_Data;
dh->dh_fc.fc_to_ds = 0;dh->dh_fc.fc_from_ds = 0;dh->dh_fc.fc_more_frag = 0;dh->dh_fc.fc_retry = 0;dh->dh_fc.fc_pwr_mgt = 0;dh->dh_fc.fc_more_data = 0;dh->dh_fc.fc_wep = 0;dh->dh_fc.fc_order = 0;
/* store data tx time */ ch->txtime() = txtime(ch->size(), dataRate_);
Back to send ( )
Back to procedure
sendRTS( )void Mac802_11::sendRTS(int dst){
Packet *p = Packet::alloc();hdr_cmn* ch = HDR_CMN(p);struct rts_frame *rf = (struct rts_frame*)p->access(hdr_mac::offset_);
assert(pktTx_);assert(pktRTS_ == 0);
if( (u_int32_t) HDR_CMN(pktTx_)->size() < macmib_.getRTSThreshold() ||
(u_int32_t) dst == MAC_BROADCAST) {Packet::free(p);return;
}
ch->uid() = 0;ch->ptype() = PT_MAC;ch->size() = phymib_.getRTSlen();ch->iface() = -2;ch->error() = 0;
bzero(rf, MAC_HDR_LEN);
rf->rf_fc.fc_protocol_version = MAC_ProtocolVersion; rf->rf_fc.fc_type = MAC_Type_Control; rf->rf_fc.fc_subtype = MAC_Subtype_RTS; rf->rf_fc.fc_to_ds = 0; rf->rf_fc.fc_from_ds = 0; rf->rf_fc.fc_more_frag = 0; rf->rf_fc.fc_retry = 0; rf->rf_fc.fc_pwr_mgt = 0; rf->rf_fc.fc_more_data= 0; rf->rf_fc.fc_wep = 0; rf->rf_fc.fc_order = 0;
STORE4BYTE(&dst, (rf->rf_ra));
ch->txtime() = txtime(ch->size(), basicRate_ );
STORE4BYTE(&index_, (rf->rf_ta));
rf->rf_duration = usec(phymib_.getSIFS() + txtime(phymib_.getCTSlen(), basicRate_) + phymib_.getSIFS()+ txtime(pktTx_) + phymib_.getSIFS()
+ txtime(phymib_.getACKlen(), basicRate_));pktRTS_ = p;
} Back to send ( )
Back to procedure
deferHandler( )
void Mac802_11::deferHandler(){
assert(pktCTRL_ || pktRTS_ || pktTx_);
if( check_pktCTRL() == 0)return;
assert(mhBackoff_.busy() == 0);if( check_pktRTS() == 0)
return;if( check_pktTx() == 0)
return;}
Back to procedure
Check_pktCTRL()
int Mac802_11::check_pktCTRL(){
struct hdr_mac802_11 *mh;double timeout;
if(pktCTRL_ == 0)return -1;
…………………….}
Back to deferHandler()
Back to procedure
check_pktRTS()int Mac802_11::check_pktRTS(){
struct hdr_mac802_11 *mh;double timeout;assert(mhBackoff_.busy() == 0);if(pktRTS_ == 0) return -1;
mh = HDR_MAC802_11(pktRTS_);
switch(mh->dh_fc.fc_subtype) {case MAC_Subtype_RTS:
if(! is_idle()) {inc_cw();mhBackoff_.start(cw_, is_idle());return 0;
}setTxState(MAC_RTS);timeout = txtime(phymib_.getRTSlen(), basicRate_) + DSSS_MaxPropagationDelay
+ phymib_.getSIFS()+ txtime(phymib_.getCTSlen(), basicRate_)+ DSSS_MaxPropagationDelay;break;
default:fprintf(stderr, "check_pktRTS:Invalid MAC Control subtype\n");exit(1);
}transmit(pktRTS_, timeout);
return 0;} Back to deferHandler()
Back to procedure
check_pktTx()Int Mac802_11::check_pktTx(){
struct hdr_mac802_11 *mh;double timeout;assert(mhBackoff_.busy() == 0);if(pktTx_ == 0)
return -1;mh = HDR_MAC802_11(pktTx_);switch(mh->dh_fc.fc_subtype) {case MAC_Subtype_Data:
if(! is_idle()) {sendRTS(ETHER_ADDR(mh->dh_ra));inc_cw();mhBackoff_.start(cw_, is_idle());return 0;
}setTxState(MAC_SEND);if((u_int32_t)ETHER_ADDR(mh->dh_ra) != MAC_BROADCAST)
timeout = txtime(pktTx_) + DSSS_MaxPropagationDelay + phymib_.getSIFS() + txtime(phymib_.getACKlen(), basicRate_) + DSSS_MaxPropagationDelay; else
timeout = txtime(pktTx_);break;
default:fprintf(stderr, "check_pktTx:Invalid MAC Control subtype\n");exit(1);
}transmit(pktTx_, timeout);return 0;
}Back to deferHandler()
Back to procedure
check_pktTx()Int Mac802_11::check_pktTx(){
struct hdr_mac802_11 *mh;double timeout;
assert(mhBackoff_.busy() == 0);
if(pktTx_ == 0)return -1;
mh = HDR_MAC802_11(pktTx_);
switch(mh->dh_fc.fc_subtype) {case MAC_Subtype_Data:
if(! is_idle()) {sendRTS(ETHER_ADDR(mh->dh_ra));inc_cw();mhBackoff_.start(cw_, is_idle());return 0;
}setTxState(MAC_SEND);if((u_int32_t)ETHER_ADDR(mh->dh_ra) != MAC_BROADCAST)
timeout = txtime(pktTx_) + DSSS_MaxPropagationDelay + phymib_.getSIFS() + txtime(phymib_.getACKlen(), basicRate_) + DSSS_MaxPropagationDelay;
elsetimeout = txtime(pktTx_);
break;default:
fprintf(stderr, "check_pktTx:Invalid MAC Control subtype\n");exit(1);
}transmit(pktTx_, timeout);return 0;
}
Back to procedure
Back to recv_timer()
recv_timer()Void Mac802_11::recv_timer(){………………….switch(type) {
case MAC_Type_Management:………………………………………goto done;
case MAC_Type_Control:switch(subtype) {case MAC_Subtype_RTS:
recvRTS(pktRx_);break;
case MAC_Subtype_CTS:recvCTS(pktRx_);break;
case MAC_Subtype_ACK:recvACK(pktRx_);break;
default: …………………………………………
}break;
case MAC_Type_Data:switch(subtype) {case MAC_Subtype_Data:
recvDATA(pktRx_);break;
default:fprintf(stderr, "recv_ti
mer2:Invalid MAC Data Subtype %x\n",subtype);
exit(1);}break;
default:fprintf(stderr, "recv_timer3:Invali
d MAC Type %x\n", subtype);exit(1);
} done:
pktRx_ = 0;rx_resume();
}
Back to procedure
} else if(pktTx_) {if (mhBackoff_.busy() == 0) {
hdr_cmn *ch = HDR_CMN(pktTx_);
struct hdr_mac802_11 *mh = HDR_MAC802_11(pktTx_);
if ((u_int32_t) ch->size() < macmib_.getRTSThreshold()
|| (u_int32_t) ETHER_ADDR(mh->dh_ra) == MAC_BROADCAST) {
rTime = (Random::random() % cw_)* phymib_.getSlotTime();mhDefer_.start(phymib_.getDIFS() + rTime);
} else {
mhDefer_.start(phymib_.getSIFS());
}}
} else if(callback_) {Handler *h = callback_;callback_ = 0;h->handle((Event*) 0);
}setTxState(MAC_IDLE);
}
tx_resume()void Mac802_11::tx_resume(){
double rTime;assert(mhSend_.busy() == 0);assert(mhDefer_.busy() == 0);
if(pktCTRL_) {mhDefer_.start(phymib_.getSIFS());
} else if(pktRTS_) {if (mhBackoff_.busy() == 0) {
rTime = (Random::random() % cw_) * phymib_.getSlotTime();
mhDefer_.start( phymib_.getDIFS() + rTime);
}
Back to procedure
Back to recvCTS
Back to recvACK
rx_resume( )
Void Mac802_11::rx_resume()
{
assert(pktRx_ == 0);
assert(mhRecv_.busy() == 0);
setRxState(MAC_IDLE);
}
Back to procedure
Back to recv_timer
recvCTS( )Void Mac802_11::recvCTS(Packet *p){
if(tx_state_ != MAC_RTS) {discard(p, DROP_MAC_INVALID_STATE);return;
}
assert(pktRTS_);Packet::free(pktRTS_); pktRTS_ = 0;
assert(pktTx_);mhSend_.stop();
/* * The successful reception of this CTS packet implies * that our RTS was successful. * According to the IEEE spec 9.2.5.3, you must * reset the ssrc_, but not the congestion window. */ssrc_ = 0;tx_resume();
mac_log(p);}
Back to procedure
Back to recv_timer()
recvACK( )Void Mac802_11::recvACK(Packet *p){
struct hdr_cmn *ch = HDR_CMN(p);
if(tx_state_ != MAC_SEND) {discard(p, DROP_MAC_INVALID_STATE);return;
}assert(pktTx_);
mhSend_.stop();
if((u_int32_t) HDR_CMN(pktTx_)->size() <= macmib_.getRTSThreshold())ssrc_ = 0;
elseslrc_ = 0;
rst_cw();Packet::free(pktTx_); pktTx_ = 0;
assert(mhBackoff_.busy() == 0);mhBackoff_.start(cw_, is_idle());
tx_resume();
mac_log(p);}
Back to procedure
Back to recv_timer()
inline void Mac802_11::transmit(Packet *p, double timeout){
tx_active_ = 1;
if (EOTtarget_) {assert (eotPacket_ == NULL);eotPacket_ = p->copy();
}
/* * 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.
*/downtarget_->recv(p->copy(), this);mhSend_.start(timeout);mhIF_.start(txtime(p));
}Back to procedure
Back to check_pktRTS()
txtime( )/* * txtime() - calculate tx time for packet of size "psz" bytes * at rate "drt" bps */double Mac802_11::txtime(double psz, double drt){
double dsz = psz - phymib_.getPLCPhdrLen(); int plcp_hdr = phymib_.getPLCPhdrLen() << 3;
int datalen = (int)dsz << 3;double t = (((double)plcp_hdr)/phymib_.getPLCPDataRate())
+ (((double)datalen)/drt);return(t);
}
Back to procedure
Back to sendDATA()
When mhSend_ timer expiresvoid Mac802_11::send_timer(){
switch(tx_state_) {case MAC_RTS:RetransmitRTS();break;case MAC_CTS:assert(pktCTRL_);Packet::free(pktCTRL_); pktCTRL_ = 0;break;case MAC_SEND:RetransmitDATA();break;case MAC_ACK:assert(pktCTRL_);Packet::free(pktCTRL_); pktCTRL_ = 0;break;case MAC_IDLE:break;default:assert(0);}tx_resume();
}
Back to procedure
Back to transmit()
When mhIF_ timer expires
voidMac802_11::txHandler(){
if (EOTtarget_) {assert(eotPacket_);EOTtarget_->recv(eotPacket_, (Handler *)
0);eotPacket_ = NULL;
}tx_active_ = 0;
}Back to procedure
Back to transmit()
References
• mac-802_11.cc, mac-802_11.h
• mac-timers.cc, mac-timers.h
• http://www.ece.rice.edu/~jpr/ns/docs/802_11.html#DeferTimer
Top Related