v2: *refine some codes Add 2 macros in NetLib.h #define IP4_MASK_MAX 32 #define IP6_PREFIX_MAX 128 we will use these two macros to check the max mask/prefix length, instead of #define IP4_MASK_NUM 33 #define IP6_PREFIX_NUM 129 which means a valid number This will make the code readability and maintainability. Cc: Subramanian Sriram <sriram-s@hpe.com> Cc: Fu Siyuan <siyuan.fu@intel.com> Cc: Ye Ting <ting.ye@intel.com> Cc: Wu Jiaxin <jiaxin.wu@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo <lubo.zhang@intel.com> Reviewed-by: Sriram Subramanian <sriram-s@@hpe.com>
		
			
				
	
	
		
			674 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			674 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   The implementation of common functions shared by IP6 driver.
 | |
| 
 | |
|   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php.
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Ip6Impl.h"
 | |
| 
 | |
| /**
 | |
|   Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
 | |
|   of EFI_IP6_ADDRESS_INFO is also returned. If AddressList is NULL,
 | |
|   only the address count is returned.
 | |
| 
 | |
|   @param[in]  IpSb              The IP6 service binding instance.
 | |
|   @param[out] AddressCount      The number of returned addresses.
 | |
|   @param[out] AddressList       The pointer to the array of EFI_IP6_ADDRESS_INFO.
 | |
|                                 This is an optional parameter.
 | |
| 
 | |
| 
 | |
|   @retval EFI_SUCCESS           The address array successfully built.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the address info.
 | |
|   @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Ip6BuildEfiAddressList (
 | |
|   IN IP6_SERVICE            *IpSb,
 | |
|   OUT UINT32                *AddressCount,
 | |
|   OUT EFI_IP6_ADDRESS_INFO  **AddressList OPTIONAL
 | |
|   )
 | |
| {
 | |
|   UINT32                Count;
 | |
|   LIST_ENTRY            *Entry;
 | |
|   EFI_IP6_ADDRESS_INFO  *EfiAddrInfo;
 | |
|   IP6_ADDRESS_INFO      *AddrInfo;
 | |
| 
 | |
|   if (AddressCount == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (IpSb->LinkLocalOk) {
 | |
|     Count = 1 + IpSb->DefaultInterface->AddressCount;
 | |
|   } else {
 | |
|     Count = 0;
 | |
|   }
 | |
| 
 | |
|   *AddressCount = Count;
 | |
| 
 | |
|   if ((AddressList == NULL) || (Count == 0)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (*AddressList == NULL) {
 | |
|     *AddressList = AllocatePool (sizeof (EFI_IP6_ADDRESS_INFO) * Count);
 | |
|     if (*AddressList == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   EfiAddrInfo = *AddressList;
 | |
| 
 | |
|   IP6_COPY_ADDRESS (&EfiAddrInfo->Address, &IpSb->LinkLocalAddr);
 | |
|   EfiAddrInfo->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
 | |
| 
 | |
|   EfiAddrInfo++;
 | |
|   Count = 1;
 | |
| 
 | |
|   NET_LIST_FOR_EACH (Entry, &IpSb->DefaultInterface->AddressList) {
 | |
|     AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
 | |
| 
 | |
|     IP6_COPY_ADDRESS (&EfiAddrInfo->Address, &AddrInfo->Address);
 | |
|     EfiAddrInfo->PrefixLength = AddrInfo->PrefixLength;
 | |
| 
 | |
|     EfiAddrInfo++;
 | |
|     Count++;
 | |
|   }
 | |
| 
 | |
|   ASSERT (Count == *AddressCount);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Generate the multicast addresses identify the group of all IPv6 nodes or IPv6
 | |
|   routers defined in RFC4291.
 | |
| 
 | |
|   All Nodes Addresses: FF01::1, FF02::1.
 | |
|   All Router Addresses: FF01::2, FF02::2, FF05::2.
 | |
| 
 | |
|   @param[in]  Router            If TRUE, generate all routers addresses,
 | |
|                                 else generate all node addresses.
 | |
|   @param[in]  Scope             interface-local(1), link-local(2), or site-local(5)
 | |
|   @param[out] Ip6Addr           The generated multicast address.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
 | |
|   @retval EFI_SUCCESS           The address is generated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Ip6SetToAllNodeMulticast (
 | |
|   IN  BOOLEAN          Router,
 | |
|   IN  UINT8            Scope,
 | |
|   OUT EFI_IPv6_ADDRESS *Ip6Addr
 | |
|   )
 | |
| {
 | |
|   if (Ip6Addr == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (!Router && Scope == IP6_SITE_LOCAL_SCOPE) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (Ip6Addr, sizeof (EFI_IPv6_ADDRESS));
 | |
|   Ip6Addr->Addr[0] = 0xFF;
 | |
|   Ip6Addr->Addr[1] = Scope;
 | |
| 
 | |
|   if (!Router) {
 | |
|     Ip6Addr->Addr[15] = 0x1;
 | |
|   } else {
 | |
|     Ip6Addr->Addr[15] = 0x2;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function converts MAC address to 64 bits interface ID according to RFC4291
 | |
|   and returns the interface ID. Currently only 48-bit MAC address is supported by
 | |
|   this function.
 | |
| 
 | |
|   @param[in, out]  IpSb      The IP6 service binding instance.
 | |
| 
 | |
|   @retval          NULL      The operation fails.
 | |
|   @return                    Pointer to the generated interface ID.
 | |
| 
 | |
| **/
 | |
