NS3 WiFiNetDevice结构

先看一个图

wifinetdevice.png

这个图是说明了WiFi模块下,WiFiNetDevice的调用过程。

从WiFiNetDevice向下层调用过程,从这一张图就可以看出来。而从WiFiNetDevice向上层的调用过程,只用从WiFiNetDevice开始。这样隔离开,方便简单一些。

下面从源码的角度,一步步说明图中的调用过程。

WifiNetDevice::Send

bool
WifiNetDevice::Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
{
  NS_LOG_FUNCTION (this << packet << dest << protocolNumber);
  NS_ASSERT (Mac48Address::IsMatchingType (dest));

  Mac48Address realTo = Mac48Address::ConvertFrom (dest);

  LlcSnapHeader llc;
  llc.SetType (protocolNumber);
  packet->AddHeader (llc);

  m_mac->NotifyTx (packet);
  m_mac->Enqueue (packet, realTo);
  return true;
}

m_mac参数的类型是Ptr<WifiMac>,NotifyTx方法是Trace追踪,Enqueue 方法将packet加入队列。

WiFiMac::Enqueue

virtual void Enqueue (Ptr<const Packet> packet, Mac48Address to) = 0;

这是WiFiMac::Enqueue方法的声明,是一个纯虚函数,子类必须实现这个方法。

WiFiMac的子类有:


WiFiMac的子类.png

RegularWifiMac::Enqueue

void
RegularWifiMac::Enqueue (Ptr<const Packet> packet,
                         Mac48Address to, Mac48Address from)
{
  //We expect RegularWifiMac subclasses which do support forwarding (e.g.,
  //AP) to override this method. Therefore, we throw a fatal error if
  //someone tries to invoke this method on a class which has not done
  //this.
  NS_FATAL_ERROR ("This MAC entity (" << this << ", " << GetAddress ()
                                      << ") does not support Enqueue() with from address");
}

这个方法并没有什么实质性的功能。并且这个方法默认WiFiMac不支持。

AdhocWifiMac::Enqueue

以AdhocWifiMac::Enqueue函数为例,其他的两个是AP-STA模式下应用。AdhocWifiMac使用与Adhoc网络。

void
AdhocWifiMac::Enqueue (Ptr<const Packet> packet, Mac48Address to)
{
  NS_LOG_FUNCTION (this << packet << to);
  ...

  WifiMacHeader hdr;
  ...
  if (m_qosSupported)
    {
      NS_ASSERT (tid < 8);
      m_edca[QosUtilsMapTidToAc (tid)]->Queue (packet, hdr);
    }
  else
    {
      m_dca->Queue (packet, hdr);
    }
}

AdhocWifiMac::Enqueue函数中有if语句

如果网络支持Qos,就会进入类EdcaTxopN的Queue函数;
如果不支持Qos,就会进入DcaTxop类的Queue函数。

这两个函数区别在于业务类型,EdcaTxopN类有四种业务类型:

*   -AC_VO : voice, tid = 6,7         ^
*   -AC_VI : video, tid = 4,5         |
*   -AC_BE : best-effort, tid = 0,3   |  priority
*   -AC_BK : background, tid = 1,2    |

DcaTxop类就没有这种业务类型的区别。

这两个类完成的功能就是packet排队,等到信道空闲,节点获取到信道,发送packet。发送packet的代码是一样的,有差别的地方都在这两个类中完成了。

DcaTxop类简单些,以这个类为例,向下说明代码流程。

DcaTxop::Queue

void
DcaTxop::Queue (Ptr<const Packet> packet, const WifiMacHeader &hdr)
{
  NS_LOG_FUNCTION (this << packet << &hdr);
  WifiMacTrailer fcs;
  m_stationManager->PrepareForQueue (hdr.GetAddr1 (), &hdr, packet);
  m_queue->Enqueue (packet, hdr);
  StartAccessIfNeeded ();
}

从该方法中可以看出,packet加入队列,m_queue的类型为Ptr<WifiMacQueue>,功能就是讲packet加入队列。
StartAccessIfNeeded ();这一行代码就会判断当前信道空闲与否,随机回退值等。

