arpimpl.c

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

C
1,698
字号
  )
/*++

Routine Description:

  Find the CacheEntry which matches the requirements in the specified CacheTable.

Arguments:

  CacheTable      - Pointer to the arp cache table.
  StartEntry      - Pointer to the start entry this search begins with in the cache table.
  FindOpType      - The search type.
  ProtocolAddress - Pointer to the protocol address to match.
  HardwareAddress - Pointer to the hardware address to match.

Returns:

  Pointer to the matched arp cache entry, if NULL, no match is found.

--*/
{
  NET_LIST_ENTRY   *Entry;
  ARP_CACHE_ENTRY  *CacheEntry;

  if (StartEntry == NULL) {
    //
    // Start from the beginning of the table if no StartEntry is specified.
    //
    StartEntry = CacheTable;
  }

  for (Entry = StartEntry->ForwardLink; Entry != CacheTable; Entry = Entry->ForwardLink) {
    CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);

    if (FindOpType & MATCH_SW_ADDRESS) {
      //
      // Find by the software address.
      //
      if (!ArpMatchAddress (ProtocolAddress, &CacheEntry->Addresses[Protocol])) {
        //
        // The ProtocolAddress doesn't match, continue to the next cache entry.
        //
        continue;
      }
    }

    if (FindOpType & MATCH_HW_ADDRESS) {
      //
      // Find by the hardware address.
      //
      if (!ArpMatchAddress (HardwareAddress, &CacheEntry->Addresses[Hardware])) {
        //
        // The HardwareAddress doesn't match, continue to the next cache entry.
        //
        continue;
      }
    }

    //
    // The CacheEntry meets the requirements now, return this entry.
    //
    return CacheEntry;
  }

  //
  // No matching.
  //
  return NULL;
}

ARP_CACHE_ENTRY *
ArpFindDeniedCacheEntry (
  IN ARP_SERVICE_DATA  *ArpService,
  IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,
  IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL
  )
/*++

Routine Description:

  Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,
  in the DeniedCacheTable.

Arguments:

  ArpService      - Pointer to the arp service context data.
  ProtocolAddress - Pointer to the protocol address.
  HardwareAddress - Pointer to the hardware address.

Returns:

  Pointer to the matched cache entry, if NULL no match is found.

--*/
{
  ARP_CACHE_ENTRY  *CacheEntry;

  ASSERT ((ProtocolAddress != NULL) || (HardwareAddress != NULL));
  NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);

  CacheEntry = NULL;

  if ((ProtocolAddress != NULL) && (ProtocolAddress->AddressPtr != NULL)) {
    //
    // Find the cache entry in the DeniedCacheTable by the protocol address.
    //
    CacheEntry = ArpFindNextCacheEntryInTable (
                   &ArpService->DeniedCacheTable,
                   NULL,
                   ByProtoAddress,
                   ProtocolAddress,
                   NULL
                   );
    if (CacheEntry != NULL) {
      //
      // There is a match. 
      //
      return CacheEntry;
    }
  }

  if ((HardwareAddress != NULL) && (HardwareAddress->AddressPtr != NULL)) {
    //
    // Find the cache entry in the DeniedCacheTable by the hardware address.
    //
    CacheEntry = ArpFindNextCacheEntryInTable (
                   &ArpService->DeniedCacheTable,
                   NULL,
                   ByHwAddress,
                   NULL,
                   HardwareAddress
                   );
  }

  return CacheEntry;
}

ARP_CACHE_ENTRY *
ArpAllocCacheEntry (
  IN ARP_INSTANCE_DATA  *Instance  
  )
