blob: a976459692a9648709e77e10740a38f06eb44578 [file] [log] [blame]
/** @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;
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
);
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 || 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 (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
);
}