void
DcaTxop::StartAccessIfNeeded (void)
{
  NS_LOG_FUNCTION (this);
  if (m_currentPacket == 0
      && !m_queue->IsEmpty ()
      && !m_dcf->IsAccessRequested ())
    {
      m_manager->RequestAccess (m_dcf);
    }
}

m_currentPacket 代表当前正在发送的packet。
m_queue 就是packet队列。
m_dcf 设置窗口大小、状态等,同时能够完成回调,通知DcaTxop或者EdcaTxopN获取信道权限、出现碰撞、唤醒、休眠等。
m_manager负责请求信道,判断时间等,并通过m_dcf 对象回调DcaTxop或者EdcaTxopN中的方法。

这里的回调跟Java是一样的。
DcaTxop或者EdcaTxopN类中有m_dcf 对象,将m_dcf 对象传递给m_manager对象,m_manager对象再通过m_dcf 对象调用m_dcf 对象的方法,m_dcf 对象的方法又调用DcaTxop或者EdcaTxopN类中的方法。

DcfManager::RequestAccess

void
DcfManager::RequestAccess (DcfState *state)
{
  NS_LOG_FUNCTION (this << state);
  ...
  DoGrantAccess ();
  DoRestartAccessTimeoutIfNeeded ();
}

void
DcfManager::DoGrantAccess (void)
{
  NS_LOG_FUNCTION (this);
  uint32_t k = 0;
  for (States::const_iterator i = m_states.begin (); i != m_states.end (); k++)
    {
      DcfState *state = *i;
      if (state->IsAccessRequested ()
          && GetBackoffEndFor (state) <= Simulator::Now () )
        {
          i++; //go to the next item in the list.
          k++;
          std::vector<DcfState *> internalCollisionStates;
          for (States::const_iterator j = i; j != m_states.end (); j++, k++)
            {
              DcfState *otherState = *j;
              if (otherState->IsAccessRequested ()
                  && GetBackoffEndFor (otherState) <= Simulator::Now ())
              {
                  internalCollisionStates.push_back (otherState);
                }
            }

          /**
           * 现在,我们一次通知所有这些更改。 有必要首先执行哪些状态发生冲突的计算,
           * 然后仅应用改变,因为通过通知应用改变可以改变管理器的全局状态,并且因此可以改变计算的结果。
           */
          state->NotifyAccessGranted ();
          for (std::vector<DcfState *>::const_iterator k = internalCollisionStates.begin ();
               k != internalCollisionStates.end (); k++)
            {
              (*k)->NotifyInternalCollision ();
            }
          break;
        }
      i++;
    }
}

DcfManager::RequestAccess方法调用DcfManager::DoGrantAccess方法,最后调用state->NotifyAccessGranted ()方法回调。state就是上面传递的m_dcf 对象。

DcfState对象的NotifyAccessGranted

void
DcfState::NotifyAccessGranted (void)
{
  NS_ASSERT (m_accessRequested);
  m_accessRequested = false;
  DoNotifyAccessGranted ();
}

virtual void DoNotifyAccessGranted (void)
  {
    m_txop->NotifyAccessGranted ();
  }

m_txop对象就是上文的DcaTxop类对象。

DcaTxop::NotifyAccessGranted

void
DcaTxop::NotifyAccessGranted (void)
{
  NS_LOG_FUNCTION (this);
     ...
     ...
  MacLowTransmissionParameters params;
  params.DisableOverrideDurationId ();

  /**
   * 如果是一个组播,程序走这里
   */
   params.DisableOverrideDurationId ();
   params.DisableRts ();
   params.DisableAck ();
   params.DisableNextData ();
   
  if (m_currentHdr.GetAddr1 ().IsGroup ())
    {
      params.DisableRts ();
      params.DisableAck ();
      params.DisableNextData ();
      Low ()->StartTransmission (m_currentPacket,
                                 &m_currentHdr,
                                 params,
                                 m_transmissionListener);
      NS_LOG_DEBUG ("tx broadcast");
    }
  else
    {
      params.EnableAck ();
      if (NeedFragmentation ())//默认情况下,不需要分片。
        {
          WifiMacHeader hdr;
          Ptr<Packet> fragment = GetFragmentPacket (&hdr);
          if (IsLastFragment ())
            {
              NS_LOG_DEBUG ("fragmenting last fragment size=" << fragment->GetSize ());
              params.DisableNextData ();
            }
          else
            {
              NS_LOG_DEBUG ("fragmenting size=" << fragment->GetSize ());
              params.EnableNextData (GetNextFragmentSize ());
            }
          Low ()->StartTransmission (fragment, &hdr, params,
                                     m_transmissionListener);
        }
      //=====================正常情况下,走这里========================
      else
        {
          params.DisableNextData ();//表示没有下一个fragment分片。
          Low ()->StartTransmission (m_currentPacket, &m_currentHdr,
                                     params, m_transmissionListener);
        }
    }
}

上面的代码会调用Low ()->StartTransmission 方法。Low ()返回的是MacLow类对象。

MacLow::StartTransmission

void
MacLow::StartTransmission (Ptr<const Packet> packet,
                           const WifiMacHeader* hdr,
                           MacLowTransmissionParameters params,
                           MacLowTransmissionListener *listener)
{
  NS_LOG_FUNCTION (this << packet << hdr << params << listener);
  m_currentPacket = packet->Copy ();

  SocketPriorityTag priorityTag;
  m_currentPacket->RemovePacketTag (priorityTag);
  m_currentHdr = *hdr;
  CancelAllEvents ();
  m_listener = listener;
  m_txParams = params;
  m_currentTxVector = GetDataTxVector (m_currentPacket, &m_currentHdr);
    
  ...
  ...

  NS_LOG_DEBUG ("startTx size=" << GetSize (m_currentPacket, &m_currentHdr) <<
                ", to=" << m_currentHdr.GetAddr1 () << ", listener=" << m_listener);

  if (m_txParams.MustSendRts ())
    {
      SendRtsForPacket ();//发送RTS
    }
  else
    {
      if ((m_ctsToSelfSupported || m_stationManager->GetUseNonErpProtection ()) && NeedCtsToSelf ())
        {
          SendCtsToSelf ();//发送CTS
        }
      else
        {
          SendDataPacket ();//发送数据
        }
    }

  /* 
   * 当这个方法完成,我们已经取得媒质的所有权。
   *  */
  NS_ASSERT (m_phy->IsStateTx ());
}

ampdu设计packet聚合之类的东西,麻烦。
一般情况下,三种发送:

SendRtsForPacket ();//发送RTS
SendCtsToSelf ();//发送CTS
SendDataPacket ();//发送数据

RTS/CTS大家应该知道吧。
重点说SendDataPacket ()。

MacLow::SendDataPacket

void
MacLow::SendDataPacket (void)
{
  NS_LOG_FUNCTION (this);
  ...
  ...
  ForwardDown (m_currentPacket, &m_currentHdr, m_currentTxVector, preamble);
  m_currentPacket = 0;
}

MacLow::ForwardDown

void
MacLow::ForwardDown (Ptr<const Packet> packet, const WifiMacHeader* hdr,
                     WifiTxVector txVector, WifiPreamble preamble)
{
  NS_LOG_FUNCTION (this << packet << hdr << txVector);
  NS_LOG_DEBUG ("send " << hdr->GetTypeString () <<
                ", to=" << hdr->GetAddr1 () <<
                ", size=" << packet->GetSize () <<
                ", mode=" << txVector.GetMode  () <<
                ", duration=" << hdr->GetDuration () <<
                ", seq=0x" << std::hex << m_currentHdr.GetSequenceControl () << std::dec);

  if (!m_ampdu || hdr->IsRts () || hdr->IsBlockAck ())
    {
      NS_LOG_LOGIC("mac-low.cc  if->    m_ampdu:"<<m_ampdu<<",hdr->isrts:"
                    <<hdr->IsRts()<<",hdr->isblockack:"<<hdr->IsBlockAck());
      m_phy->SendPacket (packet, txVector, preamble);
    }
    ...
}

MacLow::ForwardDown 会调用m_phy对象的SendPacket 方法。

m_phy就是WifiPhy类型,代表物理层

WifiPhy

WifiPhy类包含虚函数,不能构建对象。它的子类可以。

WifiPhy类子类.png

其实,上面的m_phy就是YansWifiPhy类类型。

YansWifiPhy::SendPacket

void
YansWifiPhy::SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble)
{
  SendPacket (packet, txVector, preamble, NORMAL_MPDU);
}

void
YansWifiPhy::SendPacket (Ptr<const Packet> packet, WifiTxVector txVector, WifiPreamble preamble, 
                        enum mpduType mpdutype)
{
  NS_LOG_FUNCTION (this << packet << txVector.GetMode () 
    << txVector.GetMode ().GetDataRate (txVector)
    << preamble << (uint32_t)txVector.GetTxPowerLevel () << (uint32_t)mpdutype);
 
  NS_ASSERT (!m_state->IsStateTx () && !m_state->IsStateSwitching ());
  ......
  m_channel->Send (this, packet, GetPowerDbm (txVector.GetTxPowerLevel ()) +
                           GetTxGain (), txVector, preamble, mpdutype, txDuration);
}

YansWifiPhy::SendPacket 方法会调用m_channel->Send方法。
m_channel对象是YansWifiChannel类类型。

WiFiChannel类子类.png

YansWifiChannel::Send

void
YansWifiChannel::Send (Ptr<YansWifiPhy> sender, Ptr<const Packet> packet, double txPowerDbm,
                       WifiTxVector txVector, WifiPreamble preamble, enum mpduType mpdutype, Time duration) const
{
  Ptr<MobilityModel> senderMobility = sender->GetMobility ()->GetObject<MobilityModel> ();
  NS_ASSERT (senderMobility != 0);
  uint32_t j = 0;
  for (PhyList::const_iterator i = m_phyList.begin (); i != m_phyList.end (); i++, j++)
    {
      if (sender != (*i))
        {
          //For now don't account for inter channel interference
          if ((*i)->GetChannelNumber () != sender->GetChannelNumber ())
            {
              continue;
            }
          ...
          Simulator::ScheduleWithContext (dstNode,
                                          delay, &YansWifiChannel::Receive, this,
                                          j, copy, parameters);
        }
    }
}

YansWifiChannel::Send里面调用了:

Simulator::ScheduleWithContext (dstNode,
                                          delay, &YansWifiChannel::Receive, this,
                                          j, copy, parameters);

这个方法的意思是经过delay时间后,调用YansWifiChannel::Receive方法,并以 this,j, copy, parameters这四个变量为参数。dstNode是上下文,是一个uint16_t类型值,不重要。

YansWifiChannel::Receive

void
YansWifiChannel::Receive (uint32_t i, Ptr<Packet> packet, struct Parameters parameters) const
{
  m_phyList[i]->StartReceivePreambleAndHeader (packet, parameters.rxPowerDbm, 
                                                parameters.txVector, parameters.preamble,
                                                parameters.type, parameters.duration);
}

该方法 调用YansWifiPhy的StartReceivePreambleAndHeader 方法。

YansWifiPhy::StartReceivePreambleAndHeader

void
YansWifiPhy::StartReceivePreambleAndHeader (Ptr<Packet> packet,
                                            double rxPowerDbm,
                                            WifiTxVector txVector,
                                            enum WifiPreamble preamble,
                                            enum mpduType mpdutype,
                                            Time rxDuration)
{
  NS_LOG_FUNCTION (this << packet << rxPowerDbm << txVector.GetMode () << preamble << (uint32_t)mpdutype);
  ...

  switch (m_state->GetState ())
    {
    case YansWifiPhy::SWITCHING:
      NS_LOG_DEBUG ("drop packet because of channel switching");
      ....
      break;
    case YansWifiPhy::RX:
      NS_LOG_DEBUG ("drop packet because already in Rx (power=" <<
                    rxPowerW << "W)");
      ...
      break;
    case YansWifiPhy::TX:
      NS_LOG_DEBUG ("drop packet because already in Tx (power=" <<
                    rxPowerW << "W)");
      ...
      break;
    case YansWifiPhy::CCA_BUSY:
    case YansWifiPhy::IDLE:
      
      if (rxPowerW > GetEdThresholdW ())
        {
          .....
          if (preamble != WIFI_PREAMBLE_NONE)
            {
              NS_ASSERT (m_endPlcpRxEvent.IsExpired ());
              m_endPlcpRxEvent = Simulator::Schedule (preambleAndHeaderDuration, 
                                                      &YansWifiPhy::StartReceivePacket, this,
                                                      packet, txVector, preamble, mpdutype, event);
            }

          NS_ASSERT (m_endRxEvent.IsExpired ());
          m_endRxEvent = Simulator::Schedule (rxDuration, &YansWifiPhy::EndReceive, this,
                                              packet, preamble, mpdutype, event);
        }
      else
        {
          ...
        }
      break;
    case YansWifiPhy::SLEEP:
      NotifyRxDrop (packet);
      m_plcpSuccess = false;
      break;
    }

  return;

maybeCcaBusy:
  ...
}