/*++

Routine Description:

  Allocate a cache entry and initialize it.

Arguments:

  Instance - Pointer to the instance context data.

Returns:

  Pointer to the new created cache entry.

--*/
{
  ARP_CACHE_ENTRY  *CacheEntry;
  NET_ARP_ADDRESS  *Address;
  UINT16           Index;

  //
  // Allocate memory for the cache entry.
  //
  CacheEntry = NetAllocatePool (sizeof (ARP_CACHE_ENTRY));
  if (CacheEntry == NULL) {
    return NULL;
  }

  //
  // Init the lists.
  //
  NetListInit (&CacheEntry->List);
  NetListInit (&CacheEntry->UserRequestList);

  for (Index = 0; Index < 2; Index++) {
    //
    // Init the address pointers to point to the concrete buffer.
    //
    Address = &CacheEntry->Addresses[Index];
    Address->AddressPtr = Address->Buffer.ProtoAddress;
  }

  //
  // Zero the hardware address first.
  //
  NetZeroMem (CacheEntry->Addresses[Hardware].AddressPtr, ARP_MAX_HARDWARE_ADDRESS_LEN);

  if (Instance != NULL) {
    //
    // Inherit the parameters from the instance configuration.
    //
    CacheEntry->RetryCount       = Instance->ConfigData.RetryCount;
    CacheEntry->NextRetryTime    = Instance->ConfigData.RetryTimeOut;
    CacheEntry->DefaultDecayTime = Instance->ConfigData.EntryTimeOut;
    CacheEntry->DecayTime        = Instance->ConfigData.EntryTimeOut;
  } else {
    //
    // Use the default parameters if this cache entry isn't allocate in a
    // instance's  scope.
    //
    CacheEntry->RetryCount       = ARP_DEFAULT_RETRY_COUNT;
    CacheEntry->NextRetryTime    = ARP_DEFAULT_RETRY_INTERVAL;
    CacheEntry->DefaultDecayTime = ARP_DEFAULT_TIMEOUT_VALUE;
    CacheEntry->DecayTime        = ARP_DEFAULT_TIMEOUT_VALUE;
  }

  return CacheEntry;
}

UINTN
ArpAddressResolved (
  IN ARP_CACHE_ENTRY    *CacheEntry,
  IN ARP_INSTANCE_DATA  *Instance OPTIONAL,
  IN EFI_EVENT          UserEvent OPTIONAL
  )
/*++

Routine Description:

  Turn the CacheEntry into the resolved status.

Arguments:

  CacheEntry - Pointer to the resolved cache entry.
  Instance   - Pointer to the instance context data.
  UserEvent  - Pointer to the UserEvent to notify.

Returns:

  The count of notifications sent to the instance.

--*/
{
  NET_LIST_ENTRY        *Entry;
  NET_LIST_ENTRY        *NextEntry;
  USER_REQUEST_CONTEXT  *Context;
  UINTN                 Count;

  Count = 0;

  //
  // Iterate all the linked user requests to notify them.
  //
  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &CacheEntry->UserRequestList) {
    Context = NET_LIST_USER_STRUCT (Entry, USER_REQUEST_CONTEXT, List);

    if (((Instance == NULL) || (Context->Instance == Instance)) &&
      ((UserEvent == NULL) || (Context->UserRequestEvent == UserEvent))) {
      //
      // Copy the address to the user-provided buffer and notify the user.
      //
      NetCopyMem (
        Context->UserHwAddrBuffer,
        CacheEntry->Addresses[Hardware].AddressPtr,
        CacheEntry->Addresses[Hardware].Length
        );
      gBS->SignalEvent (Context->UserRequestEvent);

      //
      // Remove this user request and free the context data.
      //
      NetListRemoveEntry (&Context->List);
      NetFreePool (Context);

      Count++;
    }
  }

  return Count;
}

VOID
ArpFillAddressInCacheEntry (
  IN ARP_CACHE_ENTRY  *CacheEntry,
  IN NET_ARP_ADDRESS  *HwAddr OPTIONAL,
  IN NET_ARP_ADDRESS  *SwAddr OPTIONAL
  )
