官方文檔說明
處理IEEE 802.11數據幀的序列號。
源碼分析
位置:
/src/wifi/model/mac-tx-middle.cc
它的源代碼很簡單。僅僅有四五個函數。
完成的功能就是計算數據幀的序號。
MacTxMiddle::MacTxMiddle ()
: m_sequence (0)
{
}
MacTxMiddle::~MacTxMiddle ()
{
for (std::map<Mac48Address,uint16_t*>::iterator i = m_qosSequences.begin (); i != m_qosSequences.end (); i++)
{
delete [] i->second;
}
}
構造器函數很簡單,僅有一個uint16_t類型的變量。
而m_qosSequences變量比較特殊:
std::map <Mac48Address,uint16_t*> m_qosSequences;
m_qosSequences變量以mac地址為key,以uint16_t類型的數組為value.
為什么這樣設置呢?
對應一個node節點,有一個mac地址,作為key。
它的value值,也就是uint16_t類型的數組,數組長度從源碼可以看出設置為16.
關鍵就在此,為什么是16?因為802.11有很多改進版本,其中的改進版本提出了EDCA,Enhanced Distributed Channel Access,支持QOS。對數據幀提出了優先級的概念,優先級高的優先發送,優先級低的稍后發送,這里可以看看edca-txop.cc的代碼。所以這個數組就是對應的各個優先級考慮的。每一個優先級有一個編號。
uint16_t
MacTxMiddle::GetNextSequenceNumberfor (const WifiMacHeader *hdr)
{
uint16_t retval;
if (hdr->IsQosData ()
&& !hdr->GetAddr1 ().IsGroup ())
{
uint8_t tid = hdr->GetQosTid ();
NS_ASSERT (tid < 16);
std::map<Mac48Address, uint16_t*>::iterator it = m_qosSequences.find (hdr->GetAddr1 ());
if (it != m_qosSequences.end ())
{
retval = it->second[tid];
it->second[tid]++;
it->second[tid] %= 4096;
}
else
{
retval = 0;
std::pair <Mac48Address,uint16_t*> newSeq (hdr->GetAddr1 (), new uint16_t[16]);
std::pair <std::map<Mac48Address,uint16_t*>::iterator,bool> newIns = m_qosSequences.insert (newSeq);
NS_ASSERT (newIns.second == true);
for (uint8_t i = 0; i < 16; i++)
{
newIns.first->second[i] = 0;
}
newIns.first->second[tid]++;
}
}
else
{
retval = m_sequence;
m_sequence++;
m_sequence %= 4096;
}
return retval;
}
GetNextSequenceNumberfor方法就是根據Mac頭生成對應的序列號。
分為兩種情況:
一種情況:如果mac幀不支持Qos或者是組播或廣播的話,直接在序號m_sequence加一返回就行。
二種情況:如果Mac幀支持Qos且不是廣播或組播,此時就根據m_qosSequences這個map類型變量查找對應的mac頭,如果找到了,則對應的序列號加一返回。如果沒有找到,則創建一個信息的key-value對,并序列號初始化為0,然后返回。
uint16_t
MacTxMiddle::PeekNextSequenceNumberfor (const WifiMacHeader *hdr)
{
uint16_t retval;
if (hdr->IsQosData ()
&& !hdr->GetAddr1 ().IsGroup ())
{
uint8_t tid = hdr->GetQosTid ();
NS_ASSERT (tid < 16);
std::map<Mac48Address, uint16_t*>::iterator it = m_qosSequences.find (hdr->GetAddr1 ());
if (it != m_qosSequences.end ())
{
retval = it->second[tid];
}
else
{
retval = 0;
}
}
else
{
retval = m_sequence;
}
return retval;
}
這個方法PeekNextSequenceNumberfor 是上面的GetNextSequenceNumberfor 功能類似,只不過GetNextSequenceNumberfor 方法下一個序列號,并改變了其中的變量的值。
而PeekNextSequenceNumberfor 同樣返回下一個序列號的值,但不改變其中的變量的值。
uint16_t
MacTxMiddle::GetNextSeqNumberByTidAndAddress (uint8_t tid, Mac48Address addr) const
{
NS_ASSERT (tid < 16);
uint16_t seq = 0;
std::map <Mac48Address,uint16_t*>::const_iterator it = m_qosSequences.find (addr);
if (it != m_qosSequences.end ())
{
return it->second[tid];
}
return seq;
}
GetNextSeqNumberByTidAndAddress 方法根據tid和addr地址直接返回下一個序列號的值,不會對其中的變量做更改。
功能類似于PeekNextSequenceNumberfor 。
完全可以對PeekNextSequenceNumberfor 方法進行更改,利用GetNextSeqNumberByTidAndAddress 方法來實現上述功能。
更改后的方法如下:
uint16_t
MacTxMiddle::PeekNextSequenceNumberfor (const WifiMacHeader *hdr)
{
uint16_t retval;
if (hdr->IsQosData ()
&& !hdr->GetAddr1 ().IsGroup ())
{
retval = GetNextSeqNumberByTidAndAddress (hdr->GetQosTid () , hdr->GetAddr1());
}
else
{
retval = m_sequence;
}
return retval;
}
更改后,PeekNextSequenceNumberfor 方法就簡化了一點。