其中两个重要的方法在于:

m_endPlcpRxEvent = Simulator::Schedule (preambleAndHeaderDuration, 
                                                      &YansWifiPhy::StartReceivePacket, this,
                                                      packet, txVector, preamble, mpdutype, event);

m_endRxEvent = Simulator::Schedule (rxDuration, &YansWifiPhy::EndReceive, this,
                                              packet, preamble, mpdutype, event);

先调用YansWifiPhy::StartReceivePacket,后调用YansWifiPhy::EndReceive。
YansWifiPhy::StartReceivePacket方法没有发生跳转,重要的跳转发生在YansWifiPhy::EndReceive。

YansWifiPhy::EndReceive

void
YansWifiPhy::EndReceive (Ptr<Packet> packet, enum WifiPreamble preamble, 
                        enum mpduType mpdutype, Ptr<InterferenceHelper::Event> event)
{
  NS_LOG_FUNCTION (this << packet << event);
  ....
  if (m_plcpSuccess == true)
    {
      ....
      if (m_random->GetValue () > snrPer.per)
        {
          ...
          ...
          m_state->SwitchFromRxEndOk (packet, snrPer.snr, event->GetTxVector (), event->GetPreambleType ());
        }
      else
        {
          /* failure. */
          ...
          m_state->SwitchFromRxEndError (packet, snrPer.snr);
        }
    }
  else
    {
      m_state->SwitchFromRxEndError (packet, snrPer.snr);
    }

  ...
}

这里的跳转发生在m_state->SwitchFromRxEndOk方法。
m_state对象是WifiPhyStateHelper类。

WifiPhyStateHelper::SwitchFromRxEndOk

void
WifiPhyStateHelper::SwitchFromRxEndOk (Ptr<Packet> packet, double snr, WifiTxVector txVector,
                                         enum WifiPreamble preamble)
{
  m_rxOkTrace (packet, snr, txVector.GetMode (), preamble);
  NotifyRxEndOk ();
  DoSwitchFromRx ();
  if (!m_rxOkCallback.IsNull ())
    {
      m_rxOkCallback (packet, snr, txVector, preamble);
    }

}

m_rxOkCallback 是个回调函数指针,这个指针的值的设置代码如下:

void
MacLow::SetPhy (Ptr<WifiPhy> phy)
{
  m_phy = phy;
  m_phy->SetReceiveOkCallback (MakeCallback (&MacLow::DeaggregateAmpduAndReceive, this));
  m_phy->SetReceiveErrorCallback (MakeCallback (&MacLow::ReceiveError, this));
  SetupPhyMacLowListener (phy);
}

也就是说m_rxOkCallback 指向MacLow::DeaggregateAmpduAndReceive函数。m_rxOkCallback (packet, snr, txVector, preamble)就是MacLow::DeaggregateAmpduAndReceive(packet, snr, txVector, preamble)。

MacLow::DeaggregateAmpduAndReceive

void
MacLow::DeaggregateAmpduAndReceive (Ptr<Packet> aggregatedPacket, double rxSnr, 
                                  WifiTxVector txVector, WifiPreamble preamble)
{
  NS_LOG_FUNCTION (this<<aggregatedPacket<<rxSnr<<txVector<<GetPreambleStr(preamble));
  ····
  if (aggregatedPacket->RemovePacketTag (ampdu))
    {
       ···
    }
  else
    {
      ReceiveOk (aggregatedPacket, rxSnr, txVector, preamble, ampduSubframe);
    }
}

void
MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiTxVector txVector, 
                    WifiPreamble preamble, bool ampduSubframe)
{
  NS_LOG_FUNCTION (this << packet << rxSnr << txVector.GetMode () << GetPreambleStr(preamble));
  if (hdr.IsRts ())
    {
      ···
    }
  else if (hdr.IsCts ()
           && hdr.GetAddr1 () == m_self
           && m_ctsTimeoutEvent.IsRunning ()
           && m_currentPacket != 0)
    {
      ···
    }
  //=========================ACK================================================
  else if (hdr.IsAck ()
           && hdr.GetAddr1 () == m_self
           && (m_normalAckTimeoutEvent.IsRunning ()
               || m_fastAckTimeoutEvent.IsRunning ()
               || m_superFastAckTimeoutEvent.IsRunning ())
           && m_txParams.MustWaitAck ())
    {
        ····
    }
  else if (hdr.IsBlockAck () && hdr.GetAddr1 () == m_self
           && (m_txParams.MustWaitBasicBlockAck () || m_txParams.MustWaitCompressedBlockAck ())
           && m_blockAckTimeoutEvent.IsRunning ())
    {
      NS_LOG_DEBUG ("got block ack from " << hdr.GetAddr2 ());
      ····
    }
  else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self)
    {
      ···
    }
  else if (hdr.IsCtl ())
    {
      ···
    }
  //=========================m_self================================================
  else if (hdr.GetAddr1 () == m_self)
    {
      ···
       
      //=========================m_self  and data================================================
      else if (hdr.IsData () || hdr.IsMgt ())
        {
          ····
        }
      goto rxPacket;
    }
  //=========================GROUP================================================
  else if (hdr.GetAddr1 ().IsGroup ())
    {
     ···
    }
 //=========================promisc================================================
  else if (m_promisc)
    {
      NS_ASSERT (hdr.GetAddr1 () != m_self);
      if (hdr.IsData ())
        {
          goto rxPacket;
        }
    }
  else
    {
      //NS_LOG_DEBUG_VERBOSE ("rx not-for-me from %d", GetSource (packet));
    }
  return;
rxPacket:
  WifiMacTrailer fcs;
  packet->RemoveTrailer (fcs);
  m_rxCallback (packet, &hdr);
  return;
}

ReceiveOk 方法都会进入rxPacket标记位置,继续运行代码。m_rxCallback 也是一个函数指针。该值的设置代码:

m_low->SetRxCallback (MakeCallback (&MacRxMiddle::Receive, m_rxMiddle));

MacRxMiddle::Receive

void
MacRxMiddle::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
{
  NS_LOG_FUNCTION (packet << hdr);
  ···
  m_callback (agregate, hdr);
}

m_callback 也是一个函数指针,设置代码为:

m_rxMiddle->SetForwardCallback (MakeCallback (&RegularWifiMac::Receive, this));

也就是说,m_callback (agregate, hdr)也就是RegularWifiMac::Receive(agregate, hdr)。

但是需要注意的是RegularWifiMac包含虚函数,不能创建对象,我们之前使用的它的子类AdhocWifiMac对象。
所以上面的代码运行应该是AdhocWifiMac::Receive

AdhocWifiMac::Receive

void
AdhocWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
{
  NS_LOG_FUNCTION (this << packet << hdr);
  ...
  if (hdr->IsData ())
    {
      if (hdr->IsQosData () && hdr->IsQosAmsdu ())
        {
          DeaggregateAmsduAndForward (packet, hdr);
        }
      else
        {
          ForwardUp (packet, from, to);
        }
      return;
    }
  RegularWifiMac::Receive (packet, hdr);
}

上面if语句判断,两种情况。
DeaggregateAmsduAndForward 方法会在聚合情况下调用。
packet布局和情况下会调用ForwardUp 方法。ForwardUp方法是父类RegularWifiMac中的方法。

AdhocWifiMac::Receive方法的最后调用了父类RegularWifiMac::Receive方法。

RegularWifiMac::ForwardUp和RegularWifiMac::Receive

void
RegularWifiMac::ForwardUp (Ptr<Packet> packet, Mac48Address from, Mac48Address to)
{
  NS_LOG_FUNCTION (this << packet << from);
  m_forwardUp (packet, from, to);
}

void
RegularWifiMac::Receive (Ptr<Packet> packet, const WifiMacHeader *hdr)
{
  NS_LOG_FUNCTION (this << packet << hdr);

  Mac48Address to = hdr->GetAddr1 ();
  Mac48Address from = hdr->GetAddr2 ();

  if (to != GetAddress ())
    {
      NS_LOG_LOGIC("RegularWifiMac::Receive()   目的地不是我,直接返回");
      return;
    }

  if (hdr->IsMgt () && hdr->IsAction ())
    {
      ...
    }
  NS_FATAL_ERROR ("Don't know how to handle frame (type=" << hdr->GetType ());
}

RegularWifiMac::Receive方法主要做一些子类没处理的情况。

RegularWifiMac::ForwardUp 方法会继续想上层传递接收到的packet。m_forwardUp 同样是一个函数指针。设置的代码如下:

m_mac->SetForwardUpCallback (MakeCallback (&WifiNetDevice::ForwardUp, this));

WifiNetDevice::ForwardUp

void
WifiNetDevice::ForwardUp (Ptr<Packet> packet, Mac48Address from, Mac48Address to)
{
  NS_LOG_FUNCTION (this << packet << from << to);
  LlcSnapHeader llc;
  enum NetDevice::PacketType type;
  ...

  if (type != NetDevice::PACKET_OTHERHOST)
    {
      m_mac->NotifyRx (packet);
      packet->RemoveHeader (llc);
      m_forwardUp (this, packet, llc.GetType (), from);
    }
  else
    {
      packet->RemoveHeader (llc);
    }
    
  if (!m_promiscRx.IsNull ())
    {
      m_mac->NotifyPromiscRx (packet);
      m_promiscRx (this, packet, llc.GetType (), from, to, type);
    }
}

然后在WifiNetDevice::ForwardUp方法继续向上层传递接收到的packet。


整个代码传递流程,简写为:

WifiNetDevice::Send                                                                WifiNetDevice::ForwardUp
          |                                                                                      |
          |                                                                                      |
WiFiMac::Enqueue
          |                                                                                      |
          |                                                                                      |
RegularWifiMac::Enqueue                                                            RegularWifiMac::ForwardUp
          |                                                                                      |
          |                                                                                      |
AdhocWifiMac::Enqueue                                                              AdhocWifiMac::Receive
          |                                                                                      |
          |                                                                                      |
DcaTxop::Queue                                                                      MacRxMiddle::Receive
          |                                                                                      |
          |                                                                                      |
DcfManager::RequestAccess                                                                        ^  
          |                                                                                      |
          |                                                                                      |
DcfState::NotifyAccessGranted                                                                    ^
          |                                                                                      |
          |                                                                                      |
DcaTxop::NotifyAccessGranted                                                                     ^
          |                                                                                      |
          |                                                                                      |
MacLow::StartTransmission                                                       MacLow::DeaggregateAmpduAndReceive
          |                                                                                      |
          |                                                                                      |
MacLow::SendDataPacket                                                        WifiPhyStateHelper::SwitchFromRxEndOk
          |                                                                                      |
          |                                                                                      |
MacLow::ForwardDown                                                                   YansWifiPhy::EndReceive
          |                                                                                      |
          |                                                                                      |
YansWifiPhy::SendPacket                                                YansWifiPhy::StartReceivePreambleAndHeader
          |                                                                                      |
          |                                                                                      |
YansWifiChannel::Send       ---------------------------------->                   YansWifiChannel::Receive
          










最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,566评论 25 707
  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,151评论 0 4
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,293评论 18 399
  • 作别 西天的云彩 斩断 拉扯的风筝线 挥手 泥尘中的花瓣 许愿 渐行渐远的星辰 这一切以后 我知道 那不是一行小诗...
    囡囡蒹葭阅读 178评论 0 0
  • 初夏,花园里午后阳光的气味,像时光机一样嗖的一下把我送到过去。有时候味道比图像更能唤醒旧时光 什么时候能发明一种气...
    黑白之间阅读 376评论 2 0