/*++

Routine Description:

  Fill the addresses in the CacheEntry using the information passed in by
  HwAddr and SwAddr.

Arguments:

  CacheEntry - Pointer to the cache entry.
  HwAddr     - Pointer to the software address.
  SwAddr     - Pointer to the hardware address.

Returns:

  None.

--*/
{
  NET_ARP_ADDRESS  *Address[2];
  NET_ARP_ADDRESS  *CacheAddress;
  UINT32           Index;

  Address[Hardware] = HwAddr;
  Address[Protocol] = SwAddr;
  
  for (Index = 0; Index < 2; Index++) {
    if (Address[Index] != NULL) {
      //
      // Fill the address if the passed in pointer is not NULL.
      //
      CacheAddress = &CacheEntry->Addresses[Index];

      CacheAddress->Type   = Address[Index]->Type;
      CacheAddress->Length = Address[Index]->Length;

      if (Address[Index]->AddressPtr != NULL) {
        //
        // Copy it if the AddressPtr points to some buffer.
        //
        NetCopyMem (
          CacheAddress->AddressPtr,
          Address[Index]->AddressPtr,
          CacheAddress->Length
          );
      } else {
        //
        // Zero the corresponding address buffer in the CacheEntry.
        //
        NetZeroMem (CacheAddress->AddressPtr, CacheAddress->Length);
      }
    }
  }
}

EFI_STATUS
ArpConfigureInstance (
  IN ARP_INSTANCE_DATA    *Instance,
  IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL
  )
/*++

Routine Description:

  Configure the instance using the ConfigData. ConfigData is already validated.

Arguments:

  Instance   - Pointer to the instance context data to be configured.
  ConfigData - Pointer to the configuration data used to configure the instance.

Returns:

  EFI_SUCCESS           - The instance is configured with the ConfigData.
  EFI_ACCESS_DENIED     - The instance is already configured and the ConfigData tries to
                          reset some unchangeable fields.
  EFI_INVALID_PARAMETER - The ConfigData provides a non-unicast IPv4 address when the
                          SwAddressType is IPv4.
  EFI_OUT_OF_RESOURCES  - The instance fails to configure due to memory limitation.

--*/
{
  EFI_ARP_CONFIG_DATA  *OldConfigData;

  OldConfigData = &Instance->ConfigData;

  if (ConfigData != NULL) {

    if (Instance->Configured) {
      //
      // The instance is configured, check the unchangeable fields.
      //
      if ((OldConfigData->SwAddressType != ConfigData->SwAddressType) ||
        (OldConfigData->SwAddressLength != ConfigData->SwAddressLength) ||
        (NetCompareMem (
           OldConfigData->StationAddress,
           ConfigData->StationAddress,
           OldConfigData->SwAddressLength
           ) != 0)) {
        //
        // Deny the unallowed changes.
        //
        return EFI_ACCESS_DENIED;
      }
    } else {
      //
      // The instance is not configured.
      //

      if ((ConfigData->SwAddressType == IPv4_ETHER_PROTO_TYPE) &&
        (!Ip4IsUnicast (EFI_IP4 (*((EFI_IPv4_ADDRESS *)ConfigData->StationAddress)), 0))) {
        //
        // The station address is not a valid IPv4 unicast address.
        //
        return EFI_INVALID_PARAMETER;
      }

      //
      // Save the configuration.
      //
      *OldConfigData = *ConfigData;

      OldConfigData->StationAddress = NetAllocatePool (OldConfigData->SwAddressLength);
      if (OldConfigData->StationAddress == NULL) {
        ARP_DEBUG_ERROR (("ArpConfigInstance: NetAllocatePool for the StationAddress "
          "failed.\n"));
        return EFI_OUT_OF_RESOURCES;
      }

      //
      // Save the StationAddress.
      //
      NetCopyMem (
        OldConfigData->StationAddress,
        ConfigData->StationAddress,
        OldConfigData->SwAddressLength
        );

      //
      // Set the state to configured.
      //
      Instance->Configured = TRUE;
    }

    //
    // Use the implementation specific values if the following field is zero.
    //
    OldConfigData->EntryTimeOut = (ConfigData->EntryTimeOut == 0) ?
      ARP_DEFAULT_TIMEOUT_VALUE : ConfigData->EntryTimeOut;

    OldConfigData->RetryCount   = (ConfigData->RetryCount == 0) ?
      ARP_DEFAULT_RETRY_COUNT : ConfigData->RetryCount;

    OldConfigData->RetryTimeOut = (ConfigData->RetryTimeOut == 0) ?
      ARP_DEFAULT_RETRY_INTERVAL : ConfigData->RetryTimeOut;
  } else {
    //
    // Reset the configuration.
    //

    if (Instance->Configured) {
      //
      // Cancel the arp requests issued by this instance.
      //
      ArpCancelRequest (Instance, NULL, NULL);

      //
      // Free the buffer previously allocated to hold the station address.
      //
      NetFreePool (OldConfigData->StationAddress);
    }

    Instance->Configured = FALSE;
  }

  return EFI_SUCCESS;
}

