📄 mac_80211.h
字号:
m_in_session=true; m_session_peer=p->hdr.dh_sa; assert(m_nav>=SimTime()); nav_timer.Set(m_nav); // discard the RTS packet. Other mac components may be still processing // this packet so here only the reference count is decreased by one p->free(); } else { DropPacket(p,"unexpected RTS"); return; }}template <class PLD>void MAC80211<PLD>::RecvCTS(packet_t* p){ if(m_state != MAC_CTS) { // sorry I don't need a CTS. Simply drop the packet and // do nothing. DropPacket(p, "CTS without RTS"); return; } // prepare the data packet. Please refer to the same code in // Defer() function. packet_t* np = packet_t::alloc(); np->hdr.dh_fc.fc_protocol_version = MAC_ProtocolVersion; np->hdr.dh_fc.fc_type = MAC_Type_Data; np->hdr.dh_fc.fc_subtype = MAC_Subtype_Data; np->hdr.dh_da=p->hdr.dh_sa;; np->hdr.dh_sa=MyEtherAddr; np->hdr.dh_scontrol=m_seq_no; np->hdr.size=m_pldinfo.size+HDR_LEN; np->pld=m_pldinfo.pld; np->hdr.tx_time = np->hdr.size/DataRate; np->hdr.dh_duration = usec(2*m_sifs+ACK_LEN/BasicRate + np->hdr.size/DataRate); m_state = MAC_ACK; ack_timer.Set(np, np->hdr.dh_duration*1e-6 + m_difs + SimTime()); np->inc_ref(); // I need to keep a hand on this packet TxPacket(np,m_sifs,np->hdr.tx_time); // discard the CTS packet p->free(); // cts timer still stores the RTS packet. Now need to discard it too cts_timer.GetData()->free(); cts_timer.Cancel(); // the CTS packet has been received, so cancels // the CTSTimeout event // (Gang) Actually cts timer doesn't need to store the RTS packet. // The RTS packet can be immediately freed when the CTS is sent, // for it is not used in the CTSTimer() function. The code has // been so because of my initial misunderstanding of the protocol. // I believed RTS must be retransmitted when CTSTimeout fires. Now // I know deferral has to be restarted when this happens (am I // right?)}template <class PLD>void MAC80211<PLD>::RecvData(packet_t* p){ if( m_state != MAC_IDLE && m_state != MAC_DEFER ) { // sorry, I am waiting for a CTS or an ACK DropPacket(p,"mac is busy"); return; } if(p->hdr.dh_da==MyEtherAddr )// ack is needed { // if nav_timer is not active, we can ack the data packet. // Otherwise, we need to check if the current session involves // this address (by looking at m_in_session) and if the sender of // the data packet is the session peer. Only when both conditions // are satisfied can we reply this data packet. if( nav_timer.Active() && !(m_in_session&&p->hdr.dh_sa==m_session_peer) ) { ResumeDefer(); DropPacket(p,"unexpected DATA"); return; } packet_t* np = packet_t::alloc(); np->hdr.dh_fc.fc_protocol_version = MAC_ProtocolVersion; np->hdr.dh_fc.fc_type = MAC_Type_Control; np->hdr.dh_fc.fc_subtype = MAC_Subtype_ACK; np->hdr.dh_da=p->hdr.dh_sa; np->hdr.dh_sa=MyEtherAddr; np->hdr.size = ACK_LEN; np->hdr.tx_time = np->hdr.size /BasicRate; np->hdr.dh_duration = 0; TxPacket(np,m_sifs,np->hdr.tx_time); } ResumeDefer(); // maintain a database of latest sequence numbers received // from each neighbor cache_t::iterator src=m_recv_cache.find(p->hdr.dh_sa); if(src!=m_recv_cache.end()) { // src->second is the latest sequence number // recently seen from the same source if(src->second==p->hdr.dh_scontrol) { // duplicate data packets. It seems that the source // did not receive the ack in the last round of // transmissions DropPacket(p,"duplicated DATA packet"); return; } else { // update the sequence number src->second=p->hdr.dh_scontrol; } } else { // source not found in the neighbor list, so add it to the cache m_recv_cache.insert(make_pair(p->hdr.dh_sa,p->hdr.dh_scontrol)); } // increase the reference count of the payload by one. This is to // claim that I now partly own the payload. The ownership will be // transferred to the hight layer. p->inc_pld_ref(); // forward the payload contained in the data packet to higher layer. to_network_data(p->pld,p->hdr.dh_da); p->free(); // discard the data packet;}template <class PLD>void MAC80211<PLD>::RecvACK(packet_t* p){ if(m_state != MAC_ACK) { DropPacket(p, "ACK without DATA"); return; } p->free(); // discard the ack packet ack_timer.GetData()->free(); // discard the data packet ack_timer.Cancel(); m_state=MAC_IDLE; m_cw=CWMin; // reset the contention window to_network_ack(true); // inform the higher layer that // the transmission has been successful}template <class PLD>void MAC80211<PLD>::CTSTimer(packet_t*& p){ // discard the RTS packet. It was stored in the cts timer when the cts // timer was set. Now it is returned as the first argument of the CTSTimer // function p->free(); assert(m_state==MAC_CTS); // QUESTION FOR YOU: should I increase ssrc or slrc? m_ssrc++; if(m_ssrc< ShortRetryLimit ) { if(m_cw<CWMax)m_cw=2*m_cw+1; // nearly double the contention window StartDefer(true); // as name implies, must use backoff } else { m_state=MAC_IDLE; m_cw=CWMin; // reset the contention window to_network_ack(false); // say sorry to the higher layer }}template <class PLD>void MAC80211<PLD>::ACKTimer(packet_t*& p){ assert(m_state==MAC_ACK); bool retry=false; if(m_long_pld) { m_slrc++; if(m_slrc < LongRetryLimit) retry=true; } else { m_ssrc++; if(m_ssrc < ShortRetryLimit) retry=true; } if(retry) // same as above { if(m_cw<CWMax)m_cw=2*m_cw+1; StartDefer(true); p->inc_pld_ref(); } else { m_state=MAC_IDLE; m_cw=CWMin; to_network_ack(false); } p->free();}template <class PLD>void MAC80211<PLD>::NAVTimer(trigger_t&){ // the current session should terminate at this time m_in_session=false;}template <class PLD>void MAC80211<PLD>::StartDefer(bool backoff){ // if the state is MAC_DEFER then ResumeDefer instead of this function must be called assert(m_state!=MAC_DEFER); assert(defer_timer.Active()==false); m_backoff_time = Random( m_cw * SlotTime); // select a backoff time Printf((DumpPackets, "mac%d deferring (%d)\n",(int)MyEtherAddr,m_state)); // if the recv timer is active then do nothing except changing // the state to MAC_DEFER, because it is guaranteed that at the // end of RecvTimer, backoff must be resumed. if(!recv_timer.Active()) { // if last transmission failed, eifs must be used if(m_tx_failed) m_ifs=m_eifs; else m_ifs=m_difs; double pt = m_ifs; if(backoff) pt+=m_backoff_time; // may not need backoff double now=SimTime(); if(now<m_last_send)now=m_last_send; if(m_nav>now) m_defer_start=m_nav; else m_defer_start=now; defer_timer.Set(m_defer_start+pt); } m_state=MAC_DEFER;}template <class PLD>void MAC80211<PLD>::ResumeDefer(){ // backoff can only be resumed when it is already in this state if(m_state!=MAC_DEFER)return; // don't need to select a new backoff time if(defer_timer.Active())printf("Mac%d\n",(int)MyEtherAddr); assert(defer_timer.Active()==false); if(m_tx_failed) m_ifs=m_eifs; else m_ifs=m_difs; double now=SimTime(); if(now<m_last_send)now=m_last_send; if(m_nav>now) m_defer_start=m_nav; else m_defer_start=now; defer_timer.Set(m_defer_start+m_ifs+m_backoff_time); Printf((DumpPackets, "mac%d resumes deferring\n", (int)MyEtherAddr));}template <class PLD>void MAC80211<PLD>::TxPacket(packet_t* p, simtime_t tx_time){ // sends out a packet immediately double now=SimTime(); Printf((DumpPackets,"mac%d sends %s until %f\n",(int)MyEtherAddr, p->dump().c_str(),now+tx_time)); if(now<m_last_send) { printf("two sends overlap\n"); return; } m_last_send=now+tx_time; to_phy(p); SentPackets++;}template <class PLD>void MAC80211<PLD>::TxPacket(packet_t* p, simtime_t start_time, simtime_t tx_time){ // sends out a packet with certain delay double start=SimTime()+start_time; Printf((DumpPackets,"mac%d sends %s from %f to %f\n",(int)MyEtherAddr,p->dump().c_str(),start,start+tx_time)); if(start<m_last_send) { printf("two sends overlap\n"); return; } m_last_send=start+tx_time; assert(!phy_timer.Active()); phy_timer.Set(p,start); SentPackets++;}template <class PLD>void MAC80211<PLD>::NetworkAckTimer(bool& ack){ to_network_ack(ack);}template <class PLD>void MAC80211<PLD>::PhyTimer(packet_t* &p){ to_phy(p);}template <class PLD>void MAC80211<PLD>::DropPacket(packet_t* p, const char* reason){ Printf((DumpPackets,"mac%d drops %s (%s)\n",(int)MyEtherAddr,p->dump().c_str(),reason)); p->free();}#endif /* mac80211_h */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -