NS3 WiFiNetDevice结构

作者: shawn168 | 来源:发表于2017-06-25 20:33 被阅读629次

    先看一个图

    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
              
    
    
    
    
    
    
    
    
    
    
    

    相关文章

      网友评论

        本文标题:NS3 WiFiNetDevice结构

        本文链接:https://www.haomeiwen.com/subject/mrbgnttx.html