From a3bcde70e6dc69000f85cc5deee98101d2ae200a Mon Sep 17 00:00:00 2001 From: hhtian Date: Mon, 1 Nov 2010 06:13:54 +0000 Subject: Add NetworkPkg (P.UDK2010.UP3.Network.P1) git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10986 6f19259b-4bc3-4df7-8a09-765794883524 --- NetworkPkg/IpSecDxe/ComponentName.c | 310 ++++ NetworkPkg/IpSecDxe/IpSecConfigImpl.c | 2928 +++++++++++++++++++++++++++++++++ NetworkPkg/IpSecDxe/IpSecConfigImpl.h | 952 +++++++++++ NetworkPkg/IpSecDxe/IpSecCryptIo.c | 133 ++ NetworkPkg/IpSecDxe/IpSecCryptIo.h | 322 ++++ NetworkPkg/IpSecDxe/IpSecDebug.c | 172 ++ NetworkPkg/IpSecDxe/IpSecDebug.h | 102 ++ NetworkPkg/IpSecDxe/IpSecDriver.c | 282 ++++ NetworkPkg/IpSecDxe/IpSecDxe.inf | 63 + NetworkPkg/IpSecDxe/IpSecImpl.c | 856 ++++++++++ NetworkPkg/IpSecDxe/IpSecImpl.h | 313 ++++ NetworkPkg/IpSecDxe/IpSecSaEngine.c | 934 +++++++++++ 12 files changed, 7367 insertions(+) create mode 100644 NetworkPkg/IpSecDxe/ComponentName.c create mode 100644 NetworkPkg/IpSecDxe/IpSecConfigImpl.c create mode 100644 NetworkPkg/IpSecDxe/IpSecConfigImpl.h create mode 100644 NetworkPkg/IpSecDxe/IpSecCryptIo.c create mode 100644 NetworkPkg/IpSecDxe/IpSecCryptIo.h create mode 100644 NetworkPkg/IpSecDxe/IpSecDebug.c create mode 100644 NetworkPkg/IpSecDxe/IpSecDebug.h create mode 100644 NetworkPkg/IpSecDxe/IpSecDriver.c create mode 100644 NetworkPkg/IpSecDxe/IpSecDxe.inf create mode 100644 NetworkPkg/IpSecDxe/IpSecImpl.c create mode 100644 NetworkPkg/IpSecDxe/IpSecImpl.h create mode 100644 NetworkPkg/IpSecDxe/IpSecSaEngine.c (limited to 'NetworkPkg/IpSecDxe') diff --git a/NetworkPkg/IpSecDxe/ComponentName.c b/NetworkPkg/IpSecDxe/ComponentName.c new file mode 100644 index 0000000000..22b3861081 --- /dev/null +++ b/NetworkPkg/IpSecDxe/ComponentName.c @@ -0,0 +1,310 @@ +/** @file + UEFI Component Name(2) protocol implementation for IPsec driver. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IpSecImpl.h" + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user-readable name of the driver. + + This function retrieves the user-readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user-readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +IpSecComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user-readable name of the controller + that is being managed by a driver. + + This function retrieves the user-readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user-readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param[in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +IpSecComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, OPTIONAL + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIpSecComponentName = { + IpSecComponentNameGetDriverName, + IpSecComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIpSecComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IpSecComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IpSecComponentNameGetControllerName, + "en" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIpSecDriverNameTable[] = { + { + "eng;en", + L"IpSec Driver" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user-readable name of the driver. + + This function retrieves the user-readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user-readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param[out] DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This, and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +IpSecComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mIpSecDriverNameTable, + DriverName, + (BOOLEAN) (This == &gIpSecComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user-readable name of the controller + that is being managed by a driver. + + This function retrieves the user-readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user-readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param[in] ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param[in] Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +IpSecComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, OPTIONAL + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c new file mode 100644 index 0000000000..e671e42e27 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c @@ -0,0 +1,2928 @@ +/** @file + The implementation of IPSEC_CONFIG_PROTOCOL. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IpSecConfigImpl.h" +#include "IpSecDebug.h" + +LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum]; +BOOLEAN mSetBySelf = FALSE; + +// +// Common CompareSelector routine entry for spd/sad/pad. +// +IPSEC_COMPARE_SELECTOR mCompareSelector[] = { + (IPSEC_COMPARE_SELECTOR) CompareSpdSelector, + (IPSEC_COMPARE_SELECTOR) CompareSaId, + (IPSEC_COMPARE_SELECTOR) ComparePadId +}; + +// +// Common IsZeroSelector routine entry for spd/sad/pad. +// +IPSEC_IS_ZERO_SELECTOR mIsZeroSelector[] = { + (IPSEC_IS_ZERO_SELECTOR) IsZeroSpdSelector, + (IPSEC_IS_ZERO_SELECTOR) IsZeroSaId, + (IPSEC_IS_ZERO_SELECTOR) IsZeroPadId +}; + +// +// Common DuplicateSelector routine entry for spd/sad/pad. +// +IPSEC_DUPLICATE_SELECTOR mDuplicateSelector[] = { + (IPSEC_DUPLICATE_SELECTOR) DuplicateSpdSelector, + (IPSEC_DUPLICATE_SELECTOR) DuplicateSaId, + (IPSEC_DUPLICATE_SELECTOR) DuplicatePadId +}; + +// +// Common FixPolicyEntry routine entry for spd/sad/pad. +// +IPSEC_FIX_POLICY_ENTRY mFixPolicyEntry[] = { + (IPSEC_FIX_POLICY_ENTRY) FixSpdEntry, + (IPSEC_FIX_POLICY_ENTRY) FixSadEntry, + (IPSEC_FIX_POLICY_ENTRY) FixPadEntry +}; + +// +// Common UnfixPolicyEntry routine entry for spd/sad/pad. +// +IPSEC_FIX_POLICY_ENTRY mUnfixPolicyEntry[] = { + (IPSEC_FIX_POLICY_ENTRY) UnfixSpdEntry, + (IPSEC_FIX_POLICY_ENTRY) UnfixSadEntry, + (IPSEC_FIX_POLICY_ENTRY) UnfixPadEntry +}; + +// +// Common SetPolicyEntry routine entry for spd/sad/pad. +// +IPSEC_SET_POLICY_ENTRY mSetPolicyEntry[] = { + (IPSEC_SET_POLICY_ENTRY) SetSpdEntry, + (IPSEC_SET_POLICY_ENTRY) SetSadEntry, + (IPSEC_SET_POLICY_ENTRY) SetPadEntry +}; + +// +// Common GetPolicyEntry routine entry for spd/sad/pad. +// +IPSEC_GET_POLICY_ENTRY mGetPolicyEntry[] = { + (IPSEC_GET_POLICY_ENTRY) GetSpdEntry, + (IPSEC_GET_POLICY_ENTRY) GetSadEntry, + (IPSEC_GET_POLICY_ENTRY) GetPadEntry +}; + +// +// Routine entry for IpSecConfig protocol. +// +EFI_IPSEC_CONFIG_PROTOCOL mIpSecConfigInstance = { + EfiIpSecConfigSetData, + EfiIpSecConfigGetData, + EfiIpSecConfigGetNextSelector, + EfiIpSecConfigRegisterNotify, + EfiIpSecConfigUnregisterNotify +}; + +/** + Get the all IPSec configuration variables and store those variables + to the internal data structure. + + This founction is called by IpSecConfigInitialize() that is to intialize the + IPsecConfiguration Protocol. + + @param[in] Private Point to IPSEC_PRIVATE_DATA. + + @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated. + @retval EFI_SUCCESS Restore the IPsec Configuration successfully. + @retval others Other errors is found during the variable getting. + +**/ +EFI_STATUS +IpSecConfigRestore ( + IN IPSEC_PRIVATE_DATA *Private + ); + +/** + Check if the specified EFI_IP_ADDRESS_INFO is in EFI_IP_ADDRESS_INFO list. + + @param[in] AddressInfo Pointer of IP_ADDRESS_INFO to be search in AddressInfo list. + @param[in] AddressInfoList A list that contains IP_ADDRESS_INFOs. + @param[in] AddressCount Point out how many IP_ADDRESS_INFO in the list. + + @retval TRUE The specified AddressInfo is in the AddressInfoList. + @retval FALSE The specified AddressInfo is not in the AddressInfoList. + +**/ +BOOLEAN +IsInAddressInfoList( + IN EFI_IP_ADDRESS_INFO *AddressInfo, + IN EFI_IP_ADDRESS_INFO *AddressInfoList, + IN UINT32 AddressCount + ) +{ + UINT8 Index; + + for (Index = 0; Index < AddressCount ; Index++) { + if (CompareMem ( + AddressInfo, + &AddressInfoList[Index].Address, + sizeof (EFI_IP_ADDRESS) + ) == 0 && + AddressInfo->PrefixLength == AddressInfoList[Index].PrefixLength + ) { + return TRUE; + } + } + return FALSE; +} + +/** + Compare two SPD Selectors. + + Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/ + NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the + Local Addresses and remote Addresses. + + @param[in] Selector1 Pointer of first SPD Selector. + @param[in] Selector2 Pointer of second SPD Selector. + + @retval TRUE This two Selector have the same value in above fields. + @retval FALSE Not all above fields have the same value in these two Selectors. + +**/ +BOOLEAN +CompareSpdSelector ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ) +{ + EFI_IPSEC_SPD_SELECTOR *SpdSel1; + EFI_IPSEC_SPD_SELECTOR *SpdSel2; + BOOLEAN IsMatch; + UINTN Index; + + SpdSel1 = &Selector1->SpdSelector; + SpdSel2 = &Selector2->SpdSelector; + IsMatch = TRUE; + + // + // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/ + // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the + // two Spdselectors. Since the SPD supports two directions, it needs to + // compare two directions. + // + if ((SpdSel1->LocalAddressCount != SpdSel2->LocalAddressCount && + SpdSel1->LocalAddressCount != SpdSel2->RemoteAddressCount) || + (SpdSel1->RemoteAddressCount != SpdSel2->RemoteAddressCount && + SpdSel1->RemoteAddressCount != SpdSel2->LocalAddressCount) || + SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol || + SpdSel1->LocalPort != SpdSel2->LocalPort || + SpdSel1->LocalPortRange != SpdSel2->LocalPortRange || + SpdSel1->RemotePort != SpdSel2->RemotePort || + SpdSel1->RemotePortRange != SpdSel2->RemotePortRange + ) { + IsMatch = FALSE; + return IsMatch; + } + + // + // Compare the all LocalAddress fields in the two Spdselectors. + // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare + // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return + // TRUE. + // + for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel1->LocalAddress[Index], + SpdSel2->LocalAddress, + SpdSel2->LocalAddressCount + )) { + IsMatch = FALSE; + break; + } + } + if (IsMatch) { + for (Index = 0; Index < SpdSel2->LocalAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel2->LocalAddress[Index], + SpdSel1->LocalAddress, + SpdSel1->LocalAddressCount + )) { + IsMatch = FALSE; + break; + } + } + } + if (IsMatch) { + for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel1->RemoteAddress[Index], + SpdSel2->RemoteAddress, + SpdSel2->RemoteAddressCount + )) { + IsMatch = FALSE; + break; + } + } + } + if (IsMatch) { + for (Index = 0; Index < SpdSel2->RemoteAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel2->RemoteAddress[Index], + SpdSel1->RemoteAddress, + SpdSel1->RemoteAddressCount + )) { + IsMatch = FALSE; + break; + } + } + } + // + // Finish the one direction compare. If it is matched, return; otherwise, + // compare the other direction. + // + if (IsMatch) { + return IsMatch; + } + // + // Secondly, the SpdSel1->LocalAddress doesn't equal to SpdSel2->LocalAddress and + // SpdSel1->RemoteAddress doesn't equal to SpdSel2->RemoteAddress. Try to compare + // the RemoteAddress to LocalAddress. + // + IsMatch = TRUE; + for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel1->RemoteAddress[Index], + SpdSel2->LocalAddress, + SpdSel2->LocalAddressCount + )) { + IsMatch = FALSE; + break; + } + } + if (IsMatch) { + for (Index = 0; Index < SpdSel2->RemoteAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel2->RemoteAddress[Index], + SpdSel1->LocalAddress, + SpdSel1->LocalAddressCount + )) { + IsMatch = FALSE; + break; + } + } + } + if (IsMatch) { + for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel1->LocalAddress[Index], + SpdSel2->RemoteAddress, + SpdSel2->RemoteAddressCount + )) { + IsMatch = FALSE; + break; + } + } + } + if (IsMatch) { + for (Index = 0; Index < SpdSel2->LocalAddressCount; Index++) { + if (!IsInAddressInfoList ( + &SpdSel2->LocalAddress[Index], + SpdSel1->RemoteAddress, + SpdSel1->RemoteAddressCount + )) { + IsMatch = FALSE; + break; + } + } + } + return IsMatch; +} + +/** + Compare two SA IDs. + + @param[in] Selector1 Pointer of first SA ID. + @param[in] Selector2 Pointer of second SA ID. + + @retval TRUE This two Selectors have the same SA ID. + @retval FALSE This two Selecotrs don't have the same SA ID. + +**/ +BOOLEAN +CompareSaId ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ) +{ + EFI_IPSEC_SA_ID *SaId1; + EFI_IPSEC_SA_ID *SaId2; + BOOLEAN IsMatch; + + SaId1 = &Selector1->SaId; + SaId2 = &Selector2->SaId; + IsMatch = TRUE; + + if (CompareMem (SaId1, SaId2, sizeof (EFI_IPSEC_SA_ID)) != 0) { + IsMatch = FALSE; + } + + return IsMatch; +} + +/** + Compare two PAD IDs. + + @param[in] Selector1 Pointer of first PAD ID. + @param[in] Selector2 Pointer of second PAD ID. + + @retval TRUE This two Selectors have the same PAD ID. + @retval FALSE This two Selecotrs don't have the same PAD ID. + +**/ +BOOLEAN +ComparePadId ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ) +{ + EFI_IPSEC_PAD_ID *PadId1; + EFI_IPSEC_PAD_ID *PadId2; + BOOLEAN IsMatch; + + PadId1 = &Selector1->PadId; + PadId2 = &Selector2->PadId; + IsMatch = TRUE; + + // + // Compare the PeerIdValid fields in PadId. + // + if (PadId1->PeerIdValid != PadId2->PeerIdValid) { + IsMatch = FALSE; + } + // + // Compare the PeerId fields in PadId if PeerIdValid is true. + // + if (IsMatch && + PadId1->PeerIdValid && + AsciiStriCmp ((CONST CHAR8 *) PadId1->Id.PeerId, (CONST CHAR8 *) PadId2->Id.PeerId) != 0 + ) { + IsMatch = FALSE; + } + // + // Compare the IpAddress fields in PadId if PeerIdValid is false. + // + if (IsMatch && + !PadId1->PeerIdValid && + (PadId1->Id.IpAddress.PrefixLength != PadId2->Id.IpAddress.PrefixLength || + CompareMem (&PadId1->Id.IpAddress.Address, &PadId2->Id.IpAddress.Address, sizeof (EFI_IP_ADDRESS)) != 0) + ) { + IsMatch = FALSE; + } + + return IsMatch; +} + +/** + Check if the SPD Selector is Zero by its LocalAddressCount and RemoteAddressCount + fields. + + @param[in] Selector Pointer of the SPD Selector. + + @retval TRUE If the SPD Selector is Zero. + @retval FALSE If the SPD Selector is not Zero. + +**/ +BOOLEAN +IsZeroSpdSelector ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector + ) +{ + EFI_IPSEC_SPD_SELECTOR *SpdSel; + BOOLEAN IsZero; + + SpdSel = &Selector->SpdSelector; + IsZero = FALSE; + + if (SpdSel->LocalAddressCount == 0 && SpdSel->RemoteAddressCount == 0) { + IsZero = TRUE; + } + + return IsZero; +} + +/** + Check if the SA ID is Zero by its DestAddress. + + @param[in] Selector Pointer of the SA ID. + + @retval TRUE If the SA ID is Zero. + @retval FALSE If the SA ID is not Zero. + +**/ +BOOLEAN +IsZeroSaId ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector + ) +{ + EFI_IP_ADDRESS *DestAddr; + EFI_IP_ADDRESS ZeroAddr; + BOOLEAN IsZero; + + DestAddr = &Selector->SaId.DestAddress; + IsZero = FALSE; + + ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS)); + + if (CompareMem (DestAddr, &ZeroAddr, sizeof (EFI_IP_ADDRESS)) == 0) { + IsZero = TRUE; + } + + return IsZero; +} + +/** + Check if the PAD ID is Zero. + + @param[in] Selector Pointer of the PAD ID. + + @retval TRUE If the PAD ID is Zero. + @retval FALSE If the PAD ID is not Zero. + +**/ +BOOLEAN +IsZeroPadId ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector + ) +{ + EFI_IPSEC_PAD_ID *PadId; + EFI_IPSEC_PAD_ID ZeroId; + BOOLEAN IsZero; + + PadId = &Selector->PadId; + IsZero = FALSE; + + ZeroMem (&ZeroId, sizeof (EFI_IPSEC_PAD_ID)); + + if (CompareMem (PadId, &ZeroId, sizeof (EFI_IPSEC_PAD_ID)) == 0) { + IsZero = TRUE; + } + + return IsZero; +} + +/** + Copy Source SPD Selector to the Destination SPD Selector. + + @param[in, out] DstSel Pointer of Destination SPD Selector. + @param[in] SrcSel Pointer of Source SPD Selector. + @param[in, out] Size The size of the Destination SPD Selector. If it + not NULL and its value less than the size of + Source SPD Selector, the value of Source SPD + Selector's size will be passed to caller by this + parameter. + + @retval EFI_INVALID_PARAMETER If the Destination or Source SPD Selector is NULL + @retval EFI_BUFFER_TOO_SMALL If the input Size is less than size of the Source SPD Selector. + @retval EFI_SUCCESS Copy Source SPD Selector to the Destination SPD + Selector successfully. + +**/ +EFI_STATUS +DuplicateSpdSelector ( + IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel, + IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel, + IN OUT UINTN *Size + ) +{ + EFI_IPSEC_SPD_SELECTOR *Dst; + EFI_IPSEC_SPD_SELECTOR *Src; + + Dst = &DstSel->SpdSelector; + Src = &SrcSel->SpdSelector; + + if (Dst == NULL || Src == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Size != NULL && (*Size) < SIZE_OF_SPD_SELECTOR (Src)) { + *Size = SIZE_OF_SPD_SELECTOR (Src); + return EFI_BUFFER_TOO_SMALL; + } + // + // Copy the base structure of spd selector. + // + CopyMem (Dst, Src, sizeof (EFI_IPSEC_SPD_SELECTOR)); + + // + // Copy the local address array of spd selector. + // + Dst->LocalAddress = (EFI_IP_ADDRESS_INFO *) (Dst + 1); + CopyMem ( + Dst->LocalAddress, + Src->LocalAddress, + sizeof (EFI_IP_ADDRESS_INFO) * Dst->LocalAddressCount + ); + + // + // Copy the remote address array of spd selector. + // + Dst->RemoteAddress = Dst->LocalAddress + Dst->LocalAddressCount; + CopyMem ( + Dst->RemoteAddress, + Src->RemoteAddress, + sizeof (EFI_IP_ADDRESS_INFO) * Dst->RemoteAddressCount + ); + + return EFI_SUCCESS; +} + +/** + Copy Source SA ID to the Destination SA ID. + + @param[in, out] DstSel Pointer of Destination SA ID. + @param[in] SrcSel Pointer of Source SA ID. + @param[in, out] Size The size of the Destination SA ID. If it + not NULL and its value less than the size of + Source SA ID, the value of Source SA ID's size + will be passed to caller by this parameter. + + @retval EFI_INVALID_PARAMETER If the Destination or Source SA ID is NULL. + @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source SA ID. + @retval EFI_SUCCESS Copy Source SA ID to the Destination SA ID successfully. + +**/ +EFI_STATUS +DuplicateSaId ( + IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel, + IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel, + IN OUT UINTN *Size + ) +{ + EFI_IPSEC_SA_ID *Dst; + EFI_IPSEC_SA_ID *Src; + + Dst = &DstSel->SaId; + Src = &SrcSel->SaId; + + if (Dst == NULL || Src == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Size != NULL && *Size < sizeof (EFI_IPSEC_SA_ID)) { + *Size = sizeof (EFI_IPSEC_SA_ID); + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem (Dst, Src, sizeof (EFI_IPSEC_SA_ID)); + + return EFI_SUCCESS; +} + +/** + Copy Source PAD ID to the Destination PAD ID. + + @param[in, out] DstSel Pointer of Destination PAD ID. + @param[in] SrcSel Pointer of Source PAD ID. + @param[in, out] Size The size of the Destination PAD ID. If it + not NULL and its value less than the size of + Source PAD ID, the value of Source PAD ID's size + will be passed to caller by this parameter. + + @retval EFI_INVALID_PARAMETER If the Destination or Source PAD ID is NULL. + @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source PAD ID . + @retval EFI_SUCCESS Copy Source PAD ID to the Destination PAD ID successfully. + +**/ +EFI_STATUS +DuplicatePadId ( + IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel, + IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel, + IN OUT UINTN *Size + ) +{ + EFI_IPSEC_PAD_ID *Dst; + EFI_IPSEC_PAD_ID *Src; + + Dst = &DstSel->PadId; + Src = &SrcSel->PadId; + + if (Dst == NULL || Src == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Size != NULL && *Size < sizeof (EFI_IPSEC_PAD_ID)) { + *Size = sizeof (EFI_IPSEC_PAD_ID); + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem (Dst, Src, sizeof (EFI_IPSEC_PAD_ID)); + + return EFI_SUCCESS; +} + +/** + Fix the value of some members of SPD Selector. + + This function is called by IpSecCopyPolicyEntry()which copy the Policy + Entry into the Variable. Since some members in SPD Selector are pointers, + a physical address to relative address convertion is required before copying + this SPD entry into the variable. + + @param[in] Selector Pointer of SPD Selector. + @param[in, out] Data Pointer of SPD Data. + +**/ +VOID +FixSpdEntry ( + IN EFI_IPSEC_SPD_SELECTOR *Selector, + IN OUT EFI_IPSEC_SPD_DATA *Data + ) +{ + // + // It assumes that all ref buffers in spd selector and data are + // stored in the continous memory and close to the base structure. + // + FIX_REF_BUF_ADDR (Selector->LocalAddress, Selector); + FIX_REF_BUF_ADDR (Selector->RemoteAddress, Selector); + + if (Data->ProcessingPolicy != NULL) { + if (Data->ProcessingPolicy->TunnelOption != NULL) { + FIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data); + } + + FIX_REF_BUF_ADDR (Data->ProcessingPolicy, Data); + } + +} + +/** + Fix the value of some members of SA ID. + + This function is called by IpSecCopyPolicyEntry()which copy the Policy + Entry into the Variable. Since some members in SA ID are pointers, + a physical address to relative address conversion is required before copying + this SAD into the variable. + + @param[in] SaId Pointer of SA ID + @param[in, out] Data Pointer of SA Data. + +**/ +VOID +FixSadEntry ( + IN EFI_IPSEC_SA_ID *SaId, + IN OUT EFI_IPSEC_SA_DATA *Data + ) +{ + // + // It assumes that all ref buffers in sad selector and data are + // stored in the continous memory and close to the base structure. + // + if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { + FIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.AuthKey, Data); + } + + if (SaId->Proto == EfiIPsecESP && Data->AlgoInfo.EspAlgoInfo.EncKey != NULL) { + FIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.EncKey, Data); + } + + if (Data->SpdSelector != NULL) { + if (Data->SpdSelector->LocalAddress != NULL) { + FIX_REF_BUF_ADDR (Data->SpdSelector->LocalAddress, Data); + } + + FIX_REF_BUF_ADDR (Data->SpdSelector->RemoteAddress, Data); + FIX_REF_BUF_ADDR (Data->SpdSelector, Data); + } + +} + +/** + Fix the value of some members of PAD ID. + + This function is called by IpSecCopyPolicyEntry()which copy the Policy + Entry into the Variable. Since some members in PAD ID are pointers, + a physical address to relative address conversion is required before copying + this PAD into the variable. + + @param[in] PadId Pointer of PAD ID. + @param[in, out] Data Pointer of PAD Data. + +**/ +VOID +FixPadEntry ( + IN EFI_IPSEC_PAD_ID *PadId, + IN OUT EFI_IPSEC_PAD_DATA *Data + ) +{ + // + // It assumes that all ref buffers in pad selector and data are + // stored in the continous memory and close to the base structure. + // + if (Data->AuthData != NULL) { + FIX_REF_BUF_ADDR (Data->AuthData, Data); + } + + if (Data->RevocationData != NULL) { + FIX_REF_BUF_ADDR (Data->RevocationData, Data); + } + +} + +/** + Recover the value of some members of SPD Selector. + + This function is corresponding to FixSpdEntry(). It recovers the value of members + of SPD Selector that are fixed by FixSpdEntry(). + + @param[in, out] Selector Pointer of SPD Selector. + @param[in, out] Data Pointer of SPD Data. + +**/ +VOID +UnfixSpdEntry ( + IN OUT EFI_IPSEC_SPD_SELECTOR *Selector, + IN OUT EFI_IPSEC_SPD_DATA *Data + ) +{ + // + // It assumes that all ref buffers in spd selector and data are + // stored in the continous memory and close to the base structure. + // + UNFIX_REF_BUF_ADDR (Selector->LocalAddress, Selector); + UNFIX_REF_BUF_ADDR (Selector->RemoteAddress, Selector); + + if (Data->ProcessingPolicy != NULL) { + UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy, Data); + if (Data->ProcessingPolicy->TunnelOption != NULL) { + UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data); + } + } + +} + +/** + Recover the value of some members of SA ID. + + This function is corresponding to FixSadEntry(). It recovers the value of members + of SAD ID that are fixed by FixSadEntry(). + + @param[in, out] SaId Pointer of SAD ID. + @param[in, out] Data Pointer of SAD Data. + +**/ +VOID +UnfixSadEntry ( + IN OUT EFI_IPSEC_SA_ID *SaId, + IN OUT EFI_IPSEC_SA_DATA *Data + ) +{ + // + // It assumes that all ref buffers in sad selector and data are + // stored in the continous memory and close to the base structure. + // + if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { + UNFIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.AuthKey, Data); + } + + if (SaId->Proto == EfiIPsecESP && Data->AlgoInfo.EspAlgoInfo.EncKey != NULL) { + UNFIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.EncKey, Data); + } + + if (Data->SpdSelector != NULL) { + UNFIX_REF_BUF_ADDR (Data->SpdSelector, Data); + if (Data->SpdSelector->LocalAddress != NULL) { + UNFIX_REF_BUF_ADDR (Data->SpdSelector->LocalAddress, Data); + } + + UNFIX_REF_BUF_ADDR (Data->SpdSelector->RemoteAddress, Data); + } + +} + +/** + Recover the value of some members of PAD ID. + + This function is corresponding to FixPadEntry(). It recovers the value of members + of PAD ID that are fixed by FixPadEntry(). + + @param[in] PadId Pointer of PAD ID. + @param[in, out] Data Pointer of PAD Data. + +**/ +VOID +UnfixPadEntry ( + IN EFI_IPSEC_PAD_ID *PadId, + IN OUT EFI_IPSEC_PAD_DATA *Data + ) +{ + // + // It assumes that all ref buffers in pad selector and data are + // stored in the continous memory and close to the base structure. + // + if (Data->AuthData != NULL) { + UNFIX_REF_BUF_ADDR (Data->AuthData, Data); + } + + if (Data->RevocationData != NULL) { + UNFIX_REF_BUF_ADDR (Data->RevocationData, Data); + } + +} + +/** + Set the security policy information for the EFI IPsec driver. + + The IPsec configuration data has a unique selector/identifier separately to + identify a data entry. + + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type + configuration information to be flushed. + @param[in] Data The data buffer to be set. The structure + of the data buffer should be EFI_IPSEC_SPD_DATA. + @param[in] Context Pointer to one entry selector that describes + the expected position the new data entry will + be added. If Context is NULL, the new entry will + be appended the end of database. + + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - Selector is not NULL and its LocalAddress + is NULL or its RemoteAddress is NULL. + - Data is not NULL and its Action is Protected + and its plolicy is NULL. + - Data is not NULL, its Action is not protected, + and its policy is not NULL. + - The Action of Data is Protected, its policy + mode is Tunnel, and its tunnel option is NULL. + - The Action of Data is protected and its policy + mode is not Tunnel and it tunnel option is not NULL. + @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + +**/ +EFI_STATUS +SetSpdEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN VOID *Context OPTIONAL + ) +{ + EFI_IPSEC_SPD_SELECTOR *SpdSel; + EFI_IPSEC_SPD_DATA *SpdData; + EFI_IPSEC_SPD_SELECTOR *InsertBefore; + LIST_ENTRY *SpdList; + LIST_ENTRY *SadList; + LIST_ENTRY *SpdSas; + LIST_ENTRY *EntryInsertBefore; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + LIST_ENTRY *Entry2; + IPSEC_SPD_ENTRY *SpdEntry; + IPSEC_SAD_ENTRY *SadEntry; + UINTN SpdEntrySize; + UINTN Index; + + SpdSel = (Selector == NULL) ? NULL : &Selector->SpdSelector; + SpdData = (Data == NULL) ? NULL : (EFI_IPSEC_SPD_DATA *) Data; + InsertBefore = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SpdSelector; + SpdList = &mConfigData[IPsecConfigDataTypeSpd]; + + if (SpdSel != NULL) { + if (SpdSel->LocalAddress == NULL || SpdSel->RemoteAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + } + + if (SpdData != NULL) { + if ((SpdData->Action == EfiIPsecActionProtect && SpdData->ProcessingPolicy == NULL) || + (SpdData->Action != EfiIPsecActionProtect && SpdData->ProcessingPolicy != NULL) + ) { + return EFI_INVALID_PARAMETER; + } + + if (SpdData->Action == EfiIPsecActionProtect) { + if ((SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption == NULL) || + (SpdData->ProcessingPolicy->Mode != EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption != NULL) + ) { + return EFI_INVALID_PARAMETER; + } + } + } + // + // The default behavior is to insert the node ahead of the header. + // + EntryInsertBefore = SpdList; + + // + // Remove the existed spd entry. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SpdList) { + + SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); + + if (SpdSel == NULL || + CompareSpdSelector ((EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel) + ) { + // + // Record the existed entry position to keep the original order. + // + EntryInsertBefore = SpdEntry->List.ForwardLink; + RemoveEntryList (&SpdEntry->List); + + // + // Update the reverse ref of sad entry in the spd.sas list. + // + SpdSas = &SpdEntry->Data->Sas; + NET_LIST_FOR_EACH (Entry2, SpdSas) { + SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry2); + SadEntry->Data->SpdEntry = NULL; + } + // + // Free the existed spd entry + // + FreePool (SpdEntry); + } + } + // + // Return success here if only want to remove the spd entry. + // + if (SpdData == NULL || SpdSel == NULL) { + return EFI_SUCCESS; + } + // + // Search the appointed entry position if InsertBefore is not NULL. + // + if (InsertBefore != NULL) { + + NET_LIST_FOR_EACH (Entry, SpdList) { + SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); + + if (CompareSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, + (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore + )) { + EntryInsertBefore = Entry; + break; + } + } + } + + // + // Do Padding for the different Arch. + // + SpdEntrySize = ALIGN_VARIABLE (sizeof (IPSEC_SPD_ENTRY)); + SpdEntrySize = ALIGN_VARIABLE (SpdEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SpdSel)); + SpdEntrySize += IpSecGetSizeOfEfiSpdData (SpdData); + + SpdEntry = AllocateZeroPool (SpdEntrySize); + + if (SpdEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Fix the address of Selector and Data buffer and copy them, which is + // continous memory and close to the base structure of spd entry. + // + SpdEntry->Selector = (EFI_IPSEC_SPD_SELECTOR *) ALIGN_POINTER ((SpdEntry + 1), sizeof (UINTN)); + SpdEntry->Data = (IPSEC_SPD_DATA *) ALIGN_POINTER ( + ((UINT8 *) SpdEntry->Selector + SIZE_OF_SPD_SELECTOR (SpdSel)), + sizeof (UINTN) + ); + + DuplicateSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, + (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel, + NULL + ); + + CopyMem ( + SpdEntry->Data->Name, + SpdData->Name, + sizeof (SpdData->Name) + ); + SpdEntry->Data->PackageFlag = SpdData->PackageFlag; + SpdEntry->Data->Action = SpdData->Action; + + // + // Fix the address of ProcessingPolicy and copy it if need, which is continous + // memory and close to the base structure of sad data. + // + if (SpdData->Action != EfiIPsecActionProtect) { + SpdEntry->Data->ProcessingPolicy = NULL; + } else { + SpdEntry->Data->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ALIGN_POINTER ( + SpdEntry->Data + 1, + sizeof (UINTN) + ); + IpSecDuplicateProcessPolicy (SpdEntry->Data->ProcessingPolicy, SpdData->ProcessingPolicy); + } + // + // Update the sas list of the new spd entry. + // + InitializeListHead (&SpdEntry->Data->Sas); + + SadList = &mConfigData[IPsecConfigDataTypeSad]; + + NET_LIST_FOR_EACH (Entry, SadList) { + SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry); + + for (Index = 0; Index < SpdData->SaIdCount; Index++) { + + if (CompareSaId ( + (EFI_IPSEC_CONFIG_SELECTOR *) &SpdData->SaId[Index], + (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id + )) { + InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd); + SadEntry->Data->SpdEntry = SpdEntry; + } + } + } + // + // Insert the new spd entry. + // + InsertTailList (EntryInsertBefore, &SpdEntry->List); + + return EFI_SUCCESS; +} + +/** + Set the security association information for the EFI IPsec driver. + + The IPsec configuration data has a unique selector/identifier separately to + identify a data entry. + + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type + configuration information to be flushed. + @param[in] Data The data buffer to be set. The structure + of the data buffer should be EFI_IPSEC_SA_DATA. + @param[in] Context Pointer to one entry selector which describes + the expected position the new data entry will + be added. If Context is NULL,the new entry will + be appended the end of database. + + @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + +**/ +EFI_STATUS +SetSadEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN VOID *Context OPTIONAL + ) +{ + IPSEC_SAD_ENTRY *SadEntry; + IPSEC_SPD_ENTRY *SpdEntry; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + LIST_ENTRY *SadList; + LIST_ENTRY *SpdList; + EFI_IPSEC_SA_ID *SaId; + EFI_IPSEC_SA_DATA *SaData; + EFI_IPSEC_SA_ID *InsertBefore; + LIST_ENTRY *EntryInsertBefore; + UINTN SadEntrySize; + + SaId = (Selector == NULL) ? NULL : &Selector->SaId; + SaData = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA *) Data; + InsertBefore = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SaId; + SadList = &mConfigData[IPsecConfigDataTypeSad]; + + // + // The default behavior is to insert the node ahead of the header. + // + EntryInsertBefore = SadList; + + // + // Remove the existed sad entry. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SadList) { + + SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry); + + if (SaId == NULL || + CompareSaId ( + (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id, + (EFI_IPSEC_CONFIG_SELECTOR *) SaId + )) { + // + // Record the existed entry position to keep the original order. + // + EntryInsertBefore = SadEntry->List.ForwardLink; + + // + // Update the related sad.byspd field. + // + if (SadEntry->Data->SpdEntry != NULL) { + RemoveEntryList (&SadEntry->BySpd); + } + + RemoveEntryList (&SadEntry->List); + FreePool (SadEntry); + } + } + // + // Return success here if only want to remove the sad entry + // + if (SaData == NULL || SaId == NULL) { + return EFI_SUCCESS; + } + // + // Search the appointed entry position if InsertBefore is not NULL. + // + if (InsertBefore != NULL) { + + NET_LIST_FOR_EACH (Entry, SadList) { + SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry); + + if (CompareSaId ( + (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id, + (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore + )) { + EntryInsertBefore = Entry; + break; + } + } + } + + // + // Do Padding for different Arch. + // + SadEntrySize = ALIGN_VARIABLE (sizeof (IPSEC_SAD_ENTRY)); + SadEntrySize = ALIGN_VARIABLE (SadEntrySize + sizeof (EFI_IPSEC_SA_DATA)); + SadEntrySize = ALIGN_VARIABLE (SadEntrySize + sizeof (IPSEC_SAD_DATA)); + + if (SaId->Proto == EfiIPsecAH) { + SadEntrySize += SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength; + } else { + SadEntrySize = ALIGN_VARIABLE (SadEntrySize + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength); + SadEntrySize += SaData->AlgoInfo.EspAlgoInfo.EncKeyLength; + } + + SadEntry = AllocateZeroPool (SadEntrySize); + + if (SadEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Fix the address of Id and Data buffer and copy them, which is + // continous memory and close to the base structure of sad entry. + // + SadEntry->Id = (EFI_IPSEC_SA_ID *) ALIGN_POINTER ((SadEntry + 1), sizeof (UINTN)); + SadEntry->Data = (IPSEC_SAD_DATA *) ALIGN_POINTER ((SadEntry->Id + 1), sizeof (UINTN)); + + CopyMem (SadEntry->Id, SaId, sizeof (EFI_IPSEC_SA_ID)); + + SadEntry->Data->Mode = SaData->Mode; + SadEntry->Data->SequenceNumber = SaData->SNCount; + SadEntry->Data->AntiReplayWindowSize = SaData->AntiReplayWindows; + + ZeroMem ( + &SadEntry->Data->AntiReplayBitmap, + sizeof (SadEntry->Data->AntiReplayBitmap) + ); + + ZeroMem ( + &SadEntry->Data->AlgoInfo, + sizeof (EFI_IPSEC_ALGO_INFO) + ); + + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId = SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId; + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength = SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength; + + if (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) { + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SadEntry->Data + 1), sizeof (UINTN)); + CopyMem ( + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey, + SaData->AlgoInfo.EspAlgoInfo.AuthKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength + ); + } + + if (SaId->Proto == EfiIPsecESP) { + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId = SaData->AlgoInfo.EspAlgoInfo.EncAlgoId; + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength = SaData->AlgoInfo.EspAlgoInfo.EncKeyLength; + + if (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) { + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER ( + ((UINT8 *) (SadEntry->Data + 1) + + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength), + sizeof (UINTN) + ); + CopyMem ( + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey, + SaData->AlgoInfo.EspAlgoInfo.EncKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength + ); + } + } + + CopyMem ( + &SadEntry->Data->SaLifetime, + &SaData->SaLifetime, + sizeof (EFI_IPSEC_SA_LIFETIME) + ); + + SadEntry->Data->PathMTU = SaData->PathMTU; + SadEntry->Data->SpdEntry = NULL; + SadEntry->Data->ESNEnabled = FALSE; + SadEntry->Data->ManualSet = SaData->ManualSet; + + // + // Update the spd.sas list of the spd entry specified by sad.selector + // + SpdList = &mConfigData[IPsecConfigDataTypeSpd]; + + for (Entry = SpdList->ForwardLink; Entry != SpdList && SaData->SpdSelector != NULL; Entry = Entry->ForwardLink) { + + SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); + if (CompareSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, + (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector + ) && SpdEntry->Data->Action == EfiIPsecActionProtect) { + SadEntry->Data->SpdEntry = SpdEntry; + InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd); + } + } + // + // Insert the new sad entry. + // + InsertTailList (EntryInsertBefore, &SadEntry->List); + + return EFI_SUCCESS; +} + +/** + Set the peer authorization configuration information for the EFI IPsec driver. + + The IPsec configuration data has a unique selector/identifier separately to + identify a data entry. + + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type + configuration information to be flushed. + @param[in] Data The data buffer to be set. The structure + of the data buffer should be EFI_IPSEC_PAD_DATA. + @param[in] Context Pointer to one entry selector that describes + the expected position the new data entry will + be added. If Context is NULL, the new entry will + be appended the end of database. + + @retval EFI_OUT_OF_RESOURCES The required system resources could not be allocated. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + +**/ +EFI_STATUS +SetPadEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN VOID *Context OPTIONAL + ) +{ + IPSEC_PAD_ENTRY *PadEntry; + EFI_IPSEC_PAD_ID *PadId; + EFI_IPSEC_PAD_DATA *PadData; + LIST_ENTRY *PadList; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + EFI_IPSEC_PAD_ID *InsertBefore; + LIST_ENTRY *EntryInsertBefore; + UINTN PadEntrySize; + + PadId = (Selector == NULL) ? NULL : &Selector->PadId; + PadData = (Data == NULL) ? NULL : (EFI_IPSEC_PAD_DATA *) Data; + InsertBefore = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->PadId; + PadList = &mConfigData[IPsecConfigDataTypePad]; + + // + // The default behavior is to insert the node ahead of the header. + // + EntryInsertBefore = PadList; + + // + // Remove the existed pad entry. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, PadList) { + + PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry); + + if (PadId == NULL || + ComparePadId ((EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) PadId) + ) { + // + // Record the existed entry position to keep the original order. + // + EntryInsertBefore = PadEntry->List.ForwardLink; + RemoveEntryList (&PadEntry->List); + + FreePool (PadEntry); + } + } + // + // Return success here if only want to remove the pad entry + // + if (PadData == NULL || PadId == NULL) { + return EFI_SUCCESS; + } + // + // Search the appointed entry position if InsertBefore is not NULL. + // + if (InsertBefore != NULL) { + + NET_LIST_FOR_EACH (Entry, PadList) { + PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry); + + if (ComparePadId ( + (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, + (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore + )) { + EntryInsertBefore = Entry; + break; + } + } + } + + // + // Do PADDING for different arch. + // + PadEntrySize = ALIGN_VARIABLE (sizeof (IPSEC_PAD_ENTRY)); + PadEntrySize = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_ID)); + PadEntrySize = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_DATA)); + PadEntrySize = ALIGN_VARIABLE (PadEntrySize + (PadData->AuthData != NULL ? PadData->AuthDataSize : 0)); + PadEntrySize += PadData->RevocationData != NULL ? PadData->RevocationDataSize : 0; + + PadEntry = AllocateZeroPool (PadEntrySize); + + if (PadEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Fix the address of Id and Data buffer and copy them, which is + // continous memory and close to the base structure of pad entry. + // + PadEntry->Id = (EFI_IPSEC_PAD_ID *) ALIGN_POINTER ((PadEntry + 1), sizeof (UINTN)); + PadEntry->Data = (EFI_IPSEC_PAD_DATA *) ALIGN_POINTER ((PadEntry->Id + 1), sizeof (UINTN)); + + CopyMem (PadEntry->Id, PadId, sizeof (EFI_IPSEC_PAD_ID)); + + PadEntry->Data->AuthProtocol = PadData->AuthProtocol; + PadEntry->Data->AuthMethod = PadData->AuthMethod; + PadEntry->Data->IkeIdFlag = PadData->IkeIdFlag; + + if (PadData->AuthData != NULL) { + PadEntry->Data->AuthDataSize = PadData->AuthDataSize; + PadEntry->Data->AuthData = (VOID *) ALIGN_POINTER (PadEntry->Data + 1, sizeof (UINTN)); + CopyMem ( + PadEntry->Data->AuthData, + PadData->AuthData, + PadData->AuthDataSize + ); + } else { + PadEntry->Data->AuthDataSize = 0; + PadEntry->Data->AuthData = NULL; + } + + if (PadData->RevocationData != NULL) { + PadEntry->Data->RevocationDataSize = PadData->RevocationDataSize; + PadEntry->Data->RevocationData = (VOID *) ALIGN_POINTER ( + ((UINT8 *) (PadEntry->Data + 1) + PadData->AuthDataSize), + sizeof (UINTN) + ); + CopyMem ( + PadEntry->Data->RevocationData, + PadData->RevocationData, + PadData->RevocationDataSize + ); + } else { + PadEntry->Data->RevocationDataSize = 0; + PadEntry->Data->RevocationData = NULL; + } + // + // Insert the new pad entry. + // + InsertTailList (EntryInsertBefore, &PadEntry->List); + + return EFI_SUCCESS; +} + +/** + This function lookup the data entry from IPsec SPD. Return the configuration + value of the specified SPD Entry. + + @param[in] Selector Pointer to an entry selector which is an identifier + of the SPD entry. + @param[in, out] DataSize On output the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec + configuration data. The type of the data buffer + is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero. + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +EFI_STATUS +GetSpdEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + IPSEC_SPD_ENTRY *SpdEntry; + IPSEC_SAD_ENTRY *SadEntry; + EFI_IPSEC_SPD_SELECTOR *SpdSel; + EFI_IPSEC_SPD_DATA *SpdData; + LIST_ENTRY *SpdList; + LIST_ENTRY *SpdSas; + LIST_ENTRY *Entry; + UINTN RequiredSize; + + SpdSel = &Selector->SpdSelector; + SpdData = (EFI_IPSEC_SPD_DATA *) Data; + SpdList = &mConfigData[IPsecConfigDataTypeSpd]; + + NET_LIST_FOR_EACH (Entry, SpdList) { + SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); + + // + // Find the required spd entry + // + if (CompareSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel, + (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector + )) { + + RequiredSize = IpSecGetSizeOfSpdData (SpdEntry->Data); + if (*DataSize < RequiredSize) { + *DataSize = RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + + if (SpdData == NULL) { + return EFI_INVALID_PARAMETER; + } + + *DataSize = RequiredSize; + + // + // Extract and fill all SaId array from the spd.sas list + // + SpdSas = &SpdEntry->Data->Sas; + SpdData->SaIdCount = 0; + + NET_LIST_FOR_EACH (Entry, SpdSas) { + SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry); + CopyMem ( + &SpdData->SaId[SpdData->SaIdCount++], + SadEntry->Id, + sizeof (EFI_IPSEC_SA_ID) + ); + } + // + // Fill the other fields in spd data. + // + CopyMem (SpdData->Name, SpdEntry->Data->Name, sizeof (SpdData->Name)); + + SpdData->PackageFlag = SpdEntry->Data->PackageFlag; + SpdData->Action = SpdEntry->Data->Action; + + if (SpdData->Action != EfiIPsecActionProtect) { + SpdData->ProcessingPolicy = NULL; + } else { + SpdData->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ((UINT8 *) SpdData + sizeof (EFI_IPSEC_SPD_DATA) + (SpdData->SaIdCount - 1) * sizeof (EFI_IPSEC_SA_ID)); + + IpSecDuplicateProcessPolicy ( + SpdData->ProcessingPolicy, + SpdEntry->Data->ProcessingPolicy + ); + } + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + This function lookup the data entry from IPsec SAD. Return the configuration + value of the specified SAD Entry. + + @param[in] Selector Pointer to an entry selector which is an identifier + of the SAD entry. + @param[in, out] DataSize On output, the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec + configuration data. The type of the data buffer + is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +EFI_STATUS +GetSadEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + IPSEC_SAD_ENTRY *SadEntry; + LIST_ENTRY *Entry; + LIST_ENTRY *SadList; + EFI_IPSEC_SA_ID *SaId; + EFI_IPSEC_SA_DATA *SaData; + UINTN RequiredSize; + + SaId = &Selector->SaId; + SaData = (EFI_IPSEC_SA_DATA *) Data; + SadList = &mConfigData[IPsecConfigDataTypeSad]; + + NET_LIST_FOR_EACH (Entry, SadList) { + SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry); + + // + // Find the required sad entry. + // + if (CompareSaId ( + (EFI_IPSEC_CONFIG_SELECTOR *) SaId, + (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id + )) { + // + // Calculate the required size of the sad entry. + // Data Layout is follows: + // |EFI_IPSEC_SA_DATA + // |AuthKey + // |EncryptKey (Optional) + // |SpdSelector (Optional) + // + RequiredSize = ALIGN_VARIABLE (sizeof (EFI_IPSEC_SA_DATA)); + + if (SaId->Proto == EfiIPsecAH) { + RequiredSize = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength); + } else { + RequiredSize = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength); + RequiredSize = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength); + } + + if (SadEntry->Data->SpdEntry != NULL) { + RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdEntry->Selector); + } + + + + if (*DataSize < RequiredSize) { + *DataSize = RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + // + // Fill the data fields of sad entry. + // + *DataSize = RequiredSize; + SaData->Mode = SadEntry->Data->Mode; + SaData->SNCount = SadEntry->Data->SequenceNumber; + SaData->AntiReplayWindows = SadEntry->Data->AntiReplayWindowSize; + + CopyMem ( + &SaData->SaLifetime, + &SadEntry->Data->SaLifetime, + sizeof (EFI_IPSEC_SA_LIFETIME) + ); + + ZeroMem ( + &SaData->AlgoInfo, + sizeof (EFI_IPSEC_ALGO_INFO) + ); + + if (SaId->Proto == EfiIPsecAH) { + // + // Copy AH alogrithm INFO to SaData + // + SaData->AlgoInfo.AhAlgoInfo.AuthAlgoId = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthAlgoId; + SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength; + if (SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength != 0) { + SaData->AlgoInfo.AhAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN)); + CopyMem ( + SaData->AlgoInfo.AhAlgoInfo.AuthKey, + SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKey, + SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength + ); + } + } else if (SaId->Proto == EfiIPsecESP) { + // + // Copy ESP alogrithem INFO to SaData + // + SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId; + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength; + if (SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) { + SaData->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN)); + CopyMem ( + SaData->AlgoInfo.EspAlgoInfo.AuthKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey, + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength + ); + } + + SaData->AlgoInfo.EspAlgoInfo.EncAlgoId = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId; + SaData->AlgoInfo.EspAlgoInfo.EncKeyLength = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength; + + if (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) { + SaData->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER ( + ((UINT8 *) (SaData + 1) + + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength), + sizeof (UINTN) + ); + CopyMem ( + SaData->AlgoInfo.EspAlgoInfo.EncKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey, + SaData->AlgoInfo.EspAlgoInfo.EncKeyLength + ); + } + } + + SaData->PathMTU = SadEntry->Data->PathMTU; + + // + // Fill the spd selector field of sad data + // + if (SadEntry->Data->SpdEntry != NULL) { + + SaData->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) ( + (UINT8 *)SaData + + RequiredSize - + SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdEntry->Selector) + ); + + DuplicateSpdSelector ( + (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector, + (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdEntry->Selector, + NULL + ); + + } else { + + SaData->SpdSelector = NULL; + } + + SaData->ManualSet = SadEntry->Data->ManualSet; + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + This function lookup the data entry from IPsec PAD. Return the configuration + value of the specified PAD Entry. + + @param[in] Selector Pointer to an entry selector which is an identifier + of the PAD entry. + @param[in, out] DataSize On output the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec + configuration data. The type of the data buffer + is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +EFI_STATUS +GetPadEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + IPSEC_PAD_ENTRY *PadEntry; + LIST_ENTRY *PadList; + LIST_ENTRY *Entry; + EFI_IPSEC_PAD_ID *PadId; + EFI_IPSEC_PAD_DATA *PadData; + UINTN RequiredSize; + + PadId = &Selector->PadId; + PadData = (EFI_IPSEC_PAD_DATA *) Data; + PadList = &mConfigData[IPsecConfigDataTypePad]; + + NET_LIST_FOR_EACH (Entry, PadList) { + PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry); + + // + // Find the required pad entry. + // + if (ComparePadId ( + (EFI_IPSEC_CONFIG_SELECTOR *) PadId, + (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id + )) { + // + // Calculate the required size of the pad entry. + // + RequiredSize = ALIGN_VARIABLE (sizeof (EFI_IPSEC_PAD_DATA)); + RequiredSize = ALIGN_VARIABLE (RequiredSize + PadEntry->Data->AuthDataSize); + RequiredSize += PadEntry->Data->RevocationDataSize; + + if (*DataSize < RequiredSize) { + *DataSize = RequiredSize; + return EFI_BUFFER_TOO_SMALL; + } + // + // Fill the data fields of pad entry + // + *DataSize = RequiredSize; + PadData->AuthProtocol = PadEntry->Data->AuthProtocol; + PadData->AuthMethod = PadEntry->Data->AuthMethod; + PadData->IkeIdFlag = PadEntry->Data->IkeIdFlag; + + // + // Copy Authentication data. + // + if (PadEntry->Data->AuthData != NULL) { + + PadData->AuthDataSize = PadEntry->Data->AuthDataSize; + PadData->AuthData = (VOID *) ALIGN_POINTER ((PadData + 1), sizeof (UINTN)); + CopyMem ( + PadData->AuthData, + PadEntry->Data->AuthData, + PadData->AuthDataSize + ); + } else { + + PadData->AuthDataSize = 0; + PadData->AuthData = NULL; + } + // + // Copy Revocation Data. + // + if (PadEntry->Data->RevocationData != NULL) { + + PadData->RevocationDataSize = PadEntry->Data->RevocationDataSize; + PadData->RevocationData = (VOID *) ALIGN_POINTER ( + ((UINT8 *) (PadData + 1) + PadData->AuthDataSize), + sizeof (UINTN) + ); + CopyMem ( + PadData->RevocationData, + PadEntry->Data->RevocationData, + PadData->RevocationDataSize + ); + } else { + + PadData->RevocationDataSize = 0; + PadData->RevocationData = NULL; + } + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Copy Source Process Policy to the Destination Process Policy. + + @param[in] Dst Pointer to the Source Process Policy. + @param[in] Src Pointer to the Destination Process Policy. + +**/ +VOID +IpSecDuplicateProcessPolicy ( + IN EFI_IPSEC_PROCESS_POLICY *Dst, + IN EFI_IPSEC_PROCESS_POLICY *Src + ) +{ + // + // Firstly copy the structure content itself. + // + CopyMem (Dst, Src, sizeof (EFI_IPSEC_PROCESS_POLICY)); + + // + // Recursively copy the tunnel option if needed. + // + if (Dst->Mode != EfiIPsecTunnel) { + ASSERT (Dst->TunnelOption == NULL); + } else { + Dst->TunnelOption = (EFI_IPSEC_TUNNEL_OPTION *) ALIGN_POINTER ((Dst + 1), sizeof (UINTN)); + CopyMem ( + Dst->TunnelOption, + Src->TunnelOption, + sizeof (EFI_IPSEC_TUNNEL_OPTION) + ); + } +} + +/** + Calculate the a whole size of EFI_IPSEC_SPD_DATA, which includes the buffer size pointed + to by the pointer members. + + @param[in] SpdData Pointer to a specified EFI_IPSEC_SPD_DATA. + + @return the whole size the specified EFI_IPSEC_SPD_DATA. + +**/ +UINTN +IpSecGetSizeOfEfiSpdData ( + IN EFI_IPSEC_SPD_DATA *SpdData + ) +{ + UINTN Size; + + Size = ALIGN_VARIABLE (sizeof (IPSEC_SPD_DATA)); + + if (SpdData->Action == EfiIPsecActionProtect) { + Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_PROCESS_POLICY)); + + if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) { + Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_TUNNEL_OPTION)); + } + } + + return Size; +} + +/** + Calculate the a whole size of IPSEC_SPD_DATA which includes the buffer size pointed + to by the pointer members and the buffer size used by the Sa List. + + @param[in] SpdData Pointer to the specified IPSEC_SPD_DATA. + + @return the whole size of IPSEC_SPD_DATA. + +**/ +UINTN +IpSecGetSizeOfSpdData ( + IN IPSEC_SPD_DATA *SpdData + ) +{ + UINTN Size; + LIST_ENTRY *Link; + + Size = sizeof (EFI_IPSEC_SPD_DATA) - sizeof (EFI_IPSEC_SA_ID); + + if (SpdData->Action == EfiIPsecActionProtect) { + Size += sizeof (EFI_IPSEC_PROCESS_POLICY); + + if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) { + Size += sizeof (EFI_IPSEC_TUNNEL_OPTION); + } + } + + NET_LIST_FOR_EACH (Link, &SpdData->Sas) { + Size += sizeof (EFI_IPSEC_SA_ID); + } + + return Size; +} + +/** + Get the IPsec Variable. + + Get the all variables which start with the string contained in VaraiableName. + Since all IPsec related variable store in continual space, those kinds of + variable can be searched by the EfiGetNextVariableName. Those variables also are + returned in a continual buffer. + + @param[in] VariableName Pointer to a specified Variable Name. + @param[in] VendorGuid Pointer to a specified Vendor Guid. + @param[in] Attributes Point to memory location to return the attributes + of variable. If the point is NULL, the parameter + would be ignored. + @param[in, out] DataSize As input, point to the maximum size of return + Data-Buffer. As output, point to the actual + size of the returned Data-Buffer. + @param[in] Data Point to return Data-Buffer. + + @retval EFI_ABORTED If the Variable size which contained in the variable + structure doesn't match the variable size obtained + from the EFIGetVariable. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has + been updated with the size needed to complete the request. + @retval EFI_SUCCESS The function completed successfully. + @retval others Other errors found during the variable getting. +**/ +EFI_STATUS +IpSecGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 *Attributes, OPTIONAL + IN OUT UINTN *DataSize, + IN VOID *Data + ) +{ + EFI_STATUS Status; + EFI_GUID VendorGuidI; + UINTN VariableNameLength; + CHAR16 *VariableNameI; + UINTN VariableNameISize; + UINTN VariableNameISizeNew; + UINTN VariableIndex; + UINTN VariableCount; + IP_SEC_VARIABLE_INFO IpSecVariableInfo; + UINTN DataSizeI; + + // + // The variable name constructor is "VariableName + Info/0001/0002/... + NULL". + // So the varialbe name is like "VariableNameInfo", "VariableName0001", ... + // "VariableNameNULL". + // + VariableNameLength = StrLen (VariableName); + VariableNameISize = (VariableNameLength + 5) * sizeof (CHAR16); + VariableNameI = AllocateZeroPool (VariableNameISize); + ASSERT (VariableNameI != NULL); + + // + // Construct the varible name of ipsecconfig meta data. + // + UnicodeSPrint (VariableNameI, VariableNameISize, L"%s%s", VariableName, L"Info"); + + DataSizeI = sizeof (IpSecVariableInfo); + + Status = gRT->GetVariable ( + VariableNameI, + VendorGuid, + Attributes, + &DataSizeI, + &IpSecVariableInfo + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (*DataSize < IpSecVariableInfo.VariableSize) { + *DataSize = IpSecVariableInfo.VariableSize; + Status = EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + + VariableCount = IpSecVariableInfo.VariableCount; + VariableNameI[0] = L'\0'; + + while (VariableCount != 0) { + // + // Get the variable name one by one in the variable database. + // + VariableNameISizeNew = VariableNameISize; + Status = gRT->GetNextVariableName ( + &VariableNameISizeNew, + VariableNameI, + &VendorGuidI + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + VariableNameI = ReallocatePool ( + VariableNameISize, + VariableNameISizeNew, + VariableNameI + ); + VariableNameISize = VariableNameISizeNew; + + Status = gRT->GetNextVariableName ( + &VariableNameISizeNew, + VariableNameI, + &VendorGuidI + ); + } + + if (EFI_ERROR (Status)) { + break; + } + // + // Check whether the current variable is the required "ipsecconfig". + // + if (StrnCmp (VariableNameI, VariableName, VariableNameLength) == 0 || + CompareGuid (VendorGuid, &VendorGuidI) + ) { + // + // Parse the variable count of the current ipsecconfig data. + // + VariableIndex = StrDecimalToUintn (VariableNameI + VariableNameLength); + if (VariableIndex!= 0 && VariableIndex <= IpSecVariableInfo.VariableCount) { + // + // Get the variable size of the current ipsecconfig data. + // + DataSizeI = 0; + Status = gRT->GetVariable ( + VariableNameI, + VendorGuid, + Attributes, + &DataSizeI, + NULL + ); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + // + // Validate the variable count and variable size. + // + if (VariableIndex != IpSecVariableInfo.VariableCount) { + // + // If the varaibe is not the last one, its size should be the max + // size of the single variable. + // + if (DataSizeI != IpSecVariableInfo.SingleVariableSize) { + return EFI_ABORTED; + } + } else { + if (DataSizeI != IpSecVariableInfo.VariableSize % IpSecVariableInfo.SingleVariableSize) { + return EFI_ABORTED; + } + } + // + // Get the variable data of the current ipsecconfig data and + // store it into user buffer continously. + // + Status = gRT->GetVariable ( + VariableNameI, + VendorGuid, + Attributes, + &DataSizeI, + (UINT8 *) Data + (VariableIndex - 1) * IpSecVariableInfo.SingleVariableSize + ); + ASSERT_EFI_ERROR (Status); + VariableCount--; + } + } + } + // + // The VariableCount in "VariableNameInfo" varaible should have the correct + // numbers of variables which name starts with VariableName. + // + if (VariableCount != 0) { + Status = EFI_ABORTED; + } + +ON_EXIT: + FreePool (VariableNameI); + return Status; +} + +/** + Set the IPsec variables. + + Set all IPsec variables which start with the specified variable name. Those variables + are set one by one. + + @param[in] VariableName The name of the vendor's variable. It is a + Null-Terminated Unicode String. + @param[in] VendorGuid Unify identifier for vendor. + @param[in] Attributes Point to memory location to return the attributes of + variable. If the point is NULL, the parameter would be ignored. + @param[in] DataSize The size in bytes of Data-Buffer. + @param[in] Data Points to the content of the variable. + + @retval EFI_SUCCESS The firmware successfully stored the variable and its data, as + defined by the Attributes. + @retval others Storing the variables failed. + +**/ +EFI_STATUS +IpSecSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + EFI_STATUS Status; + CHAR16 *VariableNameI; + UINTN VariableNameSize; + UINTN VariableIndex; + IP_SEC_VARIABLE_INFO IpSecVariableInfo; + UINT64 MaximumVariableStorageSize; + UINT64 RemainingVariableStorageSize; + UINT64 MaximumVariableSize; + + Status = gRT->QueryVariableInfo ( + Attributes, + &MaximumVariableStorageSize, + &RemainingVariableStorageSize, + &MaximumVariableSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // "VariableName + Info/0001/0002/... + NULL" + // + VariableNameSize = (StrLen (VariableName) + 5) * sizeof (CHAR16); + VariableNameI = AllocateZeroPool (VariableNameSize); + + if (VariableNameI == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + // + // Construct the variable of ipsecconfig general information. Like the total + // numbers of the Ipsecconfig variables, the total size of all ipsecconfig variables. + // + UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%s", VariableName, L"Info"); + MaximumVariableSize -= VariableNameSize; + + IpSecVariableInfo.VariableCount = (UINT32) ((DataSize + (UINTN) MaximumVariableSize - 1) / (UINTN) MaximumVariableSize); + IpSecVariableInfo.VariableSize = (UINT32) DataSize; + IpSecVariableInfo.SingleVariableSize = (UINT32) MaximumVariableSize; + + // + // Set the variable of ipsecconfig general information. + // + Status = gRT->SetVariable ( + VariableNameI, + VendorGuid, + Attributes, + sizeof (IpSecVariableInfo), + &IpSecVariableInfo + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error set ipsecconfig meta data with %r\n", Status)); + goto ON_EXIT; + } + + for (VariableIndex = 0; VariableIndex < IpSecVariableInfo.VariableCount; VariableIndex++) { + // + // Construct and set the variable of ipsecconfig data one by one. + // The index of variable name begin from 0001, and the varaible name + // likes "VariableName0001", "VaraiableName0002".... + // + UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%04d", VariableName, VariableIndex + 1); + Status = gRT->SetVariable ( + VariableNameI, + VendorGuid, + Attributes, + (VariableIndex == IpSecVariableInfo.VariableCount - 1) ? + (DataSize % (UINTN) MaximumVariableSize) : + (UINTN) MaximumVariableSize, + (UINT8 *) Data + VariableIndex * (UINTN) MaximumVariableSize + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error set ipsecconfig variable data with %r\n", Status)); + goto ON_EXIT; + } + } + +ON_EXIT: + if (VariableNameI != NULL) { + FreePool (VariableNameI); + } + + return Status; +} + +/** + Return the configuration value for the EFI IPsec driver. + + This function lookup the data entry from IPsec database or IKEv2 configuration + information. The expected data type and unique identification are described in + DataType and Selector parameters. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to retrieve. + @param[in] Selector Pointer to an entry selector that is an identifier of the IPsec + configuration data entry. + @param[in, out] DataSize On output the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec configuration data. + The type of the data buffer associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + - This is NULL. + - Selector is NULL. + - DataSize is NULL. + - Data is NULL and *DataSize is not zero + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_UNSUPPORTED The specified DataType is not supported. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigGetData ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + if (This == NULL || Selector == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (*DataSize != 0 && Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (DataType >= IPsecConfigDataTypeMaximum) { + return EFI_UNSUPPORTED; + } + + return mGetPolicyEntry[DataType](Selector, DataSize, Data); +} + +/** + Set the security association, security policy and peer authorization configuration + information for the EFI IPsec driver. + + This function is used to set the IPsec configuration information of type DataType for + the EFI IPsec driver. + The IPsec configuration data has a unique selector/identifier separately to identify + a data entry. The selector structure depends on DataType's definition. + Using SetData() with a Data of NULL causes the IPsec configuration data entry identified + by DataType and Selector to be deleted. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to be set. + @param[in] Selector Pointer to an entry selector on operated configuration data + specified by DataType. A NULL Selector causes the entire + specified-type configuration information to be flushed. + @param[in] Data The data buffer to be set. The structure of the data buffer is + associated with the DataType. + @param[in] InsertBefore Pointer to one entry selector which describes the expected + position the new data entry will be added. If InsertBefore is NULL, + the new entry will be appended to the end of the database. + + @retval EFI_SUCCESS The specified configuration entry data was set successfully. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + @retval EFI_UNSUPPORTED The specified DataType is not supported. + @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigSetData ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN EFI_IPSEC_CONFIG_SELECTOR *InsertBefore OPTIONAL + ) +{ + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (DataType >= IPsecConfigDataTypeMaximum) { + return EFI_UNSUPPORTED; + } + + Status = mSetPolicyEntry[DataType](Selector, Data, InsertBefore); + + if (!EFI_ERROR (Status) && !mSetBySelf) { + // + // Save the updated config data into variable. + // + IpSecConfigSave (); + } + + return Status; +} + +/** + Enumerates the current selector for IPsec configuration data entry. + + This function is called multiple times to retrieve the entry Selector in IPsec + configuration database. On each call to GetNextSelector(), the next entry + Selector are retrieved into the output interface. + + If the entire IPsec configuration database has been iterated, the error + EFI_NOT_FOUND is returned. + If the Selector buffer is too small for the next Selector copy, an + EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect + the size of buffer needed. + + On the initial call to GetNextSelector() to start the IPsec configuration database + search, a pointer to the buffer with all zero value is passed in Selector. Calls + to SetData() between calls to GetNextSelector may produce unpredictable results. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The type of IPsec configuration data to retrieve. + @param[in, out] SelectorSize The size of the Selector buffer. + @param[in, out] Selector On input, supplies the pointer to last Selector that was + returned by GetNextSelector(). + On output, returns one copy of the current entry Selector + of a given DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + - This is NULL. + - SelectorSize is NULL. + - Selector is NULL. + @retval EFI_NOT_FOUND The next configuration data entry was not found. + @retval EFI_UNSUPPORTED The specified DataType is not supported. + @retval EFI_BUFFER_TOO_SMALL The SelectorSize is too small for the result. This parameter + has been updated with the size needed to complete the search + request. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigGetNextSelector ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN OUT UINTN *SelectorSize, + IN OUT EFI_IPSEC_CONFIG_SELECTOR *Selector + ) +{ + LIST_ENTRY *Link; + IPSEC_COMMON_POLICY_ENTRY *CommonEntry; + BOOLEAN IsFound; + + if (This == NULL || Selector == NULL || SelectorSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (DataType >= IPsecConfigDataTypeMaximum) { + return EFI_UNSUPPORTED; + } + + IsFound = FALSE; + + NET_LIST_FOR_EACH (Link, &mConfigData[DataType]) { + CommonEntry = BASE_CR (Link, IPSEC_COMMON_POLICY_ENTRY, List); + + if (IsFound || mIsZeroSelector[DataType](Selector)) { + // + // If found the appointed entry, then duplicate the next one and return, + // or if the appointed entry is zero, then return the first one directly. + // + return mDuplicateSelector[DataType](Selector, CommonEntry->Selector, SelectorSize); + } else { + // + // Set the flag if find the appointed entry. + // + IsFound = mCompareSelector[DataType](Selector, CommonEntry->Selector); + } + } + + return EFI_NOT_FOUND; +} + +/** + Register an event that is to be signaled whenever a configuration process on the + specified IPsec configuration information is done. + + The register function is not surpport now and always returns EFI_UNSUPPORTED. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to be registered the event for. + @param[in] Event The event to be registered. + + @retval EFI_SUCCESS The event is registered successfully. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. + @retval EFI_UNSUPPORTED The notify registration is unsupported, or the specified + DataType is not supported. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigRegisterNotify ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN EFI_EVENT Event + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Remove the specified event that was previously registered on the specified IPsec + configuration data. + + This function is not support now and alwasy return EFI_UNSUPPORTED. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The configuration data type to remove the registered event for. + @param[in] Event The event to be unregistered. + + @retval EFI_SUCCESS The event was removed successfully. + @retval EFI_NOT_FOUND The Event specified by DataType could not be found in the + database. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_UNSUPPORTED The notify registration is unsupported, or the specified + DataType is not supported. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigUnregisterNotify ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN EFI_EVENT Event + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Copy whole data in specified EFI_SIPEC_CONFIG_SELECTOR and the Data to a buffer. + + This function is a caller defined function, and it is called by the IpSecVisitConfigData(). + The orignal caller is IpSecConfigSave(), which calls the IpsecVisitConfigData() to + copy all types of IPsec Config datas into one buffer and store this buffer into firmware in + the form of several variables. + + @param[in] Type A specified IPSEC_CONFIG_DATA_TYPE. + @param[in] Selector Points to a EFI_IPSEC_CONFIG_SELECTOR to be copied + to the buffer. + @param[in] Data Points to data to be copied to the buffer. The + Data type is related to the Type. + @param[in] SelectorSize The size of the Selector. + @param[in] DataSize The size of the Data. + @param[in, out] Buffer The buffer to store the Selector and Data. + + @retval EFI_SUCCESS Copy the Selector and Data to a buffer successfully. + @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated. + +**/ +EFI_STATUS +IpSecCopyPolicyEntry ( + IN EFI_IPSEC_CONFIG_DATA_TYPE Type, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN UINTN SelectorSize, + IN UINTN DataSize, + IN OUT IPSEC_VARIABLE_BUFFER *Buffer + ) +{ + IPSEC_VAR_ITEM_HEADER SelectorHeader; + IPSEC_VAR_ITEM_HEADER DataHeader; + UINTN EntrySize; + UINT8 *TempPoint; + + if (Type == IPsecConfigDataTypeSad) { + // + // Don't save automatically-generated sa entry into variable. + // + if (((EFI_IPSEC_SA_DATA *) Data)->ManualSet == FALSE) { + return EFI_SUCCESS; + } + } + // + // Increase the capacity size of the buffer if needed. + // + EntrySize = ALIGN_VARIABLE (sizeof (SelectorHeader)); + EntrySize = ALIGN_VARIABLE (EntrySize + SelectorSize); + EntrySize = ALIGN_VARIABLE (EntrySize + sizeof (SelectorHeader)); + EntrySize = ALIGN_VARIABLE (EntrySize + DataSize); + + //EntrySize = SelectorSize + DataSize + 2 * sizeof (SelectorHeader); + if (Buffer->Capacity - Buffer->Size < EntrySize) { + // + // Calculate the required buffer + // + Buffer->Capacity += EntrySize; + TempPoint = AllocatePool (Buffer->Capacity); + + if (Buffer->Ptr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Copy the old Buffer to new buffer and free the old one. + // + CopyMem (TempPoint, Buffer->Ptr, Buffer->Size); + FreePool (Buffer->Ptr); + + Buffer->Ptr = TempPoint; + } + + mFixPolicyEntry[Type](Selector, Data); + + // + // Fill the selector header and copy it into buffer. + // + SelectorHeader.Type = (UINT8) (Type | IPSEC_VAR_ITEM_HEADER_LOGO_BIT); + SelectorHeader.Size = (UINT16) SelectorSize; + + CopyMem ( + Buffer->Ptr + Buffer->Size, + &SelectorHeader, + sizeof (SelectorHeader) + ); + Buffer->Size = ALIGN_VARIABLE (Buffer->Size + sizeof (SelectorHeader)); + + // + // Copy the selector into buffer. + // + CopyMem ( + Buffer->Ptr + Buffer->Size, + Selector, + SelectorSize + ); + Buffer->Size = ALIGN_VARIABLE (Buffer->Size + SelectorSize); + + // + // Fill the data header and copy it into buffer. + // + DataHeader.Type = (UINT8) Type; + DataHeader.Size = (UINT16) DataSize; + + CopyMem ( + Buffer->Ptr + Buffer->Size, + &DataHeader, + sizeof (DataHeader) + ); + Buffer->Size = ALIGN_VARIABLE (Buffer->Size + sizeof (DataHeader)); + // + // Copy the data into buffer. + // + CopyMem ( + Buffer->Ptr + Buffer->Size, + Data, + DataSize + ); + Buffer->Size = ALIGN_VARIABLE (Buffer->Size + DataSize); + + mUnfixPolicyEntry[Type](Selector, Data); + + return EFI_SUCCESS; +} + +/** + Visit all IPsec Configurations of specified Type and call the caller defined + interface. + + @param[in] DataType The specified IPsec Config Data Type. + @param[in] Routine The function defined by the caller. + @param[in] Context The data passed to the Routine. + + @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated + @retval EFI_SUCCESS This function completed successfully. + +**/ +EFI_STATUS +IpSecVisitConfigData ( + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN IPSEC_COPY_POLICY_ENTRY Routine, + IN VOID *Context + ) +{ + EFI_STATUS GetNextStatus; + EFI_STATUS GetDataStatus; + EFI_STATUS RoutineStatus; + EFI_IPSEC_CONFIG_SELECTOR *Selector; + VOID *Data; + UINTN SelectorSize; + UINTN DataSize; + UINTN SelectorBufferSize; + UINTN DataBufferSize; + BOOLEAN FirstGetNext; + + FirstGetNext = TRUE; + DataBufferSize = 0; + Data = NULL; + SelectorBufferSize = sizeof (EFI_IPSEC_CONFIG_SELECTOR); + Selector = AllocateZeroPool (SelectorBufferSize); + + if (Selector == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + while (TRUE) { + // + // Get the real size of the selector. + // + SelectorSize = SelectorBufferSize; + GetNextStatus = EfiIpSecConfigGetNextSelector ( + &mIpSecConfigInstance, + DataType, + &SelectorSize, + Selector + ); + if (GetNextStatus == EFI_BUFFER_TOO_SMALL) { + FreePool (Selector); + SelectorBufferSize = SelectorSize; + // + // Allocate zero pool for the first selector, while store the last + // selector content for the other selectors. + // + if (FirstGetNext) { + Selector = AllocateZeroPool (SelectorBufferSize); + } else { + Selector = AllocateCopyPool (SelectorBufferSize, Selector); + } + + if (Selector == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Get the content of the selector. + // + GetNextStatus = EfiIpSecConfigGetNextSelector ( + &mIpSecConfigInstance, + DataType, + &SelectorSize, + Selector + ); + } + + if (EFI_ERROR (GetNextStatus)) { + break; + } + + FirstGetNext = FALSE; + + // + // Get the real size of the policy entry according to the selector. + // + DataSize = DataBufferSize; + GetDataStatus = EfiIpSecConfigGetData ( + &mIpSecConfigInstance, + DataType, + Selector, + &DataSize, + Data + ); + if (GetDataStatus == EFI_BUFFER_TOO_SMALL) { + if (Data != NULL) { + FreePool (Data); + } + + DataBufferSize = DataSize; + Data = AllocateZeroPool (DataBufferSize); + + if (Data == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Get the content of the policy entry according to the selector. + // + GetDataStatus = EfiIpSecConfigGetData ( + &mIpSecConfigInstance, + DataType, + Selector, + &DataSize, + Data + ); + } + + if (EFI_ERROR (GetDataStatus)) { + break; + } + // + // Prepare the buffer of updated policy entry, which is stored in + // the continous memory, and then save into variable later. + // + RoutineStatus = Routine ( + DataType, + Selector, + Data, + SelectorSize, + DataSize, + Context + ); + if (EFI_ERROR (RoutineStatus)) { + break; + } + } + + if (Data != NULL) { + FreePool (Data); + } + + if (Selector != NULL) { + FreePool (Selector); + } + + return EFI_SUCCESS; +} + +/** + This function is the subfunction of EFIIpSecConfigSetData. + + This function call IpSecSetVaraible to set the IPsec Configuration into the firmware. + + @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated. + @retval EFI_SUCCESS Saved the configration successfully. + @retval Others Other errors were found while obtaining the variable. + +**/ +EFI_STATUS +IpSecConfigSave ( + VOID + ) +{ + IPSEC_VARIABLE_BUFFER Buffer; + EFI_STATUS Status; + EFI_IPSEC_CONFIG_DATA_TYPE Type; + + Buffer.Size = 0; + Buffer.Capacity = IPSEC_DEFAULT_VARIABLE_SIZE; + Buffer.Ptr = AllocateZeroPool (Buffer.Capacity); + + if (Buffer.Ptr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // For each policy database, prepare the contious buffer to save into variable. + // + for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) { + IpSecVisitConfigData ( + Type, + (IPSEC_COPY_POLICY_ENTRY) IpSecCopyPolicyEntry, + &Buffer + ); + } + // + // Save the updated policy database into variable. + // + Status = IpSecSetVariable ( + IPSECCONFIG_VARIABLE_NAME, + &gEfiIpSecConfigProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + Buffer.Size, + Buffer.Ptr + ); + + FreePool (Buffer.Ptr); + + return Status; +} + +/** + Get the all IPSec configuration variables and store those variables + to the internal data structure. + + This founction is called by IpSecConfigInitialize() which is to intialize the + IPsecConfiguration Protocol. + + @param[in] Private Point to IPSEC_PRIVATE_DATA. + + @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated + @retval EFI_SUCCESS Restore the IPsec Configuration successfully. + @retval others Other errors is found while obtaining the variable. + +**/ +EFI_STATUS +IpSecConfigRestore ( + IN IPSEC_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + UINT8 *Buffer; + IPSEC_VAR_ITEM_HEADER *Header; + UINT8 *Ptr; + EFI_IPSEC_CONFIG_SELECTOR *Selector; + EFI_IPSEC_CONFIG_DATA_TYPE Type; + VOID *Data; + UINT8 Value; + UINTN Size; + + Value = 0; + Size = sizeof (Value); + BufferSize = 0; + Buffer = NULL; + + Status = gRT->GetVariable ( + IPSECCONFIG_STATUS_NAME, + &gEfiIpSecConfigProtocolGuid, + NULL, + &Size, + &Value + ); + + if (!EFI_ERROR (Status) && Value == IPSEC_STATUS_ENABLED) { + Private->IpSec.DisabledFlag = FALSE; + } + // + // Get the real size of policy database in variable. + // + Status = IpSecGetVariable ( + IPSECCONFIG_VARIABLE_NAME, + &gEfiIpSecConfigProtocolGuid, + NULL, + &BufferSize, + Buffer + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + + Buffer = AllocateZeroPool (BufferSize); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Get the content of policy database in variable. + // + Status = IpSecGetVariable ( + IPSECCONFIG_VARIABLE_NAME, + &gEfiIpSecConfigProtocolGuid, + NULL, + &BufferSize, + Buffer + ); + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + for (Ptr = Buffer; Ptr < Buffer + BufferSize;) { + + Header = (IPSEC_VAR_ITEM_HEADER *) Ptr; + Type = (EFI_IPSEC_CONFIG_DATA_TYPE) (Header->Type & IPSEC_VAR_ITEM_HEADER_CONTENT_BIT); + ASSERT (((Header->Type & 0x80) == IPSEC_VAR_ITEM_HEADER_LOGO_BIT) && (Type < IPsecConfigDataTypeMaximum)); + + Selector = (EFI_IPSEC_CONFIG_SELECTOR *) ALIGN_POINTER (Header + 1, sizeof (UINTN)); + Header = (IPSEC_VAR_ITEM_HEADER *) ALIGN_POINTER ( + (UINT8 *) Selector + Header->Size, + sizeof (UINTN) + ); + ASSERT (Header->Type == Type); + + Data = ALIGN_POINTER (Header + 1, sizeof (UINTN)); + + mUnfixPolicyEntry[Type](Selector, Data); + + // + // Update each policy entry according to the content in variable. + // + mSetBySelf = TRUE; + Status = EfiIpSecConfigSetData ( + &Private->IpSecConfig, + Type, + Selector, + Data, + NULL + ); + mSetBySelf = FALSE; + + if (EFI_ERROR (Status)) { + FreePool (Buffer); + return Status; + } + + Ptr = ALIGN_POINTER ((UINT8 *) Data + Header->Size, sizeof (UINTN)); + } + + FreePool (Buffer); + } + + return EFI_SUCCESS; +} + +/** + Install and Initialize IPsecConfig protocol + + @param[in, out] Private Pointer to IPSEC_PRIVATE_DATA. After this function finish, + the pointer of IPsecConfig Protocol implementation will copy + into its IPsecConfig member. + + @retval EFI_SUCCESS Initialized the IPsecConfig Protocol successfully. + @retval Others Initializing the IPsecConfig Protocol failed. +**/ +EFI_STATUS +IpSecConfigInitialize ( + IN OUT IPSEC_PRIVATE_DATA *Private + ) +{ + EFI_IPSEC_CONFIG_DATA_TYPE Type; + + CopyMem ( + &Private->IpSecConfig, + &mIpSecConfigInstance, + sizeof (EFI_IPSEC_CONFIG_PROTOCOL) + ); + + // + // Initialize the list head of policy database. + // + for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) { + InitializeListHead (&mConfigData[Type]); + } + // + // Restore the content of policy database according to the variable. + // + IpSecConfigRestore (Private); + + return gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiIpSecConfigProtocolGuid, + &Private->IpSecConfig, + NULL + ); +} diff --git a/NetworkPkg/IpSecDxe/IpSecConfigImpl.h b/NetworkPkg/IpSecDxe/IpSecConfigImpl.h new file mode 100644 index 0000000000..54d43bd01c --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecConfigImpl.h @@ -0,0 +1,952 @@ +/** @file + Definitions related to IPSEC_CONFIG_PROTOCOL implementations. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _IPSEC_CONFIG_IMPL_H_ +#define _IPSEC_CONFIG_IMPL_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "IpSecImpl.h" + +#define EFI_IPSEC_ANY_PROTOCOL 0xFFFF +#define EFI_IPSEC_ANY_PORT 0 + +#define IPSEC_VAR_ITEM_HEADER_LOGO_BIT 0x80 +#define IPSEC_VAR_ITEM_HEADER_CONTENT_BIT 0x7F + +#define IPSECCONFIG_VARIABLE_NAME L"IpSecConfig" +#define IPSECCONFIG_STATUS_NAME L"IpSecStatus" + +#define SIZE_OF_SPD_SELECTOR(x) (UINTN) (sizeof (EFI_IPSEC_SPD_SELECTOR) \ + + sizeof (EFI_IP_ADDRESS_INFO) * ((x)->LocalAddressCount + (x)->RemoteAddressCount)) + +#define FIX_REF_BUF_ADDR(addr, base) addr = (VOID *) ((UINTN) (addr) - (UINTN) (base)) +#define UNFIX_REF_BUF_ADDR(addr, base) addr = (VOID *) ((UINTN) (addr) + (UINTN) (base)) + +// +// The data structure used to store the genernall information of IPsec configuration. +// +typedef struct { + UINT32 VariableCount; // the total number of the IPsecConfig variables. + UINT32 VariableSize; // The total size of all IpsecConfig variables. + UINT32 SingleVariableSize; // The max size of single variable +} IP_SEC_VARIABLE_INFO; + +typedef struct { + EFI_IPSEC_CONFIG_SELECTOR *Selector; + VOID *Data; + LIST_ENTRY List; +} IPSEC_COMMON_POLICY_ENTRY; + +typedef struct { + UINT8 *Ptr; + UINTN Size; + UINTN Capacity; +} IPSEC_VARIABLE_BUFFER; + +#pragma pack(1) +typedef struct { + UINT8 Type; + UINT16 Size; +} IPSEC_VAR_ITEM_HEADER; +#pragma pack() + +/** + The prototype of Copy Source Selector to the Destination Selector. + + @param[in out] DstSel Pointer of Destination Selector. It would be + SPD Selector, or SAD Selector or PAD Selector. + @param[in] SrcSel Pointer of Source Selector. It would be + SPD Selector, or SAD Selector or PAD Selector. + @param[in out] Size The size of the Destination Selector. If it + is not NULL and its value is less than the size of + Source Selector, the value of Source Selector's + size will be passed to the caller by this parameter. + + @retval EFI_INVALID_PARAMETER If the Destination or Source Selector is NULL. + @retval EFI_BUFFER_TOO_SMALL If the input Size is less than size of Source Selector. + @retval EFI_SUCCESS Copy Source Selector to the Destination + Selector successfully. + +**/ +typedef +EFI_STATUS +(*IPSEC_DUPLICATE_SELECTOR) ( + IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel, + IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel, + IN OUT UINTN *Size + ); + +/** + It is prototype of compare two Selectors. The Selector would be SPD Selector, + or SAD Selector, or PAD selector. + + @param[in] Selector1 Pointer of the first Selector. + @param[in] Selector2 Pointer of the second Selector. + + @retval TRUE These two Selectors have the same value in certain fields. + @retval FALSE Not all fields have the same value in these two Selectors. + +**/ +typedef +BOOLEAN +(*IPSEC_COMPARE_SELECTOR) ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ); + +/** + The prototype of a function to check if the Selector is Zero by its certain fields. + + @param[in] Selector Pointer of the Selector. + + @retval TRUE If the Selector is Zero. + @retval FALSE If the Selector is not Zero. + +**/ +typedef +BOOLEAN +(*IPSEC_IS_ZERO_SELECTOR) ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector + ); + +/** + The prototype of a function to fix the value of particular members of the Selector. + + @param[in] Selector Pointer of Selector. + @param[in] Data Pointer of Data. + +**/ +typedef +VOID +(*IPSEC_FIX_POLICY_ENTRY) ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data + ); + +/** + It is prototype function to define a routine function by the caller of IpSecVisitConfigData(). + + @param[in] Type A specified IPSEC_CONFIG_DATA_TYPE. + @param[in] Selector Points to EFI_IPSEC_CONFIG_SELECTOR to be copied + to the buffer. + @param[in] Data Points to data to be copied to the buffer. The + Data type is related to the Type. + @param[in] SelectorSize The size of the Selector. + @param[in] DataSize The size of the Data. + @param[in out] Buffer The buffer to store the Selector and Data. + + @retval EFI_SUCCESS Copied the Selector and Data to a buffer successfully. + @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated. + +**/ +typedef +EFI_STATUS +(*IPSEC_COPY_POLICY_ENTRY) ( + IN EFI_IPSEC_CONFIG_DATA_TYPE Type, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN UINTN SelectorSize, + IN UINTN DataSize, + IN OUT VOID *Context + ); + +/** + Set the security policy information for the EFI IPsec driver. + + The IPsec configuration data has a unique selector/identifier separately to + identify a data entry. + + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type + configuration information to be flushed. + @param[in] Data The data buffer to be set. + @param[in] Context Pointer to one entry selector that describes + the expected position the new data entry will + be added. If Context is NULL, the new entry will + be appended to the end of the database. + + @retval EFI_INVALID_PARAMETER Certain Parameters are not correct. The Parameter + requiring a check depends on the Selector type. + @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + +**/ +typedef +EFI_STATUS +(*IPSEC_SET_POLICY_ENTRY) ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN VOID *Context OPTIONAL + ); + +/** + A prototype function definition to lookup the data entry from IPsec. Return the configuration + value of the specified Entry. + + @param[in] Selector Pointer to an entry selector that is an identifier + of the entry. + @param[in, out] DataSize On output, the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec + configuration data. The type of the data buffer + is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero. + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +typedef +EFI_STATUS +(*IPSEC_GET_POLICY_ENTRY) ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + IN VOID *Data + ); + +/** + Compare two SPD Selectors. + + Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/ + NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the + Local Addresses and remote Addresses. + + @param[in] Selector1 Pointer of the first SPD Selector. + @param[in] Selector2 Pointer of the second SPD Selector. + + @retval TRUE These two Selectors have the same value in above fields. + @retval FALSE Not all of the above fields have the same value in these two Selectors. + +**/ +BOOLEAN +CompareSpdSelector ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ); + + +/** + Visit all IPsec Configurations of specified Type and call the caller defined + interface. + + @param[in] DataType The specified IPsec Config Data Type. + @param[in] Routine The function caller defined. + @param[in] Context The data passed to the Routine. + + @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated. + @retval EFI_SUCCESS This function complete successfully. + +**/ +EFI_STATUS +IpSecVisitConfigData ( + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN IPSEC_COPY_POLICY_ENTRY Routine, + IN VOID *Context + ); + + +/** + This function is the subfunction of the EFIIpSecConfigSetData. + + This function call IpSecSetVaraible to set the IPsec Configuration into the firmware. + + @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated. + @retval EFI_SUCCESS Saved the configration successfully. + @retval Others Other errors were found while obtaining the variable. + +**/ +EFI_STATUS +IpSecConfigSave ( + VOID + ); + +/** + Initialize IPsecConfig protocol + + @param[in, out] Private Pointer to IPSEC_PRIVATE_DATA. After this function finish, + the pointer of IPsecConfig Protocol implementation will copy + into its IPsecConfig member. + + @retval EFI_SUCCESS Initialized the IPsecConfig Protocol successfully. + @retval Others Initializing the IPsecConfig Protocol failed. + +**/ +EFI_STATUS +IpSecConfigInitialize ( + IN OUT IPSEC_PRIVATE_DATA *Private + ); + +/** + Calculate the entire size of EFI_IPSEC_SPD_DATA, which includes the buffer size pointed + by the pointer members. + + @param[in] SpdData Pointer to a specified EFI_IPSEC_SPD_DATA. + + @return The entire size of the specified EFI_IPSEC_SPD_DATA. + +**/ +UINTN +IpSecGetSizeOfEfiSpdData ( + IN EFI_IPSEC_SPD_DATA *SpdData + ); + +/** + Calculate the a entire size of IPSEC_SPD_DATA, which includes the buffer size pointed + by the pointer members and the buffer size used by Sa List. + + @param[in] SpdData Pointer to the specified IPSEC_SPD_DATA. + + @return The entire size of IPSEC_SPD_DATA. + +**/ +UINTN +IpSecGetSizeOfSpdData ( + IN IPSEC_SPD_DATA *SpdData + ); + +/** + Copy Source Process Policy to the Destination Process Policy. + + @param[in] Dst Pointer to the Source Process Policy. + @param[in] Src Pointer to the Destination Process Policy. + +**/ +VOID +IpSecDuplicateProcessPolicy ( + IN EFI_IPSEC_PROCESS_POLICY *Dst, + IN EFI_IPSEC_PROCESS_POLICY *Src + ); + +/** + Compare two SPD Selectors. + + Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/ + NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the + Local Addresses and remote Addresses. + + @param[in] Selector1 Pointer of the first SPD Selector. + @param[in] Selector2 Pointer of the second SPD Selector. + + @retval TRUE This two Selector have the same value in above fields. + @retval FALSE Not all of the above fields have the same value in these two Selectors. + +**/ +BOOLEAN +CompareSpdSelector ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ); + +/** + Compare two SA IDs. + + @param[in] Selector1 Pointer of the first SA ID. + @param[in] Selector2 Pointer of the second SA ID. + + @retval TRUE This two Selectors have the same SA ID. + @retval FALSE This two Selecotrs don't have the same SA ID. + +**/ +BOOLEAN +CompareSaId ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ); + +/** + Compare two PAD IDs. + + @param[in] Selector1 Pointer of the first PAD ID. + @param[in] Selector2 Pointer of the second PAD ID. + + @retval TRUE This two Selectors have the same PAD ID. + @retval FALSE This two Selecotrs don't have the same PAD ID. + +**/ +BOOLEAN +ComparePadId ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector1, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector2 + ); + +/** + Check if the SPD Selector is Zero by its LocalAddressCount and RemoteAddressCount + fields. + + @param[in] Selector Pointer of the SPD Selector. + + @retval TRUE If the SPD Selector is Zero. + @retval FALSE If the SPD Selector is not Zero. + +**/ +BOOLEAN +IsZeroSpdSelector ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector + ); + +/** + Check if the SA ID is Zero by its DestAddress. + + @param[in] Selector Pointer of the SA ID. + + @retval TRUE If the SA ID is Zero. + @retval FALSE If the SA ID is not Zero. + +**/ +BOOLEAN +IsZeroSaId ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector + ); + +/** + Check if the PAD ID is Zero. + + @param[in] Selector Pointer of the PAD ID. + + @retval TRUE If the PAD ID is Zero. + @retval FALSE If the PAD ID is not Zero. + +**/ +BOOLEAN +IsZeroPadId ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector + ); + +/** + Copy Source SPD Selector to the Destination SPD Selector. + + @param[in, out] DstSel Pointer of Destination SPD Selector. + @param[in] SrcSel Pointer of Source SPD Selector. + @param[in, out] Size The size of the Destination SPD Selector. If + it is not NULL and its value is less than the + size of Source SPD Selector, the value of + Source SPD Selector's size will be passed to + the caller by this parameter. + + @retval EFI_INVALID_PARAMETER If the Destination or Source SPD Selector is NULL. + @retval EFI_BUFFER_TOO_SMALL If the input Size is less than size of Source SPD Selector. + @retval EFI_SUCCESS Copy Source SPD Selector to the Destination SPD + Selector successfully. + +**/ +EFI_STATUS +DuplicateSpdSelector ( + IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel, + IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel, + IN OUT UINTN *Size + ); + +/** + Copy Source SA ID to the Destination SA ID. + + @param[in, out] DstSel Pointer of the Destination SA ID. + @param[in] SrcSel Pointer of the Source SA ID. + @param[in, out] Size The size of the Destination SA ID. If it + not NULL, and its value is less than the size of + Source SA ID, the value of Source SA ID's size + will be passed to the caller by this parameter. + + @retval EFI_INVALID_PARAMETER If the Destination or Source SA ID is NULL. + @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source SA ID. + @retval EFI_SUCCESS Copied Source SA ID to the Destination SA ID successfully. + +**/ +EFI_STATUS +DuplicateSaId ( + IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel, + IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel, + IN OUT UINTN *Size + ); + +/** + Copy Source PAD ID to the Destination PAD ID. + + @param[in, out] DstSel Pointer of Destination PAD ID. + @param[in] SrcSel Pointer of Source PAD ID. + @param[in, out] Size The size of the Destination PAD ID. If it + not NULL, and its value less than the size of + Source PAD ID, the value of Source PAD ID's size + will be passed to the caller by this parameter. + + @retval EFI_INVALID_PARAMETER If the Destination or Source PAD ID is NULL. + @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source PAD ID. + @retval EFI_SUCCESS Copied Source PAD ID to the Destination PAD ID successfully. + +**/ +EFI_STATUS +DuplicatePadId ( + IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel, + IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel, + IN OUT UINTN *Size + ); + +/** + Fix the value of some members of the SPD Selector. + + This function is called by IpSecCopyPolicyEntry(), which copies the Policy + Entry into the Variable. Since some members in SPD Selector are pointers, + a physical address to relative address conversion is required before copying + this SPD entry into the variable. + + @param[in] Selector Pointer of SPD Selector. + @param[in, out] Data Pointer of SPD Data. + +**/ +VOID +FixSpdEntry ( + IN EFI_IPSEC_SPD_SELECTOR *Selector, + IN OUT EFI_IPSEC_SPD_DATA *Data + ); + +/** + Fix the value of some members of SA ID. + + This function is called by IpSecCopyPolicyEntry(), which copies the Policy + Entry into the Variable. Since some members in SA ID are pointers, + a physical address to relative address conversion is required before copying + this SAD into the variable. + + @param[in] SaId Pointer of SA ID. + @param[in, out] Data Pointer of SA Data. + +**/ +VOID +FixSadEntry ( + IN EFI_IPSEC_SA_ID *SaId, + IN OUT EFI_IPSEC_SA_DATA *Data + ); + +/** + Fix the value of some members of PAD ID. + + This function is called by IpSecCopyPolicyEntry(), which copy the Policy + Entry into the Variable. Since some members in PAD ID are pointers, + a physical address to relative address conversion is required before copying + this PAD into the variable. + + @param[in] PadId Pointer of PAD ID. + @param[in, out] Data Pointer of PAD Data. + +**/ +VOID +FixPadEntry ( + IN EFI_IPSEC_PAD_ID *PadId, + IN OUT EFI_IPSEC_PAD_DATA *Data + ); + +/** + Recover the value of some members of SPD Selector. + + This function is corresponding to FixSpdEntry(). It recovers the value of members + of SPD Selector which fix by the FixSpdEntry(). + + @param[in, out] Selector Pointer of SPD Selector. + @param[in, out] Data Pointer of SPD Data. + +**/ +VOID +UnfixSpdEntry ( + IN OUT EFI_IPSEC_SPD_SELECTOR *Selector, + IN OUT EFI_IPSEC_SPD_DATA *Data + ); + + +/** + Recover the value of some members of SA ID. + + This function is corresponding to FixSadEntry(). It recovers the value of members + of SAD ID which fix by the FixSadEntry(). + + @param[in, out] SaId Pointer of SAD ID + @param[in, out] Data Pointer of SAD Data. + +**/ +VOID +UnfixSadEntry ( + IN OUT EFI_IPSEC_SA_ID *SaId, + IN OUT EFI_IPSEC_SA_DATA *Data + ); + +/** + Recover the value of some members of PAD ID. + + This function is corresponding to FixPadEntry(). It recovers the value of members + of PAD ID which fix by the FixPadEntry(). + + @param[in] PadId Pointer of PAD ID + @param[in, out] Data Pointer of PAD Data. + +**/ +VOID +UnfixPadEntry ( + IN EFI_IPSEC_PAD_ID *PadId, + IN OUT EFI_IPSEC_PAD_DATA *Data + ); + +/** + Set the security policy information for the EFI IPsec driver. + + The IPsec configuration data has a unique selector/identifier separately to + identify a data entry. + + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type + configuration information to be flushed. + @param[in] Data The data buffer to be set. The structure + of the data buffer should be EFI_IPSEC_SPD_DATA. + @param[in] Context Pointer to one entry selector that describes + the expected position the new data entry will + be added. If Context is NULL,the new entry will + be appended the end of database. + + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - Selector is not NULL and its LocalAddress + is NULL or its RemoteAddress is NULL. + - Data is not NULL, its Action is Protected, + and its policy is NULL. + - Data is not NULL and its Action is not protected + and its policy is not NULL. + - The Action of Data is Protected, its policy + mode is Tunnel, and its tunnel option is NULL. + - The Action of Data is protected, its policy + mode is not Tunnel, and it tunnel option is not NULL. + @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + +**/ +EFI_STATUS +SetSpdEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN VOID *Context OPTIONAL + ); + +/** + Set the security association information for the EFI IPsec driver. + + The IPsec configuration data has a unique selector/identifier separately to + identify a data entry. + + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type + configuration information to be flushed. + @param[in] Data The data buffer to be set. The structure + of the data buffer should be EFI_IPSEC_SA_DATA. + @param[in] Context Pointer to one entry selector which describes + the expected position the new data entry will + be added. If Context is NULL,the new entry will + be appended to the end of database. + + @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + +**/ +EFI_STATUS +SetSadEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN VOID *Context OPTIONAL + ); + +/** + Set the peer authorization configuration information for the EFI IPsec driver. + + The IPsec configuration data has a unique selector/identifier separately to + identify a data entry. + + @param[in] Selector Pointer to an entry selector on operated + configuration data specified by DataType. + A NULL Selector causes the entire specified-type + configuration information to be flushed. + @param[in] Data The data buffer to be set. The structure + of the data buffer should be EFI_IPSEC_PAD_DATA. + @param[in] Context Pointer to one entry selector that describes + the expected position where the new data entry will + be added. If Context is NULL, the new entry will + be appended the end of database. + + @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + +**/ +EFI_STATUS +SetPadEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN VOID *Context OPTIONAL + ); + +/** + This function looks up the data entry from IPsec SPD, and returns the configuration + value of the specified SPD Entry. + + @param[in] Selector Pointer to an entry selector which is an identifier + of the SPD entry. + @param[in, out] DataSize On output the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec + configuration data. The type of the data buffer + is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero. + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +EFI_STATUS +GetSpdEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + This function looks up the data entry from IPsec SAD and returns the configuration + value of the specified SAD Entry. + + @param[in] Selector Pointer to an entry selector that is an identifier + of the SAD entry. + @param[in, out] DataSize On output, the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec + configuration data. This type of the data buffer + is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +EFI_STATUS +GetSadEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + This function looks up the data entry from IPsec PADand returns the configuration + value of the specified PAD Entry. + + @param[in] Selector Pointer to an entry selector that is an identifier + of the PAD entry. + @param[in, out] DataSize On output the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec + configuration data. This type of the data buffer + is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +EFI_STATUS +GetPadEntry ( + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + Return the configuration value for the EFI IPsec driver. + + This function lookup the data entry from IPsec database or IKEv2 configuration + information. The expected data type and unique identification are described in + DataType and Selector parameters. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to retrieve. + @param[in] Selector Pointer to an entry selector that is an identifier of the IPsec + configuration data entry. + @param[in, out] DataSize On output the size of data returned in Data. + @param[out] Data The buffer to return the contents of the IPsec configuration data. + The type of the data buffer is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + - This is NULL. + - Selector is NULL. + - DataSize is NULL. + - Data is NULL and *DataSize is not zero + @retval EFI_NOT_FOUND The configuration data specified by Selector is not found. + @retval EFI_UNSUPPORTED The specified DataType is not supported. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been + updated with the size needed to complete the request. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigGetData ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + Set the security association, security policy and peer authorization configuration + information for the EFI IPsec driver. + + This function is used to set the IPsec configuration information of type DataType for + the EFI IPsec driver. + The IPsec configuration data has a unique selector/identifier separately to identify + a data entry. The selector structure depends on DataType's definition. + Using SetData() with a Data of NULL causes the IPsec configuration data entry identified + by DataType and Selector to be deleted. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to be set. + @param[in] Selector Pointer to an entry selector on operated configuration data + specified by DataType. A NULL Selector causes the entire + specified-type configuration information to be flushed. + @param[in] Data The data buffer to be set. The structure of the data buffer is + associated with the DataType. + @param[in] InsertBefore Pointer to one entry selector which describes the expected + position the new data entry will be added. If InsertBefore is NULL, + the new entry will be appended the end of database. + + @retval EFI_SUCCESS The specified configuration entry data was set successfully. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + @retval EFI_UNSUPPORTED The specified DataType is not supported. + @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigSetData ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN EFI_IPSEC_CONFIG_SELECTOR *Selector, + IN VOID *Data, + IN EFI_IPSEC_CONFIG_SELECTOR *InsertBefore OPTIONAL + ); + +/** + Enumerates the current selector for IPsec configuration data entry. + + This function is called multiple times to retrieve the entry Selector in IPsec + configuration database. On each call to GetNextSelector(), the next entry + Selector are retrieved into the output interface. + + If the entire IPsec configuration database has been iterated, the error + EFI_NOT_FOUND is returned. + If the Selector buffer is too small for the next Selector copy, an + EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect + the size of buffer needed. + + On the initial call to GetNextSelector() to start the IPsec configuration database + search, a pointer to the buffer with all zero value is passed in Selector. Calls + to SetData() between calls to GetNextSelector may produce unpredictable results. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The type of IPsec configuration data to retrieve. + @param[in, out] SelectorSize The size of the Selector buffer. + @param[in, out] Selector On input, supplies the pointer to last Selector that was + returned by GetNextSelector(). + On output, returns one copy of the current entry Selector + of a given DataType. + + @retval EFI_SUCCESS The specified configuration data was obtained successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + - This is NULL. + - SelectorSize is NULL. + - Selector is NULL. + @retval EFI_NOT_FOUND The next configuration data entry was not found. + @retval EFI_UNSUPPORTED The specified DataType is not supported. + @retval EFI_BUFFER_TOO_SMALL The SelectorSize is too small for the result. This parameter + has been updated with the size needed to complete the search + request. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigGetNextSelector ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN OUT UINTN *SelectorSize, + IN OUT EFI_IPSEC_CONFIG_SELECTOR *Selector + ); + +/** + Register an event that is to be signaled whenever a configuration process on the + specified IPsec configuration information is done. + + The register function is not surpport now and always returns EFI_UNSUPPORTED. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to be registered the event for. + @param[in] Event The event to be registered. + + @retval EFI_SUCCESS The event is registered successfully. + @retval EFI_INVALID_PARAMETER This is NULL, or Event is NULL. + @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. + @retval EFI_UNSUPPORTED The notify registration unsupported, or the specified + DataType is not supported. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigRegisterNotify ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + + +/** + Remove the specified event that was previously registered on the specified IPsec + configuration data. + + This function is not supported now and always returns EFI_UNSUPPORTED. + + @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance. + @param[in] DataType The configuration data type to remove the registered event for. + @param[in] Event The event to be unregistered. + + @retval EFI_SUCCESS The event was removed successfully. + @retval EFI_NOT_FOUND The Event specified by DataType could not be found in the + database. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_UNSUPPORTED The notify registration unsupported or the specified + DataType is not supported. + +**/ +EFI_STATUS +EFIAPI +EfiIpSecConfigUnregisterNotify ( + IN EFI_IPSEC_CONFIG_PROTOCOL *This, + IN EFI_IPSEC_CONFIG_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +#endif diff --git a/NetworkPkg/IpSecDxe/IpSecCryptIo.c b/NetworkPkg/IpSecDxe/IpSecCryptIo.c new file mode 100644 index 0000000000..7011f98b06 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecCryptIo.c @@ -0,0 +1,133 @@ +/** @file + Common operation for Security. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IpSecCryptIo.h" +// +// Alogrithm's informations for the Encrypt/Decrpt Alogrithm. +// +ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = { + {EFI_IPSEC_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL}, + {(UINT8)-1, 0, 0, 0, NULL, NULL, NULL, NULL} +}; +// +// Alogrithm's informations for the Authentication algorithm +// +AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = { + {EFI_IPSEC_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL}, + {EFI_IPSEC_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL}, + {(UINT8)-1, 0, 0, 0, NULL, NULL, NULL, NULL} +}; + + +/** + Get the block size of encrypt alogrithm. The block size is based on the algorithm used. + + @param[in] AlgorithmId The encrypt algorithm ID. + + @return The value of block size. + +**/ +UINTN +IpSecGetEncryptBlockSize ( + IN UINT8 AlgorithmId + ) +{ + UINT8 Index; + + for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) { + if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) { + // + // The BlockSize is same with IvSize. + // + return mIpsecEncryptAlgorithmList[Index].BlockSize; + } + } + + return (UINTN) -1; +} + +/** + Get the IV size of encrypt alogrithm. The IV size is based on the algorithm used. + + @param[in] AlgorithmId The encrypt algorithm ID. + + @return The value of IV size. + +**/ +UINTN +IpSecGetEncryptIvLength ( + IN UINT8 AlgorithmId + ) +{ + UINT8 Index; + + for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) { + if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) { + // + // The BlockSize is same with IvSize. + // + return mIpsecEncryptAlgorithmList[Index].IvLength; + } + } + + return (UINTN) -1; +} + +/** + Get the ICV size of Authenticaion alogrithm. The ICV size is based on the algorithm used. + + @param[in] AuthAlgorithmId The Authentication algorithm ID. + + @return The value of ICV size. + +**/ +UINTN +IpSecGetIcvLength ( + IN UINT8 AuthAlgorithmId + ) +{ + UINT8 Index; + for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) { + if (AuthAlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) { + return mIpsecAuthAlgorithmList[Index].IcvLength; + } + } + return (UINTN) -1; +} + +/** + Generate a random data for IV. If the IvSize is zero, not needed to create + IV and return EFI_SUCCESS. + + @param[in] IvBuffer The pointer of the IV buffer. + @param[in] IvSize The IV size. + + @retval EFI_SUCCESS Create a random data for IV. + +**/ +EFI_STATUS +IpSecGenerateIv ( + IN UINT8 *IvBuffer, + IN UINTN IvSize + ) +{ + if (IvSize != 0) { + // + //TODO: return CryptGenerateRandom (IvBuffer, IvSize); + // + return EFI_SUCCESS; + } + return EFI_SUCCESS; +} diff --git a/NetworkPkg/IpSecDxe/IpSecCryptIo.h b/NetworkPkg/IpSecDxe/IpSecCryptIo.h new file mode 100644 index 0000000000..d883a2ef72 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecCryptIo.h @@ -0,0 +1,322 @@ +/** @file + Definition related to the Security operation. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_IPSEC_CRYPTIO_H_ +#define _EFI_IPSEC_CRYPTIO_H_ + +#include +#include + +#define IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE 2 +#define IPSEC_AUTH_ALGORITHM_LIST_SIZE 3 + +/** + Prototype of Hash GetContextSize. + + Retrieves the size, in bytes, of the context buffer required. + + @return The size, in bytes, of the context buffer required. + +**/ +typedef +UINTN +(EFIAPI *CPL_HASH_GETCONTEXTSIZE) ( + VOID + ); + +/** + Prototype of Hash Operation Initiating. + + Initialization with a new context. + + + @param[in,out] Context Input Context. + + @retval TRUE Initialization Successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *CPL_HASH_INIT) ( + IN OUT VOID *Context + ); + +/** + Prototype of HASH update. + Hash update operation. Continue an Hash message digest operation, processing + another message block, and updating the Hash context. + + If Context is NULL, then ASSERT(). + If Data is NULL, then ASSERT(). + + @param[in,out] Context The Specified Context. + @param[in,out] Data The Input Data to hash. + @param[in] DataLength The length, in bytes, of Data. + + @retval TRUE Update data successfully. + @retval FALSE The Context has been finalized. + +**/ +typedef +BOOLEAN +(EFIAPI *CPL_HASH_UPDATE) ( + IN OUT VOID *Context, + IN CONST VOID *Data, + IN UINTN DataLength + ); + +/** + Prototype of Hash finallization. + Terminate a Hash message digest operation and output the message digest. + + If Context is NULL, then ASSERT(). + If HashValue is NULL, then ASSERT(). + + @param[in,out] Context The specified Context. + @param[out] HashValue Pointer to a 16-byte message digest output buffer. + + @retval TRUE Finalized successfully. + +**/ +typedef +BOOLEAN +(EFIAPI *CPL_HASH_FINAL) ( + IN OUT VOID *Context, + OUT UINT8 *HashValue + ); + +/** + Prototype of Cipher GetContextSize. + + Retrieves the size, in bytes, of the context buffer required. + + @return The size, in bytes, of the context buffer required. + +**/ +typedef +UINTN +(EFIAPI *CPL_CIPHER_GETCONTEXTSIZE) ( + VOID + ); + +/** + Prototype of Cipher initiation. + Intializes the user-supplied key as the specifed context (key materials) for both + encryption and decryption operations. + + If Context is NULL, then ASSERT(). + If Key is NULL, then generate random key for usage. + + @param[in,out] Context The specified Context. + @param[in] Key User-supplied TDES key (64/128/192 bits). + @param[in] KeyBits Key length in bits. + + @retval TRUE TDES Initialization was successful. + +**/ +typedef +BOOLEAN +(EFIAPI *CPL_CIPHER_INIT) ( + IN OUT VOID *Context, + IN CONST UINT8 *Key, + IN CONST UINTN KeyBits + ); + + +/** + Prototype of Cipher encryption. + Encrypts plaintext message with the specified cipher. + + If Context is NULL, then ASSERT(). + if InData is NULL, then ASSERT(). + If Size of input data is not multiple of Cipher algorithm related block size, + then ASSERT(). + + @param[in] Context The specified Context. + @param[in] InData The input plaintext data to be encrypted. + @param[out] OutData The resultant encrypted ciphertext. + @param[in] DataLength Length of input data in bytes. + + @retval TRUE Encryption successful. + +**/ +typedef +BOOLEAN +(EFIAPI *CPL_CIPHER_ENCRYPT) ( + IN VOID *Context, + IN CONST UINT8 *InData, + OUT UINT8 *OutData, + IN CONST UINTN DataLength + ); + + +/** + Prototype of Cipher decryption. + Decrypts cipher message with specified cipher. + + If Context is NULL, then ASSERT(). + if InData is NULL, then ASSERT(). + If Size of input data is not a multiple of a certaion block size , then ASSERT(). + + @param[in] Context The specified Context. + @param[in] InData The input ciphertext data to be decrypted. + @param[out] OutData The resultant decrypted plaintext. + @param[in] DataLength Length of input data in bytes. + + @retval TRUE Decryption successful. + +**/ +typedef +BOOLEAN +(EFIAPI *CPL_CIPHER_DECRYPT) ( + IN CONST VOID *Context, + IN CONST UINT8 *InData, + OUT UINT8 *OutData, + IN CONST UINTN DataLength + ); + +// +// The struct used to store the informatino and operation of Cipher algorithm. +// +typedef struct _ENCRYPT_ALGORITHM { +// +// The ID of the Algorithm +// +UINT8 AlgorithmId; +// +// The Key length of the Algorithm +// +UINTN KeyLength; +// +// Iv Size of the Algorithm +// +UINTN IvLength; +// +// The Block Size of the Algorithm +// +UINTN BlockSize; +// +// The Function pointer of GetContextSize. +// +CPL_CIPHER_GETCONTEXTSIZE CipherGetContextSize; +// +// The Function pointer of Cipher intitiaion. +// +CPL_CIPHER_INIT CipherInitiate; +// +// The Function pointer of Cipher Encryption. +// +CPL_CIPHER_ENCRYPT CipherEncrypt; +// +// The Function pointer of Cipher Decrption. +// +CPL_CIPHER_DECRYPT CipherDecrypt; +} ENCRYPT_ALGORITHM; + +// +// The struct used to store the informatino and operation of Autahentication algorithm. +// +typedef struct _AUTH_ALGORITHM { + // + // ID of the Algorithm + // + UINT8 AlgorithmId; + // + // The Key length of the Algorithm + // + UINTN KeyLength; + // + // The ICV length of the Algorithm + // + UINTN IcvLength; + // + // The block size of the Algorithm + // + UINTN BlockSize; + // + // The function pointer of GetContextSize. + // + CPL_HASH_GETCONTEXTSIZE HashGetContextSize; + // + // The function pointer of Initiatoion + // + CPL_HASH_INIT HashInitiate; + // + // The function pointer of Hash Update. + // + CPL_HASH_UPDATE HashUpdate; + // + // The fucntion pointer of Hash Final + // + CPL_HASH_FINAL HashFinal; +} AUTH_ALGORITHM; + +/** + Get the IV size of encrypt alogrithm. IV size is different from different algorithm. + + @param[in] AlgorithmId The encrypt algorithm ID. + + @return The value of IV size. + +**/ +UINTN +IpSecGetEncryptIvLength ( + IN UINT8 AlgorithmId + ); + +/** + Get the block size of encrypt alogrithm. Block size is different from different algorithm. + + @param[in] AlgorithmId The encrypt algorithm ID. + + @return The value of block size. + +**/ +UINTN +IpSecGetEncryptBlockSize ( + IN UINT8 AlgorithmId + ); + +/** + Get the ICV size of Authenticaion alogrithm. ICV size is different from different algorithm. + + @param[in] AuthAlgorithmId The Authentication algorithm ID. + + @return The value of ICV size. + +**/ +UINTN +IpSecGetIcvLength ( + IN UINT8 AuthAlgorithmId + ); + +/** + Generate a random data for IV. If the IvSize is zero, not needed to create + IV and return EFI_SUCCESS. + + @param[in] IvBuffer The pointer of the IV buffer. + @param[in] IvSize The IV size. + + @retval EFI_SUCCESS Create random data for IV. + +**/ +EFI_STATUS +IpSecGenerateIv ( + IN UINT8 *IvBuffer, + IN UINTN IvSize + ); + +#endif + diff --git a/NetworkPkg/IpSecDxe/IpSecDebug.c b/NetworkPkg/IpSecDxe/IpSecDebug.c new file mode 100644 index 0000000000..8a5811b960 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecDebug.c @@ -0,0 +1,172 @@ +/** @file + Interface of IPsec printing debug information. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IpSecImpl.h" +#include "IpSecDebug.h" + +// +// The print title for IKEv1 variety phase. +// +CHAR8 *mStateStr[] = { + "IKEv1_MAIN_1", + "IKEv1_MAIN_2", + "IKEv1_MAIN_3", + "IKEv1_MAIN_ESTABLISHED", + "IKEv1_QUICK_1", + "IKEv1_QUICK_2", + "IKEv1_QUICK_ESTABLISHED" +}; +// +// The print title for IKEv1 variety Exchagne. +// +CHAR8 *mExchangeStr[] = { + "IKEv1 Main Exchange", + "IKEv1 Info Exchange", + "IKEv1 Quick Exchange", + "IKEv1 Unknown Exchange" +}; + +// +// The print title for IKEv1 variety Payload. +// +CHAR8 *mPayloadStr[] = { + "IKEv1 None Payload", + "IKEv1 SA Payload", + "IKEv1 Proposal Payload", + "IKEv1 Transform Payload", + "IKEv1 KE Payload", + "IKEv1 ID Payload", + "IKEv1 Certificate Payload", + "IKEv1 Certificate Request Payload", + "IKEv1 Hash Payload", + "IKEv1 Signature Payload", + "IKEv1 Nonce Payload", + "IKEv1 Notify Payload", + "IKEv1 Delete Payload", + "IKEv1 Vendor Payload" +}; + +/** + Print the IP address. + + @param[in] Level Debug print error level. Pass to DEBUG(). + @param[in] Ip Point to a specified IP address. + @param[in] IpVersion The IP Version. + +**/ +VOID +IpSecDumpAddress ( + IN UINTN Level, + IN EFI_IP_ADDRESS *Ip, + IN UINT8 IpVersion + ) +{ + if (IpVersion == IP_VERSION_6) { + DEBUG ( + (Level, + "%x%x:%x%x:%x%x:%x%x", + Ip->v6.Addr[0], + Ip->v6.Addr[1], + Ip->v6.Addr[2], + Ip->v6.Addr[3], + Ip->v6.Addr[4], + Ip->v6.Addr[5], + Ip->v6.Addr[6], + Ip->v6.Addr[7]) + ); + DEBUG ( + (Level, + ":%x%x:%x%x:%x%x:%x%x\n", + Ip->v6.Addr[8], + Ip->v6.Addr[9], + Ip->v6.Addr[10], + Ip->v6.Addr[11], + Ip->v6.Addr[12], + Ip->v6.Addr[13], + Ip->v6.Addr[14], + Ip->v6.Addr[15]) + ); + } else { + DEBUG ( + (Level, + "%d.%d.%d.%d\n", + Ip->v4.Addr[0], + Ip->v4.Addr[1], + Ip->v4.Addr[2], + Ip->v4.Addr[3]) + ); + } + +} + +/** + Print IKEv1 Current states. + + @param[in] Previous The Previous state of IKEv1. + @param[in] Current The current state of IKEv1. + +**/ +VOID +IpSecDumpState ( + IN UINT32 Previous, + IN UINT32 Current + ) +{ + if (Previous == Current) { + DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mStateStr[Previous])); + } else { + DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mStateStr[Previous], mStateStr[Current])); + } + +} + +/** + Print the buffer in form of Hex. + + @param[in] Title The strings to be printed before the data of the buffer. + @param[in] Data Points to buffer to be printed. + @param[in] DataSize The size of the buffer to be printed. + +**/ +VOID +IpSecDumpBuf ( + IN CHAR8 *Title, + IN UINT8 *Data, + IN UINTN DataSize + ) +{ + UINTN Index; + UINTN DataIndex; + UINTN BytesRemaining; + UINTN BytesToPrint; + + DataIndex = 0; + BytesRemaining = DataSize; + + DEBUG ((DEBUG_INFO, "==%a %d bytes==\n", Title, DataSize)); + + while (BytesRemaining > 0) { + + BytesToPrint = (BytesRemaining > IPSEC_DEBUG_BYTE_PER_LINE) ? IPSEC_DEBUG_BYTE_PER_LINE : BytesRemaining; + + for (Index = 0; Index < BytesToPrint; Index++) { + DEBUG ((DEBUG_INFO, " 0x%02x,", Data[DataIndex++])); + } + + DEBUG ((DEBUG_INFO, "\n")); + BytesRemaining -= BytesToPrint; + } + +} diff --git a/NetworkPkg/IpSecDxe/IpSecDebug.h b/NetworkPkg/IpSecDxe/IpSecDebug.h new file mode 100644 index 0000000000..0e6e6811c5 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecDebug.h @@ -0,0 +1,102 @@ +/** @file + The definition of functions and MACROs used for IPsec debug information print. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_IPSEC_DEBUG_H_ +#define _EFI_IPSEC_DEBUG_H_ + +#include + +#define IPSEC_DUMP_ADDRESS(Level, Ip, Version) IpSecDumpAddress (Level, Ip, Version) +#define IPSEC_DUMP_STATE(Previous, Current) IpSecDumpState (Previous, Current) +#define IPSEC_DUMP_PACKET(Packet, Direction, IpVersion) IpSecDumpPacket (Packet, Direction, IpVersion) +#define IPSEC_DUMP_PAYLOAD(IkePayload) IpSecDumpPayload (IkePayload) +#define IPSEC_DUMP_BUF(Title, Data, DataSize) IpSecDumpBuf (Title, Data, DataSize) + +#define IPSEC_DEBUG_BYTE_PER_LINE 8 + + +/** + Print the IP address. + + @param[in] Level Debug print error level. Pass to DEBUG(). + @param[in] Ip Point to specified IP address. + @param[in] IpVersion The IP Version. + +**/ +VOID +IpSecDumpAddress ( + IN UINTN Level, + IN EFI_IP_ADDRESS *Ip, + IN UINT8 IpVersion + ); + +/** + Print IKEv1 Current states. + + @param[in] Previous The Previous state of IKEv1. + @param[in] Current The current state of IKEv1. + +**/ +VOID +IpSecDumpState ( + IN UINT32 Previous, + IN UINT32 Current + ); + +/** + Print the Ike Packet. + + @param[in] Packet Point to IKE packet to be printed. + @param[in] Direction Point to the IKE packet is inbound or outbound. + @param[in] IpVersion Specified IP Version. + +**/ +/* +VOID +IpSecDumpPacket ( + IN IKE_PACKET *Packet, + IN EFI_IPSEC_TRAFFIC_DIR Direction, + IN UINT8 IpVersion + ); +*/ + +/** + Print the IKE Paylolad. + + @param[in] IkePayload Points to the payload to be printed. + +**/ +/* +VOID +IpSecDumpPayload ( + IN IKE_PAYLOAD *IkePayload + ); +*/ +/** + Print the buffer in form of Hex. + + @param[in] Title The strings to be printed before the data of the buffer. + @param[in] Data Points to the buffer to be printed. + @param[in] DataSize The size of the buffer to be printed. + +**/ +VOID +IpSecDumpBuf ( + IN CHAR8 *Title, + IN UINT8 *Data, + IN UINTN DataSize + ); + +#endif diff --git a/NetworkPkg/IpSecDxe/IpSecDriver.c b/NetworkPkg/IpSecDxe/IpSecDriver.c new file mode 100644 index 0000000000..b38f2a9452 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecDriver.c @@ -0,0 +1,282 @@ +/** @file + Driver Binding Protocol for IPsec Driver. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include "IpSecConfigImpl.h" +#include "IpSecDebug.h" + +/** + Test to see if this driver supports ControllerHandle. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to test. + @param[in] RemainingDevicePath Optional parameter used to pick a specific child + device to start. + + @retval EFI_SUCCES This driver supports this device. + @retval EFI_ALREADY_STARTED This driver is already running on this device. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +IpSecDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + // + //TODO: Add Udp4Protocol and Udp6Protocol testing. + // + return EFI_UNSUPPORTED; +} + +/** + Start this driver on ControllerHandle. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to bind driver to. + @param[in] RemainingDevicePath Optional parameter used to pick a specific child + device to start. + + @retval EFI_SUCCES This driver is added to ControllerHandle + @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle + @retval EFI_DEVICE_ERROR The device could not be started due to a device error. + Currently not implemented. + @retval other This driver does not support this device + +**/ +EFI_STATUS +EFIAPI +IpSecDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + // + //TODO: Add Udp4Io and Udp6Io creation for the IKE. + // + return EFI_SUCCESS; +} + +/** + Stop this driver on ControllerHandle. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of a device to stop the driver on. + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If the number of + children is zero, stop the entire bus driver. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCES This driver removed ControllerHandle. + @retval other This driver was not removed from this device. + +**/ +EFI_STATUS +EFIAPI +IpSecDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + // + //TODO: Add UdpIo4 and UdpIo6 destruction when the Udp driver unload or stop. + // + return EFI_UNSUPPORTED; +} + +EFI_DRIVER_BINDING_PROTOCOL gIpSecDriverBinding = { + IpSecDriverBindingSupported, + IpSecDriverBindingStart, + IpSecDriverBindingStop, + 0xa, + NULL, + NULL +}; + +/** + This is a callback function when the mIpSecInstance.DisabledEvent is signaled. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +IpSecCleanupAllSa ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + IPSEC_PRIVATE_DATA *Private; + UINT8 Value; + EFI_STATUS Status; + + Private = (IPSEC_PRIVATE_DATA *) Context; + + // + // Set the Status Variable + // + Value = IPSEC_STATUS_DISABLED; + Status = gRT->SetVariable ( + IPSECCONFIG_STATUS_NAME, + &gEfiIpSecConfigProtocolGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (Value), + &Value + ); + if (!EFI_ERROR (Status)) { + Private->IpSec.DisabledFlag = TRUE; + } + +} + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including + both device drivers and bus drivers. + + The entry point for IPsec driver which installs the driver binding, + component name protocol, IPsec Config protcolon, and IPsec protocol in + its ImageHandle. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_ALREADY_STARTED The IPsec driver has been already loaded. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The operation is failed. + +**/ +EFI_STATUS +EFIAPI +IpSecDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + IPSEC_PRIVATE_DATA *Private; + EFI_IPSEC_PROTOCOL *IpSec; + + // + // Check whether ipsec protocol has already been installed. + // + Status = gBS->LocateProtocol (&gEfiIpSecProtocolGuid, NULL, (VOID **) &IpSec); + + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "_ModuleEntryPoint: IpSec has been already loaded\n")); + Status = EFI_ALREADY_STARTED; + goto ON_EXIT; + } + + Status = gBS->LocateProtocol (&gEfiDpcProtocolGuid, NULL, (VOID **) &mDpc); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "_ModuleEntryPoint: Failed to locate EfiDpcProtocol\n")); + goto ON_EXIT; + } + + Private = AllocateZeroPool (sizeof (IPSEC_PRIVATE_DATA)); + + if (Private == NULL) { + DEBUG ((DEBUG_ERROR, "_ModuleEntryPoint: Failed to allocate private data\n")); + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + // + // Create disable event to cleanup all sa when ipsec disabled by user. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + IpSecCleanupAllSa, + Private, + &mIpSecInstance.DisabledEvent + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "_ModuleEntryPoint: Failed to create disable event\n")); + goto ON_FREE_PRIVATE; + } + + Private->Signature = IPSEC_PRIVATE_DATA_SIGNATURE; + Private->ImageHandle = ImageHandle; + CopyMem (&Private->IpSec, &mIpSecInstance, sizeof (EFI_IPSEC_PROTOCOL)); + + // + // Initilize Private's members. Thess members is used for IKE. + // + InitializeListHead (&Private->Udp4List); + InitializeListHead (&Private->Udp6List); + InitializeListHead (&Private->Ikev1SessionList); + InitializeListHead (&Private->Ikev1EstablishedList); + InitializeListHead (&Private->Ikev2SessionList); + InitializeListHead (&Private->Ikev2EstablishedList); + + // + // Initialize the ipsec config data and restore it from variable. + // + Status = IpSecConfigInitialize (Private); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "_ModuleEntryPoint: Failed to initialize IpSecConfig\n")); + goto ON_CLOSE_EVENT; + } + // + // Install ipsec protocol which is used by ip driver to process ipsec header. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiIpSecProtocolGuid, + &Private->IpSec, + NULL + ); + if (EFI_ERROR (Status)) { + goto ON_UNINSTALL_CONFIG; + } + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gIpSecDriverBinding, + ImageHandle, + &gIpSecComponentName, + &gIpSecComponentName2 + ); + if (EFI_ERROR (Status)) { + goto ON_UNINSTALL_CONFIG; + } + + return Status; + +ON_UNINSTALL_CONFIG: + gBS->UninstallProtocolInterface ( + Private->Handle, + &gEfiIpSecConfigProtocolGuid, + &Private->IpSecConfig + ); +ON_CLOSE_EVENT: + gBS->CloseEvent (mIpSecInstance.DisabledEvent); + mIpSecInstance.DisabledEvent = NULL; +ON_FREE_PRIVATE: + FreePool (Private); +ON_EXIT: + return Status; +} + diff --git a/NetworkPkg/IpSecDxe/IpSecDxe.inf b/NetworkPkg/IpSecDxe/IpSecDxe.inf new file mode 100644 index 0000000000..250ef1cdca --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecDxe.inf @@ -0,0 +1,63 @@ +## @file +# Component description file for IpSec module. +# +# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = IpSecDxe + FILE_GUID = EE8367C0-A1D6-4565-8F89-EF628547B722 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = IpSecDriverEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + IpSecConfigImpl.c + IpSecConfigImpl.h + IpSecCryptIo.h + IpSecCryptIo.c + IpSecDebug.h + ComponentName.c + IpSecImpl.c + IpSecDebug.c + IpSecSaEngine.c + IpSecDriver.c + IpSecImpl.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + DebugLib + PrintLib + DpcLib + NetLib + +[Protocols] + gEfiIp4ConfigProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiIpSecConfigProtocolGuid # PROTOCOL ALWAYS_PRODUCED + gEfiIpSecProtocolGuid # PROTOCOL ALWAYS_PRODUCED diff --git a/NetworkPkg/IpSecDxe/IpSecImpl.c b/NetworkPkg/IpSecDxe/IpSecImpl.c new file mode 100644 index 0000000000..15884ae403 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecImpl.c @@ -0,0 +1,856 @@ +/** @file + The implementation of IPsec Protocol + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IpSecConfigImpl.h" + +EFI_IPSEC_PROTOCOL mIpSecInstance = { IpSecProcess, NULL, TRUE }; + +extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum]; + +/** + Check if the specified Address is the Valid Address Range. + + This function checks if the bytes after prefixed length are all Zero in this + Address. This Address is supposed to point to a range address, meaning it only + gives the correct prefixed address. + + @param[in] IpVersion The IP version. + @param[in] Address Points to EFI_IP_ADDRESS to be checked. + @param[in] PrefixLength The PrefixeLength of this address. + + @retval TRUE The address is a vaild address range. + @retval FALSE The address is not a vaild address range. + +**/ +BOOLEAN +IpSecValidAddressRange ( + IN UINT8 IpVersion, + IN EFI_IP_ADDRESS *Address, + IN UINT8 PrefixLength + ) +{ + UINT8 Div; + UINT8 Mod; + UINT8 Mask; + UINT8 AddrLen; + UINT8 *Addr; + EFI_IP_ADDRESS ZeroAddr; + + if (PrefixLength == 0) { + return TRUE; + } + + AddrLen = (UINT8) ((IpVersion == IP_VERSION_4) ? 32 : 128); + + if (AddrLen <= PrefixLength) { + return FALSE; + } + + Div = (UINT8) (PrefixLength / 8); + Mod = (UINT8) (PrefixLength % 8); + Addr = (UINT8 *) Address; + ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS)); + + // + // Check whether the mod part of host scope is zero or not. + // + if (Mod > 0) { + Mask = (UINT8) (0xFF << (8 - Mod)); + + if ((Addr[Div] | Mask) != Mask) { + return FALSE; + } + + Div++; + } + // + // Check whether the div part of host scope is zero or not. + // + if (CompareMem ( + &Addr[Div], + &ZeroAddr, + sizeof (EFI_IP_ADDRESS) - Div + ) != 0) { + return FALSE; + } + + return TRUE; +} + +/** + Extrct the Address Range from a Address. + + This function keep the prefix address and zero other part address. + + @param[in] Address Point to a specified address. + @param[in] PrefixLength The prefix length. + @param[out] Range Contain the return Address Range. + +**/ +VOID +IpSecExtractAddressRange ( + IN EFI_IP_ADDRESS *Address, + IN UINT8 PrefixLength, + OUT EFI_IP_ADDRESS *Range + ) +{ + UINT8 Div; + UINT8 Mod; + UINT8 Mask; + UINT8 *Addr; + + if (PrefixLength == 0) { + return ; + } + + Div = (UINT8) (PrefixLength / 8); + Mod = (UINT8) (PrefixLength % 8); + Addr = (UINT8 *) Range; + + CopyMem (Range, Address, sizeof (EFI_IP_ADDRESS)); + + // + // Zero the mod part of host scope. + // + if (Mod > 0) { + Mask = (UINT8) (0xFF << (8 - Mod)); + Addr[Div] = (UINT8) (Addr[Div] & Mask); + Div++; + } + // + // Zero the div part of host scope. + // + ZeroMem (&Addr[Div], sizeof (EFI_IP_ADDRESS) - Div); + +} + +/** + Checks if the IP Address in the address range of AddressInfos specified. + + @param[in] IpVersion The IP version. + @param[in] IpAddr Point to EFI_IP_ADDRESS to be check. + @param[in] AddressInfo A list of EFI_IP_ADDRESS_INFO that is used to check + the IP Address is matched. + @param[in] AddressCount The total numbers of the AddressInfo. + + @retval TRUE If the Specified IP Address is in the range of the AddressInfos specified. + @retval FALSE If the Specified IP Address is not in the range of the AddressInfos specified. + +**/ +BOOLEAN +IpSecMatchIpAddress ( + IN UINT8 IpVersion, + IN EFI_IP_ADDRESS *IpAddr, + IN EFI_IP_ADDRESS_INFO *AddressInfo, + IN UINT32 AddressCount + ) +{ + EFI_IP_ADDRESS Range; + UINT32 Index; + BOOLEAN IsMatch; + + IsMatch = FALSE; + + for (Index = 0; Index < AddressCount; Index++) { + // + // Check whether the target address is in the address range + // if it's a valid range of address. + // + if (IpSecValidAddressRange ( + IpVersion, + &AddressInfo[Index].Address, + AddressInfo[Index].PrefixLength + )) { + // + // Get the range of the target address belongs to. + // + ZeroMem (&Range, sizeof (EFI_IP_ADDRESS)); + IpSecExtractAddressRange ( + IpAddr, + AddressInfo[Index].PrefixLength, + &Range + ); + + if (CompareMem ( + &Range, + &AddressInfo[Index].Address, + sizeof (EFI_IP_ADDRESS) + ) == 0) { + // + // The target address is in the address range. + // + IsMatch = TRUE; + break; + } + } + + if (CompareMem ( + IpAddr, + &AddressInfo[Index].Address, + sizeof (EFI_IP_ADDRESS) + ) == 0) { + // + // The target address is exact same as the address. + // + IsMatch = TRUE; + break; + } + } + + return IsMatch; +} + +/** + Check if the specified Protocol and Prot is supported by the specified SPD Entry. + + This function is the subfunction of IPsecLookUpSpdEntry() that is used to + check if the sent/received IKE packet has the related SPD entry support. + + @param[in] Protocol The Protocol to be checked. + @param[in] IpPayload Point to IP Payload to be check. + @param[in] SpdProtocol The Protocol supported by SPD. + @param[in] SpdLocalPort The Local Port in SPD. + @param[in] SpdRemotePort The Remote Port in SPD. + @param[in] IsOutbound Flag to indicate the is for IKE Packet sending or recieving. + + @retval TRUE The Protocol and Port are supported by the SPD Entry. + @retval FALSE The Protocol and Port are not supported by the SPD Entry. + +**/ +BOOLEAN +IpSecMatchNextLayerProtocol ( + IN UINT8 Protocol, + IN UINT8 *IpPayload, + IN UINT16 SpdProtocol, + IN UINT16 SpdLocalPort, + IN UINT16 SpdRemotePort, + IN BOOLEAN IsOutbound + ) +{ + BOOLEAN IsMatch; + + if (SpdProtocol == EFI_IPSEC_ANY_PROTOCOL) { + return TRUE; + } + + IsMatch = FALSE; + + if (SpdProtocol == Protocol) { + switch (Protocol) { + case EFI_IP_PROTO_UDP: + case EFI_IP_PROTO_TCP: + // + // For udp and tcp, (0, 0) means no need to check local and remote + // port. The payload is passed from upper level, which means it should + // be in network order. + // + IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0); + IsMatch = (BOOLEAN) (IsMatch || + (IsOutbound && + (BOOLEAN)( + NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdLocalPort && + NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdRemotePort + ) + )); + + IsMatch = (BOOLEAN) (IsMatch || + (!IsOutbound && + (BOOLEAN)( + NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdLocalPort && + NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdRemotePort + ) + )); + break; + + case EFI_IP_PROTO_ICMP: + // + // For icmpv4, type code is replaced with local port and remote port, + // and (0, 0) means no need to check. + // + IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0); + IsMatch = (BOOLEAN) (IsMatch || + (BOOLEAN) (((IP4_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort && + ((IP4_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort + ) + ); + break; + + case IP6_ICMP: + // + // For icmpv6, type code is replaced with local port and remote port, + // and (0, 0) means no need to check. + // + IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0); + + IsMatch = (BOOLEAN) (IsMatch || + (BOOLEAN) (((IP6_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort && + ((IP6_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort + ) + ); + break; + + default: + IsMatch = TRUE; + break; + } + } + + return IsMatch; +} + +/** + Find the SAD through a specified SPD's SAD list. + + @param[in] SadList SAD list related to a specified SPD entry. + @param[in] DestAddress The destination address used to find the SAD entry. + + @return The pointer to a certain SAD entry. + +**/ +IPSEC_SAD_ENTRY * +IpSecLookupSadBySpd ( + IN LIST_ENTRY *SadList, + IN EFI_IP_ADDRESS *DestAddress + ) +{ + LIST_ENTRY *Entry; + IPSEC_SAD_ENTRY *SadEntry; + + for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) { + + SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry); + // + // Find the right sad entry which contains the appointed dest address. + // + if (CompareMem ( + &SadEntry->Id->DestAddress, + DestAddress, + sizeof (EFI_IP_ADDRESS) + ) == 0) { + return SadEntry; + } + } + + return NULL; +} + +/** + Find the SAD through whole SAD list. + + @param[in] Spi The SPI used to search the SAD entry. + @param[in] DestAddress The destination used to search the SAD entry. + + @return the pointer to a certain SAD entry. + +**/ +IPSEC_SAD_ENTRY * +IpSecLookupSadBySpi ( + IN UINT32 Spi, + IN EFI_IP_ADDRESS *DestAddress + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *SadList; + IPSEC_SAD_ENTRY *SadEntry; + + SadList = &mConfigData[IPsecConfigDataTypeSad]; + + for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) { + + SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry); + // + // Find the right sad entry which contain the appointed spi and dest addr. + // + if (SadEntry->Id->Spi == Spi && CompareMem ( + &SadEntry->Id->DestAddress, + DestAddress, + sizeof (EFI_IP_ADDRESS) + ) == 0) { + + return SadEntry; + } + } + + return NULL; +} + +/** + Look up if there is existing SAD entry for specified IP packet sending. + + This function is called by the IPsecProcess when there is some IP packet needed to + send out. This function checks if there is an existing SAD entry that can be serviced + to this IP packet sending. If no existing SAD entry could be used, this + function will invoke an IPsec Key Exchange Negotiation. + + @param[in] Private Points to private data. + @param[in] NicHandle Points to a NIC handle. + @param[in] IpVersion The version of IP. + @param[in] IpHead The IP Header of packet to be sent out. + @param[in] IpPayload The IP Payload to be sent out. + @param[in] OldLastHead The Last protocol of the IP packet. + @param[in] SpdEntry Points to a related SPD entry. + @param[out] SadEntry Contains the Point of a related SAD entry. + + @retval EFI_DEVICE_ERROR One of following conditions is TRUE: + - If don't find related UDP service. + - Sequence Number is used up. + - Extension Sequence Number is used up. + @retval EFI_DEVICE_ERROR GC_TODO: Add description for return value. + @retval EFI_NOT_READY No existing SAD entry could be used. + @retval EFI_SUCCESS Find the related SAD entry. + +**/ +EFI_STATUS +IpSecLookupSadEntry ( + IN IPSEC_PRIVATE_DATA *Private, + IN EFI_HANDLE NicHandle, + IN UINT8 IpVersion, + IN VOID *IpHead, + IN UINT8 *IpPayload, + IN UINT8 OldLastHead, + IN IPSEC_SPD_ENTRY *SpdEntry, + OUT IPSEC_SAD_ENTRY **SadEntry + ) +{ + IPSEC_SAD_ENTRY *Entry; + IPSEC_SAD_DATA *Data; + EFI_IP_ADDRESS DestIp; + UINT32 SeqNum32; + + *SadEntry = NULL; + // + // Parse the destination address from ip header. + // + ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS)); + if (IpVersion == IP_VERSION_4) { + CopyMem ( + &DestIp, + &((IP4_HEAD *) IpHead)->Dst, + sizeof (IP4_ADDR) + ); + } else { + CopyMem ( + &DestIp, + &((EFI_IP6_HEADER *) IpHead)->DestinationAddress, + sizeof (EFI_IP_ADDRESS) + ); + } + // + // Find the sad entry in the spd.sas list according to the dest address. + // + Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp); + + if (Entry == NULL) { + + if (OldLastHead != IP6_ICMP || + (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST) + ) { + // + // TODO: Start ike negotiation process except the request packet of ping. + // + //IkeNegotiate (UdpService, SpdEntry, &DestIp); + } + + return EFI_NOT_READY; + } + + Data = Entry->Data; + + if (!Data->ManualSet) { + if (Data->ESNEnabled) { + // + // Validate the 64bit sn number if 64bit sn enabled. + // + if (Data->SequenceNumber + 1 < Data->SequenceNumber) { + // + // TODO: Re-negotiate SA + // + return EFI_DEVICE_ERROR; + } + } else { + // + // Validate the 32bit sn number if 64bit sn disabled. + // + SeqNum32 = (UINT32) Data->SequenceNumber; + if (SeqNum32 + 1 < SeqNum32) { + // + // TODO: Re-negotiate SA + // + return EFI_DEVICE_ERROR; + } + } + } + + *SadEntry = Entry; + + return EFI_SUCCESS; +} + +/** + Find a PAD entry according to a remote IP address. + + @param[in] IpVersion The version of IP. + @param[in] IpAddr Points to remote IP address. + + @return the pointer of related PAD entry. + +**/ +IPSEC_PAD_ENTRY * +IpSecLookupPadEntry ( + IN UINT8 IpVersion, + IN EFI_IP_ADDRESS *IpAddr + ) +{ + LIST_ENTRY *PadList; + LIST_ENTRY *Entry; + EFI_IP_ADDRESS_INFO *IpAddrInfo; + IPSEC_PAD_ENTRY *PadEntry; + + PadList = &mConfigData[IPsecConfigDataTypePad]; + + for (Entry = PadList->ForwardLink; Entry != PadList; Entry = Entry->ForwardLink) { + + PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry); + IpAddrInfo = &PadEntry->Id->Id.IpAddress; + // + // Find the right pad entry which contain the appointed dest addr. + // + if (IpSecMatchIpAddress (IpVersion, IpAddr, IpAddrInfo, 1)) { + return PadEntry; + } + } + + return NULL; +} + +/** + Check if the specified IP packet can be serviced by this SPD entry. + + @param[in] SpdEntry Point to SPD entry. + @param[in] IpVersion Version of IP. + @param[in] IpHead Point to IP header. + @param[in] IpPayload Point to IP payload. + @param[in] Protocol The Last protocol of IP packet. + @param[in] IsOutbound Traffic direction. + + @retval EFI_IPSEC_ACTION The support action of SPD entry. + @retval -1 If the input packet header doesn't match the SpdEntry. + +**/ +EFI_IPSEC_ACTION +IpSecLookupSpdEntry ( + IN IPSEC_SPD_ENTRY *SpdEntry, + IN UINT8 IpVersion, + IN VOID *IpHead, + IN UINT8 *IpPayload, + IN UINT8 Protocol, + IN BOOLEAN IsOutbound + ) +{ + EFI_IPSEC_SPD_SELECTOR *SpdSel; + IP4_HEAD *Ip4; + EFI_IP6_HEADER *Ip6; + EFI_IP_ADDRESS SrcAddr; + EFI_IP_ADDRESS DstAddr; + BOOLEAN SpdMatch; + + ASSERT (SpdEntry != NULL); + SpdSel = SpdEntry->Selector; + Ip4 = (IP4_HEAD *) IpHead; + Ip6 = (EFI_IP6_HEADER *) IpHead; + + ZeroMem (&SrcAddr, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&DstAddr, sizeof (EFI_IP_ADDRESS)); + + // + // Parse the source and destination address from ip header. + // + if (IpVersion == IP_VERSION_4) { + CopyMem (&SrcAddr, &Ip4->Src, sizeof (IP4_ADDR)); + CopyMem (&DstAddr, &Ip4->Dst, sizeof (IP4_ADDR)); + } else { + CopyMem (&SrcAddr, &Ip6->SourceAddress, sizeof (EFI_IPv6_ADDRESS)); + CopyMem (&DstAddr, &Ip6->DestinationAddress, sizeof (EFI_IPv6_ADDRESS)); + } + // + // Check the local and remote addresses for outbound traffic + // + SpdMatch = (BOOLEAN)(IsOutbound && + IpSecMatchIpAddress ( + IpVersion, + &SrcAddr, + SpdSel->LocalAddress, + SpdSel->LocalAddressCount + ) && + IpSecMatchIpAddress ( + IpVersion, + &DstAddr, + SpdSel->RemoteAddress, + SpdSel->RemoteAddressCount + ) + ); + + // + // Check the local and remote addresses for inbound traffic + // + SpdMatch = (BOOLEAN) (SpdMatch || + (!IsOutbound && + IpSecMatchIpAddress ( + IpVersion, + &DstAddr, + SpdSel->LocalAddress, + SpdSel->LocalAddressCount + ) && + IpSecMatchIpAddress ( + IpVersion, + &SrcAddr, + SpdSel->RemoteAddress, + SpdSel->RemoteAddressCount + ) + )); + + // + // Check the next layer protocol and local and remote ports. + // + SpdMatch = (BOOLEAN) (SpdMatch && + IpSecMatchNextLayerProtocol ( + Protocol, + IpPayload, + SpdSel->NextLayerProtocol, + SpdSel->LocalPort, + SpdSel->RemotePort, + IsOutbound + ) + ); + + if (SpdMatch) { + // + // Find the right spd entry if match the 5 key elements. + // + return SpdEntry->Data->Action; + } + + return (EFI_IPSEC_ACTION) - 1; +} + +/** + Handles IPsec packet processing for inbound and outbound IP packets. + + The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet. + The behavior is that it can perform one of the following actions: + bypass the packet, discard the packet, or protect the packet. + + @param[in] This Pointer to the EFI_IPSEC_PROTOCOL instance. + @param[in] NicHandle Instance of the network interface. + @param[in] IpVersion IPV4 or IPV6. + @param[in, out] IpHead Pointer to the IP Header. + @param[in] LastHead The protocol of the next layer to be processed by IPsec. + @param[in] OptionsBuffer Pointer to the options buffer. + @param[in] OptionsLength Length of the options buffer. + @param[in, out] FragmentTable Pointer to a list of fragments. + @param[in] FragmentCount Number of fragments. + @param[in] TrafficDirection Traffic direction. + @param[out] RecycleSignal Event for recycling of resources. + + @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same. + @retval EFI_SUCCESS The packet was protected. + @retval EFI_ACCESS_DENIED The packet was discarded. + +**/ +EFI_STATUS +EFIAPI +IpSecProcess ( + IN EFI_IPSEC_PROTOCOL *This, + IN EFI_HANDLE NicHandle, + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN UINT8 *LastHead, + IN VOID *OptionsBuffer, + IN UINT32 OptionsLength, + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + IN EFI_IPSEC_TRAFFIC_DIR TrafficDirection, + OUT EFI_EVENT *RecycleSignal + ) +{ + IPSEC_PRIVATE_DATA *Private; + IPSEC_SPD_ENTRY *SpdEntry; + IPSEC_SAD_ENTRY *SadEntry; + LIST_ENTRY *SpdList; + LIST_ENTRY *Entry; + EFI_IPSEC_ACTION Action; + EFI_STATUS Status; + UINT8 *IpPayload; + UINT8 OldLastHead; + BOOLEAN IsOutbound; + + Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (This); + IpPayload = (*FragmentTable)[0].FragmentBuffer; + IsOutbound = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE); + OldLastHead = *LastHead; + *RecycleSignal = NULL; + + if (!IsOutbound) { + // + // For inbound traffic, process the ipsec header of the packet. + // + Status = IpSecProtectInboundPacket ( + IpVersion, + IpHead, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount, + &SpdEntry, + RecycleSignal + ); + + if (Status == EFI_ACCESS_DENIED) { + // + // The packet is denied to access. + // + goto ON_EXIT; + } + + if (Status == EFI_SUCCESS) { + // + // Check the spd entry if the packet is accessible. + // + if (SpdEntry == NULL) { + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + Action = IpSecLookupSpdEntry ( + SpdEntry, + IpVersion, + IpHead, + IpPayload, + *LastHead, + IsOutbound + ); + + if (Action != EfiIPsecActionProtect) { + // + // Discard the packet if the spd entry is not protect. + // + gBS->SignalEvent (*RecycleSignal); + *RecycleSignal = NULL; + Status = EFI_ACCESS_DENIED; + } + + goto ON_EXIT; + } + } + + Status = EFI_ACCESS_DENIED; + SpdList = &mConfigData[IPsecConfigDataTypeSpd]; + + for (Entry = SpdList->ForwardLink; Entry != SpdList; Entry = Entry->ForwardLink) { + // + // For outbound and non-ipsec Inbound traffic: check the spd entry. + // + SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry); + Action = IpSecLookupSpdEntry ( + SpdEntry, + IpVersion, + IpHead, + IpPayload, + OldLastHead, + IsOutbound + ); + + switch (Action) { + + case EfiIPsecActionProtect: + + if (IsOutbound) { + // + // For outbound traffic, lookup the sad entry. + // + Status = IpSecLookupSadEntry ( + Private, + NicHandle, + IpVersion, + IpHead, + IpPayload, + OldLastHead, + SpdEntry, + &SadEntry + ); + + if (SadEntry != NULL) { + // + // Process the packet by the found sad entry. + // + Status = IpSecProtectOutboundPacket ( + IpVersion, + IpHead, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount, + SadEntry, + RecycleSignal + ); + + } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) { + // + // TODO: if no need return not ready to upper layer, change here. + // + Status = EFI_SUCCESS; + } + } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) { + // + // For inbound icmpv6 traffic except ping request, accept the packet + // although no sad entry associated with protect spd entry. + // + IpSecLookupSadEntry ( + Private, + NicHandle, + IpVersion, + IpHead, + IpPayload, + OldLastHead, + SpdEntry, + &SadEntry + ); + if (SadEntry == NULL) { + Status = EFI_SUCCESS; + } + } + + goto ON_EXIT; + + case EfiIPsecActionBypass: + Status = EFI_SUCCESS; + goto ON_EXIT; + + case EfiIPsecActionDiscard: + goto ON_EXIT; + + default: + // + // Discard the packet if no spd entry match. + // + break; + } + } + +ON_EXIT: + return Status; +} + diff --git a/NetworkPkg/IpSecDxe/IpSecImpl.h b/NetworkPkg/IpSecDxe/IpSecImpl.h new file mode 100644 index 0000000000..644c658082 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecImpl.h @@ -0,0 +1,313 @@ +/** @file + The definitions related to IPsec protocol implementation. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _IP_SEC_IMPL_H_ +#define _IP_SEC_IMPL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct _IPSEC_PRIVATE_DATA IPSEC_PRIVATE_DATA; +typedef struct _IPSEC_SPD_ENTRY IPSEC_SPD_ENTRY; +typedef struct _IPSEC_PAD_ENTRY IPSEC_PAD_ENTRY; +typedef struct _IPSEC_SPD_DATA IPSEC_SPD_DATA; + +#define IPSEC_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I', 'P', 'S', 'E') + +#define IPSEC_PRIVATE_DATA_FROM_IPSEC(a) CR (a, IPSEC_PRIVATE_DATA, IpSec, IPSEC_PRIVATE_DATA_SIGNATURE) +#define IPSEC_PRIVATE_DATA_FROM_UDP4LIST(a) CR (a, IPSEC_PRIVATE_DATA, Udp4List, IPSEC_PRIVATE_DATA_SIGNATURE) +#define IPSEC_PRIVATE_DATA_FROM_UDP6LIST(a) CR (a, IPSEC_PRIVATE_DATA, Udp6List, IPSEC_PRIVATE_DATA_SIGNATURE) +#define IPSEC_UDP_SERVICE_FROM_LIST(a) BASE_CR (a, IKE_UDP_SERVICE, List) +#define IPSEC_SPD_ENTRY_FROM_LIST(a) BASE_CR (a, IPSEC_SPD_ENTRY, List) +#define IPSEC_SAD_ENTRY_FROM_LIST(a) BASE_CR (a, IPSEC_SAD_ENTRY, List) +#define IPSEC_PAD_ENTRY_FROM_LIST(a) BASE_CR (a, IPSEC_PAD_ENTRY, List) +#define IPSEC_SAD_ENTRY_FROM_SPD(a) BASE_CR (a, IPSEC_SAD_ENTRY, BySpd) + +#define IPSEC_STATUS_DISABLED 0 +#define IPSEC_STATUS_ENABLED 1 +#define IPSEC_ESP_PROTOCOL 50 +#define IPSEC_AH_PROTOCOL 51 +#define IPSEC_DEFAULT_VARIABLE_SIZE 0x100 + +// +// Internal Structure Definition +// +#pragma pack(1) +typedef struct _EFI_AH_HEADER { + UINT8 NextHeader; + UINT8 PayloadLen; + UINT16 Reserved; + UINT32 Spi; + UINT32 SequenceNumber; +} EFI_AH_HEADER; + +typedef struct _EFI_ESP_HEADER { + UINT32 Spi; + UINT32 SequenceNumber; +} EFI_ESP_HEADER; + +typedef struct _EFI_ESP_TAIL { + UINT8 PaddingLength; + UINT8 NextHeader; +} EFI_ESP_TAIL; +#pragma pack() + +struct _IPSEC_SPD_DATA { + CHAR16 Name[100]; + UINT32 PackageFlag; + EFI_IPSEC_ACTION Action; + EFI_IPSEC_PROCESS_POLICY *ProcessingPolicy; + LIST_ENTRY Sas; +}; + +struct _IPSEC_SPD_ENTRY { + EFI_IPSEC_SPD_SELECTOR *Selector; + IPSEC_SPD_DATA *Data; + LIST_ENTRY List; +}; + +typedef struct _IPSEC_SAD_DATA { + EFI_IPSEC_MODE Mode; + UINT64 SequenceNumber; + UINT8 AntiReplayWindowSize; + UINT64 AntiReplayBitmap[4]; // bitmap for received packet + EFI_IPSEC_ALGO_INFO AlgoInfo; + EFI_IPSEC_SA_LIFETIME SaLifetime; + UINT32 PathMTU; + IPSEC_SPD_ENTRY *SpdEntry; + BOOLEAN ESNEnabled; // Extended (64-bit) SN enabled + BOOLEAN ManualSet; +} IPSEC_SAD_DATA; + +typedef struct _IPSEC_SAD_ENTRY { + EFI_IPSEC_SA_ID *Id; + IPSEC_SAD_DATA *Data; + LIST_ENTRY List; + LIST_ENTRY BySpd; // Linked on IPSEC_SPD_DATA.Sas +} IPSEC_SAD_ENTRY; + +struct _IPSEC_PAD_ENTRY { + EFI_IPSEC_PAD_ID *Id; + EFI_IPSEC_PAD_DATA *Data; + LIST_ENTRY List; +}; + +typedef struct _IPSEC_RECYCLE_CONTEXT { + EFI_IPSEC_FRAGMENT_DATA *FragmentTable; + UINT8 *PayloadBuffer; +} IPSEC_RECYCLE_CONTEXT; + +struct _IPSEC_PRIVATE_DATA { + UINT32 Signature; + EFI_HANDLE Handle; // Virtual handle to install private prtocol + EFI_HANDLE ImageHandle; + EFI_IPSEC_PROTOCOL IpSec; + EFI_IPSEC_CONFIG_PROTOCOL IpSecConfig; + BOOLEAN SetBySelf; + LIST_ENTRY Udp4List; + UINTN Udp4Num; + LIST_ENTRY Udp6List; + UINTN Udp6Num; + LIST_ENTRY Ikev1SessionList; + LIST_ENTRY Ikev1EstablishedList; + LIST_ENTRY Ikev2SessionList; + LIST_ENTRY Ikev2EstablishedList; + BOOLEAN IsIPsecDisabling; +}; + +/** + This function processes the inbound traffic with IPsec. + + It checks the received packet security property, trims the ESP/AH header, and then + returns without an IPsec protected IP Header and FragmentTable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Points to IP header containing the ESP/AH header + to be trimed on input, and without ESP/AH header + on return. + @param[in] LastHead The Last Header in IP header on return. + @param[in] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec + protected on input, and without IPsec protected + on return. + @param[in] FragmentCount Number of fragments. + @param[out] SpdEntry Pointer to contain the address of SPD entry on return. + @param[out] RecycleEvent Event for recycling of resources. + + @retval EFI_SUCCESS The operation is successful. + @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported. + +**/ +EFI_STATUS +IpSecProtectInboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN UINT8 *LastHead, + IN VOID *OptionsBuffer, OPTIONAL + IN UINT32 OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + OUT IPSEC_SPD_ENTRY **SpdEntry, + OUT EFI_EVENT *RecycleEvent + ); + + +/** + This fucntion processes the output traffic with IPsec. + + It protected the sending packet by encrypting it payload and inserting ESP/AH header + in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Point to IP header containing the orginal IP header + to be processed on input, and inserted ESP/AH header + on return. + @param[in] LastHead The Last Header in IP header. + @param[in] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments to be protected by + IPsec on input, and with IPsec protected + on return. + @param[in] FragmentCount Number of fragments. + @param[in] SadEntry Related SAD entry. + @param[out] RecycleEvent Event for recycling of resources. + + @retval EFI_SUCCESS The operation is successful. + @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported. + +**/ +EFI_STATUS +IpSecProtectOutboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN UINT8 *LastHead, + IN VOID *OptionsBuffer, OPTIONAL + IN UINT32 OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + IN IPSEC_SAD_ENTRY *SadEntry, + OUT EFI_EVENT *RecycleEvent + ); + +/** + Check if the IP Address in the address range of AddressInfos specified. + + @param[in] IpVersion The IP version. + @param[in] IpAddr Points to EFI_IP_ADDRESS to be check. + @param[in] AddressInfo A list of EFI_IP_ADDRESS_INFO that is used to check + the IP Address is matched. + @param[in] AddressCount The total numbers of the AddressInfo. + + @retval TRUE If the Specified IP Address is in the range of the AddressInfos specified. + @retval FALSE If the Specified IP Address is not in the range of the AddressInfos specified. + +**/ +BOOLEAN +IpSecMatchIpAddress ( + IN UINT8 IpVersion, + IN EFI_IP_ADDRESS *IpAddr, + IN EFI_IP_ADDRESS_INFO *AddressInfo, + IN UINT32 AddressCount + ); + +/** + Find a PAD entry according to remote IP address. + + @param[in] IpVersion The version of IP. + @param[in] IpAddr Point to remote IP address. + + @return The pointer of related PAD entry. + +**/ +IPSEC_PAD_ENTRY * +IpSecLookupPadEntry ( + IN UINT8 IpVersion, + IN EFI_IP_ADDRESS *IpAddr + ); + +/** + Find the SAD through whole SAD list. + + @param[in] Spi The SPI used to search the SAD entry. + @param[in] DestAddress The destination used to search the SAD entry. + + @return The pointer to a certain SAD entry. + +**/ +IPSEC_SAD_ENTRY * +IpSecLookupSadBySpi ( + IN UINT32 Spi, + IN EFI_IP_ADDRESS *DestAddress + ) +; + +/** + Handles IPsec packet processing for inbound and outbound IP packets. + + The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet. + The behavior is that it can perform one of the following actions: + bypass the packet, discard the packet, or protect the packet. + + @param[in] This Pointer to the EFI_IPSEC_PROTOCOL instance. + @param[in] NicHandle Instance of the network interface. + @param[in] IpVersion IPV4 or IPV6. + @param[in, out] IpHead Pointer to the IP Header. + @param[in] LastHead The protocol of the next layer to be processed by IPsec. + @param[in] OptionsBuffer Pointer to the options buffer. + @param[in] OptionsLength Length of the options buffer. + @param[in, out] FragmentTable Pointer to a list of fragments. + @param[in] FragmentCount Number of fragments. + @param[in] TrafficDirection Traffic direction. + @param[out] RecycleSignal Event for recycling of resources. + + @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same. + @retval EFI_SUCCESS The packet was protected. + @retval EFI_ACCESS_DENIED The packet was discarded. + +**/ +EFI_STATUS +EFIAPI +IpSecProcess ( + IN EFI_IPSEC_PROTOCOL *This, + IN EFI_HANDLE NicHandle, + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN UINT8 *LastHead, + IN VOID *OptionsBuffer, + IN UINT32 OptionsLength, + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + IN EFI_IPSEC_TRAFFIC_DIR TrafficDirection, + OUT EFI_EVENT *RecycleSignal + ); + +extern EFI_DPC_PROTOCOL *mDpc; +extern EFI_IPSEC_PROTOCOL mIpSecInstance; + +extern EFI_COMPONENT_NAME2_PROTOCOL gIpSecComponentName2; +extern EFI_COMPONENT_NAME_PROTOCOL gIpSecComponentName; + + +#endif diff --git a/NetworkPkg/IpSecDxe/IpSecSaEngine.c b/NetworkPkg/IpSecDxe/IpSecSaEngine.c new file mode 100644 index 0000000000..8abf4d6bf4 --- /dev/null +++ b/NetworkPkg/IpSecDxe/IpSecSaEngine.c @@ -0,0 +1,934 @@ +/** @file + IPsec inbound and outbound traffic processing. + + Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "IpSecImpl.h" +#include "IpSecDebug.h" +#include "IpSecCryptIo.h" + +extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum]; + +/** + The call back function of NetbufFromExt. + + @param[in] Arg The argument passed from the caller. + +**/ +VOID +EFIAPI +IpSecOnRecyclePacket ( + IN VOID *Arg + ) +{ +} + +/** + This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP + is released. + + @param[in] Event The related event. + @param[in] Context The data passed by the caller. + +**/ +VOID +EFIAPI +IpSecRecycleCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + IPSEC_RECYCLE_CONTEXT *RecycleContext; + + RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context; + + if (RecycleContext->FragmentTable != NULL) { + FreePool (RecycleContext->FragmentTable); + } + + if (RecycleContext->PayloadBuffer != NULL) { + FreePool (RecycleContext->PayloadBuffer); + } + + FreePool (RecycleContext); + gBS->CloseEvent (Event); + +} + +/** + Calculate the extension header of IP. The return length only doesn't contain + the fixed IP header length. + + @param[in] IpHead Points to an IP head to be calculated. + @param[in] LastHead Points to the last header of the IP header. + + @return The length of the extension header. + +**/ +UINT16 +IpSecGetPlainExtHeadSize ( + IN VOID *IpHead, + IN UINT8 *LastHead + ) +{ + UINT16 Size; + + Size = (UINT16) (LastHead - (UINT8 *) IpHead); + + if (Size > sizeof (EFI_IP6_HEADER)) { + // + // * (LastHead+1) point the last header's length but not include the first + // 8 octers, so this formluation add 8 at the end. + // + Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8); + } else { + Size = 0; + } + + return Size; +} + +/** + Authenticate the IpSec Payload and store the result in the IcvBuffer. + + @param[in] BufferToAuth The buffer to be Authenticated. + @param[in] AuthSize The size of the buffer to be Authenticated. + @param[in, out] IcvBuffer The buffer to store the ICV. + @param[in] IcvSize The size of ICV. + @param[in] Key The Key passed to the CryptLib to generate a + CRYPT_HANDLE. + @param[in] AuthAlgId The Authentication Algorithm ID. + + @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list. + @retval EFI_SUCCESS Authenticated the payload successfully. + @retval otherwise Authentication of the payload failed. +**/ +EFI_STATUS +IpSecAuthPayload ( + IN UINT8 *BufferToAuth, + IN UINTN AuthSize, + IN OUT UINT8 *IcvBuffer, + IN UINTN IcvSize, + IN VOID *Key, + IN UINT8 AuthAlgId + ) +{ + switch (AuthAlgId) { + case EFI_IPSEC_AALG_NONE : + case EFI_IPSEC_AALG_NULL : + return EFI_SUCCESS; + + default: + return EFI_UNSUPPORTED; + } +} + +/** + Verify if the Authentication payload is correct. + + @param[in] EspBuffer Points to the ESP wrapped buffer. + @param[in] EspSize The size of the ESP wrapped buffer. + @param[in] SadEntry The related SAD entry to store the authentication + algorithm key. + @param[in] IcvSize The length of ICV. + + @retval EFI_SUCCESS The authentication data is correct. + @retval EFI_ACCESS_DENIED The authentication data is not correct. + +**/ +EFI_STATUS +IpSecEspAuthVerifyPayload ( + IN UINT8 *EspBuffer, + IN UINTN EspSize, + IN IPSEC_SAD_ENTRY *SadEntry, + IN UINTN *IcvSize + ) +{ + EFI_STATUS Status; + UINTN AuthSize; + UINT8 IcvBuffer[12]; + + // + // Calculate the size of authentication payload. + // + *IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId); + AuthSize = EspSize - *IcvSize; + + // + // Calculate the icv buffer and size of the payload. + // + Status = IpSecAuthPayload ( + EspBuffer, + AuthSize, + IcvBuffer, + *IcvSize, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Compare the calculated icv and the appended original icv. + // + if (CompareMem (EspBuffer + AuthSize, IcvBuffer, *IcvSize) == 0) { + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_ERROR, "Error auth verify payload\n")); + return EFI_ACCESS_DENIED; +} + +/** + ESP Decrypt the payload. + + @param[in, out] PayloadBuffer Pointer to the buffer containing the ESP wrapped; + to be decrypted on input, and plaintext on return. The + number of bytes of data to be decrypted is + specified by EncryptSize. + @param[in] EncryptSize The size of the PayloadBuffer as input. + @param[in] SadEntry The related SAD entry. + @param[in] IvSize The size of IV. + @param[out] PlainPayloadSize Contains the return value of decrypted size. + @param[out] PaddingSize Contains the return value of Padding size. + @param[out] NextHeader Contains the return value of the last protocol header + of the IP packet. + + @retval EFI_UNSUPPORTED The Algorithm pointed to by the SAD entry is not supported. + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +IpSecEspDecryptPayload ( + IN OUT UINT8 *PayloadBuffer, + IN UINTN EncryptSize, + IN IPSEC_SAD_ENTRY *SadEntry, + IN UINTN *IvSize, + OUT UINTN *PlainPayloadSize, + OUT UINTN *PaddingSize, + OUT UINT8 *NextHeader + ) +{ + EFI_ESP_TAIL *EspTail; + + switch (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId) { + case EFI_IPSEC_EALG_NULL: + EspTail = (EFI_ESP_TAIL *) (PayloadBuffer + EncryptSize - sizeof (EFI_ESP_TAIL)); + *PaddingSize = EspTail->PaddingLength; + *NextHeader = EspTail->NextHeader; + *PlainPayloadSize = EncryptSize - EspTail->PaddingLength - sizeof (EFI_ESP_TAIL); + break; + + case EFI_IPSEC_EALG_3DESCBC: + case EFI_IPSEC_EALG_AESCBC: + // + // TODO: support these algorithm + // + return EFI_UNSUPPORTED; + default : + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + ESP Encrypt the payload. + + @param[in, out] BufferToEncrypt Pointer to the buffer containing plaintext to be + encrypted on input, and ciphertext on return. The + number of bytes of data to be encrypted is + specified by EncryptSize. + @param[in, out] EncryptSize The size of the plaintext on input, and the size of the + ciphertext on return. + @param[in] IvBuffer Points to IV data. + @param[in] IvSize Size of IV. + @param[in] SadEntry Related SAD entry. + + @retval EFI_UNSUPPORTED The Algorithm pointed by SAD entry is not supported. + @retval EFI_SUCCESS The operation completed successfully. + +**/ +EFI_STATUS +IpSecEspEncryptPayload ( + IN OUT UINT8 *BufferToEncrypt, + IN OUT UINTN EncryptSize, + IN UINT8 *IvBuffer, + IN UINTN IvSize, + IN IPSEC_SAD_ENTRY *SadEntry + ) +{ + switch (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId) { + case EFI_IPSEC_EALG_NULL: + return EFI_SUCCESS; + + case EFI_IPSEC_EALG_3DESCBC: + case EFI_IPSEC_EALG_AESCBC: + // + // TODO: support these algorithms + // + return EFI_UNSUPPORTED; + default : + return EFI_UNSUPPORTED; + + } +} + +/** + The actual entry to relative function processes the inbound traffic of ESP header. + + This function is the subfunction of IpSecProtectInboundPacket(). It checks the + received packet security property and trim the ESP header and then returns without + an IPsec protected IP Header and FramgmentTable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Points to the IP header containing the ESP header + to be trimed on input, and without ESP header + on return. + @param[out] LastHead The Last Header in IP header on return. + @param[in] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec + protected on input, and without IPsec protected + on return. + @param[in] FragmentCount The number of fragments. + @param[out] SpdEntry Pointer to contain the address of SPD entry on return. + @param[out] RecycleEvent The event for recycling of resources. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_ACCESS_DENIED One or more following conditions is TRUE: + - ESP header was not found. + - The related SAD entry was not found. + - The related SAD entry does not support the ESP protocol. + @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated. + +**/ +EFI_STATUS +IpSecEspInboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + OUT UINT8 *LastHead, + IN VOID *OptionsBuffer, OPTIONAL + IN UINT32 OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + OUT IPSEC_SPD_ENTRY **SpdEntry, + OUT EFI_EVENT *RecycleEvent + ) +{ + EFI_STATUS Status; + NET_BUF *Payload; + UINTN EspSize; + UINTN IvSize; + UINTN PlainPayloadSize; + UINTN PaddingSize; + UINTN IcvSize; + UINT8 *ProcessBuffer; + EFI_IP_ADDRESS DestIp; + EFI_ESP_HEADER *EspHeader; + EFI_ESP_TAIL *EspTail; + EFI_IPSEC_SA_ID *SaId; + IPSEC_SAD_DATA *SadData; + IPSEC_SAD_ENTRY *SadEntry; + IPSEC_RECYCLE_CONTEXT *RecycleContext; + UINT32 Spi; + UINT8 NextHeader; + UINT16 IpSecHeadSize; + + Status = EFI_SUCCESS; + Payload = NULL; + ProcessBuffer = NULL; + RecycleContext = NULL; + *RecycleEvent = NULL; + PlainPayloadSize = 0; + NextHeader = 0; + // + // Build netbuf from fragment table first. + // + Payload = NetbufFromExt ( + (NET_FRAGMENT *) *FragmentTable, + *FragmentCount, + 0, + sizeof (EFI_ESP_HEADER), + IpSecOnRecyclePacket, + NULL + ); + if (Payload == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + // + // Get the esp size and eso header from netbuf. + // + EspSize = Payload->TotalSize; + EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL); + if (EspHeader == NULL) { + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Parse destination address from ip header. + // + ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS)); + if (IpVersion == IP_VERSION_4) { + CopyMem ( + &DestIp, + &((IP4_HEAD *) IpHead)->Dst, + sizeof (IP4_ADDR) + ); + } else { + CopyMem ( + &DestIp, + &((EFI_IP6_HEADER *) IpHead)->DestinationAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + } + // + // Lookup sad entry according to the spi and dest address. + // + Spi = NTOHL (EspHeader->Spi); + SadEntry = IpSecLookupSadBySpi (Spi, &DestIp); + if (SadEntry == NULL) { + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + + SaId = SadEntry->Id; + SadData = SadEntry->Data; + + // + // Only support esp protocol currently. + // + if (SaId->Proto != EfiIPsecESP) { + Status = EFI_ACCESS_DENIED; + goto ON_EXIT; + } + + if (!SadData->ManualSet) { + // + // TODO: Check sa lifetime and sequence number + // + } + // + // Allocate buffer for decryption and authentication by esp. + // + ProcessBuffer = AllocateZeroPool (EspSize); + if (ProcessBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer); + + // + // Authenticate the esp wrapped buffer by the sad entry if has auth key. + // + IcvSize = 0; + if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { + Status = IpSecEspAuthVerifyPayload ( + ProcessBuffer, + EspSize, + SadEntry, + &IcvSize + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + // + // Decrypt the payload by the sad entry if has decrypt key. + // + IvSize = 0; + if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { + Status = IpSecEspDecryptPayload ( + ProcessBuffer + sizeof (EFI_ESP_HEADER), + EspSize - sizeof (EFI_ESP_HEADER) - IcvSize, + SadEntry, + &IvSize, + &PlainPayloadSize, + &PaddingSize, + &NextHeader + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } else { + EspTail = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL)); + PaddingSize = EspTail->PaddingLength; + NextHeader = EspTail->NextHeader; + PlainPayloadSize = EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize - sizeof (EFI_ESP_TAIL) - PaddingSize; + } + // + // TODO: handle anti-replay window + // + // + // Decryption and authentication with esp has been done, so it's time to + // reload the new packet, create recycle event and fixup ip header. + // + RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT)); + if (RecycleContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IpSecRecycleCallback, + RecycleContext, + RecycleEvent + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + // + // TODO: Who take responsible to handle the original fragment table? + // + *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA)); + if (*FragmentTable == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + RecycleContext->PayloadBuffer = ProcessBuffer; + RecycleContext->FragmentTable = *FragmentTable; + (*FragmentTable)[0].FragmentBuffer = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize; + (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize; + *FragmentCount = 1; + + // + // Update the total length field in ip header since processed by esp. + // + if (IpVersion == IP_VERSION_4) { + ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + PlainPayloadSize)); + } else { + IpSecHeadSize = IpSecGetPlainExtHeadSize (IpHead, LastHead); + ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize)); + } + // + // Update the next layer field in ip header since esp header inserted. + // + *LastHead = NextHeader; + + // + // Update the spd association of the sad entry. + // + *SpdEntry = SadData->SpdEntry; + +ON_EXIT: + if (Payload != NULL) { + NetbufFree (Payload); + } + + if (EFI_ERROR (Status)) { + if (ProcessBuffer != NULL) { + FreePool (ProcessBuffer); + } + + if (RecycleContext != NULL) { + FreePool (RecycleContext); + } + + if (*RecycleEvent != NULL) { + gBS->CloseEvent (*RecycleEvent); + } + } + + return Status; +} + +/** + The actual entry to the relative function processes the output traffic using the ESP protocol. + + This function is the subfunction of IpSecProtectOutboundPacket(). It protected + the sending packet by encrypting its payload and inserting ESP header in the orginal + IP header, then return the IpHeader and IPsec protected Fragmentable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Points to IP header containing the orginal IP header + to be processed on input, and inserted ESP header + on return. + @param[in] LastHead The Last Header in IP header. + @param[in] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments to be protected by + IPsec on input, and with IPsec protected + on return. + @param[in] FragmentCount The number of fragments. + @param[in] SadEntry The related SAD entry. + @param[out] RecycleEvent The event for recycling of resources. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated. + +**/ +EFI_STATUS +IpSecEspOutboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN UINT8 *LastHead, + IN VOID *OptionsBuffer, OPTIONAL + IN UINT32 OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + IN IPSEC_SAD_ENTRY *SadEntry, + OUT EFI_EVENT *RecycleEvent + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_IPSEC_SA_ID *SaId; + IPSEC_SAD_DATA *SadData; + IPSEC_RECYCLE_CONTEXT *RecycleContext; + UINT8 *ProcessBuffer; + UINTN BytesCopied; + INTN EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4 + UINTN EspSize; // Total size of esp wrapped ip payload + UINTN IvSize; // Size of IV, optional, might be 0 + UINTN PlainPayloadSize;// Original IP payload size + UINTN PaddingSize; // Size of padding + UINTN EncryptSize; // Size of data to be encrypted, start after IV and + // stop before ICV + UINTN IcvSize; // Size of ICV, optional, might be 0 + UINT8 *RestOfPayload; // Start of Payload after IV + UINT8 *Padding; // Start address of padding + EFI_ESP_HEADER *EspHeader; // Start address of ESP frame + EFI_ESP_TAIL *EspTail; // Address behind padding + + Status = EFI_ACCESS_DENIED; + SaId = SadEntry->Id; + SadData = SadEntry->Data; + ProcessBuffer = NULL; + RecycleContext = NULL; + *RecycleEvent = NULL; + + if (!SadData->ManualSet && + SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL && + SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL + ) { + // + // Invalid manual sad entry configuration. + // + goto ON_EXIT; + } + // + // Calculate enctrypt block size, need iv by default and 4 bytes alignment. + // + EncryptBlockSize = 4; + + if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { + EncryptBlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId); + + if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) { + goto ON_EXIT; + } + } + // + // Calculate the plain payload size accroding to the fragment table. + // + PlainPayloadSize = 0; + for (Index = 0; Index < *FragmentCount; Index++) { + PlainPayloadSize += (*FragmentTable)[Index].FragmentLength; + } + // + // Calculate icv size, optional by default and 4 bytes alignment. + // + IcvSize = 0; + if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { + IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId); + if (IcvSize % 4 != 0) { + goto ON_EXIT; + } + } + // + // Calcuate the total size of esp wrapped ip payload. + // + IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId); + EncryptSize = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize; + PaddingSize = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL); + EspSize = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize; + + ProcessBuffer = AllocateZeroPool (EspSize); + if (ProcessBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + // + // Calculate esp header and esp tail including header, payload and padding. + // + EspHeader = (EFI_ESP_HEADER *) ProcessBuffer; + RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize; + Padding = RestOfPayload + PlainPayloadSize; + EspTail = (EFI_ESP_TAIL *) (Padding + PaddingSize); + + // + // Fill the sn and spi fields in esp header. + // + EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1); + EspHeader->Spi = HTONL (SaId->Spi); + + // + // Copy the rest of payload (after iv) from the original fragment buffer. + // + BytesCopied = 0; + for (Index = 0; Index < *FragmentCount; Index++) { + CopyMem ( + (RestOfPayload + BytesCopied), + (*FragmentTable)[Index].FragmentBuffer, + (*FragmentTable)[Index].FragmentLength + ); + BytesCopied += (*FragmentTable)[Index].FragmentLength; + } + // + // Fill the padding buffer by natural number sequence. + // + for (Index = 0; Index < PaddingSize; Index++) { + Padding[Index] = (UINT8) (Index + 1); + } + // + // Fill the padding length and next header fields in esp tail. + // + EspTail->PaddingLength = (UINT8) PaddingSize; + EspTail->NextHeader = *LastHead; + + // + // Generate iv at random by crypt library. + // + Status = IpSecGenerateIv ( + (UINT8 *) (EspHeader + 1), + IvSize + ); + + + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + // + // Encrypt the payload (after iv) by the sad entry if has encrypt key. + // + if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) { + Status = IpSecEspEncryptPayload ( + RestOfPayload, + EncryptSize, + (UINT8 *) (EspHeader + 1), + IvSize, + SadEntry + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + // + // Authenticate the esp wrapped buffer by the sad entry if has auth key. + // + if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) { + Status = IpSecAuthPayload ( + ProcessBuffer, + EspSize - IcvSize, + ProcessBuffer + EspSize - IcvSize, + IcvSize, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey, + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + // + // Encryption and authentication with esp has been done, so it's time to + // reload the new packet, create recycle event and fixup ip header. + // + RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT)); + if (RecycleContext == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IpSecRecycleCallback, + RecycleContext, + RecycleEvent + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + // + // TODO: Who take responsible to handle the original fragment table? + // + *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA)); + if (*FragmentTable == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + RecycleContext->FragmentTable = *FragmentTable; + RecycleContext->PayloadBuffer = ProcessBuffer; + (*FragmentTable)[0].FragmentBuffer = ProcessBuffer; + (*FragmentTable)[0].FragmentLength = (UINT32) EspSize; + *FragmentCount = 1; + + // + // Update the total length field in ip header since processed by esp. + // + if (IpVersion == IP_VERSION_4) { + ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + EspSize)); + } else { + ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize); + } + // + // Update the next layer field in ip header since esp header inserted. + // + *LastHead = IPSEC_ESP_PROTOCOL; + + // + // Increase the sn number in sad entry according to rfc4303. + // + SadData->SequenceNumber++; + +ON_EXIT: + if (EFI_ERROR (Status)) { + if (ProcessBuffer != NULL) { + FreePool (ProcessBuffer); + } + + if (RecycleContext != NULL) { + FreePool (RecycleContext); + } + + if (*RecycleEvent != NULL) { + gBS->CloseEvent (*RecycleEvent); + } + } + + return Status; +} + +/** + This function processes the inbound traffic with IPsec. + + It checks the received packet security property, trims the ESP/AH header, and then + returns without an IPsec protected IP Header and FragmentTable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Points to IP header containing the ESP/AH header + to be trimed on input, and without ESP/AH header + on return. + @param[in] LastHead The Last Header in IP header on return. + @param[in] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec + protected on input, and without IPsec protected + on return. + @param[in] FragmentCount The number of fragments. + @param[out] SpdEntry Pointer to contain the address of SPD entry on return. + @param[out] RecycleEvent The event for recycling of resources. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED The IPSEC protocol is not supported. + +**/ +EFI_STATUS +IpSecProtectInboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN UINT8 *LastHead, + IN VOID *OptionsBuffer, OPTIONAL + IN UINT32 OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + OUT IPSEC_SPD_ENTRY **SpdEntry, + OUT EFI_EVENT *RecycleEvent + ) +{ + if (*LastHead == IPSEC_ESP_PROTOCOL) { + // + // Process the esp ipsec header of the inbound traffic. + // + return IpSecEspInboundPacket ( + IpVersion, + IpHead, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount, + SpdEntry, + RecycleEvent + ); + } + // + // The other protocols are not supported. + // + return EFI_UNSUPPORTED; +} + +/** + This function processes the output traffic with IPsec. + + It protected the sending packet by encrypting it payload and inserting ESP/AH header + in the orginal IP header, then returns the IpHeader and IPsec protected Fragmentable. + + @param[in] IpVersion The version of IP. + @param[in, out] IpHead Points to IP header containing the orginal IP header + to be processed on input, and inserted ESP/AH header + on return. + @param[in] LastHead The Last Header in the IP header. + @param[in] OptionsBuffer Pointer to the options buffer. It is optional. + @param[in] OptionsLength Length of the options buffer. It is optional. + @param[in, out] FragmentTable Pointer to a list of fragments to be protected by + IPsec on input, and with IPsec protected + on return. + @param[in] FragmentCount The number of fragments. + @param[in] SadEntry The related SAD entry. + @param[out] RecycleEvent The event for recycling of resources. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported. + +**/ +EFI_STATUS +IpSecProtectOutboundPacket ( + IN UINT8 IpVersion, + IN OUT VOID *IpHead, + IN UINT8 *LastHead, + IN VOID *OptionsBuffer, OPTIONAL + IN UINT32 OptionsLength, OPTIONAL + IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable, + IN UINT32 *FragmentCount, + IN IPSEC_SAD_ENTRY *SadEntry, + OUT EFI_EVENT *RecycleEvent + ) +{ + if (SadEntry->Id->Proto == EfiIPsecESP) { + // + // Process the esp ipsec header of the outbound traffic. + // + return IpSecEspOutboundPacket ( + IpVersion, + IpHead, + LastHead, + OptionsBuffer, + OptionsLength, + FragmentTable, + FragmentCount, + SadEntry, + RecycleEvent + ); + } + // + // The other protocols are not supported. + // + return EFI_UNSUPPORTED; +} -- cgit v1.2.3