/** @file\r
- The implementation of IPsec Protocol\r
+ The implementation of IPsec.\r
\r
- Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\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
-EFI_IPSEC2_PROTOCOL mIpSecInstance = { IpSecProcess, NULL, TRUE };\r
-\r
-extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum];\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, meaning it only\r
- gives the correct prefixed address.\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
break;\r
}\r
}\r
-\r
return IsMatch;\r
}\r
\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
IPSEC_SAD_ENTRY *\r
IpSecLookupSadBySpd (\r
IN LIST_ENTRY *SadList,\r
- IN EFI_IP_ADDRESS *DestAddress\r
+ IN EFI_IP_ADDRESS *DestAddress,\r
+ IN UINT8 IpVersion\r
)\r
{\r
LIST_ENTRY *Entry;\r
IPSEC_SAD_ENTRY *SadEntry;\r
\r
- for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) {\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
+ // Find the right SAD entry which contains the appointed dest address.\r
//\r
- if (CompareMem (\r
- &SadEntry->Id->DestAddress,\r
+ if (IpSecMatchIpAddress (\r
+ IpVersion,\r
DestAddress,\r
- sizeof (EFI_IP_ADDRESS)\r
- ) == 0) {\r
+ SadEntry->Data->SpdSelector->RemoteAddress,\r
+ SadEntry->Data->SpdSelector->RemoteAddressCount\r
+ )){\r
return SadEntry;\r
}\r
}\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
IPSEC_SAD_ENTRY *\r
IpSecLookupSadBySpi (\r
IN UINT32 Spi,\r
- IN EFI_IP_ADDRESS *DestAddress\r
+ IN EFI_IP_ADDRESS *DestAddress,\r
+ IN UINT8 IpVersion\r
)\r
{\r
LIST_ENTRY *Entry;\r
\r
SadList = &mConfigData[IPsecConfigDataTypeSad];\r
\r
- for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) {\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
+ // Find the right SAD entry which contain the appointed spi and dest addr.\r
//\r
- if (SadEntry->Id->Spi == Spi && CompareMem (\r
- &SadEntry->Id->DestAddress,\r
- DestAddress,\r
- sizeof (EFI_IP_ADDRESS)\r
- ) == 0) {\r
-\r
- return SadEntry;\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
-\r
return NULL;\r
}\r
\r
- If don't find related UDP service.\r
- Sequence Number is used up.\r
- Extension Sequence Number is used up.\r
- @retval EFI_DEVICE_ERROR GC_TODO: Add description for return value.\r
@retval EFI_NOT_READY No existing SAD entry could be used.\r
@retval EFI_SUCCESS Find the related SAD entry.\r
\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
sizeof (EFI_IP_ADDRESS)\r
);\r
}\r
+\r
//\r
- // Find the sad entry in the spd.sas list according to the dest address.\r
+ // Find the SAD entry in the spd.sas list according to the dest address.\r
//\r
- Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp);\r
+ Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp, IpVersion);\r
\r
if (Entry == NULL) {\r
-\r
if (OldLastHead != IP6_ICMP ||\r
(OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST)\r
) {\r
//\r
- // TODO: Start ike negotiation process except the request packet of ping.\r
+ // Start ike negotiation process except the request packet of ping.\r
//\r
- //IkeNegotiate (UdpService, SpdEntry, &DestIp);\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
// Validate the 64bit sn number if 64bit sn enabled.\r
//\r
- if (Data->SequenceNumber + 1 < Data->SequenceNumber) {\r
+ if ((UINT64) (Data->SequenceNumber + 1) == 0) {\r
//\r
// TODO: Re-negotiate SA\r
//\r
// Validate the 32bit sn number if 64bit sn disabled.\r
//\r
SeqNum32 = (UINT32) Data->SequenceNumber;\r
- if (SeqNum32 + 1 < SeqNum32) {\r
+ if ((UINT32) (SeqNum32 + 1) == 0) {\r
//\r
// TODO: Re-negotiate SA\r
//\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_IPSEC_ACTION The support action of SPD entry.\r
- @retval -1 If the input packet header doesn't match the SpdEntry.\r
+ @retval EFI_SUCCESS Find the related SPD.\r
+ @retval EFI_NOT_FOUND Not find the related SPD entry;\r
\r
**/\r
-EFI_IPSEC_ACTION\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
+ 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
\r
if (SpdMatch) {\r
//\r
- // Find the right spd entry if match the 5 key elements.\r
+ // Find the right SPD entry if match the 5 key elements.\r
//\r
- return SpdEntry->Data->Action;\r
+ *Action = SpdEntry->Data->Action;\r
+ return EFI_SUCCESS;\r
}\r
\r
- return (EFI_IPSEC_ACTION) - 1;\r
+ return EFI_NOT_FOUND;\r
}\r
\r
/**\r
- Handles IPsec packet processing for inbound and outbound IP packets.\r
-\r
- The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.\r
- The behavior is that it can perform one of the following actions:\r
- bypass the packet, discard the packet, or protect the packet.\r
-\r
- @param[in] This Pointer to the EFI_IPSEC_PROTOCOL instance.\r
- @param[in] NicHandle Instance of the network interface.\r
- @param[in] IpVersion IPV4 or IPV6.\r
- @param[in, out] IpHead Pointer to the IP Header.\r
- @param[in, out] LastHead The protocol of the next layer to be processed by IPsec.\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.\r
- @param[in, out] FragmentCount Number of fragments.\r
- @param[in] TrafficDirection Traffic direction.\r
- @param[out] RecycleSignal Event for recycling of resources.\r
-\r
- @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same.\r
- @retval EFI_SUCCESS The packet was protected.\r
- @retval EFI_ACCESS_DENIED The packet was discarded.\r
+ The call back function of NetbufFromExt.\r
+\r
+ @param[in] Arg The argument passed from the caller.\r
\r
**/\r
-EFI_STATUS\r
+VOID\r
EFIAPI\r
-IpSecProcess (\r
- IN EFI_IPSEC2_PROTOCOL *This,\r
- IN EFI_HANDLE NicHandle,\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 EFI_IPSEC_TRAFFIC_DIR TrafficDirection,\r
- OUT EFI_EVENT *RecycleSignal\r
+IpSecOnRecyclePacket (\r
+ IN VOID *Arg\r
)\r
{\r
- IPSEC_PRIVATE_DATA *Private;\r
- IPSEC_SPD_ENTRY *SpdEntry;\r
- IPSEC_SAD_ENTRY *SadEntry;\r
- LIST_ENTRY *SpdList;\r
- LIST_ENTRY *Entry;\r
- EFI_IPSEC_ACTION Action;\r
- EFI_STATUS Status;\r
- UINT8 *IpPayload;\r
- UINT8 OldLastHead;\r
- BOOLEAN IsOutbound;\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
- Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (This);\r
- IpPayload = (*FragmentTable)[0].FragmentBuffer;\r
- IsOutbound = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE);\r
- OldLastHead = *LastHead;\r
- *RecycleSignal = NULL;\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 (!IsOutbound) {\r
+ if (Size > sizeof (EFI_IP6_HEADER)) {\r
//\r
- // For inbound traffic, process the ipsec header of the packet.\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
- Status = IpSecProtectInboundPacket (\r
- IpVersion,\r
- IpHead,\r
- LastHead,\r
- OptionsBuffer,\r
- OptionsLength,\r
- FragmentTable,\r
- FragmentCount,\r
- &SpdEntry,\r
- RecycleSignal\r
- );\r
+ Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);\r
+ } else {\r
+ Size = 0;\r
+ }\r
\r
- if (Status == EFI_ACCESS_DENIED) {\r
- //\r
- // The packet is denied to access.\r
- //\r
- goto ON_EXIT;\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
+ BOOLEAN Flag;\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
+ Flag = FALSE;\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
+ Flag = TRUE;\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
- if (Status == EFI_SUCCESS) {\r
+ case IP6_FRAGMENT:\r
+ if (++CountF > 1) {\r
+ return FALSE;\r
+ }\r
//\r
- // Check the spd entry if the packet is accessible.\r
+ // RFC2402, AH header should after fragment header.\r
//\r
- if (SpdEntry == NULL) {\r
- Status = EFI_ACCESS_DENIED;\r
- goto ON_EXIT;\r
+ if (CountA > 1) {\r
+ return FALSE;\r
}\r
- Action = IpSecLookupSpdEntry (\r
- SpdEntry,\r
- IpVersion,\r
- IpHead,\r
- IpPayload,\r
- *LastHead,\r
- IsOutbound\r
- );\r
-\r
- if (Action != EfiIPsecActionProtect) {\r
- //\r
- // Discard the packet if the spd entry is not protect.\r
- //\r
- gBS->SignalEvent (*RecycleSignal);\r
- *RecycleSignal = NULL;\r
- Status = EFI_ACCESS_DENIED;\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
- goto ON_EXIT;\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
- Status = EFI_ACCESS_DENIED;\r
- SpdList = &mConfigData[IPsecConfigDataTypeSpd];\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
- for (Entry = SpdList->ForwardLink; Entry != SpdList; Entry = Entry->ForwardLink) {\r
+ Checksum = NULL;\r
+\r
+ if (IpVersion == IP_VERSION_4) {\r
//\r
- // For outbound and non-ipsec Inbound traffic: check the spd entry.\r
+ // Zero OutIP header use this to indicate the input packet is under\r
+ // IPsec Tunnel protected.\r
//\r
- SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
- Action = IpSecLookupSpdEntry (\r
- SpdEntry,\r
- IpVersion,\r
- IpHead,\r
- IpPayload,\r
- OldLastHead,\r
- IsOutbound\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
- switch (Action) {\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
- case EfiIPsecActionProtect:\r
\r
- if (IsOutbound) {\r
- //\r
- // For outbound traffic, lookup the sad entry.\r
- //\r
- Status = IpSecLookupSadEntry (\r
- Private,\r
- NicHandle,\r
- IpVersion,\r
- IpHead,\r
- IpPayload,\r
- OldLastHead,\r
- SpdEntry,\r
- &SadEntry\r
- );\r
+ }\r
\r
- if (SadEntry != NULL) {\r
- //\r
- // Process the packet by the found sad entry.\r
- //\r
- Status = IpSecProtectOutboundPacket (\r
- IpVersion,\r
- IpHead,\r
- LastHead,\r
- OptionsBuffer,\r
- OptionsLength,\r
- FragmentTable,\r
- FragmentCount,\r
- SadEntry,\r
- RecycleSignal\r
- );\r
-\r
- } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {\r
- //\r
- // TODO: if no need return not ready to upper layer, change here.\r
- //\r
- Status = EFI_SUCCESS;\r
- }\r
- } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {\r
- //\r
- // For inbound icmpv6 traffic except ping request, accept the packet\r
- // although no sad entry associated with protect spd entry.\r
- //\r
- IpSecLookupSadEntry (\r
- Private,\r
- NicHandle,\r
- IpVersion,\r
- IpHead,\r
- IpPayload,\r
- OldLastHead,\r
- SpdEntry,\r
- &SadEntry\r
- );\r
- if (SadEntry == NULL) {\r
- Status = EFI_SUCCESS;\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
- goto ON_EXIT;\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
- case EfiIPsecActionBypass:\r
- Status = EFI_SUCCESS;\r
- goto ON_EXIT;\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
- case EfiIPsecActionDiscard:\r
- goto ON_EXIT;\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
- default:\r
//\r
- // Discard the packet if no spd entry match.\r
+ // Get the Extension Header and Header length.\r
//\r
- break;\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
-ON_EXIT:\r
- return Status;\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
+ @retval EFI_SUCCESS The operation was successful.\r
+ @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.\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
+ ASSERT (InnerHead != NULL);\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
+ ASSERT (InnerHead != NULL);\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
+ ASSERT (Packet != NULL);\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 accroding 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