官方文档说明
该类处理片段的重复检测和重组。
也就是说该类的功能主要是检测节点接收到的分组是否重复,以及是否是分片,如果是分片的话,缓存分片。并且等待接收到最后一个分片的情况下,重新组合接收到的分片成为一个完整的packet,也就是重组。
源码解析
源码位置:
/src/wifi/model/mac-rx-middle.cc
从源码的角度来看,整个MacRxMiddle类还是比较简单的。
方法数并不是很多。只有一个构造函数。
MacRxMiddle::MacRxMiddle ()
{
NS_LOG_FUNCTION_NOARGS ();
}
ns3中使用到MacRxMiddle类对象的地方,也就是RegularWifiMac类中使用。是通过回调实现的。
RegularWifiMac类在其构造器中使用下面的代码创建MacRxMiddle类对象那个,并将RegularWifiMac::Receive方法设置为回调函数地址。
m_rxMiddle = new MacRxMiddle ();
m_rxMiddle->SetForwardCallback (MakeCallback (&RegularWifiMac::Receive, this));
而MacRxMiddle的SetForwardCallback方法源码为:
void
MacRxMiddle::SetForwardCallback (ForwardUpCallback callback)
{
NS_LOG_FUNCTION_NOARGS ();
m_callback = callback;
}
MacRxMiddle类比较重要的方法是Receive方法。
void
MacRxMiddle::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
{
NS_LOG_FUNCTION (packet << hdr);
NS_ASSERT (hdr->IsData () || hdr->IsMgt ());
OriginatorRxStatus *originator = Lookup (hdr);
if (!(SequenceNumber16 (originator->GetLastSequenceControl ()) < SequenceNumber16 (hdr->GetSequenceControl ())))
{
NS_LOG_DEBUG ("Sequence numbers have looped back. last recorded=" << originator->GetLastSequenceControl () <<
" currently seen=" << hdr->GetSequenceControl ());
}
//filter duplicates.
if (IsDuplicate (hdr, originator))
{
NS_LOG_DEBUG ("duplicate from=" << hdr->GetAddr2 () <<
", seq=" << hdr->GetSequenceNumber () <<
", frag=" << hdr->GetFragmentNumber ());
return;
}
Ptr<Packet> agregate = HandleFragments (packet, hdr, originator);
if (agregate == 0)
{
return;
}
NS_LOG_DEBUG ("forwarding data from=" << hdr->GetAddr2 () <<
", seq=" << hdr->GetSequenceNumber () <<
", frag=" << hdr->GetFragmentNumber ());
if (!hdr->GetAddr1 ().IsGroup ())
{
originator->SetSequenceControl (hdr->GetSequenceControl ());
}
m_callback (agregate, hdr);
}
MacRxMiddle::Receive方法通过Mac头找到对应的OriginatorRxStatus 对象,比较上一次接收的序列控制号与本次接收到的packet的序列控制号是否是有序的。
然后通过IsDuplicate 方法判断接收的packet是否是重复的,如果重复,直接返回。
然后通过HandleFragments 方法判断是否需要重组packet,以及完成packet的重组。
如果返回的agregate 对象为空,直接返回。
如果返回的agregate 对象不空,则通过上面的MacRxMiddle::SetForwardCallback方法设置的回调函数地址调用相对应的回调函数。
综上来看,上面的MacRxMiddle::Receive设计到三个重要的方法:Lookup IsDuplicate HandleFragments 。一个个来看。
首先看Lookup 方法:
OriginatorRxStatus *
MacRxMiddle::Lookup (const WifiMacHeader *hdr)
{
NS_LOG_FUNCTION (hdr);
OriginatorRxStatus *originator;
Mac48Address source = hdr->GetAddr2 ();
if (hdr->IsQosData ()
&& !hdr->GetAddr2 ().IsGroup ())
{
/* only for qos data non-broadcast frames */
originator = m_qosOriginatorStatus[std::make_pair (source, hdr->GetQosTid ())];
if (originator == 0)
{
originator = new OriginatorRxStatus ();
m_qosOriginatorStatus[std::make_pair (source, hdr->GetQosTid ())] = originator;
}
}
else
{
originator = m_originatorStatus[source];
if (originator == 0)
{
originator = new OriginatorRxStatus ();
m_originatorStatus[source] = originator;
}
}
return originator;
}
MacRxMiddle::Lookup 方法完成的功能就是通过Mac头找到对应的OriginatorRxStatus 对象,如果没有,则创建一个对应的OriginatorRxStatus 对象。
OriginatorRxStatus 类功能也比较简单:
class OriginatorRxStatus
{
private:
//list列表,保存接收的每个分片packet,当接收到最后一个分片的时候,组合为完成的一个packet。
typedef std::list<Ptr<const Packet> > Fragments;
//迭代器
typedef std::list<Ptr<const Packet> >::const_iterator FragmentsCI;
//标记位,标记接收的packet是否为分片
bool m_defragmenting;
//记录上一次接收的packet的序列控制号
uint16_t m_lastSequenceControl;
//list对象
Fragments m_fragments;
public:
//默认构造器,初始序列控制号全是1,并标记不是分片。
OriginatorRxStatus ()
{
m_lastSequenceControl = 0xffff;
m_defragmenting = false;
}
~OriginatorRxStatus ()
{
m_fragments.clear ();
}
//返回是否是分片标记位
bool IsDeFragmenting (void)
{
return m_defragmenting;
}
//当接收到第一个分片的时候,设置标记位,并保存第一个分片packet。
void AccumulateFirstFragment (Ptr<const Packet> packet)
{
NS_ASSERT (!m_defragmenting);
m_defragmenting = true;
m_fragments.push_back (packet);
}
//当接收到最后一个分片的时候,重置标记位,并通过m_fragments对象保存的每一个分片,重新生成一个完成的packet对象,并返回。
Ptr<Packet> AccumulateLastFragment (Ptr<const Packet> packet)
{
NS_ASSERT (m_defragmenting);
m_fragments.push_back (packet);
m_defragmenting = false;
Ptr<Packet> full = Create<Packet> ();
for (FragmentsCI i = m_fragments.begin (); i != m_fragments.end (); i++)
{
full->AddAtEnd (*i);
}
m_fragments.erase (m_fragments.begin (), m_fragments.end ());
return full;
}
//当接收的分片既不是第一个,又不是最后一个分片的时候,保存在list列表中.
void AccumulateFragment (Ptr<const Packet> packet)
{
NS_ASSERT (m_defragmenting);
m_fragments.push_back (packet);
}
//该方法判断接收的分片是否是上一个分片的序列控制号m_lastSequenceControl 的下一个序列控制号
bool IsNextFragment (uint16_t sequenceControl)
{
if ((sequenceControl >> 4) == (m_lastSequenceControl >> 4)
&& (sequenceControl & 0x0f) == ((m_lastSequenceControl & 0x0f) + 1))
{
return true;
}
else
{
return false;
}
}
uint16_t GetLastSequenceControl (void)
{
return m_lastSequenceControl;
}
void SetSequenceControl (uint16_t sequenceControl)
{
m_lastSequenceControl = sequenceControl;
}
};
MacRxMiddle::Lookup 方法完成的功能就是通过Mac头找到对应的OriginatorRxStatus 对象,有了OriginatorRxStatus 对象就可以完成分片的一些判断了。
MacRxMiddle::IsDuplicate 方法就通过Mac头和上面的MacRxMiddle::Lookup 方法返回的OriginatorRxStatus 对象来判断接收的分片是否是重复的:
bool
MacRxMiddle::IsDuplicate (const WifiMacHeader* hdr,
OriginatorRxStatus *originator) const
{
NS_LOG_FUNCTION (hdr << originator);
if (hdr->IsRetry ()
&& originator->GetLastSequenceControl () == hdr->GetSequenceControl ())
{
return true;
}
return false;
}
如果上一次接收的序列控制号与本次接收的序列控制号相等,那就是重复的。
MacRxMiddle::HandleFragments方法完成对接收到的分片进行处理,也同样通过利用MacRxMiddle::Lookup 方法返回的OriginatorRxStatus 对象。
Ptr<Packet>
MacRxMiddle::HandleFragments (Ptr<Packet> packet, const WifiMacHeader *hdr,
OriginatorRxStatus *originator)
{
NS_LOG_FUNCTION (packet << hdr << originator);
if (originator->IsDeFragmenting ())
{
if (hdr->IsMoreFragments ())
{
if (originator->IsNextFragment (hdr->GetSequenceControl ()))
{
NS_LOG_DEBUG ("accumulate fragment seq=" << hdr->GetSequenceNumber () <<
", frag=" << hdr->GetFragmentNumber () <<
", size=" << packet->GetSize ());
originator->AccumulateFragment (packet);
originator->SetSequenceControl (hdr->GetSequenceControl ());
}
else
{
NS_LOG_DEBUG ("non-ordered fragment");
}
return 0;
}
else
{
if (originator->IsNextFragment (hdr->GetSequenceControl ()))
{
NS_LOG_DEBUG ("accumulate last fragment seq=" << hdr->GetSequenceNumber () <<
", frag=" << hdr->GetFragmentNumber () <<
", size=" << hdr->GetSize ());
Ptr<Packet> p = originator->AccumulateLastFragment (packet);
originator->SetSequenceControl (hdr->GetSequenceControl ());
return p;
}
else
{
NS_LOG_DEBUG ("non-ordered fragment");
return 0;
}
}
}
else
{
if (hdr->IsMoreFragments ())
{
NS_LOG_DEBUG ("accumulate first fragment seq=" << hdr->GetSequenceNumber () <<
", frag=" << hdr->GetFragmentNumber () <<
", size=" << packet->GetSize ());
originator->AccumulateFirstFragment (packet);
originator->SetSequenceControl (hdr->GetSequenceControl ());
return 0;
}
else
{
return packet;
}
}
}
1、如果接收的Mac头对应的packet是分片,即originator->IsDeFragmenting ()返回true,并且Mac头还有分片,即hdr->IsMoreFragments ()返回true,且当前接收的packet就是上一次接收的分片的下一个,序列控制号没有出错,则通过originator对象完成分片的缓存,并重置序列控制号,为下一次接收的分片做准备。
2、如果接收的Mac头对应的packet是分片,即originator->IsDeFragmenting ()返回true,并且Mac头还有分片,即hdr->IsMoreFragments ()返回true,但是当前接收的packet不是上一次接收的分片的下一个,则NS_LOG_DEBUG ("non-ordered fragment");
3、如果接收的Mac头对应的packet是分片,即originator->IsDeFragmenting ()返回true,并且Mac头没有分片,即hdr->IsMoreFragments ()返回false,且当前接收的packet就是上一次接收的分片的下一个,说明接收到了最后一个分片,则通过originator对象的AccumulateLastFragment 方法完成分片的重组,返回一个完成的packet:
Ptr<Packet> p = originator->AccumulateLastFragment (packet);
originator->SetSequenceControl (hdr->GetSequenceControl ());
return p;
4、如果接收的Mac头对应的packet不是分片,即originator->IsDeFragmenting ()返回false,并且Mac头还有分片,即hdr->IsMoreFragments ()返回true,说明接收到的packet是第一个分片,则通过originator的AccumulateFirstFragment 方法处理第一个分片,并设置标记位和序列控制号,为下一个分片做准备。
5、如果接收的Mac头对应的packet不是分片,即originator->IsDeFragmenting ()返回false,并且Mac头没有分片,即hdr->IsMoreFragments ()返回false,即接收的packet是一个独立的数据帧,不是分片,则直接返回该packet对象。
至此,MacRxMiddle类的方法基本说明完毕。
另外,需要说明MacRxMiddle类的Receive 的调用,同样是在RegularWifiMac::RegularWifiMac ()构造器函数中设置的。代码如下:
RegularWifiMac::RegularWifiMac () :
m_htSupported (0),
m_vhtSupported (0),
m_erpSupported (0),
m_dsssSupported (0)
{
NS_LOG_FUNCTION (this);
//创建MacRxMiddle 对象。
m_rxMiddle = new MacRxMiddle ();
//设置MacRxMiddle 对象中回调地址
m_rxMiddle->SetForwardCallback (MakeCallback (&RegularWifiMac::Receive, this));
m_txMiddle = new MacTxMiddle ();
m_low = CreateObject<MacLow> ();
//设置MacRxMiddle 对象的Receive方法的回调
m_low->SetRxCallback (MakeCallback (&MacRxMiddle::Receive, m_rxMiddle));
。。。。
}
也就是说MacLow对象中有一个回调地址,设置为MacRxMiddle::Receive,该回调地址调用MacRxMiddle::Receive方法,而MacRxMiddle::Receive方法中,又回调RegularWifiMac::Receive方法,这样一层层传递的。
网友评论