+++ /dev/null
-/** @file\r
- The implementation of IPsec.\r
-\r
- (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "IpSecImpl.h"\r
-#include "IkeService.h"\r
-#include "IpSecDebug.h"\r
-#include "IpSecCryptIo.h"\r
-#include "IpSecConfigImpl.h"\r
-\r
-/**\r
- Check if the specified Address is the Valid Address Range.\r
-\r
- This function checks if the bytes after prefixed length are all Zero in this\r
- Address. This Address is supposed to point to a range address. That means it\r
- should gives the correct prefixed address and the bytes outside the prefixed are\r
- zero.\r
-\r
- @param[in] IpVersion The IP version.\r
- @param[in] Address Points to EFI_IP_ADDRESS to be checked.\r
- @param[in] PrefixLength The PrefixeLength of this address.\r
-\r
- @retval TRUE The address is a vaild address range.\r
- @retval FALSE The address is not a vaild address range.\r
-\r
-**/\r
-BOOLEAN\r
-IpSecValidAddressRange (\r
- IN UINT8 IpVersion,\r
- IN EFI_IP_ADDRESS *Address,\r
- IN UINT8 PrefixLength\r
- )\r
-{\r
- UINT8 Div;\r
- UINT8 Mod;\r
- UINT8 Mask;\r
- UINT8 AddrLen;\r
- UINT8 *Addr;\r
- EFI_IP_ADDRESS ZeroAddr;\r
-\r
- if (PrefixLength == 0) {\r
- return TRUE;\r
- }\r
-\r
- AddrLen = (UINT8) ((IpVersion == IP_VERSION_4) ? 32 : 128);\r
-\r
- if (AddrLen <= PrefixLength) {\r
- return FALSE;\r
- }\r
-\r
- Div = (UINT8) (PrefixLength / 8);\r
- Mod = (UINT8) (PrefixLength % 8);\r
- Addr = (UINT8 *) Address;\r
- ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS));\r
-\r
- //\r
- // Check whether the mod part of host scope is zero or not.\r
- //\r
- if (Mod > 0) {\r
- Mask = (UINT8) (0xFF << (8 - Mod));\r
-\r
- if ((Addr[Div] | Mask) != Mask) {\r
- return FALSE;\r
- }\r
-\r
- Div++;\r
- }\r
- //\r
- // Check whether the div part of host scope is zero or not.\r
- //\r
- if (CompareMem (\r
- &Addr[Div],\r
- &ZeroAddr,\r
- sizeof (EFI_IP_ADDRESS) - Div\r
- ) != 0) {\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Extrct the Address Range from a Address.\r
-\r
- This function keep the prefix address and zero other part address.\r
-\r
- @param[in] Address Point to a specified address.\r
- @param[in] PrefixLength The prefix length.\r
- @param[out] Range Contain the return Address Range.\r
-\r
-**/\r
-VOID\r
-IpSecExtractAddressRange (\r
- IN EFI_IP_ADDRESS *Address,\r
- IN UINT8 PrefixLength,\r
- OUT EFI_IP_ADDRESS *Range\r
- )\r
-{\r
- UINT8 Div;\r
- UINT8 Mod;\r
- UINT8 Mask;\r
- UINT8 *Addr;\r
-\r
- if (PrefixLength == 0) {\r
- return ;\r
- }\r
-\r
- Div = (UINT8) (PrefixLength / 8);\r
- Mod = (UINT8) (PrefixLength % 8);\r
- Addr = (UINT8 *) Range;\r
-\r
- CopyMem (Range, Address, sizeof (EFI_IP_ADDRESS));\r
-\r
- //\r
- // Zero the mod part of host scope.\r
- //\r
- if (Mod > 0) {\r
- Mask = (UINT8) (0xFF << (8 - Mod));\r
- Addr[Div] = (UINT8) (Addr[Div] & Mask);\r
- Div++;\r
- }\r
- //\r
- // Zero the div part of host scope.\r
- //\r
- ZeroMem (&Addr[Div], sizeof (EFI_IP_ADDRESS) - Div);\r
-\r
-}\r
-\r
-/**\r
- Checks if the IP Address in the address range of AddressInfos specified.\r
-\r
- @param[in] IpVersion The IP version.\r
- @param[in] IpAddr Point to EFI_IP_ADDRESS to be check.\r
- @param[in] AddressInfo A list of EFI_IP_ADDRESS_INFO that is used to check\r
- the IP Address is matched.\r
- @param[in] AddressCount The total numbers of the AddressInfo.\r
-\r
- @retval TRUE If the Specified IP Address is in the range of the AddressInfos specified.\r
- @retval FALSE If the Specified IP Address is not in the range of the AddressInfos specified.\r
-\r
-**/\r
-BOOLEAN\r
-IpSecMatchIpAddress (\r
- IN UINT8 IpVersion,\r
- IN EFI_IP_ADDRESS *IpAddr,\r
- IN EFI_IP_ADDRESS_INFO *AddressInfo,\r
- IN UINT32 AddressCount\r
- )\r
-{\r
- EFI_IP_ADDRESS Range;\r
- UINT32 Index;\r
- BOOLEAN IsMatch;\r
-\r
- IsMatch = FALSE;\r
-\r
- for (Index = 0; Index < AddressCount; Index++) {\r
- //\r
- // Check whether the target address is in the address range\r
- // if it's a valid range of address.\r
- //\r
- if (IpSecValidAddressRange (\r
- IpVersion,\r
- &AddressInfo[Index].Address,\r
- AddressInfo[Index].PrefixLength\r
- )) {\r
- //\r
- // Get the range of the target address belongs to.\r
- //\r
- ZeroMem (&Range, sizeof (EFI_IP_ADDRESS));\r
- IpSecExtractAddressRange (\r
- IpAddr,\r
- AddressInfo[Index].PrefixLength,\r
- &Range\r
- );\r
-\r
- if (CompareMem (\r
- &Range,\r
- &AddressInfo[Index].Address,\r
- sizeof (EFI_IP_ADDRESS)\r
- ) == 0) {\r
- //\r
- // The target address is in the address range.\r
- //\r
- IsMatch = TRUE;\r
- break;\r
- }\r
- }\r
-\r
- if (CompareMem (\r
- IpAddr,\r
- &AddressInfo[Index].Address,\r
- sizeof (EFI_IP_ADDRESS)\r
- ) == 0) {\r
- //\r
- // The target address is exact same as the address.\r
- //\r
- IsMatch = TRUE;\r
- break;\r
- }\r
- }\r
- return IsMatch;\r
-}\r
-\r
-/**\r
- Check if the specified Protocol and Prot is supported by the specified SPD Entry.\r
-\r
- This function is the subfunction of IPsecLookUpSpdEntry() that is used to\r
- check if the sent/received IKE packet has the related SPD entry support.\r
-\r
- @param[in] Protocol The Protocol to be checked.\r
- @param[in] IpPayload Point to IP Payload to be check.\r
- @param[in] SpdProtocol The Protocol supported by SPD.\r
- @param[in] SpdLocalPort The Local Port in SPD.\r
- @param[in] SpdRemotePort The Remote Port in SPD.\r
- @param[in] IsOutbound Flag to indicate the is for IKE Packet sending or recieving.\r
-\r
- @retval TRUE The Protocol and Port are supported by the SPD Entry.\r
- @retval FALSE The Protocol and Port are not supported by the SPD Entry.\r
-\r
-**/\r
-BOOLEAN\r
-IpSecMatchNextLayerProtocol (\r
- IN UINT8 Protocol,\r
- IN UINT8 *IpPayload,\r
- IN UINT16 SpdProtocol,\r
- IN UINT16 SpdLocalPort,\r
- IN UINT16 SpdRemotePort,\r
- IN BOOLEAN IsOutbound\r
- )\r
-{\r
- BOOLEAN IsMatch;\r
-\r
- if (SpdProtocol == EFI_IPSEC_ANY_PROTOCOL) {\r
- return TRUE;\r
- }\r
-\r
- IsMatch = FALSE;\r
-\r
- if (SpdProtocol == Protocol) {\r
- switch (Protocol) {\r
- case EFI_IP_PROTO_UDP:\r
- case EFI_IP_PROTO_TCP:\r
- //\r
- // For udp and tcp, (0, 0) means no need to check local and remote\r
- // port. The payload is passed from upper level, which means it should\r
- // be in network order.\r
- //\r
- IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);\r
- IsMatch = (BOOLEAN) (IsMatch ||\r
- (IsOutbound &&\r
- (BOOLEAN)(\r
- NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdLocalPort &&\r
- NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdRemotePort\r
- )\r
- ));\r
-\r
- IsMatch = (BOOLEAN) (IsMatch ||\r
- (!IsOutbound &&\r
- (BOOLEAN)(\r
- NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdLocalPort &&\r
- NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdRemotePort\r
- )\r
- ));\r
- break;\r
-\r
- case EFI_IP_PROTO_ICMP:\r
- //\r
- // For icmpv4, type code is replaced with local port and remote port,\r
- // and (0, 0) means no need to check.\r
- //\r
- IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);\r
- IsMatch = (BOOLEAN) (IsMatch ||\r
- (BOOLEAN) (((IP4_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&\r
- ((IP4_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort\r
- )\r
- );\r
- break;\r
-\r
- case IP6_ICMP:\r
- //\r
- // For icmpv6, type code is replaced with local port and remote port,\r
- // and (0, 0) means no need to check.\r
- //\r
- IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);\r
-\r
- IsMatch = (BOOLEAN) (IsMatch ||\r
- (BOOLEAN) (((IP6_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&\r
- ((IP6_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort\r
- )\r
- );\r
- break;\r
-\r
- default:\r
- IsMatch = TRUE;\r
- break;\r
- }\r
- }\r
-\r
- return IsMatch;\r
-}\r
-\r
-/**\r
- Find the SAD through a specified SPD's SAD list.\r
-\r
- @param[in] SadList SAD list related to a specified SPD entry.\r
- @param[in] DestAddress The destination address used to find the SAD entry.\r
- @param[in] IpVersion The IP version. Ip4 or Ip6.\r
-\r
- @return The pointer to a certain SAD entry.\r
-\r
-**/\r
-IPSEC_SAD_ENTRY *\r
-IpSecLookupSadBySpd (\r
- IN LIST_ENTRY *SadList,\r
- IN EFI_IP_ADDRESS *DestAddress,\r
- IN UINT8 IpVersion\r
- )\r
-{\r
- LIST_ENTRY *Entry;\r
- IPSEC_SAD_ENTRY *SadEntry;\r
-\r
- NET_LIST_FOR_EACH (Entry, SadList) {\r
-\r
- SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);\r
- //\r
- // Find the right SAD entry which contains the appointed dest address.\r
- //\r
- if (IpSecMatchIpAddress (\r
- IpVersion,\r
- DestAddress,\r
- SadEntry->Data->SpdSelector->RemoteAddress,\r
- SadEntry->Data->SpdSelector->RemoteAddressCount\r
- )){\r
- return SadEntry;\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- Find the SAD through whole SAD list.\r
-\r
- @param[in] Spi The SPI used to search the SAD entry.\r
- @param[in] DestAddress The destination used to search the SAD entry.\r
- @param[in] IpVersion The IP version. Ip4 or Ip6.\r
-\r
- @return the pointer to a certain SAD entry.\r
-\r
-**/\r
-IPSEC_SAD_ENTRY *\r
-IpSecLookupSadBySpi (\r
- IN UINT32 Spi,\r
- IN EFI_IP_ADDRESS *DestAddress,\r
- IN UINT8 IpVersion\r
- )\r
-{\r
- LIST_ENTRY *Entry;\r
- LIST_ENTRY *SadList;\r
- IPSEC_SAD_ENTRY *SadEntry;\r
-\r
- SadList = &mConfigData[IPsecConfigDataTypeSad];\r
-\r
- NET_LIST_FOR_EACH (Entry, SadList) {\r
-\r
- SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);\r
-\r
- //\r
- // Find the right SAD entry which contain the appointed spi and dest addr.\r
- //\r
- if (SadEntry->Id->Spi == Spi) {\r
- if (SadEntry->Data->Mode == EfiIPsecTunnel) {\r
- if (CompareMem (\r
- &DestAddress,\r
- &SadEntry->Data->TunnelDestAddress,\r
- sizeof (EFI_IP_ADDRESS)\r
- )) {\r
- return SadEntry;\r
- }\r
- } else {\r
- if (SadEntry->Data->SpdSelector != NULL &&\r
- IpSecMatchIpAddress (\r
- IpVersion,\r
- DestAddress,\r
- SadEntry->Data->SpdSelector->RemoteAddress,\r
- SadEntry->Data->SpdSelector->RemoteAddressCount\r
- )\r
- ) {\r
- return SadEntry;\r
- }\r
- }\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-/**\r
- Look up if there is existing SAD entry for specified IP packet sending.\r
-\r
- This function is called by the IPsecProcess when there is some IP packet needed to\r
- send out. This function checks if there is an existing SAD entry that can be serviced\r
- to this IP packet sending. If no existing SAD entry could be used, this\r
- function will invoke an IPsec Key Exchange Negotiation.\r
-\r
- @param[in] Private Points to private data.\r
- @param[in] NicHandle Points to a NIC handle.\r
- @param[in] IpVersion The version of IP.\r
- @param[in] IpHead The IP Header of packet to be sent out.\r
- @param[in] IpPayload The IP Payload to be sent out.\r
- @param[in] OldLastHead The Last protocol of the IP packet.\r
- @param[in] SpdEntry Points to a related SPD entry.\r
- @param[out] SadEntry Contains the Point of a related SAD entry.\r
-\r
- @retval EFI_DEVICE_ERROR One of following conditions is TRUE:\r
- - If don't find related UDP service.\r
- - Sequence Number is used up.\r
- - Extension Sequence Number is used up.\r
- @retval EFI_NOT_READY No existing SAD entry could be used.\r
- @retval EFI_SUCCESS Find the related SAD entry.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecLookupSadEntry (\r
- IN IPSEC_PRIVATE_DATA *Private,\r
- IN EFI_HANDLE NicHandle,\r
- IN UINT8 IpVersion,\r
- IN VOID *IpHead,\r
- IN UINT8 *IpPayload,\r
- IN UINT8 OldLastHead,\r
- IN IPSEC_SPD_ENTRY *SpdEntry,\r
- OUT IPSEC_SAD_ENTRY **SadEntry\r
- )\r
-{\r
- IKE_UDP_SERVICE *UdpService;\r
- IPSEC_SAD_ENTRY *Entry;\r
- IPSEC_SAD_DATA *Data;\r
- EFI_IP_ADDRESS DestIp;\r
- UINT32 SeqNum32;\r
-\r
- *SadEntry = NULL;\r
- UdpService = IkeLookupUdp (Private, NicHandle, IpVersion);\r
-\r
- if (UdpService == NULL) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Parse the destination address from ip header.\r
- //\r
- ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));\r
- if (IpVersion == IP_VERSION_4) {\r
- CopyMem (\r
- &DestIp,\r
- &((IP4_HEAD *) IpHead)->Dst,\r
- sizeof (IP4_ADDR)\r
- );\r
- } else {\r
- CopyMem (\r
- &DestIp,\r
- &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,\r
- sizeof (EFI_IP_ADDRESS)\r
- );\r
- }\r
-\r
- //\r
- // Find the SAD entry in the spd.sas list according to the dest address.\r
- //\r
- Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp, IpVersion);\r
-\r
- if (Entry == NULL) {\r
- if (OldLastHead != IP6_ICMP ||\r
- (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST)\r
- ) {\r
- //\r
- // Start ike negotiation process except the request packet of ping.\r
- //\r
- if (SpdEntry->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {\r
- IkeNegotiate (\r
- UdpService,\r
- SpdEntry,\r
- &SpdEntry->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress\r
- );\r
- } else {\r
- IkeNegotiate (\r
- UdpService,\r
- SpdEntry,\r
- &DestIp\r
- );\r
- }\r
-\r
- }\r
-\r
- return EFI_NOT_READY;\r
- }\r
-\r
- Data = Entry->Data;\r
-\r
- if (!Data->ManualSet) {\r
- if (Data->ESNEnabled) {\r
- //\r
- // Validate the 64bit sn number if 64bit sn enabled.\r
- //\r
- if ((UINT64) (Data->SequenceNumber + 1) == 0) {\r
- //\r
- // TODO: Re-negotiate SA\r
- //\r
- return EFI_DEVICE_ERROR;\r
- }\r
- } else {\r
- //\r
- // Validate the 32bit sn number if 64bit sn disabled.\r
- //\r
- SeqNum32 = (UINT32) Data->SequenceNumber;\r
- if ((UINT32) (SeqNum32 + 1) == 0) {\r
- //\r
- // TODO: Re-negotiate SA\r
- //\r
- return EFI_DEVICE_ERROR;\r
- }\r
- }\r
- }\r
-\r
- *SadEntry = Entry;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Find a PAD entry according to a remote IP address.\r
-\r
- @param[in] IpVersion The version of IP.\r
- @param[in] IpAddr Points to remote IP address.\r
-\r
- @return the pointer of related PAD entry.\r
-\r
-**/\r
-IPSEC_PAD_ENTRY *\r
-IpSecLookupPadEntry (\r
- IN UINT8 IpVersion,\r
- IN EFI_IP_ADDRESS *IpAddr\r
- )\r
-{\r
- LIST_ENTRY *PadList;\r
- LIST_ENTRY *Entry;\r
- EFI_IP_ADDRESS_INFO *IpAddrInfo;\r
- IPSEC_PAD_ENTRY *PadEntry;\r
-\r
- PadList = &mConfigData[IPsecConfigDataTypePad];\r
-\r
- for (Entry = PadList->ForwardLink; Entry != PadList; Entry = Entry->ForwardLink) {\r
-\r
- PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);\r
- IpAddrInfo = &PadEntry->Id->Id.IpAddress;\r
- //\r
- // Find the right pad entry which contain the appointed dest addr.\r
- //\r
- if (IpSecMatchIpAddress (IpVersion, IpAddr, IpAddrInfo, 1)) {\r
- return PadEntry;\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-/**\r
- Check if the specified IP packet can be serviced by this SPD entry.\r
-\r
- @param[in] SpdEntry Point to SPD entry.\r
- @param[in] IpVersion Version of IP.\r
- @param[in] IpHead Point to IP header.\r
- @param[in] IpPayload Point to IP payload.\r
- @param[in] Protocol The Last protocol of IP packet.\r
- @param[in] IsOutbound Traffic direction.\r
- @param[out] Action The support action of SPD entry.\r
-\r
- @retval EFI_SUCCESS Find the related SPD.\r
- @retval EFI_NOT_FOUND Not find the related SPD entry;\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecLookupSpdEntry (\r
- IN IPSEC_SPD_ENTRY *SpdEntry,\r
- IN UINT8 IpVersion,\r
- IN VOID *IpHead,\r
- IN UINT8 *IpPayload,\r
- IN UINT8 Protocol,\r
- IN BOOLEAN IsOutbound,\r
- OUT EFI_IPSEC_ACTION *Action\r
- )\r
-{\r
- EFI_IPSEC_SPD_SELECTOR *SpdSel;\r
- IP4_HEAD *Ip4;\r
- EFI_IP6_HEADER *Ip6;\r
- EFI_IP_ADDRESS SrcAddr;\r
- EFI_IP_ADDRESS DstAddr;\r
- BOOLEAN SpdMatch;\r
-\r
- ASSERT (SpdEntry != NULL);\r
- SpdSel = SpdEntry->Selector;\r
- Ip4 = (IP4_HEAD *) IpHead;\r
- Ip6 = (EFI_IP6_HEADER *) IpHead;\r
-\r
- ZeroMem (&SrcAddr, sizeof (EFI_IP_ADDRESS));\r
- ZeroMem (&DstAddr, sizeof (EFI_IP_ADDRESS));\r
-\r
- //\r
- // Parse the source and destination address from ip header.\r
- //\r
- if (IpVersion == IP_VERSION_4) {\r
- CopyMem (&SrcAddr, &Ip4->Src, sizeof (IP4_ADDR));\r
- CopyMem (&DstAddr, &Ip4->Dst, sizeof (IP4_ADDR));\r
- } else {\r
- CopyMem (&SrcAddr, &Ip6->SourceAddress, sizeof (EFI_IPv6_ADDRESS));\r
- CopyMem (&DstAddr, &Ip6->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));\r
- }\r
- //\r
- // Check the local and remote addresses for outbound traffic\r
- //\r
- SpdMatch = (BOOLEAN)(IsOutbound &&\r
- IpSecMatchIpAddress (\r
- IpVersion,\r
- &SrcAddr,\r
- SpdSel->LocalAddress,\r
- SpdSel->LocalAddressCount\r
- ) &&\r
- IpSecMatchIpAddress (\r
- IpVersion,\r
- &DstAddr,\r
- SpdSel->RemoteAddress,\r
- SpdSel->RemoteAddressCount\r
- )\r
- );\r
-\r
- //\r
- // Check the local and remote addresses for inbound traffic\r
- //\r
- SpdMatch = (BOOLEAN) (SpdMatch ||\r
- (!IsOutbound &&\r
- IpSecMatchIpAddress (\r
- IpVersion,\r
- &DstAddr,\r
- SpdSel->LocalAddress,\r
- SpdSel->LocalAddressCount\r
- ) &&\r
- IpSecMatchIpAddress (\r
- IpVersion,\r
- &SrcAddr,\r
- SpdSel->RemoteAddress,\r
- SpdSel->RemoteAddressCount\r
- )\r
- ));\r
-\r
- //\r
- // Check the next layer protocol and local and remote ports.\r
- //\r
- SpdMatch = (BOOLEAN) (SpdMatch &&\r
- IpSecMatchNextLayerProtocol (\r
- Protocol,\r
- IpPayload,\r
- SpdSel->NextLayerProtocol,\r
- SpdSel->LocalPort,\r
- SpdSel->RemotePort,\r
- IsOutbound\r
- )\r
- );\r
-\r
- if (SpdMatch) {\r
- //\r
- // Find the right SPD entry if match the 5 key elements.\r
- //\r
- *Action = SpdEntry->Data->Action;\r
- return EFI_SUCCESS;\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- The call back function of NetbufFromExt.\r
-\r
- @param[in] Arg The argument passed from the caller.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-IpSecOnRecyclePacket (\r
- IN VOID *Arg\r
- )\r
-{\r
-}\r
-\r
-/**\r
- This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP\r
- is released.\r
-\r
- @param[in] Event The related event.\r
- @param[in] Context The data passed by the caller.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-IpSecRecycleCallback (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
-\r
- RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context;\r
-\r
- if (RecycleContext->FragmentTable != NULL) {\r
- FreePool (RecycleContext->FragmentTable);\r
- }\r
-\r
- if (RecycleContext->PayloadBuffer != NULL) {\r
- FreePool (RecycleContext->PayloadBuffer);\r
- }\r
-\r
- FreePool (RecycleContext);\r
- gBS->CloseEvent (Event);\r
-\r
-}\r
-\r
-/**\r
- Calculate the extension hader of IP. The return length only doesn't contain\r
- the fixed IP header length.\r
-\r
- @param[in] IpHead Points to an IP head to be calculated.\r
- @param[in] LastHead Points to the last header of the IP header.\r
-\r
- @return The length of the extension header.\r
-\r
-**/\r
-UINT16\r
-IpSecGetPlainExtHeadSize (\r
- IN VOID *IpHead,\r
- IN UINT8 *LastHead\r
- )\r
-{\r
- UINT16 Size;\r
-\r
- Size = (UINT16) (LastHead - (UINT8 *) IpHead);\r
-\r
- if (Size > sizeof (EFI_IP6_HEADER)) {\r
- //\r
- // * (LastHead+1) point the last header's length but not include the first\r
- // 8 octers, so this formluation add 8 at the end.\r
- //\r
- Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);\r
- } else {\r
- Size = 0;\r
- }\r
-\r
- return Size;\r
-}\r
-\r
-/**\r
- Verify if the Authentication payload is correct.\r
-\r
- @param[in] EspBuffer Points to the ESP wrapped buffer.\r
- @param[in] EspSize The size of the ESP wrapped buffer.\r
- @param[in] SadEntry The related SAD entry to store the authentication\r
- algorithm key.\r
- @param[in] IcvSize The length of ICV.\r
-\r
- @retval EFI_SUCCESS The authentication data is correct.\r
- @retval EFI_ACCESS_DENIED The authentication data is not correct.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecEspAuthVerifyPayload (\r
- IN UINT8 *EspBuffer,\r
- IN UINTN EspSize,\r
- IN IPSEC_SAD_ENTRY *SadEntry,\r
- IN UINTN IcvSize\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN AuthSize;\r
- UINT8 IcvBuffer[12];\r
- HASH_DATA_FRAGMENT HashFragment[1];\r
-\r
- //\r
- // Calculate the size of authentication payload.\r
- //\r
- AuthSize = EspSize - IcvSize;\r
-\r
- //\r
- // Calculate the icv buffer and size of the payload.\r
- //\r
- HashFragment[0].Data = EspBuffer;\r
- HashFragment[0].DataSize = AuthSize;\r
-\r
- Status = IpSecCryptoIoHmac (\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,\r
- HashFragment,\r
- 1,\r
- IcvBuffer,\r
- IcvSize\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Compare the calculated icv and the appended original icv.\r
- //\r
- if (CompareMem (EspBuffer + AuthSize, IcvBuffer, IcvSize) == 0) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));\r
- return EFI_ACCESS_DENIED;\r
-}\r
-\r
-/**\r
- Search the related SAD entry by the input .\r
-\r
- @param[in] IpHead The pointer to IP header.\r
- @param[in] IpVersion The version of IP (IP4 or IP6).\r
- @param[in] Spi The SPI used to search the related SAD entry.\r
-\r
-\r
- @retval NULL Not find the related SAD entry.\r
- @retval IPSEC_SAD_ENTRY Return the related SAD entry.\r
-\r
-**/\r
-IPSEC_SAD_ENTRY *\r
-IpSecFoundSadFromInboundPacket (\r
- UINT8 *IpHead,\r
- UINT8 IpVersion,\r
- UINT32 Spi\r
- )\r
-{\r
- EFI_IP_ADDRESS DestIp;\r
-\r
- //\r
- // Parse destination address from ip header.\r
- //\r
- ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));\r
- if (IpVersion == IP_VERSION_4) {\r
- CopyMem (\r
- &DestIp,\r
- &((IP4_HEAD *) IpHead)->Dst,\r
- sizeof (IP4_ADDR)\r
- );\r
- } else {\r
- CopyMem (\r
- &DestIp,\r
- &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,\r
- sizeof (EFI_IPv6_ADDRESS)\r
- );\r
- }\r
-\r
- //\r
- // Lookup SAD entry according to the spi and dest address.\r
- //\r
- return IpSecLookupSadBySpi (Spi, &DestIp, IpVersion);\r
-}\r
-\r
-/**\r
- Validate the IP6 extension header format for both the packets we received\r
- and that we will transmit.\r
-\r
- @param[in] NextHeader The next header field in IPv6 basic header.\r
- @param[in] ExtHdrs The first bye of the option.\r
- @param[in] ExtHdrsLen The length of the whole option.\r
- @param[out] LastHeader The pointer of NextHeader of the last extension\r
- header processed by IP6.\r
- @param[out] RealExtsLen The length of extension headers processed by IP6 layer.\r
- This is an optional parameter that may be NULL.\r
-\r
- @retval TRUE The option is properly formated.\r
- @retval FALSE The option is malformated.\r
-\r
-**/\r
-BOOLEAN\r
-IpSecIsIp6ExtsValid (\r
- IN UINT8 *NextHeader,\r
- IN UINT8 *ExtHdrs,\r
- IN UINT32 ExtHdrsLen,\r
- OUT UINT8 **LastHeader,\r
- OUT UINT32 *RealExtsLen OPTIONAL\r
- )\r
-{\r
- UINT32 Pointer;\r
- UINT8 *Option;\r
- UINT8 OptionLen;\r
- UINT8 CountD;\r
- UINT8 CountF;\r
- UINT8 CountA;\r
-\r
- if (RealExtsLen != NULL) {\r
- *RealExtsLen = 0;\r
- }\r
-\r
- *LastHeader = NextHeader;\r
-\r
- if (ExtHdrs == NULL && ExtHdrsLen == 0) {\r
- return TRUE;\r
- }\r
-\r
- if ((ExtHdrs == NULL && ExtHdrsLen != 0) || (ExtHdrs != NULL && ExtHdrsLen == 0)) {\r
- return FALSE;\r
- }\r
-\r
- Pointer = 0;\r
- CountD = 0;\r
- CountF = 0;\r
- CountA = 0;\r
-\r
- while (Pointer <= ExtHdrsLen) {\r
-\r
- switch (*NextHeader) {\r
- case IP6_HOP_BY_HOP:\r
- if (Pointer != 0) {\r
- return FALSE;\r
- }\r
-\r
- //\r
- // Fall through\r
- //\r
- case IP6_DESTINATION:\r
- if (*NextHeader == IP6_DESTINATION) {\r
- CountD++;\r
- }\r
-\r
- if (CountD > 2) {\r
- return FALSE;\r
- }\r
-\r
- NextHeader = ExtHdrs + Pointer;\r
-\r
- Pointer++;\r
- Option = ExtHdrs + Pointer;\r
- OptionLen = (UINT8) ((*Option + 1) * 8 - 2);\r
- Option++;\r
- Pointer++;\r
-\r
- Pointer = Pointer + OptionLen;\r
- break;\r
-\r
- case IP6_FRAGMENT:\r
- if (++CountF > 1) {\r
- return FALSE;\r
- }\r
- //\r
- // RFC2402, AH header should after fragment header.\r
- //\r
- if (CountA > 1) {\r
- return FALSE;\r
- }\r
-\r
- NextHeader = ExtHdrs + Pointer;\r
- Pointer = Pointer + 8;\r
- break;\r
-\r
- case IP6_AH:\r
- if (++CountA > 1) {\r
- return FALSE;\r
- }\r
-\r
- Option = ExtHdrs + Pointer;\r
- NextHeader = Option;\r
- Option++;\r
- //\r
- // RFC2402, Payload length is specified in 32-bit words, minus "2".\r
- //\r
- OptionLen = (UINT8) ((*Option + 2) * 4);\r
- Pointer = Pointer + OptionLen;\r
- break;\r
-\r
- default:\r
- *LastHeader = NextHeader;\r
- if (RealExtsLen != NULL) {\r
- *RealExtsLen = Pointer;\r
- }\r
-\r
- return TRUE;\r
- }\r
- }\r
-\r
- *LastHeader = NextHeader;\r
-\r
- if (RealExtsLen != NULL) {\r
- *RealExtsLen = Pointer;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/**\r
- The actual entry to process the tunnel header and inner header for tunnel mode\r
- outbound traffic.\r
-\r
- This function is the subfunction of IpSecEspInboundPacket(). It change the destination\r
- Ip address to the station address and recalculate the uplayyer's checksum.\r
-\r
-\r
- @param[in, out] IpHead Points to the IP header containing the ESP header\r
- to be trimed on input, and without ESP header\r
- on return.\r
- @param[in] IpPayload The decrypted Ip payload. It start from the inner\r
- header.\r
- @param[in] IpVersion The version of IP.\r
- @param[in] SadData Pointer of the relevant SAD.\r
- @param[in, out] LastHead The Last Header in IP header on return.\r
-\r
-**/\r
-VOID\r
-IpSecTunnelInboundPacket (\r
- IN OUT UINT8 *IpHead,\r
- IN UINT8 *IpPayload,\r
- IN UINT8 IpVersion,\r
- IN IPSEC_SAD_DATA *SadData,\r
- IN OUT UINT8 *LastHead\r
- )\r
-{\r
- EFI_UDP_HEADER *UdpHeader;\r
- TCP_HEAD *TcpHeader;\r
- UINT16 *Checksum;\r
- UINT16 PseudoChecksum;\r
- UINT16 PacketChecksum;\r
- UINT32 OptionLen;\r
- IP6_ICMP_HEAD *Icmp6Head;\r
-\r
- Checksum = NULL;\r
-\r
- if (IpVersion == IP_VERSION_4) {\r
- //\r
- // Zero OutIP header use this to indicate the input packet is under\r
- // IPsec Tunnel protected.\r
- //\r
- ZeroMem (\r
- (IP4_HEAD *)IpHead,\r
- sizeof (IP4_HEAD)\r
- );\r
- CopyMem (\r
- &((IP4_HEAD *)IpPayload)->Dst,\r
- &SadData->TunnelDestAddress.v4,\r
- sizeof (EFI_IPv4_ADDRESS)\r
- );\r
-\r
- //\r
- // Recalculate IpHeader Checksum\r
- //\r
- if (((IP4_HEAD *)(IpPayload))->Checksum != 0 ) {\r
- ((IP4_HEAD *)(IpPayload))->Checksum = 0;\r
- ((IP4_HEAD *)(IpPayload))->Checksum = (UINT16) (~NetblockChecksum (\r
- (UINT8 *)IpPayload,\r
- ((IP4_HEAD *)IpPayload)->HeadLen << 2\r
- ));\r
-\r
-\r
- }\r
-\r
- //\r
- // Recalcualte PseudoChecksum\r
- //\r
- switch (((IP4_HEAD *)IpPayload)->Protocol) {\r
- case EFI_IP_PROTO_UDP :\r
- UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));\r
- Checksum = & UdpHeader->Checksum;\r
- *Checksum = 0;\r
- break;\r
-\r
- case EFI_IP_PROTO_TCP:\r
- TcpHeader = (TCP_HEAD *) ((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));\r
- Checksum = &TcpHeader->Checksum;\r
- *Checksum = 0;\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
- PacketChecksum = NetblockChecksum (\r
- (UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2),\r
- NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)\r
- );\r
- PseudoChecksum = NetPseudoHeadChecksum (\r
- ((IP4_HEAD *)IpPayload)->Src,\r
- ((IP4_HEAD *)IpPayload)->Dst,\r
- ((IP4_HEAD *)IpPayload)->Protocol,\r
- 0\r
- );\r
-\r
- if (Checksum != NULL) {\r
- *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);\r
- *Checksum = (UINT16) ~(NetAddChecksum (*Checksum, HTONS((UINT16)(NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)))));\r
- }\r
- }else {\r
- //\r
- // Zero OutIP header use this to indicate the input packet is under\r
- // IPsec Tunnel protected.\r
- //\r
- ZeroMem (\r
- IpHead,\r
- sizeof (EFI_IP6_HEADER)\r
- );\r
- CopyMem (\r
- &((EFI_IP6_HEADER*)IpPayload)->DestinationAddress,\r
- &SadData->TunnelDestAddress.v6,\r
- sizeof (EFI_IPv6_ADDRESS)\r
- );\r
-\r
- //\r
- // Get the Extension Header and Header length.\r
- //\r
- IpSecIsIp6ExtsValid (\r
- &((EFI_IP6_HEADER *)IpPayload)->NextHeader,\r
- IpPayload + sizeof (EFI_IP6_HEADER),\r
- ((EFI_IP6_HEADER *)IpPayload)->PayloadLength,\r
- &LastHead,\r
- &OptionLen\r
- );\r
-\r
- //\r
- // Recalcualte PseudoChecksum\r
- //\r
- switch (*LastHead) {\r
- case EFI_IP_PROTO_UDP:\r
- UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);\r
- Checksum = &UdpHeader->Checksum;\r
- *Checksum = 0;\r
- break;\r
-\r
- case EFI_IP_PROTO_TCP:\r
- TcpHeader = (TCP_HEAD *)(IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);\r
- Checksum = &TcpHeader->Checksum;\r
- *Checksum = 0;\r
- break;\r
-\r
- case IP6_ICMP:\r
- Icmp6Head = (IP6_ICMP_HEAD *) (IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);\r
- Checksum = &Icmp6Head->Checksum;\r
- *Checksum = 0;\r
- break;\r
- }\r
- PacketChecksum = NetblockChecksum (\r
- IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen,\r
- NTOHS(((EFI_IP6_HEADER *)IpPayload)->PayloadLength) - OptionLen\r
- );\r
- PseudoChecksum = NetIp6PseudoHeadChecksum (\r
- &((EFI_IP6_HEADER *)IpPayload)->SourceAddress,\r
- &((EFI_IP6_HEADER *)IpPayload)->DestinationAddress,\r
- *LastHead,\r
- 0\r
- );\r
-\r
- if (Checksum != NULL) {\r
- *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);\r
- *Checksum = (UINT16) ~(NetAddChecksum (\r
- *Checksum,\r
- HTONS ((UINT16)((NTOHS (((EFI_IP6_HEADER *)(IpPayload))->PayloadLength)) - OptionLen))\r
- ));\r
- }\r
- }\r
-}\r
-\r
-/**\r
- The actual entry to create inner header for tunnel mode inbound traffic.\r
-\r
- This function is the subfunction of IpSecEspOutboundPacket(). It create\r
- the sending packet by encrypting its payload and inserting ESP header in the orginal\r
- IP header, then return the IpHeader and IPsec protected Fragmentable.\r
-\r
- @param[in, out] IpHead Points to IP header containing the orginal IP header\r
- to be processed on input, and inserted ESP header\r
- on return.\r
- @param[in] IpVersion The version of IP.\r
- @param[in] SadData The related SAD data.\r
- @param[in, out] LastHead The Last Header in IP header.\r
- @param[in] OptionsBuffer Pointer to the options buffer.\r
- @param[in] OptionsLength Length of the options buffer.\r
- @param[in, out] FragmentTable Pointer to a list of fragments to be protected by\r
- IPsec on input, and with IPsec protected\r
- on return.\r
- @param[in] FragmentCount The number of fragments.\r
-\r
-**/\r
-UINT8 *\r
-IpSecTunnelOutboundPacket (\r
- IN OUT UINT8 *IpHead,\r
- IN UINT8 IpVersion,\r
- IN IPSEC_SAD_DATA *SadData,\r
- IN OUT UINT8 *LastHead,\r
- IN VOID **OptionsBuffer,\r
- IN UINT32 *OptionsLength,\r
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r
- IN UINT32 *FragmentCount\r
- )\r
-{\r
- UINT8 *InnerHead;\r
- NET_BUF *Packet;\r
- UINT16 PacketChecksum;\r
- UINT16 *Checksum;\r
- UINT16 PseudoChecksum;\r
- IP6_ICMP_HEAD *IcmpHead;\r
-\r
- Checksum = NULL;\r
- if (OptionsLength == NULL) {\r
- return NULL;\r
- }\r
-\r
- if (IpVersion == IP_VERSION_4) {\r
- InnerHead = AllocateZeroPool (sizeof (IP4_HEAD) + *OptionsLength);\r
- if (InnerHead == NULL) {\r
- return NULL;\r
- }\r
-\r
- CopyMem (\r
- InnerHead,\r
- IpHead,\r
- sizeof (IP4_HEAD)\r
- );\r
- CopyMem (\r
- InnerHead + sizeof (IP4_HEAD),\r
- *OptionsBuffer,\r
- *OptionsLength\r
- );\r
- } else {\r
- InnerHead = AllocateZeroPool (sizeof (EFI_IP6_HEADER) + *OptionsLength);\r
- if (InnerHead == NULL) {\r
- return NULL;\r
- }\r
-\r
- CopyMem (\r
- InnerHead,\r
- IpHead,\r
- sizeof (EFI_IP6_HEADER)\r
- );\r
- CopyMem (\r
- InnerHead + sizeof (EFI_IP6_HEADER),\r
- *OptionsBuffer,\r
- *OptionsLength\r
- );\r
- }\r
- if (OptionsBuffer != NULL) {\r
- if (*OptionsLength != 0) {\r
-\r
- *OptionsBuffer = NULL;\r
- *OptionsLength = 0;\r
- }\r
- }\r
-\r
- //\r
- // 2. Reassamlbe Fragment into Packet\r
- //\r
- Packet = NetbufFromExt (\r
- (NET_FRAGMENT *)(*FragmentTable),\r
- *FragmentCount,\r
- 0,\r
- 0,\r
- IpSecOnRecyclePacket,\r
- NULL\r
- );\r
- if (Packet == NULL) {\r
- FreePool (InnerHead);\r
- return NULL;\r
- }\r
-\r
- //\r
- // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo\r
- // CheckSum.\r
- //\r
- switch (*LastHead) {\r
- case EFI_IP_PROTO_UDP:\r
- Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, 0);\r
- ASSERT (Packet->Udp != NULL);\r
- Checksum = &Packet->Udp->Checksum;\r
- *Checksum = 0;\r
- break;\r
-\r
- case EFI_IP_PROTO_TCP:\r
- Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, 0);\r
- ASSERT (Packet->Tcp != NULL);\r
- Checksum = &Packet->Tcp->Checksum;\r
- *Checksum = 0;\r
- break;\r
-\r
- case IP6_ICMP:\r
- IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);\r
- ASSERT (IcmpHead != NULL);\r
- Checksum = &IcmpHead->Checksum;\r
- *Checksum = 0;\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-\r
- PacketChecksum = NetbufChecksum (Packet);\r
-\r
- if (IpVersion == IP_VERSION_4) {\r
- //\r
- // Replace the source address of Inner Header.\r
- //\r
- CopyMem (\r
- &((IP4_HEAD *)InnerHead)->Src,\r
- &SadData->SpdSelector->LocalAddress[0].Address.v4,\r
- sizeof (EFI_IPv4_ADDRESS)\r
- );\r
-\r
- PacketChecksum = NetbufChecksum (Packet);\r
- PseudoChecksum = NetPseudoHeadChecksum (\r
- ((IP4_HEAD *)InnerHead)->Src,\r
- ((IP4_HEAD *)InnerHead)->Dst,\r
- *LastHead,\r
- 0\r
- );\r
-\r
- } else {\r
- //\r
- // Replace the source address of Inner Header.\r
- //\r
- CopyMem (\r
- &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,\r
- &(SadData->SpdSelector->LocalAddress[0].Address.v6),\r
- sizeof (EFI_IPv6_ADDRESS)\r
- );\r
- PacketChecksum = NetbufChecksum (Packet);\r
- PseudoChecksum = NetIp6PseudoHeadChecksum (\r
- &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,\r
- &((EFI_IP6_HEADER *)InnerHead)->DestinationAddress,\r
- *LastHead,\r
- 0\r
- );\r
-\r
- }\r
- if (Checksum != NULL) {\r
- *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);\r
- *Checksum = (UINT16) ~(NetAddChecksum ((UINT16)*Checksum, HTONS ((UINT16) Packet->TotalSize)));\r
- }\r
-\r
- if (Packet != NULL) {\r
- NetbufFree (Packet);\r
- }\r
- return InnerHead;\r
-}\r
-\r
-/**\r
- The actual entry to relative function processes the inbound traffic of ESP header.\r
-\r
- This function is the subfunction of IpSecProtectInboundPacket(). It checks the\r
- received packet security property and trim the ESP header and then returns without\r
- an IPsec protected IP Header and FramgmentTable.\r
-\r
- @param[in] IpVersion The version of IP.\r
- @param[in, out] IpHead Points to the IP header containing the ESP header\r
- to be trimed on input, and without ESP header\r
- on return.\r
- @param[out] LastHead The Last Header in IP header on return.\r
- @param[in, out] OptionsBuffer Pointer to the options buffer.\r
- @param[in, out] OptionsLength Length of the options buffer.\r
- @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec\r
- protected on input, and without IPsec protected\r
- on return.\r
- @param[in, out] FragmentCount The number of fragments.\r
- @param[out] SpdSelector Pointer to contain the address of SPD selector on return.\r
- @param[out] RecycleEvent The event for recycling of resources.\r
-\r
- @retval EFI_SUCCESS The operation was successful.\r
- @retval EFI_ACCESS_DENIED One or more following conditions is TRUE:\r
- - ESP header was not found or mal-format.\r
- - The related SAD entry was not found.\r
- - The related SAD entry does not support the ESP protocol.\r
- @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecEspInboundPacket (\r
- IN UINT8 IpVersion,\r
- IN OUT VOID *IpHead,\r
- OUT UINT8 *LastHead,\r
- IN OUT VOID **OptionsBuffer,\r
- IN OUT UINT32 *OptionsLength,\r
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r
- IN OUT UINT32 *FragmentCount,\r
- OUT EFI_IPSEC_SPD_SELECTOR **SpdSelector,\r
- OUT EFI_EVENT *RecycleEvent\r
- )\r
-{\r
- EFI_STATUS Status;\r
- NET_BUF *Payload;\r
- UINTN EspSize;\r
- UINTN IvSize;\r
- UINTN BlockSize;\r
- UINTN MiscSize;\r
- UINTN PlainPayloadSize;\r
- UINTN PaddingSize;\r
- UINTN IcvSize;\r
- UINT8 *ProcessBuffer;\r
- EFI_ESP_HEADER *EspHeader;\r
- EFI_ESP_TAIL *EspTail;\r
- EFI_IPSEC_SA_ID *SaId;\r
- IPSEC_SAD_DATA *SadData;\r
- IPSEC_SAD_ENTRY *SadEntry;\r
- IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
- UINT8 NextHeader;\r
- UINT16 IpSecHeadSize;\r
- UINT8 *InnerHead;\r
-\r
- Status = EFI_SUCCESS;\r
- Payload = NULL;\r
- ProcessBuffer = NULL;\r
- RecycleContext = NULL;\r
- *RecycleEvent = NULL;\r
- PlainPayloadSize = 0;\r
- NextHeader = 0;\r
-\r
- //\r
- // Build netbuf from fragment table first.\r
- //\r
- Payload = NetbufFromExt (\r
- (NET_FRAGMENT *) *FragmentTable,\r
- *FragmentCount,\r
- 0,\r
- sizeof (EFI_ESP_HEADER),\r
- IpSecOnRecyclePacket,\r
- NULL\r
- );\r
- if (Payload == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- //\r
- // Get the esp size and esp header from netbuf.\r
- //\r
- EspSize = Payload->TotalSize;\r
- EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);\r
-\r
- if (EspHeader == NULL) {\r
- Status = EFI_ACCESS_DENIED;\r
- goto ON_EXIT;\r
- }\r
-\r
- //\r
- // Parse destination address from ip header and found the related SAD Entry.\r
- //\r
- SadEntry = IpSecFoundSadFromInboundPacket (\r
- IpHead,\r
- IpVersion,\r
- NTOHL (EspHeader->Spi)\r
- );\r
-\r
- if (SadEntry == NULL) {\r
- Status = EFI_ACCESS_DENIED;\r
- goto ON_EXIT;\r
- }\r
-\r
- SaId = SadEntry->Id;\r
- SadData = SadEntry->Data;\r
-\r
- //\r
- // Only support esp protocol currently.\r
- //\r
- if (SaId->Proto != EfiIPsecESP) {\r
- Status = EFI_ACCESS_DENIED;\r
- goto ON_EXIT;\r
- }\r
-\r
- if (!SadData->ManualSet) {\r
- //\r
- // TODO: Check SA lifetime and sequence number\r
- //\r
- }\r
-\r
- //\r
- // Allocate buffer for decryption and authentication.\r
- //\r
- ProcessBuffer = AllocateZeroPool (EspSize);\r
- if (ProcessBuffer == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);\r
-\r
- //\r
- // Get the IcvSize for authentication and BlockSize/IvSize for Decryption.\r
- //\r
- IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);\r
- IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
- BlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
-\r
- //\r
- // Make sure the ESP packet is not mal-formt.\r
- // 1. Check whether the Espsize is larger than ESP header + IvSize + EspTail + IcvSize.\r
- // 2. Check whether the left payload size is multiple of IvSize.\r
- //\r
- MiscSize = sizeof (EFI_ESP_HEADER) + IvSize + IcvSize;\r
- if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL))) {\r
- Status = EFI_ACCESS_DENIED;\r
- goto ON_EXIT;\r
- }\r
- if ((EspSize - MiscSize) % BlockSize != 0) {\r
- Status = EFI_ACCESS_DENIED;\r
- goto ON_EXIT;\r
- }\r
-\r
- //\r
- // Authenticate the ESP packet.\r
- //\r
- if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
- Status = IpSecEspAuthVerifyPayload (\r
- ProcessBuffer,\r
- EspSize,\r
- SadEntry,\r
- IcvSize\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- }\r
- //\r
- // Decrypt the payload by the SAD entry if it has decrypt key.\r
- //\r
- if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
- Status = IpSecCryptoIoDecrypt (\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,\r
- ProcessBuffer + sizeof (EFI_ESP_HEADER),\r
- ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize,\r
- EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize,\r
- ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- }\r
-\r
- //\r
- // Parse EspTail and compute the plain payload size.\r
- //\r
- EspTail = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));\r
- PaddingSize = EspTail->PaddingLength;\r
- NextHeader = EspTail->NextHeader;\r
-\r
- if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL) + PaddingSize)) {\r
- Status = EFI_ACCESS_DENIED;\r
- goto ON_EXIT;\r
- }\r
- PlainPayloadSize = EspSize - MiscSize - sizeof (EFI_ESP_TAIL) - PaddingSize;\r
-\r
- //\r
- // TODO: handle anti-replay window\r
- //\r
- //\r
- // Decryption and authentication with esp has been done, so it's time to\r
- // reload the new packet, create recycle event and fixup ip header.\r
- //\r
- RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));\r
- if (RecycleContext == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_NOTIFY,\r
- IpSecRecycleCallback,\r
- RecycleContext,\r
- RecycleEvent\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- //\r
- // The caller will take responsible to handle the original fragment table\r
- //\r
- *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));\r
- if (*FragmentTable == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- RecycleContext->PayloadBuffer = ProcessBuffer;\r
- RecycleContext->FragmentTable = *FragmentTable;\r
-\r
- //\r
- // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out\r
- //\r
- if (SadData->Mode == EfiIPsecTunnel) {\r
- InnerHead = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;\r
- IpSecTunnelInboundPacket (\r
- IpHead,\r
- InnerHead,\r
- IpVersion,\r
- SadData,\r
- LastHead\r
- );\r
-\r
- if (IpVersion == IP_VERSION_4) {\r
- (*FragmentTable)[0].FragmentBuffer = InnerHead ;\r
- (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;\r
-\r
- }else {\r
- (*FragmentTable)[0].FragmentBuffer = InnerHead;\r
- (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;\r
- }\r
- } else {\r
- (*FragmentTable)[0].FragmentBuffer = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;\r
- (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;\r
- }\r
-\r
- *FragmentCount = 1;\r
-\r
- //\r
- // Update the total length field in ip header since processed by esp.\r
- //\r
- if (SadData->Mode != EfiIPsecTunnel) {\r
- if (IpVersion == IP_VERSION_4) {\r
- ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + PlainPayloadSize));\r
- } else {\r
- IpSecHeadSize = IpSecGetPlainExtHeadSize (IpHead, LastHead);\r
- ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));\r
- }\r
- //\r
- // Update the next layer field in ip header since esp header inserted.\r
- //\r
- *LastHead = NextHeader;\r
- }\r
-\r
-\r
- //\r
- // Update the SPD association of the SAD entry.\r
- //\r
- *SpdSelector = SadData->SpdSelector;\r
-\r
-ON_EXIT:\r
- if (Payload != NULL) {\r
- NetbufFree (Payload);\r
- }\r
-\r
- if (EFI_ERROR (Status)) {\r
- if (ProcessBuffer != NULL) {\r
- FreePool (ProcessBuffer);\r
- }\r
-\r
- if (RecycleContext != NULL) {\r
- FreePool (RecycleContext);\r
- }\r
-\r
- if (*RecycleEvent != NULL) {\r
- gBS->CloseEvent (*RecycleEvent);\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- The actual entry to the relative function processes the output traffic using the ESP protocol.\r
-\r
- This function is the subfunction of IpSecProtectOutboundPacket(). It protected\r
- the sending packet by encrypting its payload and inserting ESP header in the orginal\r
- IP header, then return the IpHeader and IPsec protected Fragmentable.\r
-\r
- @param[in] IpVersion The version of IP.\r
- @param[in, out] IpHead Points to IP header containing the orginal IP header\r
- to be processed on input, and inserted ESP header\r
- on return.\r
- @param[in, out] LastHead The Last Header in IP header.\r
- @param[in, out] OptionsBuffer Pointer to the options buffer.\r
- @param[in, out] OptionsLength Length of the options buffer.\r
- @param[in, out] FragmentTable Pointer to a list of fragments to be protected by\r
- IPsec on input, and with IPsec protected\r
- on return.\r
- @param[in, out] FragmentCount The number of fragments.\r
- @param[in] SadEntry The related SAD entry.\r
- @param[out] RecycleEvent The event for recycling of resources.\r
-\r
- @retval EFI_SUCCESS The operation was successful.\r
- @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecEspOutboundPacket (\r
- IN UINT8 IpVersion,\r
- IN OUT VOID *IpHead,\r
- IN OUT UINT8 *LastHead,\r
- IN OUT VOID **OptionsBuffer,\r
- IN OUT UINT32 *OptionsLength,\r
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r
- IN OUT UINT32 *FragmentCount,\r
- IN IPSEC_SAD_ENTRY *SadEntry,\r
- OUT EFI_EVENT *RecycleEvent\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Index;\r
- EFI_IPSEC_SA_ID *SaId;\r
- IPSEC_SAD_DATA *SadData;\r
- IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
- UINT8 *ProcessBuffer;\r
- UINTN BytesCopied;\r
- INTN EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4\r
- UINTN EspSize; // Total size of esp wrapped ip payload\r
- UINTN IvSize; // Size of IV, optional, might be 0\r
- UINTN PlainPayloadSize;// Original IP payload size\r
- UINTN PaddingSize; // Size of padding\r
- UINTN EncryptSize; // Size of data to be encrypted, start after IV and\r
- // stop before ICV\r
- UINTN IcvSize; // Size of ICV, optional, might be 0\r
- UINT8 *RestOfPayload; // Start of Payload after IV\r
- UINT8 *Padding; // Start address of padding\r
- EFI_ESP_HEADER *EspHeader; // Start address of ESP frame\r
- EFI_ESP_TAIL *EspTail; // Address behind padding\r
- UINT8 *InnerHead;\r
- HASH_DATA_FRAGMENT HashFragment[1];\r
-\r
- Status = EFI_ACCESS_DENIED;\r
- SaId = SadEntry->Id;\r
- SadData = SadEntry->Data;\r
- ProcessBuffer = NULL;\r
- RecycleContext = NULL;\r
- *RecycleEvent = NULL;\r
- InnerHead = NULL;\r
-\r
- if (!SadData->ManualSet &&\r
- SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&\r
- SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL\r
- ) {\r
- //\r
- // Invalid manual SAD entry configuration.\r
- //\r
- goto ON_EXIT;\r
- }\r
-\r
- //\r
- // Create OutHeader according to Inner Header\r
- //\r
- if (SadData->Mode == EfiIPsecTunnel) {\r
- InnerHead = IpSecTunnelOutboundPacket (\r
- IpHead,\r
- IpVersion,\r
- SadData,\r
- LastHead,\r
- OptionsBuffer,\r
- OptionsLength,\r
- FragmentTable,\r
- FragmentCount\r
- );\r
-\r
- if (InnerHead == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- }\r
-\r
- //\r
- // Calculate enctrypt block size, need iv by default and 4 bytes alignment.\r
- //\r
- EncryptBlockSize = 4;\r
-\r
- if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
- EncryptBlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
-\r
- if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {\r
- goto ON_EXIT;\r
- }\r
- }\r
-\r
- //\r
- // Calculate the plain payload size according to the fragment table.\r
- //\r
- PlainPayloadSize = 0;\r
- for (Index = 0; Index < *FragmentCount; Index++) {\r
- PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;\r
- }\r
-\r
- //\r
- // Add IPHeader size for Tunnel Mode\r
- //\r
- if (SadData->Mode == EfiIPsecTunnel) {\r
- if (IpVersion == IP_VERSION_4) {\r
- PlainPayloadSize += sizeof (IP4_HEAD);\r
- } else {\r
- PlainPayloadSize += sizeof (EFI_IP6_HEADER);\r
- }\r
- //\r
- // OPtions should be encryption into it\r
- //\r
- PlainPayloadSize += *OptionsLength;\r
- }\r
-\r
-\r
- //\r
- // Calculate icv size, optional by default and 4 bytes alignment.\r
- //\r
- IcvSize = 0;\r
- if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
- IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);\r
- if (IcvSize % 4 != 0) {\r
- goto ON_EXIT;\r
- }\r
- }\r
-\r
- //\r
- // Calcuate the total size of esp wrapped ip payload.\r
- //\r
- IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
- EncryptSize = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;\r
- PaddingSize = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);\r
- EspSize = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;\r
-\r
- ProcessBuffer = AllocateZeroPool (EspSize);\r
- if (ProcessBuffer == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- //\r
- // Calculate esp header and esp tail including header, payload and padding.\r
- //\r
- EspHeader = (EFI_ESP_HEADER *) ProcessBuffer;\r
- RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;\r
- Padding = RestOfPayload + PlainPayloadSize;\r
- EspTail = (EFI_ESP_TAIL *) (Padding + PaddingSize);\r
-\r
- //\r
- // Fill the sn and spi fields in esp header.\r
- //\r
- EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);\r
- //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber);\r
- EspHeader->Spi = HTONL (SaId->Spi);\r
-\r
- //\r
- // Copy the rest of payload (after iv) from the original fragment buffer.\r
- //\r
- BytesCopied = 0;\r
-\r
- //\r
- // For Tunnel Mode\r
- //\r
- if (SadData->Mode == EfiIPsecTunnel) {\r
- if (IpVersion == IP_VERSION_4) {\r
- //\r
- // HeadLen, Total Length\r
- //\r
- ((IP4_HEAD *)InnerHead)->HeadLen = (UINT8) ((sizeof (IP4_HEAD) + *OptionsLength) >> 2);\r
- ((IP4_HEAD *)InnerHead)->TotalLen = HTONS ((UINT16) PlainPayloadSize);\r
- ((IP4_HEAD *)InnerHead)->Checksum = 0;\r
- ((IP4_HEAD *)InnerHead)->Checksum = (UINT16) (~NetblockChecksum (\r
- (UINT8 *)InnerHead,\r
- sizeof(IP4_HEAD)\r
- ));\r
- CopyMem (\r
- RestOfPayload + BytesCopied,\r
- InnerHead,\r
- sizeof (IP4_HEAD) + *OptionsLength\r
- );\r
- BytesCopied += sizeof (IP4_HEAD) + *OptionsLength;\r
-\r
- } else {\r
- ((EFI_IP6_HEADER *)InnerHead)->PayloadLength = HTONS ((UINT16) (PlainPayloadSize - sizeof (EFI_IP6_HEADER)));\r
- CopyMem (\r
- RestOfPayload + BytesCopied,\r
- InnerHead,\r
- sizeof (EFI_IP6_HEADER) + *OptionsLength\r
- );\r
- BytesCopied += sizeof (EFI_IP6_HEADER) + *OptionsLength;\r
- }\r
- }\r
-\r
- for (Index = 0; Index < *FragmentCount; Index++) {\r
- CopyMem (\r
- (RestOfPayload + BytesCopied),\r
- (*FragmentTable)[Index].FragmentBuffer,\r
- (*FragmentTable)[Index].FragmentLength\r
- );\r
- BytesCopied += (*FragmentTable)[Index].FragmentLength;\r
- }\r
- //\r
- // Fill the padding buffer by natural number sequence.\r
- //\r
- for (Index = 0; Index < PaddingSize; Index++) {\r
- Padding[Index] = (UINT8) (Index + 1);\r
- }\r
- //\r
- // Fill the padding length and next header fields in esp tail.\r
- //\r
- EspTail->PaddingLength = (UINT8) PaddingSize;\r
- EspTail->NextHeader = *LastHead;\r
-\r
- //\r
- // Fill the next header for Tunnel mode.\r
- //\r
- if (SadData->Mode == EfiIPsecTunnel) {\r
- if (IpVersion == IP_VERSION_4) {\r
- EspTail->NextHeader = 4;\r
- } else {\r
- EspTail->NextHeader = 41;\r
- }\r
- }\r
-\r
- //\r
- // Generate iv at random by crypt library.\r
- //\r
- Status = IpSecGenerateIv (\r
- (UINT8 *) (EspHeader + 1),\r
- IvSize\r
- );\r
-\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- //\r
- // Encryption the payload (after iv) by the SAD entry if has encrypt key.\r
- //\r
- if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
- Status = IpSecCryptoIoEncrypt (\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,\r
- (UINT8 *)(EspHeader + 1),\r
- RestOfPayload,\r
- EncryptSize,\r
- RestOfPayload\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- }\r
-\r
- //\r
- // Authenticate the esp wrapped buffer by the SAD entry if it has auth key.\r
- //\r
- if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
-\r
- HashFragment[0].Data = ProcessBuffer;\r
- HashFragment[0].DataSize = EspSize - IcvSize;\r
- Status = IpSecCryptoIoHmac (\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,\r
- HashFragment,\r
- 1,\r
- ProcessBuffer + EspSize - IcvSize,\r
- IcvSize\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- }\r
-\r
- //\r
- // Encryption and authentication with esp has been done, so it's time to\r
- // reload the new packet, create recycle event and fixup ip header.\r
- //\r
- RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));\r
- if (RecycleContext == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = gBS->CreateEvent (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_NOTIFY,\r
- IpSecRecycleCallback,\r
- RecycleContext,\r
- RecycleEvent\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Caller take responsible to handle the original fragment table.\r
- //\r
- *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));\r
- if (*FragmentTable == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
-\r
- RecycleContext->FragmentTable = *FragmentTable;\r
- RecycleContext->PayloadBuffer = ProcessBuffer;\r
- (*FragmentTable)[0].FragmentBuffer = ProcessBuffer;\r
- (*FragmentTable)[0].FragmentLength = (UINT32) EspSize;\r
- *FragmentCount = 1;\r
-\r
- //\r
- // Update the total length field in ip header since processed by esp.\r
- //\r
- if (IpVersion == IP_VERSION_4) {\r
- ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + EspSize));\r
- } else {\r
- ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);\r
- }\r
-\r
- //\r
- // If tunnel mode, it should change the outer Ip header with tunnel source address\r
- // and destination tunnel address.\r
- //\r
- if (SadData->Mode == EfiIPsecTunnel) {\r
- if (IpVersion == IP_VERSION_4) {\r
- CopyMem (\r
- &((IP4_HEAD *) IpHead)->Src,\r
- &SadData->TunnelSourceAddress.v4,\r
- sizeof (EFI_IPv4_ADDRESS)\r
- );\r
- CopyMem (\r
- &((IP4_HEAD *) IpHead)->Dst,\r
- &SadData->TunnelDestAddress.v4,\r
- sizeof (EFI_IPv4_ADDRESS)\r
- );\r
- } else {\r
- CopyMem (\r
- &((EFI_IP6_HEADER *) IpHead)->SourceAddress,\r
- &SadData->TunnelSourceAddress.v6,\r
- sizeof (EFI_IPv6_ADDRESS)\r
- );\r
- CopyMem (\r
- &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,\r
- &SadData->TunnelDestAddress.v6,\r
- sizeof (EFI_IPv6_ADDRESS)\r
- );\r
- }\r
- }\r
-\r
- //\r
- // Update the next layer field in ip header since esp header inserted.\r
- //\r
- *LastHead = IPSEC_ESP_PROTOCOL;\r
-\r
- //\r
- // Increase the sn number in SAD entry according to rfc4303.\r
- //\r
- SadData->SequenceNumber++;\r
-\r
-ON_EXIT:\r
- if (EFI_ERROR (Status)) {\r
- if (ProcessBuffer != NULL) {\r
- FreePool (ProcessBuffer);\r
- }\r
-\r
- if (RecycleContext != NULL) {\r
- FreePool (RecycleContext);\r
- }\r
-\r
- if (*RecycleEvent != NULL) {\r
- gBS->CloseEvent (*RecycleEvent);\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This function processes the inbound traffic with IPsec.\r
-\r
- It checks the received packet security property, trims the ESP/AH header, and then\r
- returns without an IPsec protected IP Header and FragmentTable.\r
-\r
- @param[in] IpVersion The version of IP.\r
- @param[in, out] IpHead Points to IP header containing the ESP/AH header\r
- to be trimed on input, and without ESP/AH header\r
- on return.\r
- @param[in, out] LastHead The Last Header in IP header on return.\r
- @param[in, out] OptionsBuffer Pointer to the options buffer.\r
- @param[in, out] OptionsLength Length of the options buffer.\r
- @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec\r
- protected on input, and without IPsec protected\r
- on return.\r
- @param[in, out] FragmentCount The number of fragments.\r
- @param[out] SpdEntry Pointer to contain the address of SPD entry on return.\r
- @param[out] RecycleEvent The event for recycling of resources.\r
-\r
- @retval EFI_SUCCESS The operation was successful.\r
- @retval EFI_UNSUPPORTED The IPSEC protocol is not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecProtectInboundPacket (\r
- IN UINT8 IpVersion,\r
- IN OUT VOID *IpHead,\r
- IN OUT UINT8 *LastHead,\r
- IN OUT VOID **OptionsBuffer,\r
- IN OUT UINT32 *OptionsLength,\r
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r
- IN OUT UINT32 *FragmentCount,\r
- OUT EFI_IPSEC_SPD_SELECTOR **SpdEntry,\r
- OUT EFI_EVENT *RecycleEvent\r
- )\r
-{\r
- if (*LastHead == IPSEC_ESP_PROTOCOL) {\r
- //\r
- // Process the esp ipsec header of the inbound traffic.\r
- //\r
- return IpSecEspInboundPacket (\r
- IpVersion,\r
- IpHead,\r
- LastHead,\r
- OptionsBuffer,\r
- OptionsLength,\r
- FragmentTable,\r
- FragmentCount,\r
- SpdEntry,\r
- RecycleEvent\r
- );\r
- }\r
- //\r
- // The other protocols are not supported.\r
- //\r
- return EFI_UNSUPPORTED;\r
-}\r
-\r
-/**\r
- This fucntion processes the output traffic with IPsec.\r
-\r
- It protected the sending packet by encrypting it payload and inserting ESP/AH header\r
- in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.\r
-\r
- @param[in] IpVersion The version of IP.\r
- @param[in, out] IpHead Point to IP header containing the orginal IP header\r
- to be processed on input, and inserted ESP/AH header\r
- on return.\r
- @param[in, out] LastHead The Last Header in IP header.\r
- @param[in, out] OptionsBuffer Pointer to the options buffer.\r
- @param[in, out] OptionsLength Length of the options buffer.\r
- @param[in, out] FragmentTable Pointer to a list of fragments to be protected by\r
- IPsec on input, and with IPsec protected\r
- on return.\r
- @param[in, out] FragmentCount Number of fragments.\r
- @param[in] SadEntry Related SAD entry.\r
- @param[out] RecycleEvent Event for recycling of resources.\r
-\r
- @retval EFI_SUCCESS The operation is successful.\r
- @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecProtectOutboundPacket (\r
- IN UINT8 IpVersion,\r
- IN OUT VOID *IpHead,\r
- IN OUT UINT8 *LastHead,\r
- IN OUT VOID **OptionsBuffer,\r
- IN OUT UINT32 *OptionsLength,\r
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r
- IN OUT UINT32 *FragmentCount,\r
- IN IPSEC_SAD_ENTRY *SadEntry,\r
- OUT EFI_EVENT *RecycleEvent\r
- )\r
-{\r
- if (SadEntry->Id->Proto == EfiIPsecESP) {\r
- //\r
- // Process the esp ipsec header of the outbound traffic.\r
- //\r
- return IpSecEspOutboundPacket (\r
- IpVersion,\r
- IpHead,\r
- LastHead,\r
- OptionsBuffer,\r
- OptionsLength,\r
- FragmentTable,\r
- FragmentCount,\r
- SadEntry,\r
- RecycleEvent\r
- );\r
- }\r
- //\r
- // The other protocols are not supported.\r
- //\r
- return EFI_UNSUPPORTED;\r
-}\r