mnpio.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,165 行 · 第 1/2 页

C
1,165
字号
Arguments:

  Instance     - Pointer to the mnp instance context data.
  RxData       - Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
  GroupAddress - Pointer to the GroupAddress, the GroupAddress is non-NULL and
                 it contains the destination multicast mac address of the
                 received packet if the packet destinated to a multicast mac address.
  PktAttr      - The received packets attribute.

Returns:

  The received packet matches the instance's receive filters or not.

--*/
{
  EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData;
  NET_LIST_ENTRY                  *Entry;
  MNP_GROUP_CONTROL_BLOCK         *GroupCtrlBlk;

  NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);

  ConfigData = &Instance->ConfigData;

  if (ConfigData->EnablePromiscuousReceive) {
    //
    // Always match if this instance is configured to be promiscuous.
    //
    return TRUE;
  }
  //
  // Check the protocol type.
  //
  if ((ConfigData->ProtocolTypeFilter != 0) && (ConfigData->ProtocolTypeFilter != RxData->ProtocolType)) {
    return FALSE;
  }

  //
  // The protocol type is matched, check receive filter, include unicast and broadcast.
  //
  if ((Instance->ReceiveFilter & PktAttr) != 0) {
    return TRUE;
  }

  //
  // Check multicast addresses.
  //
  if (ConfigData->EnableMulticastReceive && RxData->MulticastFlag) {

    ASSERT (GroupAddress != NULL);

    NET_LIST_FOR_EACH (Entry, &Instance->GroupCtrlBlkList) {

      GroupCtrlBlk = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_CONTROL_BLOCK, CtrlBlkEntry);
      if (GroupCtrlBlk->GroupAddress == GroupAddress) {
        //
        // The instance is configured to receiveing packets destinated to this
        // multicast address.
        //
        return TRUE;
      }
    }
  }

  //
  // No match.
  //
  return FALSE;
}

STATIC
VOID
MnpAnalysePacket (
  IN  MNP_SERVICE_DATA                  *MnpServiceData,
  IN  NET_BUF                           *Nbuf,
  IN  EFI_MANAGED_NETWORK_RECEIVE_DATA  *RxData,
  OUT MNP_GROUP_ADDRESS                 **GroupAddress,
  OUT UINT8                             *PktAttr
  )
/*++

Routine Description:

  Analyse the received packets.

Arguments:

  MnpServiceData - Pointer to the mnp service context data.
  Nbuf           - Pointer to the net buffer holding the received packet.
  RxData         - Pointer to the buffer used to save the analysed result
                   in EFI_MANAGED_NETWORK_RECEIVE_DATA.
  GroupAddress   - Pointer to pointer to a MNP_GROUP_ADDRESS used to pass out
                   the address of the multicast address the received packet
                   destinated to.
  PktAttr        - Pointer to the buffer used to save the analysed packet attribute.

Returns:

  None.

--*/
{
  EFI_SIMPLE_NETWORK_MODE *SnpMode;
  UINT8                   *BufPtr;
  NET_LIST_ENTRY          *Entry;

  SnpMode = MnpServiceData->Snp->Mode;

  //
  // Get the packet buffer.
  //
  BufPtr = NetbufGetByte (Nbuf, 0, NULL);
  ASSERT (BufPtr != NULL);

  //
  // Set the initial values.
  //
  RxData->BroadcastFlag   = FALSE;
  RxData->MulticastFlag   = FALSE;
  RxData->PromiscuousFlag = FALSE;
  *PktAttr                = UNICAST_PACKET;

  if (!NET_MAC_EQUAL (&SnpMode->CurrentAddress, BufPtr, SnpMode->HwAddressSize)) {
    //
    // This packet isn't destinated to our current mac address, it't not unicast.
    //
    *PktAttr = 0;

    if (NET_MAC_EQUAL (&SnpMode->BroadcastAddress, BufPtr, SnpMode->HwAddressSize)) {
      //
      // It's broadcast.
      //
      RxData->BroadcastFlag = TRUE;
      *PktAttr              = BROADCAST_PACKET;
    } else if ((*BufPtr & 0x01) == 0x1) {
      //
      // It's multicast, try to match the multicast filters.
      //
      NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {

        *GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);
        if (NET_MAC_EQUAL (BufPtr, &((*GroupAddress)->Address), SnpMode->HwAddressSize)) {
          RxData->MulticastFlag = TRUE;
          break;
        }
      }

      if (!RxData->MulticastFlag) {
        //
        // No match, set GroupAddress to NULL. This multicast packet must
        // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
        //
        *GroupAddress           = NULL;
        RxData->PromiscuousFlag = TRUE;

        if (MnpServiceData->PromiscuousCount == 0) {
          //
          // Skip the below code, there is no receiver of this packet.
          //
          return ;
        }
      }
    } else {
      RxData->PromiscuousFlag = TRUE;
    }
  }

  NetZeroMem (&RxData->Timestamp, sizeof (EFI_TIME));

  //
  // Fill the common parts of RxData.
  //
  RxData->PacketLength  = Nbuf->TotalSize;
  RxData->HeaderLength  = SnpMode->MediaHeaderSize;
  RxData->AddressLength = SnpMode->HwAddressSize;
  RxData->DataLength    = RxData->PacketLength - RxData->HeaderLength;
  RxData->ProtocolType  = NTOHS (*(UINT16 *) (BufPtr + 2 * SnpMode->HwAddressSize));
}

