From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/NetworkPkg/Ip6Dxe/Ip6Common.c | 667 ++++++++++++++++++++++++++++++++ 1 file changed, 667 insertions(+) create mode 100644 roms/edk2/NetworkPkg/Ip6Dxe/Ip6Common.c (limited to 'roms/edk2/NetworkPkg/Ip6Dxe/Ip6Common.c') diff --git a/roms/edk2/NetworkPkg/Ip6Dxe/Ip6Common.c b/roms/edk2/NetworkPkg/Ip6Dxe/Ip6Common.c new file mode 100644 index 000000000..840fff0e7 --- /dev/null +++ b/roms/edk2/NetworkPkg/Ip6Dxe/Ip6Common.c @@ -0,0 +1,667 @@ +/** @file + The implementation of common functions shared by IP6 driver. + + Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 manually 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; +} + -- cgit 1.2.3-korg