VOID
ArpSendFrame (
  IN ARP_INSTANCE_DATA  *Instance,
  IN ARP_CACHE_ENTRY    *CacheEntry,
  IN UINT16             ArpOpCode
  )
/*++

Routine Description:

  Send out an arp frame using the CachEntry and the ArpOpCode.

Arguments:

  Instance   - Pointer to the instance context data.
  CacheEntry - Pointer to the configuration data used to configure the instance.
  ArpOpCode  - The opcode used to send out this Arp frame, either request or reply.

Returns:

  None.

--*/
{
  EFI_STATUS                            Status;
  EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;
  EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;
  UINT32                                TotalLength;
  UINT8                                 *Packet;
  ARP_SERVICE_DATA                      *ArpService;
  EFI_SIMPLE_NETWORK_MODE               *SnpMode;
  EFI_ARP_CONFIG_DATA                   *ConfigData;
  UINT8                                 *TmpPtr;
  ARP_HEAD                              *ArpHead;

  ASSERT ((Instance != NULL) && (CacheEntry != NULL));

  //
  // Allocate memory for the TxToken.
  //
  TxToken = NetAllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN));
  if (TxToken == NULL) {
    ARP_DEBUG_ERROR (("ArpSendFrame: Allocate memory for TxToken failed.\n"));
    return;
  }

  TxToken->Event = NULL;
  TxData         = NULL;
  Packet         = NULL;

  //
  // Create the event for this TxToken.
  //
  Status = gBS->CreateEvent (
                  EFI_EVENT_NOTIFY_SIGNAL,
                  NET_TPL_EVENT,
                  ArpOnFrameSent,
                  (VOID *)TxToken,
                  &TxToken->Event
                  );
  if (EFI_ERROR (Status)) {
    ARP_DEBUG_ERROR (("ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));
    goto CLEAN_EXIT;
  }

  //
  // Allocate memory for the TxData used in the TxToken.
  //
  TxData = NetAllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA));
  if (TxData == NULL) {
    ARP_DEBUG_ERROR (("ArpSendFrame: Allocate memory for TxData failed.\n"));
    goto CLEAN_EXIT;
  }

  ArpService = Instance->ArpService;
  SnpMode    = &ArpService->SnpMode;
  ConfigData = &Instance->ConfigData;

  //
  // Calculate the buffer length for this arp frame.
  //
  TotalLength = SnpMode->MediaHeaderSize + sizeof (ARP_HEAD) + 
                2 * (ConfigData->SwAddressLength + SnpMode->HwAddressSize);

  //
  // Allocate buffer for the arp frame.
  //
  Packet = NetAllocatePool (TotalLength);
  if (Packet == NULL) {
    ARP_DEBUG_ERROR (("ArpSendFrame: Allocate memory for Packet failed.\n"));
  }

  TmpPtr = Packet;

  //
  // The destination MAC address.
  //
  if (ArpOpCode == ARP_OPCODE_REQUEST) {
    NetCopyMem (TmpPtr, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);
  } else {
    NetCopyMem (
      TmpPtr,
      CacheEntry->Addresses[Hardware].AddressPtr,
      SnpMode->HwAddressSize
      );
  }
  TmpPtr += SnpMode->HwAddressSize;

  //
  // The source MAC address.

⌨️ 快捷键说明

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