STATIC
MNP_RXDATA_WRAP *
MnpWrapRxData (
  IN MNP_INSTANCE_DATA                 *Instance,
  IN EFI_MANAGED_NETWORK_RECEIVE_DATA  *RxData
  )
/*++

Routine Description:

  Wrap the RxData.

Arguments:

  Instance  - Pointer to the mnp instance context data.
  RxData    - Pointer to the receive data to wrap.

Returns:

  Pointer to a MNP_RXDATA_WRAP which wraps the RxData.

--*/
{
  EFI_STATUS      Status;
  MNP_RXDATA_WRAP *RxDataWrap;

  //
  // Allocate memory.
  //
  RxDataWrap = NetAllocatePool (sizeof (MNP_RXDATA_WRAP));
  if (RxDataWrap == NULL) {
    MNP_DEBUG_ERROR (("MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
    return NULL;
  }

  RxDataWrap->Instance = Instance;

  //
  // Fill the RxData in RxDataWrap,
  //
  RxDataWrap->RxData = *RxData;

  //
  // Create the recycle event.
  //
  Status = gBS->CreateEvent (
                  EFI_EVENT_NOTIFY_SIGNAL,
                  NET_TPL_FAST_RECYCLE,
                  MnpRecycleRxData,
                  RxDataWrap,
                  &RxDataWrap->RxData.RecycleEvent
                  );
  if (EFI_ERROR (Status)) {

    MNP_DEBUG_ERROR (("MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status));
    NetFreePool (RxDataWrap);
    return NULL;
  }

  return RxDataWrap;
}

STATIC
VOID
MnpEnqueuePacket (
  IN MNP_SERVICE_DATA   *MnpServiceData,
  IN NET_BUF            *Nbuf
  )
/*++

Routine Description:

  Enqueue the received the packets to the instances belonging to the
  MnpServiceData.

Arguments:

  MnpServiceData - Pointer to the mnp service context data.
  Nbuf           - Pointer to the net buffer representing the received packet.

Returns:

  None.

--*/
{
  NET_LIST_ENTRY                    *Entry;
  MNP_INSTANCE_DATA                 *Instance;
  EFI_MANAGED_NETWORK_RECEIVE_DATA  RxData;
  UINT8                             PktAttr;
  MNP_GROUP_ADDRESS                 *GroupAddress;
  MNP_RXDATA_WRAP                   *RxDataWrap;

  //
  // First, analyse the packet header.
  //
  MnpAnalysePacket (MnpServiceData, Nbuf, &RxData, &GroupAddress, &PktAttr);

  if (RxData.PromiscuousFlag && (MnpServiceData->PromiscuousCount == 0)) {
    //
    // No receivers, no more action need.
    //
    return ;
  }

  //
  // Iterate the children to find match.
  //
  NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {

    Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
    NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);

    if (!Instance->Configured) {
      continue;
    }

    //
    // Check the packet against the instance receive filters.
    //
    if (MnpMatchPacket (Instance, &RxData, GroupAddress, PktAttr)) {

      //
      // Wrap the RxData.
      //
      RxDataWrap = MnpWrapRxData (Instance, &RxData);
      if (RxDataWrap == NULL) {
        continue;
      }

      //
      // Associate RxDataWrap with Nbuf and increase the RefCnt.
      //
      RxDataWrap->Nbuf = Nbuf;
      NET_GET_REF (RxDataWrap->Nbuf);

      //
      // Queue the packet into the instance queue.
      //
      MnpQueueRcvdPacket (Instance, RxDataWrap);
    }
  }
}

EFI_STATUS
MnpReceivePacket (
  IN MNP_SERVICE_DATA  *MnpServiceData
  )
/*++

Routine Description:

  Try to receive a packet and deliver it.

Arguments:

 MnpServiceData - Pointer to the mnp service context data.

Returns:

 EFI_SUCCESS      - add return value to function comment
 EFI_NOT_STARTED  - The simple network protocol is not started.
 EFI_NOT_READY    - No packet received.
 EFI_DEVICE_ERROR - An unexpected error occurs.

--*/
{
  EFI_STATUS                  Status;
  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
  NET_BUF                     *Nbuf;
  UINT8                       *BufPtr;
  UINTN                       BufLen;
  UINTN                       HeaderSize;
  UINT32                      Trimmed;

  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);

  Snp = MnpServiceData->Snp;
  if (Snp->Mode->State != EfiSimpleNetworkInitialized) {
    //
    // The simple network protocol is not started.
    //
    return EFI_NOT_STARTED;
  }

  if (NetListIsEmpty (&MnpServiceData->ChildrenList)) {
    //
    // There is no child, no need to receive packets.
    //
    return EFI_SUCCESS;
  }

  if (MnpServiceData->RxNbufCache == NULL) {
    //
    // Try to get a new buffer as there may be buffers recycled.
    //
    MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);

    if (MnpServiceData->RxNbufCache == NULL) {
      //
      // No availabe buffer in the buffer pool.
      //
      return EFI_DEVICE_ERROR;
    }

    NetbufAllocSpace (
      MnpServiceData->RxNbufCache,
      MnpServiceData->BufferLength,
      NET_BUF_TAIL
      );
  }

  Nbuf    = MnpServiceData->RxNbufCache;
  BufLen  = Nbuf->TotalSize;
  BufPtr  = NetbufGetByte (Nbuf, 0, NULL);
  ASSERT (BufPtr != NULL);

  //
  // Receive packet through Snp.
  //
  Status = Snp->Receive (Snp, &HeaderSize, &BufLen, BufPtr, NULL, NULL, NULL);
  if (EFI_ERROR (Status)) {

    DEBUG_CODE (
      if (Status != EFI_NOT_READY) {
      MNP_DEBUG_ERROR (("MnpReceivePacket: Snp->Receive() = %r.\n", Status));
    }
    );

    return Status;
  }

  //
  // Sanity check.
  //
  if ((HeaderSize != Snp->Mode->MediaHeaderSize) || (BufLen < HeaderSize)) {

    MNP_DEBUG_WARN (
      ("MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
      HeaderSize,
      BufLen)
      );
    return EFI_DEVICE_ERROR;
  }

  Trimmed = 0;
  if (Nbuf->TotalSize != BufLen) {
    //
    // Trim the packet from tail.
    //
    Trimmed = NetbufTrim (Nbuf, Nbuf->TotalSize - (UINT32) BufLen, NET_BUF_TAIL);
    ASSERT (Nbuf->TotalSize == BufLen);
  }

  //
  // Enqueue the packet to the matched instances.
  //
  MnpEnqueuePacket (MnpServiceData, Nbuf);

  if (Nbuf->RefCnt > 2) {
    //
    // RefCnt > 2 indicates there is at least one receiver of this packet.
    // Free the current RxNbufCache and allocate a new one.
    //
    MnpFreeNbuf (MnpServiceData, Nbuf);

    Nbuf                        = MnpAllocNbuf (MnpServiceData);
    MnpServiceData->RxNbufCache = Nbuf;
    if (Nbuf == NULL) {
      MNP_DEBUG_ERROR (("MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
      return EFI_DEVICE_ERROR;
    }

    NetbufAllocSpace (Nbuf, MnpServiceData->BufferLength, NET_BUF_TAIL);
  } else {
    //
    // No receiver for this packet.
    //
    NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);
    goto EXIT;
  }
  //
  // Deliver the queued packets.
  //
  MnpDeliverPacket (MnpServiceData);

EXIT:

  ASSERT (Nbuf->TotalSize == MnpServiceData->BufferLength);

  return Status;
}

VOID
EFIAPI
MnpCheckPacketTimeout (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
/*++

Routine Description:

  Remove the received packets if timeout occurs.

Arguments:

  Event   - The event this notify function registered to.
  Context - Pointer to the context data registered to the event.

Returns:

  None.

--*/
{
  MNP_SERVICE_DATA  *MnpServiceData;
  NET_LIST_ENTRY    *Entry;
  NET_LIST_ENTRY    *RxEntry;
  NET_LIST_ENTRY    *NextEntry;
  MNP_INSTANCE_DATA *Instance;
  MNP_RXDATA_WRAP   *RxDataWrap;

  MnpServiceData = (MNP_SERVICE_DATA *) Context;
  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);

  //
  // Try to acquire the lock.
  //
  if (EFI_ERROR (NET_TRYLOCK (&MnpServiceData->ChildrenListLock))) {

    MNP_DEBUG_WARN (("MnpCheckPacketTimeout: Acquire MnpServiceData->""ChildrenListLock failed.\n"));
    return ;
  }

  NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {

    Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
    NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);

    if (!Instance->Configured || (Instance->ConfigData.ReceivedQueueTimeoutValue == 0)) {
      //
      // This instance is not configured or there is no receive time out,
      // just skip to the next instance.
      //
      continue;
    }

    NET_LIST_FOR_EACH_SAFE (RxEntry, NextEntry, &Instance->RcvdPacketQueue) {

      RxDataWrap = NET_LIST_USER_STRUCT (RxEntry, MNP_RXDATA_WRAP, WrapEntry);

      if (RxDataWrap->TimeoutTick >= MNP_TIMEOUT_CHECK_INTERVAL) {

        RxDataWrap->TimeoutTick -= MNP_TIMEOUT_CHECK_INTERVAL;
      } else {
        //
        // Drop the timeout packet.
        //
        MNP_DEBUG_WARN (("MnpCheckPacketTimeout: Received packet timeout.\n"));
        MnpRecycleRxData (NULL, RxDataWrap);
        Instance->RcvdPacketQueueSize--;
      }
    }
  }

  NET_UNLOCK (&MnpServiceData->ChildrenListLock);
}

VOID
EFIAPI
MnpSystemPoll (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
/*++

Routine Description:

  Poll to receive the packets from Snp. This function is either called by upperlayer
  protocols/applications or the system poll timer notify mechanism.

Arguments:

  Event   - The event this notify function registered to.
  Context - Pointer to the context data registered to the event.

Returns:

  None.

--*/
{
  MNP_SERVICE_DATA  *MnpServiceData;

  MnpServiceData = (MNP_SERVICE_DATA *) Context;
  NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);

  //
  // Try to receive packets from Snp.
  //
  MnpReceivePacket (MnpServiceData);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?