/** @file | |
The implementation of IPSEC_CONFIG_PROTOCOL. | |
Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php. | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "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; | |
EFI_IP_ADDRESS ZeroAddress; | |
ZeroMem(&ZeroAddress, sizeof (EFI_IP_ADDRESS)); | |
// | |
// Zero Address means any address is matched. | |
// | |
if (AddressCount == 1) { | |
if (CompareMem ( | |
&AddressInfoList[0].Address, | |
&ZeroAddress, | |
sizeof (EFI_IP_ADDRESS) | |
) == 0) { | |
return TRUE; | |
} | |
} | |
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; | |
} | |
/** | |
Find if the two SPD Selectors has subordinative. | |
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 The first SPD Selector is subordinate Selector of second SPD Selector. | |
@retval FALSE The first SPD Selector is not subordinate Selector of second | |
SPD Selector. | |
**/ | |
BOOLEAN | |
IsSubSpdSelector ( | |
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->RemoteAddressCount > SpdSel2->RemoteAddressCount || | |
(SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) || | |
(SpdSel1->LocalPort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0)|| | |
(SpdSel1->LocalPortRange > SpdSel2->LocalPortRange && SpdSel1->LocalPort != 0)|| | |
(SpdSel1->RemotePort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0) || | |
(SpdSel1->RemotePortRange > SpdSel2->RemotePortRange && SpdSel2->RemotePort != 0) | |
) { | |
IsMatch = FALSE; | |
} | |
// | |
// 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. | |
// | |
if (IsMatch) { | |
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 < SpdSel1->RemoteAddressCount; Index++) { | |
if (!IsInAddressInfoList ( | |
&SpdSel1->RemoteAddress[Index], | |
SpdSel2->RemoteAddress, | |
SpdSel2->RemoteAddressCount | |
)) { | |
IsMatch = FALSE; | |
break; | |
} | |
} | |
} | |
} | |
if (IsMatch) { | |
return IsMatch; | |
} | |
// | |
// | |
// The SPD selector in SPD entry is two way. | |
// | |
// 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. | |
// | |
IsMatch = TRUE; | |
if (SpdSel1->LocalAddressCount > SpdSel2->RemoteAddressCount || | |
SpdSel1->RemoteAddressCount > SpdSel2->LocalAddressCount || | |
(SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) || | |
(SpdSel1->LocalPort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0)|| | |
(SpdSel1->LocalPortRange > SpdSel2->RemotePortRange && SpdSel1->RemotePort != 0)|| | |
(SpdSel1->RemotePort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0) || | |
(SpdSel1->RemotePortRange > SpdSel2->LocalPortRange && SpdSel2->LocalPort != 0) | |
) { | |
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->RemoteAddress, | |
SpdSel2->RemoteAddressCount | |
)) { | |
IsMatch = FALSE; | |
break; | |
} | |
} | |
if (IsMatch) { | |
for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) { | |
if (!IsInAddressInfoList ( | |
&SpdSel1->RemoteAddress[Index], | |
SpdSel2->LocalAddress, | |
SpdSel2->LocalAddressCount | |
)) { | |
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 | |
) | |
{ | |
BOOLEAN IsZero; | |
EFI_IPSEC_CONFIG_SELECTOR ZeroSelector; | |
IsZero = FALSE; | |
ZeroMem (&ZeroSelector, sizeof (EFI_IPSEC_CONFIG_SELECTOR)); | |
if (CompareMem (&ZeroSelector, Selector, sizeof (EFI_IPSEC_CONFIG_SELECTOR)) == 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_DATA2 *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_DATA2 *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 *Entry2; | |
LIST_ENTRY *NextEntry; | |
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; | |
// | |
// TODO: Deleted the related 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; | |
DuplicateSpdSelector ( | |
(EFI_IPSEC_CONFIG_SELECTOR *)SadEntry->Data->SpdSelector, | |
(EFI_IPSEC_CONFIG_SELECTOR *)SpdEntry->Selector, | |
NULL | |
); | |
} | |
} | |
} | |
// | |
// 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_DATA2 *SaData; | |
EFI_IPSEC_SA_ID *InsertBefore; | |
LIST_ENTRY *EntryInsertBefore; | |
UINTN SadEntrySize; | |
SaId = (Selector == NULL) ? NULL : &Selector->SaId; | |
SaData = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA2 *) 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_ID)); | |
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 += ALIGN_VARIABLE (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength); | |
} | |
if (SaData->SpdSelector != NULL) { | |
SadEntrySize += SadEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector); | |
} | |
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->SpdSelector = NULL; | |
SadEntry->Data->ESNEnabled = FALSE; | |
SadEntry->Data->ManualSet = SaData->ManualSet; | |
// | |
// Copy Tunnel Source/Destination Address | |
// | |
if (SaData->Mode == EfiIPsecTunnel) { | |
CopyMem ( | |
&SadEntry->Data->TunnelDestAddress, | |
&SaData->TunnelDestinationAddress, | |
sizeof (EFI_IP_ADDRESS) | |
); | |
CopyMem ( | |
&SadEntry->Data->TunnelSourceAddress, | |
&SaData->TunnelSourceAddress, | |
sizeof (EFI_IP_ADDRESS) | |
); | |
} | |
// | |
// 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 (IsSubSpdSelector ( | |
(EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector, | |
(EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector | |
) && SpdEntry->Data->Action == EfiIPsecActionProtect) { | |
SadEntry->Data->SpdEntry = SpdEntry; | |
SadEntry->Data->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *)((UINT8 *)SadEntry + | |
SadEntrySize - | |
(UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector) | |
); | |
DuplicateSpdSelector ( | |
(EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector, | |
(EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector, | |
NULL | |
); | |
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_DATA2 *SaData; | |
UINTN RequiredSize; | |
SaId = &Selector->SaId; | |
SaData = (EFI_IPSEC_SA_DATA2 *) 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_DATA2)); | |
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->SpdSelector != NULL) { | |
RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector); | |
} | |
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 Tunnel Address if it is Tunnel Mode | |
// | |
if (SadEntry->Data->Mode == EfiIPsecTunnel) { | |
CopyMem ( | |
&SaData->TunnelDestinationAddress, | |
&SadEntry->Data->TunnelDestAddress, | |
sizeof (EFI_IP_ADDRESS) | |
); | |
CopyMem ( | |
&SaData->TunnelSourceAddress, | |
&SadEntry->Data->TunnelSourceAddress, | |
sizeof (EFI_IP_ADDRESS) | |
); | |
} | |
// | |
// Fill the spd selector field of SAD data | |
// | |
if (SadEntry->Data->SpdSelector != NULL) { | |
SaData->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) ( | |
(UINT8 *)SaData + | |
RequiredSize - | |
SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector) | |
); | |
DuplicateSpdSelector ( | |
(EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector, | |
(EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector, | |
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 | |
); | |
if (VariableNameI == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
break; | |
} | |
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: | |
if (VariableNameI != NULL) { | |
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 || (BOOLEAN)(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_DATA2 *) 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 (TempPoint == 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 | |
); | |
} |