| UINT8 *
 | |
| Ip6CreateInterfaceID (
 | |
|   IN OUT IP6_SERVICE         *IpSb
 | |
|   )
 | |
| {
 | |
|   UINT8                      InterfaceId[8];
 | |
|   UINT8                      Byte;
 | |
|   EFI_MAC_ADDRESS            *MacAddr;
 | |
|   UINT32                     AddrLen;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
 | |
| 
 | |
|   AddrLen = IpSb->SnpMode.HwAddressSize;
 | |
| 
 | |
|   //
 | |
|   // Currently only IEEE 802 48-bit MACs are supported to create link local address.
 | |
|   //
 | |
|   if (AddrLen != IP6_MAC_LEN || IpSb->InterfaceIdLen != IP6_IF_ID_LEN) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   MacAddr = &IpSb->SnpMode.CurrentAddress;
 | |
| 
 | |
|   //
 | |
|   // Convert MAC address to 64 bits interface ID according to Appendix A of RFC4291:
 | |
|   // 1. Insert 0xFFFE to the middle
 | |
|   // 2. Invert the universal/local bit - bit 6 in network order
 | |
|   //
 | |
|   CopyMem (InterfaceId, MacAddr, 3);
 | |
|   InterfaceId[3] = 0xFF;
 | |
|   InterfaceId[4] = 0xFE;
 | |
|   CopyMem (&InterfaceId[5], &MacAddr->Addr[3], 3);
 | |
| 
 | |
|   Byte = (UINT8) (InterfaceId[0] & IP6_U_BIT);
 | |
|   if (Byte == IP6_U_BIT) {
 | |
|     InterfaceId[0] &= ~IP6_U_BIT;
 | |
|   } else {
 | |
|     InterfaceId[0] |= IP6_U_BIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Return the interface ID.
 | |
|   //
 | |
|   return AllocateCopyPool (IpSb->InterfaceIdLen, InterfaceId);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function creates link-local address from interface identifier. The
 | |
|   interface identifier is normally created from MAC address. It might be manually
 | |
|   configured by administrator if the link-local address created from MAC address
 | |
|   is a duplicate address.
 | |
| 
 | |
|   @param[in, out]  IpSb      The IP6 service binding instance.
 | |
| 
 | |
|   @retval          NULL      If the operation fails.
 | |
|   @return                    The generated Link Local address, in network order.
 | |
| 
 | |
| **/
 | |
| EFI_IPv6_ADDRESS *
 | |
| Ip6CreateLinkLocalAddr (
 | |
|   IN OUT IP6_SERVICE           *IpSb
 | |
|   )
 | |
| {
 | |
|   EFI_IPv6_ADDRESS             *Ip6Addr;
 | |
|   EFI_IP6_CONFIG_PROTOCOL      *Ip6Config;
 | |
|   UINTN                        DataSize;
 | |
|   EFI_IP6_CONFIG_INTERFACE_ID  InterfaceId;
 | |
|   EFI_STATUS                   Status;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
 | |
| 
 | |
|   if (IpSb->InterfaceId != NULL) {
 | |
|     FreePool (IpSb->InterfaceId);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the interface id if it is manully configured.
 | |
|   //
 | |
|   Ip6Config = &IpSb->Ip6ConfigInstance.Ip6Config;
 | |
|   DataSize  = sizeof (EFI_IP6_CONFIG_INTERFACE_ID);
 | |
|   ZeroMem (&InterfaceId, DataSize);
 | |
| 
 | |
|   Status = Ip6Config->GetData (
 | |
|                         Ip6Config,
 | |
|                         Ip6ConfigDataTypeAltInterfaceId,
 | |
|                         &DataSize,
 | |
|                         &InterfaceId
 | |
|                         );
 | |
|   if (Status == EFI_NOT_FOUND) {
 | |
|     //
 | |
|     // Since the interface id is not configured, generate the interface id from
 | |
|     // MAC address.
 | |
|     //
 | |
|     IpSb->InterfaceId = Ip6CreateInterfaceID (IpSb);
 | |
|     if (IpSb->InterfaceId == NULL) {
 | |
|       return NULL;
 | |
|     }
 | |
| 
 | |
|     CopyMem (&InterfaceId, IpSb->InterfaceId, IpSb->InterfaceIdLen);
 | |
|     //
 | |
|     // Record the interface id.
 | |
|     //
 | |
|     Status = Ip6Config->SetData (
 | |
|                           Ip6Config,
 | |
|                           Ip6ConfigDataTypeAltInterfaceId,
 | |
|                           DataSize,
 | |
|                           &InterfaceId
 | |
|                           );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       FreePool (IpSb->InterfaceId);
 | |
|       IpSb->InterfaceId = NULL;
 | |
|       return NULL;
 | |
|     }
 | |
|   } else if (!EFI_ERROR (Status)) {
 | |
|     IpSb->InterfaceId = AllocateCopyPool (DataSize, &InterfaceId);
 | |
|     if (IpSb->InterfaceId == NULL) {
 | |
|       return NULL;
 | |
|     }
 | |
|   } else {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Append FE80::/64 to the left of IPv6 address then return.
 | |
|   //
 | |
|   Ip6Addr = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
 | |
|   if (Ip6Addr == NULL) {
 | |
|     FreePool (IpSb->InterfaceId);
 | |
|     IpSb->InterfaceId = NULL;
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   CopyMem (&Ip6Addr->Addr[8], IpSb->InterfaceId, IpSb->InterfaceIdLen);
 | |
|   Ip6Addr->Addr[1] = 0x80;
 | |
|   Ip6Addr->Addr[0] = 0xFE;
 | |
| 
 | |
|   return Ip6Addr;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Compute the solicited-node multicast address for an unicast or anycast address,
 | |
|   by taking the low-order 24 bits of this address, and appending those bits to
 | |
|   the prefix FF02:0:0:0:0:1:FF00::/104.
 | |
| 
 | |
|   @param[in]  Ip6Addr               The unicast or anycast address, in network order.
 | |
|   @param[out] MulticastAddr         The generated solicited-node multicast address,
 | |
|                                     in network order.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| Ip6CreateSNMulticastAddr (
 | |
|   IN EFI_IPv6_ADDRESS  *Ip6Addr,
 | |
|   OUT EFI_IPv6_ADDRESS *MulticastAddr
 | |
|   )
 | |
| {
 | |
|   ASSERT (Ip6Addr != NULL && MulticastAddr != NULL);
 | |
| 
 | |
|   ZeroMem (MulticastAddr, sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|   MulticastAddr->Addr[0]  = 0xFF;
 | |
|   MulticastAddr->Addr[1]  = 0x02;
 | |
|   MulticastAddr->Addr[11] = 0x1;
 | |
|   MulticastAddr->Addr[12] = 0xFF;
 | |
| 
 | |
|   CopyMem (&MulticastAddr->Addr[13], &Ip6Addr->Addr[13], 3);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Insert a node IP6_ADDRESS_INFO to an IP6 interface.
 | |
| 
 | |
|   @param[in, out]  IpIf             Points to an IP6 interface.
 | |
|   @param[in]       AddrInfo         Points to IP6_ADDRESS_INFO
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| Ip6AddAddr (
 | |
|   IN OUT IP6_INTERFACE *IpIf,
 | |
|   IN IP6_ADDRESS_INFO  *AddrInfo
 | |
|   )
 | |
| {
 | |
|   InsertHeadList (&IpIf->AddressList, &AddrInfo->Link);
 | |
|   IpIf->AddressCount++;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Callback function which provided by user to remove one node in NetDestroyLinkList process.
 | |
|   
 | |
|   @param[in]    Entry           The entry to be removed.
 | |
|   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The entry has been removed successfully.
 | |
|   @retval Others                Fail to remove the entry.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Ip6DestroyChildEntryByAddr (
 | |
|   IN LIST_ENTRY         *Entry,
 | |
|   IN VOID               *Context
 | |
|   )
 | |
| {
 | |
|   IP6_PROTOCOL                  *Instance;
 | |
|   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
 | |
|   EFI_IPv6_ADDRESS              *Address;
 | |
|   
 | |
|   Instance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
 | |
|   ServiceBinding = ((IP6_DESTROY_CHILD_BY_ADDR_CALLBACK_CONTEXT*) Context)->ServiceBinding;
 | |
|   Address = ((IP6_DESTROY_CHILD_BY_ADDR_CALLBACK_CONTEXT*) Context)->Address;
 | |
| 
 | |
|   if ((Instance->State == IP6_STATE_CONFIGED) && EFI_IP6_EQUAL (&Instance->ConfigData.StationAddress, Address)) {
 | |
|     return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
 | |
|   }
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Destroy the IP instance if its StationAddress is removed. It is the help function
 | |
|   for Ip6RemoveAddr().
 | |
| 
 | |
|   @param[in, out]  IpSb             Points to an IP6 service binding instance.
 | |
|   @param[in]       Address          The to be removed address
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| Ip6DestroyInstanceByAddress (
 | |
|   IN OUT IP6_SERVICE   *IpSb,
 | |
|   IN EFI_IPv6_ADDRESS  *Address
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                    *List;
 | |
|   IP6_DESTROY_CHILD_BY_ADDR_CALLBACK_CONTEXT  Context;
 | |
| 
 | |
|   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
 | |
| 
 | |
|   List = &IpSb->Children;
 | |
|   Context.ServiceBinding = &IpSb->ServiceBinding;
 | |
|   Context.Address = Address;
 | |
|   NetDestroyLinkList (
 | |
|     List,
 | |
|     Ip6DestroyChildEntryByAddr,
 | |
|     &Context,
 | |
|     NULL
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Remove the IPv6 address from the address list node points to IP6_ADDRESS_INFO.
 | |
| 
 | |
|   This function removes the matching IPv6 addresses from the address list and
 | |
|   adjusts the address count of the address list. If IpSb is not NULL, this function
 | |
|   calls Ip6LeaveGroup to see whether it should call Mnp->Groups() to remove the
 | |
|   its solicited-node multicast MAC address from the filter list and sends out
 | |
|   a Multicast Listener Done. If Prefix is NULL, all address in the address list
 | |
|   will be removed. If Prefix is not NULL, the address that matching the Prefix
 | |
|   with PrefixLength in the address list will be removed.
 | |
| 
 | |
|   @param[in]       IpSb             NULL or points to IP6 service binding instance.
 | |
|   @param[in, out]  AddressList      Address list array.
 | |
|   @param[in, out]  AddressCount     The count of addresses in address list array.
 | |
|   @param[in]       Prefix           NULL or an IPv6 address prefix.
 | |
|   @param[in]       PrefixLength     The length of Prefix.
 | |
| 
 | |
|   @retval    EFI_SUCCESS            The operation completed successfully.
 | |
|   @retval    EFI_NOT_FOUND          The address matching the Prefix with PrefixLength
 | |
|                                     cannot be found in the address list.
 | |
|   @retval    EFI_INVALID_PARAMETER  Any input parameter is invalid.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Ip6RemoveAddr (
 | |
|   IN IP6_SERVICE       *IpSb          OPTIONAL,
 | |
|   IN OUT LIST_ENTRY    *AddressList,
 | |
|   IN OUT UINT32        *AddressCount,
 | |
|   IN EFI_IPv6_ADDRESS  *Prefix        OPTIONAL,
 | |
|   IN UINT8             PrefixLength
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS           Status;
 | |
|   LIST_ENTRY           *Entry;
 | |
|   LIST_ENTRY           *Next;
 | |
|   IP6_ADDRESS_INFO     *AddrInfo;
 | |
|   EFI_IPv6_ADDRESS     SnMCastAddr;
 | |
| 
 | |
|   if (IsListEmpty (AddressList) || *AddressCount < 1 || PrefixLength > IP6_PREFIX_MAX) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_NOT_FOUND;
 | |
| 
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, Next, AddressList) {
 | |
|     AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
 | |
| 
 | |
|     if (Prefix == NULL ||
 | |
|         (PrefixLength == 128 && EFI_IP6_EQUAL (Prefix, &AddrInfo->Address)) ||
 | |
|         (PrefixLength == AddrInfo->PrefixLength && NetIp6IsNetEqual (Prefix, &AddrInfo->Address, PrefixLength))
 | |
|         ) {
 | |
|       if (IpSb != NULL) {
 | |
|         NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
 | |
|         Ip6CreateSNMulticastAddr (&AddrInfo->Address, &SnMCastAddr);
 | |
|         Ip6LeaveGroup (IpSb, &SnMCastAddr);
 | |
| 
 | |
|         //
 | |
|         // Destroy any instance who is using the dying address as the source address.
 | |
|         //
 | |
|         Ip6DestroyInstanceByAddress (IpSb, &AddrInfo->Address);
 | |
|       }
 | |
| 
 | |
|       RemoveEntryList (Entry);
 | |
|       FreePool (AddrInfo);
 | |
|       (*AddressCount)--;
 | |
| 
 | |
|       Status = EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check whether the incoming Ipv6 address is a solicited-node multicast address.
 | |
| 
 | |
|   @param[in]  Ip6               Ip6 address, in network order.
 | |
| 
 | |
|   @retval TRUE                  Yes, solicited-node multicast address
 | |
|   @retval FALSE                 No
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| Ip6IsSNMulticastAddr (
 | |
|   IN EFI_IPv6_ADDRESS *Ip6
 | |
|   )
 | |
| {
 | |
|   EFI_IPv6_ADDRESS    Sn;
 | |
|   BOOLEAN             Flag;
 | |
| 
 | |
|   Ip6CreateSNMulticastAddr (Ip6, &Sn);
 | |
|   Flag = FALSE;
 | |
| 
 | |
|   if (CompareMem (Sn.Addr, Ip6->Addr, 13) == 0) {
 | |
|     Flag = TRUE;
 | |
|   }
 | |
| 
 | |
|   return Flag;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check whether the incoming IPv6 address is one of the maintained addresses in
 | |
|   the IP6 service binding instance.
 | |
| 
 | |
|   @param[in]  IpSb              Points to a IP6 service binding instance.
 | |
|   @param[in]  Address           The IP6 address to be checked.
 | |
|   @param[out] Interface         If not NULL, output the IP6 interface which
 | |
|                                 maintains the Address.
 | |
|   @param[out] AddressInfo       If not NULL, output the IP6 address information
 | |
|                                 of the Address.
 | |
| 
 | |
|   @retval TRUE                  Yes, it is one of the maintained address.
 | |
|   @retval FALSE                 No, it is not one of the maintained address.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| Ip6IsOneOfSetAddress (
 | |
|   IN  IP6_SERVICE           *IpSb,
 | |
|   IN  EFI_IPv6_ADDRESS      *Address,
 | |
|   OUT IP6_INTERFACE         **Interface   OPTIONAL,
 | |
|   OUT IP6_ADDRESS_INFO      **AddressInfo OPTIONAL
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                *Entry;
 | |
|   LIST_ENTRY                *Entry2;
 | |
|   IP6_INTERFACE             *IpIf;
 | |
|   IP6_ADDRESS_INFO          *TmpAddressInfo;
 | |
| 
 | |
|   //
 | |
|   // Check link-local address first
 | |
|   //
 | |
|   if (IpSb->LinkLocalOk && EFI_IP6_EQUAL (&IpSb->LinkLocalAddr, Address)) {
 | |
|     if (Interface != NULL) {
 | |
|       *Interface = IpSb->DefaultInterface;
 | |
|     }
 | |
| 
 | |
|     if (AddressInfo != NULL) {
 | |
|       *AddressInfo = NULL;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
 | |
|     IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
 | |
| 
 | |
|     NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
 | |
|       TmpAddressInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
 | |
| 
 | |
|       if (EFI_IP6_EQUAL (&TmpAddressInfo->Address, Address)) {
 | |
|         if (Interface != NULL) {
 | |
|           *Interface = IpIf;
 | |
|         }
 | |
| 
 | |
|         if (AddressInfo != NULL) {
 | |
|           *AddressInfo = TmpAddressInfo;
 | |
|         }
 | |
| 
 | |
|         return TRUE;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check whether the incoming MAC address is valid.
 | |
| 
 | |
|   @param[in]  IpSb              Points to a IP6 service binding instance.
 | |
|   @param[in]  LinkAddress       The MAC address.
 | |
| 
 | |
|   @retval TRUE                  Yes, it is valid.
 | |
|   @retval FALSE                 No, it is not valid.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| Ip6IsValidLinkAddress (
 | |
|   IN  IP6_SERVICE      *IpSb,
 | |
|   IN  EFI_MAC_ADDRESS  *LinkAddress
 | |
|   )
 | |
| {
 | |
|   UINT32               Index;
 | |
| 
 | |
|   //
 | |
|   // TODO: might be updated later to be more acceptable.
 | |
|   //
 | |
|   for (Index = IpSb->SnpMode.HwAddressSize; Index < sizeof (EFI_MAC_ADDRESS); Index++) {
 | |
|     if (LinkAddress->Addr[Index] != 0) {
 | |
|       return FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Copy the PrefixLength bits from Src to Dest.
 | |
| 
 | |
|   @param[out] Dest              A pointer to the buffer to copy to.
 | |
|   @param[in]  Src               A pointer to the buffer to copy from.
 | |
|   @param[in]  PrefixLength      The number of bits to copy.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| Ip6CopyAddressByPrefix (
 | |
|   OUT EFI_IPv6_ADDRESS *Dest,
 | |
|   IN  EFI_IPv6_ADDRESS *Src,
 | |
|   IN  UINT8            PrefixLength
 | |
|   )
 | |
| {
 | |
|   UINT8 Byte;
 | |
|   UINT8 Bit;
 | |
|   UINT8 Mask;
 | |
| 
 | |
|   ASSERT (Dest != NULL && Src != NULL);
 | |
|   ASSERT (PrefixLength <= IP6_PREFIX_MAX);
 | |
| 
 | |
|   Byte = (UINT8) (PrefixLength / 8);
 | |
|   Bit  = (UINT8) (PrefixLength % 8);
 | |
| 
 | |
|   ZeroMem (Dest, sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|   CopyMem (Dest, Src, Byte);
 | |
| 
 | |
|   if (Bit > 0) {
 | |
|     Mask = (UINT8) (0xFF << (8 - Bit));
 | |
|     ASSERT (Byte < 16);
 | |
|     Dest->Addr[Byte] = (UINT8) (Src->Addr[Byte] & Mask);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the MAC address for a multicast IP address. Call
 | |
|   Mnp's McastIpToMac to find the MAC address instead of
 | |
|   hard-coding the NIC to be Ethernet.
 | |
| 
 | |
|   @param[in]  Mnp                   The Mnp instance to get the MAC address.
 | |
|   @param[in]  Multicast             The multicast IP address to translate.
 | |
|   @param[out] Mac                   The buffer to hold the translated address.
 | |
| 
 | |
|   @retval EFI_SUCCESS               The multicast IP successfully
 | |
|                                     translated to a multicast MAC address.
 | |
|   @retval Other                     The address is not converted because an error occurred.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Ip6GetMulticastMac (
 | |
|   IN  EFI_MANAGED_NETWORK_PROTOCOL *Mnp,
 | |
|   IN  EFI_IPv6_ADDRESS             *Multicast,
 | |
|   OUT EFI_MAC_ADDRESS              *Mac
 | |
|   )
 | |
| {
 | |
|   EFI_IP_ADDRESS        EfiIp;
 | |
| 
 | |
|   IP6_COPY_ADDRESS (&EfiIp.v6, Multicast);
 | |
| 
 | |
|   return Mnp->McastIpToMac (Mnp, TRUE, &EfiIp, Mac);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert the multibyte field in IP header's byter order.
 | |
|   In spite of its name, it can also be used to convert from
 | |
|   host to network byte order.
 | |
| 
 | |
|   @param[in, out]  Head                  The IP head to convert.
 | |
| 
 | |
|   @return Point to the converted IP head.
 | |
| 
 | |
| **/
 | |
| EFI_IP6_HEADER *
 | |
| Ip6NtohHead (
 | |
|   IN OUT EFI_IP6_HEADER *Head
 | |
|   )
 | |
| {
 | |
|   Head->FlowLabelL    = NTOHS (Head->FlowLabelL);
 | |
|   Head->PayloadLength = NTOHS (Head->PayloadLength);
 | |
| 
 | |
|   return Head;
 | |
| }
 | |
| 
 |