]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/IpSecDxe/IpSecConfigImpl.c
Add NetworkPkg (P.UDK2010.UP3.Network.P1)
[mirror_edk2.git] / NetworkPkg / IpSecDxe / IpSecConfigImpl.c
diff --git a/NetworkPkg/IpSecDxe/IpSecConfigImpl.c b/NetworkPkg/IpSecDxe/IpSecConfigImpl.c
new file mode 100644 (file)
index 0000000..e671e42
--- /dev/null
@@ -0,0 +1,2928 @@
+/** @file\r
+  The implementation of IPSEC_CONFIG_PROTOCOL.\r
+\r
+  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IpSecConfigImpl.h"\r
+#include "IpSecDebug.h"\r
+\r
+LIST_ENTRY                mConfigData[IPsecConfigDataTypeMaximum];\r
+BOOLEAN                   mSetBySelf = FALSE;\r
+\r
+//\r
+// Common CompareSelector routine entry for spd/sad/pad.\r
+//\r
+IPSEC_COMPARE_SELECTOR    mCompareSelector[] = {\r
+  (IPSEC_COMPARE_SELECTOR) CompareSpdSelector,\r
+  (IPSEC_COMPARE_SELECTOR) CompareSaId,\r
+  (IPSEC_COMPARE_SELECTOR) ComparePadId\r
+};\r
+\r
+//\r
+// Common IsZeroSelector routine entry for spd/sad/pad.\r
+//\r
+IPSEC_IS_ZERO_SELECTOR    mIsZeroSelector[] = {\r
+  (IPSEC_IS_ZERO_SELECTOR) IsZeroSpdSelector,\r
+  (IPSEC_IS_ZERO_SELECTOR) IsZeroSaId,\r
+  (IPSEC_IS_ZERO_SELECTOR) IsZeroPadId\r
+};\r
+\r
+//\r
+// Common DuplicateSelector routine entry for spd/sad/pad.\r
+//\r
+IPSEC_DUPLICATE_SELECTOR  mDuplicateSelector[] = {\r
+  (IPSEC_DUPLICATE_SELECTOR) DuplicateSpdSelector,\r
+  (IPSEC_DUPLICATE_SELECTOR) DuplicateSaId,\r
+  (IPSEC_DUPLICATE_SELECTOR) DuplicatePadId\r
+};\r
+\r
+//\r
+// Common FixPolicyEntry routine entry for spd/sad/pad.\r
+//\r
+IPSEC_FIX_POLICY_ENTRY    mFixPolicyEntry[] = {\r
+  (IPSEC_FIX_POLICY_ENTRY) FixSpdEntry,\r
+  (IPSEC_FIX_POLICY_ENTRY) FixSadEntry,\r
+  (IPSEC_FIX_POLICY_ENTRY) FixPadEntry\r
+};\r
+\r
+//\r
+// Common UnfixPolicyEntry routine entry for spd/sad/pad.\r
+//\r
+IPSEC_FIX_POLICY_ENTRY    mUnfixPolicyEntry[] = {\r
+  (IPSEC_FIX_POLICY_ENTRY) UnfixSpdEntry,\r
+  (IPSEC_FIX_POLICY_ENTRY) UnfixSadEntry,\r
+  (IPSEC_FIX_POLICY_ENTRY) UnfixPadEntry\r
+};\r
+\r
+//\r
+// Common SetPolicyEntry routine entry for spd/sad/pad.\r
+//\r
+IPSEC_SET_POLICY_ENTRY    mSetPolicyEntry[] = {\r
+  (IPSEC_SET_POLICY_ENTRY) SetSpdEntry,\r
+  (IPSEC_SET_POLICY_ENTRY) SetSadEntry,\r
+  (IPSEC_SET_POLICY_ENTRY) SetPadEntry\r
+};\r
+\r
+//\r
+// Common GetPolicyEntry routine entry for spd/sad/pad.\r
+//\r
+IPSEC_GET_POLICY_ENTRY    mGetPolicyEntry[] = {\r
+  (IPSEC_GET_POLICY_ENTRY) GetSpdEntry,\r
+  (IPSEC_GET_POLICY_ENTRY) GetSadEntry,\r
+  (IPSEC_GET_POLICY_ENTRY) GetPadEntry\r
+};\r
+\r
+//\r
+// Routine entry for IpSecConfig protocol.\r
+//\r
+EFI_IPSEC_CONFIG_PROTOCOL mIpSecConfigInstance = {\r
+  EfiIpSecConfigSetData,\r
+  EfiIpSecConfigGetData,\r
+  EfiIpSecConfigGetNextSelector,\r
+  EfiIpSecConfigRegisterNotify,\r
+  EfiIpSecConfigUnregisterNotify\r
+};\r
+\r
+/**\r
+  Get the all IPSec configuration variables and store those variables\r
+  to the internal data structure.\r
+\r
+  This founction is called by IpSecConfigInitialize() that is to intialize the\r
+  IPsecConfiguration Protocol.\r
+\r
+  @param[in]  Private            Point to IPSEC_PRIVATE_DATA.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated.\r
+  @retval EFI_SUCCESS            Restore the IPsec Configuration successfully.\r
+  @retval  others                Other errors is found during the variable getting.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecConfigRestore (\r
+  IN IPSEC_PRIVATE_DATA               *Private\r
+  );\r
+\r
+/**\r
+  Check if the specified EFI_IP_ADDRESS_INFO is in EFI_IP_ADDRESS_INFO list.\r
+\r
+  @param[in]   AddressInfo         Pointer of IP_ADDRESS_INFO to be search in AddressInfo list.\r
+  @param[in]   AddressInfoList     A list that contains IP_ADDRESS_INFOs.\r
+  @param[in]   AddressCount        Point out how many IP_ADDRESS_INFO in the list.\r
+\r
+  @retval  TRUE    The specified AddressInfo is in the AddressInfoList.\r
+  @retval  FALSE   The specified AddressInfo is not in the AddressInfoList.\r
+\r
+**/\r
+BOOLEAN\r
+IsInAddressInfoList(\r
+  IN EFI_IP_ADDRESS_INFO              *AddressInfo,\r
+  IN EFI_IP_ADDRESS_INFO              *AddressInfoList,\r
+  IN UINT32                           AddressCount\r
+  )\r
+{\r
+  UINT8  Index;\r
+\r
+  for (Index = 0; Index < AddressCount ; Index++) {\r
+    if (CompareMem (\r
+          AddressInfo,\r
+          &AddressInfoList[Index].Address,\r
+          sizeof (EFI_IP_ADDRESS)\r
+          ) == 0 &&\r
+          AddressInfo->PrefixLength == AddressInfoList[Index].PrefixLength\r
+          ) {\r
+       return TRUE;\r
+     }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Compare two SPD Selectors.\r
+\r
+  Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/\r
+  NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the\r
+  Local Addresses and remote Addresses.\r
+\r
+  @param[in]   Selector1           Pointer of first SPD Selector.\r
+  @param[in]   Selector2           Pointer of second SPD Selector.\r
+\r
+  @retval  TRUE    This two Selector have the same value in above fields.\r
+  @retval  FALSE   Not all above fields have the same value in these two Selectors.\r
+\r
+**/\r
+BOOLEAN\r
+CompareSpdSelector (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector1,\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector2\r
+  )\r
+{\r
+  EFI_IPSEC_SPD_SELECTOR  *SpdSel1;\r
+  EFI_IPSEC_SPD_SELECTOR  *SpdSel2;\r
+  BOOLEAN                 IsMatch;\r
+  UINTN                   Index;\r
+\r
+  SpdSel1 = &Selector1->SpdSelector;\r
+  SpdSel2 = &Selector2->SpdSelector;\r
+  IsMatch = TRUE;\r
+\r
+  //\r
+  // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/\r
+  // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the\r
+  // two Spdselectors. Since the SPD supports two directions, it needs to\r
+  // compare two directions.\r
+  //\r
+  if ((SpdSel1->LocalAddressCount != SpdSel2->LocalAddressCount &&\r
+       SpdSel1->LocalAddressCount != SpdSel2->RemoteAddressCount) ||\r
+      (SpdSel1->RemoteAddressCount != SpdSel2->RemoteAddressCount &&\r
+       SpdSel1->RemoteAddressCount != SpdSel2->LocalAddressCount) ||\r
+       SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol ||\r
+       SpdSel1->LocalPort != SpdSel2->LocalPort ||\r
+       SpdSel1->LocalPortRange != SpdSel2->LocalPortRange ||\r
+       SpdSel1->RemotePort != SpdSel2->RemotePort ||\r
+       SpdSel1->RemotePortRange != SpdSel2->RemotePortRange\r
+       ) {\r
+    IsMatch = FALSE;\r
+    return IsMatch;\r
+  }\r
+\r
+  //\r
+  // Compare the all LocalAddress fields in the two Spdselectors.\r
+  // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare\r
+  // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return\r
+  // TRUE.\r
+  //\r
+  for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {\r
+    if (!IsInAddressInfoList (\r
+          &SpdSel1->LocalAddress[Index],\r
+          SpdSel2->LocalAddress,\r
+          SpdSel2->LocalAddressCount\r
+          )) {\r
+      IsMatch = FALSE;\r
+      break;\r
+    }\r
+  }\r
+  if (IsMatch) {\r
+    for (Index = 0; Index < SpdSel2->LocalAddressCount; Index++) {\r
+      if (!IsInAddressInfoList (\r
+            &SpdSel2->LocalAddress[Index],\r
+            SpdSel1->LocalAddress,\r
+            SpdSel1->LocalAddressCount\r
+            )) {\r
+        IsMatch = FALSE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  if (IsMatch) {\r
+    for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {\r
+      if (!IsInAddressInfoList (\r
+            &SpdSel1->RemoteAddress[Index],\r
+            SpdSel2->RemoteAddress,\r
+            SpdSel2->RemoteAddressCount\r
+            )) {\r
+        IsMatch = FALSE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  if (IsMatch) {\r
+    for (Index = 0; Index < SpdSel2->RemoteAddressCount; Index++) {\r
+      if (!IsInAddressInfoList (\r
+            &SpdSel2->RemoteAddress[Index],\r
+            SpdSel1->RemoteAddress,\r
+            SpdSel1->RemoteAddressCount\r
+            )) {\r
+        IsMatch = FALSE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // Finish the one direction compare. If it is matched, return; otherwise,\r
+  // compare the other direction.\r
+  //\r
+  if (IsMatch) {\r
+    return IsMatch;\r
+  }\r
+  //\r
+  // Secondly, the SpdSel1->LocalAddress doesn't equal to  SpdSel2->LocalAddress and\r
+  // SpdSel1->RemoteAddress doesn't equal to SpdSel2->RemoteAddress. Try to compare\r
+  // the RemoteAddress to LocalAddress.\r
+  //\r
+  IsMatch = TRUE;\r
+  for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {\r
+    if (!IsInAddressInfoList (\r
+          &SpdSel1->RemoteAddress[Index],\r
+          SpdSel2->LocalAddress,\r
+          SpdSel2->LocalAddressCount\r
+          )) {\r
+      IsMatch = FALSE;\r
+      break;\r
+    }\r
+  }\r
+  if (IsMatch) {\r
+    for (Index = 0; Index < SpdSel2->RemoteAddressCount; Index++) {\r
+      if (!IsInAddressInfoList (\r
+            &SpdSel2->RemoteAddress[Index],\r
+            SpdSel1->LocalAddress,\r
+            SpdSel1->LocalAddressCount\r
+            )) {\r
+        IsMatch = FALSE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  if (IsMatch) {\r
+    for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {\r
+      if (!IsInAddressInfoList (\r
+            &SpdSel1->LocalAddress[Index],\r
+            SpdSel2->RemoteAddress,\r
+            SpdSel2->RemoteAddressCount\r
+            )) {\r
+        IsMatch = FALSE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  if (IsMatch) {\r
+    for (Index = 0; Index < SpdSel2->LocalAddressCount; Index++) {\r
+      if (!IsInAddressInfoList (\r
+            &SpdSel2->LocalAddress[Index],\r
+            SpdSel1->RemoteAddress,\r
+            SpdSel1->RemoteAddressCount\r
+            )) {\r
+        IsMatch = FALSE;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  return IsMatch;\r
+}\r
+\r
+/**\r
+  Compare two SA IDs.\r
+\r
+  @param[in]   Selector1           Pointer of first SA ID.\r
+  @param[in]   Selector2           Pointer of second SA ID.\r
+\r
+  @retval  TRUE    This two Selectors have the same SA ID.\r
+  @retval  FALSE   This two Selecotrs don't have the same SA ID.\r
+\r
+**/\r
+BOOLEAN\r
+CompareSaId (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector1,\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector2\r
+  )\r
+{\r
+  EFI_IPSEC_SA_ID *SaId1;\r
+  EFI_IPSEC_SA_ID *SaId2;\r
+  BOOLEAN         IsMatch;\r
+\r
+  SaId1   = &Selector1->SaId;\r
+  SaId2   = &Selector2->SaId;\r
+  IsMatch = TRUE;\r
+\r
+  if (CompareMem (SaId1, SaId2, sizeof (EFI_IPSEC_SA_ID)) != 0) {\r
+    IsMatch = FALSE;\r
+  }\r
+\r
+  return IsMatch;\r
+}\r
+\r
+/**\r
+  Compare two PAD IDs.\r
+\r
+  @param[in]   Selector1           Pointer of first PAD ID.\r
+  @param[in]   Selector2           Pointer of second PAD ID.\r
+\r
+  @retval  TRUE    This two Selectors have the same PAD ID.\r
+  @retval  FALSE   This two Selecotrs don't have the same PAD ID.\r
+\r
+**/\r
+BOOLEAN\r
+ComparePadId (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector1,\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector2\r
+  )\r
+{\r
+  EFI_IPSEC_PAD_ID  *PadId1;\r
+  EFI_IPSEC_PAD_ID  *PadId2;\r
+  BOOLEAN           IsMatch;\r
+\r
+  PadId1  = &Selector1->PadId;\r
+  PadId2  = &Selector2->PadId;\r
+  IsMatch = TRUE;\r
+\r
+  //\r
+  // Compare the PeerIdValid fields in PadId.\r
+  //\r
+  if (PadId1->PeerIdValid != PadId2->PeerIdValid) {\r
+    IsMatch = FALSE;\r
+  }\r
+  //\r
+  // Compare the PeerId fields in PadId if PeerIdValid is true.\r
+  //\r
+  if (IsMatch &&\r
+      PadId1->PeerIdValid &&\r
+      AsciiStriCmp ((CONST CHAR8 *) PadId1->Id.PeerId, (CONST CHAR8 *) PadId2->Id.PeerId) != 0\r
+      ) {\r
+    IsMatch = FALSE;\r
+  }\r
+  //\r
+  // Compare the IpAddress fields in PadId if PeerIdValid is false.\r
+  //\r
+  if (IsMatch &&\r
+      !PadId1->PeerIdValid &&\r
+      (PadId1->Id.IpAddress.PrefixLength != PadId2->Id.IpAddress.PrefixLength ||\r
+       CompareMem (&PadId1->Id.IpAddress.Address, &PadId2->Id.IpAddress.Address, sizeof (EFI_IP_ADDRESS)) != 0)\r
+      ) {\r
+    IsMatch = FALSE;\r
+  }\r
+\r
+  return IsMatch;\r
+}\r
+\r
+/**\r
+  Check if the SPD Selector is Zero by its LocalAddressCount and RemoteAddressCount\r
+  fields.\r
+\r
+  @param[in]  Selector      Pointer of the SPD Selector.\r
+\r
+  @retval     TRUE          If the SPD Selector is Zero.\r
+  @retval     FALSE         If the SPD Selector is not Zero.\r
+\r
+**/\r
+BOOLEAN\r
+IsZeroSpdSelector (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector\r
+  )\r
+{\r
+  EFI_IPSEC_SPD_SELECTOR  *SpdSel;\r
+  BOOLEAN                 IsZero;\r
+\r
+  SpdSel  = &Selector->SpdSelector;\r
+  IsZero  = FALSE;\r
+\r
+  if (SpdSel->LocalAddressCount == 0 && SpdSel->RemoteAddressCount == 0) {\r
+    IsZero = TRUE;\r
+  }\r
+\r
+  return IsZero;\r
+}\r
+\r
+/**\r
+  Check if the SA ID is Zero by its DestAddress.\r
+\r
+  @param[in]  Selector      Pointer of the SA ID.\r
+\r
+  @retval     TRUE          If the SA ID is Zero.\r
+  @retval     FALSE         If the SA ID is not Zero.\r
+\r
+**/\r
+BOOLEAN\r
+IsZeroSaId (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector\r
+  )\r
+{\r
+  EFI_IP_ADDRESS  *DestAddr;\r
+  EFI_IP_ADDRESS  ZeroAddr;\r
+  BOOLEAN         IsZero;\r
+\r
+  DestAddr  = &Selector->SaId.DestAddress;\r
+  IsZero    = FALSE;\r
+\r
+  ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS));\r
+\r
+  if (CompareMem (DestAddr, &ZeroAddr, sizeof (EFI_IP_ADDRESS)) == 0) {\r
+    IsZero = TRUE;\r
+  }\r
+\r
+  return IsZero;\r
+}\r
+\r
+/**\r
+  Check if the PAD ID is Zero.\r
+\r
+  @param[in]  Selector      Pointer of the PAD ID.\r
+\r
+  @retval     TRUE          If the PAD ID is Zero.\r
+  @retval     FALSE         If the PAD ID is not Zero.\r
+\r
+**/\r
+BOOLEAN\r
+IsZeroPadId (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector\r
+  )\r
+{\r
+  EFI_IPSEC_PAD_ID  *PadId;\r
+  EFI_IPSEC_PAD_ID  ZeroId;\r
+  BOOLEAN           IsZero;\r
+\r
+  PadId   = &Selector->PadId;\r
+  IsZero  = FALSE;\r
+\r
+  ZeroMem (&ZeroId, sizeof (EFI_IPSEC_PAD_ID));\r
+\r
+  if (CompareMem (PadId, &ZeroId, sizeof (EFI_IPSEC_PAD_ID)) == 0) {\r
+    IsZero = TRUE;\r
+  }\r
+\r
+  return IsZero;\r
+}\r
+\r
+/**\r
+  Copy Source SPD Selector to the Destination SPD Selector.\r
+\r
+  @param[in, out] DstSel             Pointer of Destination SPD Selector.\r
+  @param[in]      SrcSel             Pointer of Source SPD Selector.\r
+  @param[in, out] Size               The size of the Destination SPD Selector. If it\r
+                                     not NULL and its value less than the size of\r
+                                     Source SPD Selector, the value of Source SPD\r
+                                     Selector's size will be passed to caller by this\r
+                                     parameter.\r
+\r
+  @retval EFI_INVALID_PARAMETER  If the Destination or Source SPD Selector is NULL\r
+  @retval EFI_BUFFER_TOO_SMALL   If the input Size is less than size of the Source SPD Selector.\r
+  @retval EFI_SUCCESS            Copy Source SPD Selector to the Destination SPD\r
+                                 Selector successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+DuplicateSpdSelector (\r
+  IN OUT EFI_IPSEC_CONFIG_SELECTOR    *DstSel,\r
+  IN     EFI_IPSEC_CONFIG_SELECTOR    *SrcSel,\r
+  IN OUT UINTN                        *Size\r
+  )\r
+{\r
+  EFI_IPSEC_SPD_SELECTOR  *Dst;\r
+  EFI_IPSEC_SPD_SELECTOR  *Src;\r
+\r
+  Dst = &DstSel->SpdSelector;\r
+  Src = &SrcSel->SpdSelector;\r
+\r
+  if (Dst == NULL || Src == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Size != NULL && (*Size) < SIZE_OF_SPD_SELECTOR (Src)) {\r
+    *Size = SIZE_OF_SPD_SELECTOR (Src);\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  //\r
+  // Copy the base structure of spd selector.\r
+  //\r
+  CopyMem (Dst, Src, sizeof (EFI_IPSEC_SPD_SELECTOR));\r
+\r
+  //\r
+  // Copy the local address array of spd selector.\r
+  //\r
+  Dst->LocalAddress = (EFI_IP_ADDRESS_INFO *) (Dst + 1);\r
+  CopyMem (\r
+    Dst->LocalAddress,\r
+    Src->LocalAddress,\r
+    sizeof (EFI_IP_ADDRESS_INFO) * Dst->LocalAddressCount\r
+    );\r
+\r
+  //\r
+  // Copy the remote address array of spd selector.\r
+  //\r
+  Dst->RemoteAddress = Dst->LocalAddress + Dst->LocalAddressCount;\r
+  CopyMem (\r
+    Dst->RemoteAddress,\r
+    Src->RemoteAddress,\r
+    sizeof (EFI_IP_ADDRESS_INFO) * Dst->RemoteAddressCount\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Copy Source SA ID to the Destination SA ID.\r
+\r
+  @param[in, out] DstSel             Pointer of Destination SA ID.\r
+  @param[in]      SrcSel             Pointer of Source SA ID.\r
+  @param[in, out] Size               The size of the Destination SA ID. If it\r
+                                     not NULL and its value less than the size of\r
+                                     Source SA ID, the value of Source SA ID's size\r
+                                     will be passed to caller by this parameter.\r
+\r
+  @retval EFI_INVALID_PARAMETER  If the Destination or Source SA ID is NULL.\r
+  @retval EFI_BUFFER_TOO_SMALL   If the input Size less than size of source SA ID.\r
+  @retval EFI_SUCCESS            Copy Source SA ID  to the Destination SA ID successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+DuplicateSaId (\r
+  IN OUT EFI_IPSEC_CONFIG_SELECTOR    *DstSel,\r
+  IN     EFI_IPSEC_CONFIG_SELECTOR    *SrcSel,\r
+  IN OUT UINTN                        *Size\r
+  )\r
+{\r
+  EFI_IPSEC_SA_ID *Dst;\r
+  EFI_IPSEC_SA_ID *Src;\r
+\r
+  Dst = &DstSel->SaId;\r
+  Src = &SrcSel->SaId;\r
+\r
+  if (Dst == NULL || Src == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Size != NULL && *Size < sizeof (EFI_IPSEC_SA_ID)) {\r
+    *Size = sizeof (EFI_IPSEC_SA_ID);\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  CopyMem (Dst, Src, sizeof (EFI_IPSEC_SA_ID));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Copy Source PAD ID to the Destination PAD ID.\r
+\r
+  @param[in, out] DstSel             Pointer of Destination PAD ID.\r
+  @param[in]      SrcSel             Pointer of Source PAD ID.\r
+  @param[in, out] Size               The size of the Destination PAD ID. If it\r
+                                     not NULL and its value less than the size of\r
+                                     Source PAD ID, the value of Source PAD ID's size\r
+                                     will be passed to caller by this parameter.\r
+\r
+  @retval EFI_INVALID_PARAMETER  If the Destination or Source PAD ID is NULL.\r
+  @retval EFI_BUFFER_TOO_SMALL   If the input Size less than size of source PAD ID .\r
+  @retval EFI_SUCCESS            Copy Source PAD ID  to the Destination PAD ID successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+DuplicatePadId (\r
+  IN OUT EFI_IPSEC_CONFIG_SELECTOR    *DstSel,\r
+  IN     EFI_IPSEC_CONFIG_SELECTOR    *SrcSel,\r
+  IN OUT UINTN                        *Size\r
+  )\r
+{\r
+  EFI_IPSEC_PAD_ID  *Dst;\r
+  EFI_IPSEC_PAD_ID  *Src;\r
+\r
+  Dst = &DstSel->PadId;\r
+  Src = &SrcSel->PadId;\r
+\r
+  if (Dst == NULL || Src == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Size != NULL && *Size < sizeof (EFI_IPSEC_PAD_ID)) {\r
+    *Size = sizeof (EFI_IPSEC_PAD_ID);\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  CopyMem (Dst, Src, sizeof (EFI_IPSEC_PAD_ID));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Fix the value of some members of SPD Selector.\r
+\r
+  This function is called by IpSecCopyPolicyEntry()which copy the Policy\r
+  Entry into the Variable. Since some members in SPD Selector are pointers,\r
+  a physical address to relative address convertion is required before copying\r
+  this SPD entry into the variable.\r
+\r
+  @param[in]       Selector              Pointer of SPD Selector.\r
+  @param[in, out]  Data                  Pointer of SPD Data.\r
+\r
+**/\r
+VOID\r
+FixSpdEntry (\r
+  IN     EFI_IPSEC_SPD_SELECTOR            *Selector,\r
+  IN OUT EFI_IPSEC_SPD_DATA                *Data\r
+  )\r
+{\r
+  //\r
+  // It assumes that all ref buffers in spd selector and data are\r
+  // stored in the continous memory and close to the base structure.\r
+  //\r
+  FIX_REF_BUF_ADDR (Selector->LocalAddress, Selector);\r
+  FIX_REF_BUF_ADDR (Selector->RemoteAddress, Selector);\r
+\r
+  if (Data->ProcessingPolicy != NULL) {\r
+    if (Data->ProcessingPolicy->TunnelOption != NULL) {\r
+      FIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data);\r
+    }\r
+\r
+    FIX_REF_BUF_ADDR (Data->ProcessingPolicy, Data);\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Fix the value of some members of SA ID.\r
+\r
+  This function is called by IpSecCopyPolicyEntry()which copy the Policy\r
+  Entry into the Variable. Since some members in SA ID are pointers,\r
+  a physical address to relative address conversion is required before copying\r
+  this SAD into the variable.\r
+\r
+  @param[in]       SaId                  Pointer of SA ID\r
+  @param[in, out]  Data                  Pointer of SA Data.\r
+\r
+**/\r
+VOID\r
+FixSadEntry (\r
+  IN     EFI_IPSEC_SA_ID                  *SaId,\r
+  IN OUT EFI_IPSEC_SA_DATA                *Data\r
+  )\r
+{\r
+  //\r
+  // It assumes that all ref buffers in sad selector and data are\r
+  // stored in the continous memory and close to the base structure.\r
+  //\r
+  if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
+    FIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.AuthKey, Data);\r
+  }\r
+\r
+  if (SaId->Proto == EfiIPsecESP && Data->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
+    FIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.EncKey, Data);\r
+  }\r
+\r
+  if (Data->SpdSelector != NULL) {\r
+    if (Data->SpdSelector->LocalAddress != NULL) {\r
+      FIX_REF_BUF_ADDR (Data->SpdSelector->LocalAddress, Data);\r
+    }\r
+\r
+    FIX_REF_BUF_ADDR (Data->SpdSelector->RemoteAddress, Data);\r
+    FIX_REF_BUF_ADDR (Data->SpdSelector, Data);\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Fix the value of some members of PAD ID.\r
+\r
+  This function is called by IpSecCopyPolicyEntry()which copy the Policy\r
+  Entry into the Variable. Since some members in PAD ID are pointers,\r
+  a physical address to relative address conversion is required before copying\r
+  this PAD into the variable.\r
+\r
+  @param[in]       PadId              Pointer of PAD ID.\r
+  @param[in, out]  Data               Pointer of PAD Data.\r
+\r
+**/\r
+VOID\r
+FixPadEntry (\r
+  IN     EFI_IPSEC_PAD_ID                  *PadId,\r
+  IN OUT EFI_IPSEC_PAD_DATA                *Data\r
+  )\r
+{\r
+  //\r
+  // It assumes that all ref buffers in pad selector and data are\r
+  // stored in the continous memory and close to the base structure.\r
+  //\r
+  if (Data->AuthData != NULL) {\r
+    FIX_REF_BUF_ADDR (Data->AuthData, Data);\r
+  }\r
+\r
+  if (Data->RevocationData != NULL) {\r
+    FIX_REF_BUF_ADDR (Data->RevocationData, Data);\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Recover the value of some members of SPD Selector.\r
+\r
+  This function is corresponding to FixSpdEntry(). It recovers the value of members\r
+  of SPD Selector that are fixed by FixSpdEntry().\r
+\r
+  @param[in, out]  Selector              Pointer of SPD Selector.\r
+  @param[in, out]  Data                  Pointer of SPD Data.\r
+\r
+**/\r
+VOID\r
+UnfixSpdEntry (\r
+  IN OUT EFI_IPSEC_SPD_SELECTOR           *Selector,\r
+  IN OUT EFI_IPSEC_SPD_DATA               *Data\r
+  )\r
+{\r
+  //\r
+  // It assumes that all ref buffers in spd selector and data are\r
+  // stored in the continous memory and close to the base structure.\r
+  //\r
+  UNFIX_REF_BUF_ADDR (Selector->LocalAddress, Selector);\r
+  UNFIX_REF_BUF_ADDR (Selector->RemoteAddress, Selector);\r
+\r
+  if (Data->ProcessingPolicy != NULL) {\r
+    UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy, Data);\r
+    if (Data->ProcessingPolicy->TunnelOption != NULL) {\r
+      UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data);\r
+    }\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Recover the value of some members of SA ID.\r
+\r
+  This function is corresponding to FixSadEntry(). It recovers the value of members\r
+  of SAD ID that are fixed by FixSadEntry().\r
+\r
+  @param[in, out]  SaId              Pointer of SAD ID.\r
+  @param[in, out]  Data              Pointer of SAD Data.\r
+\r
+**/\r
+VOID\r
+UnfixSadEntry (\r
+  IN OUT EFI_IPSEC_SA_ID                     *SaId,\r
+  IN OUT EFI_IPSEC_SA_DATA                   *Data\r
+  )\r
+{\r
+  //\r
+  // It assumes that all ref buffers in sad selector and data are\r
+  // stored in the continous memory and close to the base structure.\r
+  //\r
+  if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
+    UNFIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.AuthKey, Data);\r
+  }\r
+\r
+  if (SaId->Proto == EfiIPsecESP && Data->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
+    UNFIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.EncKey, Data);\r
+  }\r
+\r
+  if (Data->SpdSelector != NULL) {\r
+    UNFIX_REF_BUF_ADDR (Data->SpdSelector, Data);\r
+    if (Data->SpdSelector->LocalAddress != NULL) {\r
+      UNFIX_REF_BUF_ADDR (Data->SpdSelector->LocalAddress, Data);\r
+    }\r
+\r
+    UNFIX_REF_BUF_ADDR (Data->SpdSelector->RemoteAddress, Data);\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Recover the value of some members of PAD ID.\r
+\r
+  This function is corresponding to FixPadEntry(). It recovers the value of members\r
+  of PAD ID that are fixed by FixPadEntry().\r
+\r
+  @param[in]       PadId              Pointer of PAD ID.\r
+  @param[in, out]  Data               Pointer of PAD Data.\r
+\r
+**/\r
+VOID\r
+UnfixPadEntry (\r
+  IN     EFI_IPSEC_PAD_ID                 *PadId,\r
+  IN OUT EFI_IPSEC_PAD_DATA               *Data\r
+  )\r
+{\r
+  //\r
+  // It assumes that all ref buffers in pad selector and data are\r
+  // stored in the continous memory and close to the base structure.\r
+  //\r
+  if (Data->AuthData != NULL) {\r
+    UNFIX_REF_BUF_ADDR (Data->AuthData, Data);\r
+  }\r
+\r
+  if (Data->RevocationData != NULL) {\r
+    UNFIX_REF_BUF_ADDR (Data->RevocationData, Data);\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Set the security policy information for the EFI IPsec driver.\r
+\r
+  The IPsec configuration data has a unique selector/identifier separately to\r
+  identify a data entry.\r
+\r
+  @param[in]  Selector           Pointer to an entry selector on operated\r
+                                 configuration data specified by DataType.\r
+                                 A NULL Selector causes the entire specified-type\r
+                                 configuration information to be flushed.\r
+  @param[in]  Data               The data buffer to be set. The structure\r
+                                 of the data buffer should be EFI_IPSEC_SPD_DATA.\r
+  @param[in]  Context            Pointer to one entry selector that describes\r
+                                 the expected position the new data entry will\r
+                                 be added. If Context is NULL, the new entry will\r
+                                 be appended the end of database.\r
+\r
+  @retval EFI_INVALID_PARAMETER  One or more of the following are TRUE:\r
+                                   - Selector is not NULL and its LocalAddress\r
+                                     is NULL or its RemoteAddress is NULL.\r
+                                   - Data is not NULL and its Action is Protected\r
+                                     and its plolicy is NULL.\r
+                                   - Data is not NULL, its Action is not protected,\r
+                                     and its policy is not NULL.\r
+                                   - The Action of Data is Protected, its policy\r
+                                     mode is Tunnel, and its tunnel option is NULL.\r
+                                   - The Action of Data is protected and its policy\r
+                                     mode is not Tunnel and it tunnel option is not NULL.\r
+  @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SetSpdEntry (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,\r
+  IN VOID                            *Data,\r
+  IN VOID                            *Context OPTIONAL\r
+  )\r
+{\r
+  EFI_IPSEC_SPD_SELECTOR  *SpdSel;\r
+  EFI_IPSEC_SPD_DATA      *SpdData;\r
+  EFI_IPSEC_SPD_SELECTOR  *InsertBefore;\r
+  LIST_ENTRY              *SpdList;\r
+  LIST_ENTRY              *SadList;\r
+  LIST_ENTRY              *SpdSas;\r
+  LIST_ENTRY              *EntryInsertBefore;\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *NextEntry;\r
+  LIST_ENTRY              *Entry2;\r
+  IPSEC_SPD_ENTRY         *SpdEntry;\r
+  IPSEC_SAD_ENTRY         *SadEntry;\r
+  UINTN                   SpdEntrySize;\r
+  UINTN                   Index;\r
+\r
+  SpdSel        = (Selector == NULL) ? NULL : &Selector->SpdSelector;\r
+  SpdData       = (Data == NULL) ? NULL : (EFI_IPSEC_SPD_DATA *) Data;\r
+  InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SpdSelector;\r
+  SpdList       = &mConfigData[IPsecConfigDataTypeSpd];\r
+\r
+  if (SpdSel != NULL) {\r
+    if (SpdSel->LocalAddress == NULL || SpdSel->RemoteAddress == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  if (SpdData != NULL) {\r
+    if ((SpdData->Action == EfiIPsecActionProtect && SpdData->ProcessingPolicy == NULL) ||\r
+        (SpdData->Action != EfiIPsecActionProtect && SpdData->ProcessingPolicy != NULL)\r
+        ) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (SpdData->Action == EfiIPsecActionProtect) {\r
+      if ((SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption == NULL) ||\r
+          (SpdData->ProcessingPolicy->Mode != EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption != NULL)\r
+          ) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // The default behavior is to insert the node ahead of the header.\r
+  //\r
+  EntryInsertBefore = SpdList;\r
+\r
+  //\r
+  // Remove the existed spd entry.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SpdList) {\r
+\r
+    SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
+\r
+    if (SpdSel == NULL ||\r
+        CompareSpdSelector ((EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel)\r
+        ) {\r
+      //\r
+      // Record the existed entry position to keep the original order.\r
+      //\r
+      EntryInsertBefore = SpdEntry->List.ForwardLink;\r
+      RemoveEntryList (&SpdEntry->List);\r
+\r
+      //\r
+      // Update the reverse ref of sad entry in the spd.sas list.\r
+      //\r
+      SpdSas = &SpdEntry->Data->Sas;\r
+      NET_LIST_FOR_EACH (Entry2, SpdSas) {\r
+        SadEntry                  = IPSEC_SAD_ENTRY_FROM_SPD (Entry2);\r
+        SadEntry->Data->SpdEntry  = NULL;\r
+      }\r
+      //\r
+      // Free the existed spd entry\r
+      //\r
+      FreePool (SpdEntry);\r
+    }\r
+  }\r
+  //\r
+  // Return success here if only want to remove the spd entry.\r
+  //\r
+  if (SpdData == NULL || SpdSel == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Search the appointed entry position if InsertBefore is not NULL.\r
+  //\r
+  if (InsertBefore != NULL) {\r
+\r
+    NET_LIST_FOR_EACH (Entry, SpdList) {\r
+      SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
+\r
+      if (CompareSpdSelector (\r
+            (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,\r
+            (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore\r
+            )) {\r
+        EntryInsertBefore = Entry;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Do Padding for the different Arch.\r
+  //\r
+  SpdEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_SPD_ENTRY));\r
+  SpdEntrySize  = ALIGN_VARIABLE (SpdEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SpdSel));\r
+  SpdEntrySize += IpSecGetSizeOfEfiSpdData (SpdData);\r
+\r
+  SpdEntry = AllocateZeroPool (SpdEntrySize);\r
+\r
+  if (SpdEntry == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Fix the address of Selector and Data buffer and copy them, which is\r
+  // continous memory and close to the base structure of spd entry.\r
+  //\r
+  SpdEntry->Selector  = (EFI_IPSEC_SPD_SELECTOR *) ALIGN_POINTER ((SpdEntry + 1), sizeof (UINTN));\r
+  SpdEntry->Data      = (IPSEC_SPD_DATA *) ALIGN_POINTER (\r
+                                            ((UINT8 *) SpdEntry->Selector + SIZE_OF_SPD_SELECTOR (SpdSel)),\r
+                                            sizeof (UINTN)\r
+                                            );\r
+\r
+  DuplicateSpdSelector (\r
+    (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,\r
+    (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,\r
+    NULL\r
+    );\r
+\r
+  CopyMem (\r
+    SpdEntry->Data->Name,\r
+    SpdData->Name,\r
+    sizeof (SpdData->Name)\r
+    );\r
+  SpdEntry->Data->PackageFlag = SpdData->PackageFlag;\r
+  SpdEntry->Data->Action      = SpdData->Action;\r
+\r
+  //\r
+  // Fix the address of ProcessingPolicy and copy it if need, which is continous\r
+  // memory and close to the base structure of sad data.\r
+  //\r
+  if (SpdData->Action != EfiIPsecActionProtect) {\r
+    SpdEntry->Data->ProcessingPolicy = NULL;\r
+  } else {\r
+    SpdEntry->Data->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ALIGN_POINTER (\r
+                                                                      SpdEntry->Data + 1,\r
+                                                                      sizeof (UINTN)\r
+                                                                      );\r
+    IpSecDuplicateProcessPolicy (SpdEntry->Data->ProcessingPolicy, SpdData->ProcessingPolicy);\r
+  }\r
+  //\r
+  // Update the sas list of the new spd entry.\r
+  //\r
+  InitializeListHead (&SpdEntry->Data->Sas);\r
+\r
+  SadList = &mConfigData[IPsecConfigDataTypeSad];\r
+\r
+  NET_LIST_FOR_EACH (Entry, SadList) {\r
+    SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);\r
+\r
+    for (Index = 0; Index < SpdData->SaIdCount; Index++) {\r
+\r
+      if (CompareSaId (\r
+            (EFI_IPSEC_CONFIG_SELECTOR *) &SpdData->SaId[Index],\r
+            (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id\r
+            )) {\r
+        InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);\r
+        SadEntry->Data->SpdEntry = SpdEntry;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // Insert the new spd entry.\r
+  //\r
+  InsertTailList (EntryInsertBefore, &SpdEntry->List);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set the security association information for the EFI IPsec driver.\r
+\r
+  The IPsec configuration data has a unique selector/identifier separately to\r
+  identify a data entry.\r
+\r
+  @param[in]  Selector           Pointer to an entry selector on operated\r
+                                 configuration data specified by DataType.\r
+                                 A NULL Selector causes the entire specified-type\r
+                                 configuration information to be flushed.\r
+  @param[in]  Data               The data buffer to be set. The structure\r
+                                 of the data buffer should be EFI_IPSEC_SA_DATA.\r
+  @param[in]  Context            Pointer to one entry selector which describes\r
+                                 the expected position the new data entry will\r
+                                 be added. If Context is NULL,the new entry will\r
+                                 be appended the end of database.\r
+\r
+  @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SetSadEntry (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,\r
+  IN VOID                            *Data,\r
+  IN VOID                            *Context OPTIONAL\r
+  )\r
+{\r
+  IPSEC_SAD_ENTRY   *SadEntry;\r
+  IPSEC_SPD_ENTRY   *SpdEntry;\r
+  LIST_ENTRY        *Entry;\r
+  LIST_ENTRY        *NextEntry;\r
+  LIST_ENTRY        *SadList;\r
+  LIST_ENTRY        *SpdList;\r
+  EFI_IPSEC_SA_ID   *SaId;\r
+  EFI_IPSEC_SA_DATA *SaData;\r
+  EFI_IPSEC_SA_ID   *InsertBefore;\r
+  LIST_ENTRY        *EntryInsertBefore;\r
+  UINTN             SadEntrySize;\r
+\r
+  SaId          = (Selector == NULL) ? NULL : &Selector->SaId;\r
+  SaData        = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA *) Data;\r
+  InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SaId;\r
+  SadList       = &mConfigData[IPsecConfigDataTypeSad];\r
+\r
+  //\r
+  // The default behavior is to insert the node ahead of the header.\r
+  //\r
+  EntryInsertBefore = SadList;\r
+\r
+  //\r
+  // Remove the existed sad entry.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SadList) {\r
+\r
+    SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);\r
+\r
+    if (SaId == NULL ||\r
+        CompareSaId (\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SaId\r
+          )) {\r
+      //\r
+      // Record the existed entry position to keep the original order.\r
+      //\r
+      EntryInsertBefore = SadEntry->List.ForwardLink;\r
+\r
+      //\r
+      // Update the related sad.byspd field.\r
+      //\r
+      if (SadEntry->Data->SpdEntry != NULL) {\r
+        RemoveEntryList (&SadEntry->BySpd);\r
+      }\r
+\r
+      RemoveEntryList (&SadEntry->List);\r
+      FreePool (SadEntry);\r
+    }\r
+  }\r
+  //\r
+  // Return success here if only want to remove the sad entry\r
+  //\r
+  if (SaData == NULL || SaId == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Search the appointed entry position if InsertBefore is not NULL.\r
+  //\r
+  if (InsertBefore != NULL) {\r
+\r
+    NET_LIST_FOR_EACH (Entry, SadList) {\r
+      SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);\r
+\r
+      if (CompareSaId (\r
+           (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,\r
+           (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore\r
+           )) {\r
+        EntryInsertBefore = Entry;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Do Padding for different Arch.\r
+  //\r
+  SadEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_SAD_ENTRY));\r
+  SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + sizeof (EFI_IPSEC_SA_DATA));\r
+  SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + sizeof (IPSEC_SAD_DATA));\r
+\r
+  if (SaId->Proto == EfiIPsecAH) {\r
+    SadEntrySize += SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength;\r
+  } else {\r
+    SadEntrySize  = ALIGN_VARIABLE (SadEntrySize + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength);\r
+    SadEntrySize += SaData->AlgoInfo.EspAlgoInfo.EncKeyLength;\r
+  }\r
+\r
+  SadEntry      = AllocateZeroPool (SadEntrySize);\r
+\r
+  if (SadEntry == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Fix the address of Id and Data buffer and copy them, which is\r
+  // continous memory and close to the base structure of sad entry.\r
+  //\r
+  SadEntry->Id    = (EFI_IPSEC_SA_ID *) ALIGN_POINTER ((SadEntry + 1), sizeof (UINTN));\r
+  SadEntry->Data  = (IPSEC_SAD_DATA *) ALIGN_POINTER ((SadEntry->Id + 1), sizeof (UINTN));\r
+\r
+  CopyMem (SadEntry->Id, SaId, sizeof (EFI_IPSEC_SA_ID));\r
+\r
+  SadEntry->Data->Mode                  = SaData->Mode;\r
+  SadEntry->Data->SequenceNumber        = SaData->SNCount;\r
+  SadEntry->Data->AntiReplayWindowSize  = SaData->AntiReplayWindows;\r
+\r
+  ZeroMem (\r
+    &SadEntry->Data->AntiReplayBitmap,\r
+    sizeof (SadEntry->Data->AntiReplayBitmap)\r
+    );\r
+\r
+  ZeroMem (\r
+    &SadEntry->Data->AlgoInfo,\r
+    sizeof (EFI_IPSEC_ALGO_INFO)\r
+    );\r
+\r
+  SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId     = SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId;\r
+  SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength  = SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength;\r
+\r
+  if (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {\r
+    SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SadEntry->Data + 1), sizeof (UINTN));\r
+    CopyMem (\r
+      SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r
+      SaData->AlgoInfo.EspAlgoInfo.AuthKey,\r
+      SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength\r
+      );\r
+  }\r
+\r
+  if (SaId->Proto == EfiIPsecESP) {\r
+    SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId    = SaData->AlgoInfo.EspAlgoInfo.EncAlgoId;\r
+    SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength = SaData->AlgoInfo.EspAlgoInfo.EncKeyLength;\r
+\r
+    if (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {\r
+      SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (\r
+                                                               ((UINT8 *) (SadEntry->Data + 1) +\r
+                                                                 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength),\r
+                                                                 sizeof (UINTN)\r
+                                                                 );\r
+      CopyMem (\r
+        SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,\r
+        SaData->AlgoInfo.EspAlgoInfo.EncKey,\r
+        SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength\r
+        );\r
+    }\r
+  }\r
+\r
+  CopyMem (\r
+    &SadEntry->Data->SaLifetime,\r
+    &SaData->SaLifetime,\r
+    sizeof (EFI_IPSEC_SA_LIFETIME)\r
+    );\r
+\r
+  SadEntry->Data->PathMTU     = SaData->PathMTU;\r
+  SadEntry->Data->SpdEntry    = NULL;\r
+  SadEntry->Data->ESNEnabled  = FALSE;\r
+  SadEntry->Data->ManualSet   = SaData->ManualSet;\r
+\r
+  //\r
+  // Update the spd.sas list of the spd entry specified by sad.selector\r
+  //\r
+  SpdList = &mConfigData[IPsecConfigDataTypeSpd];\r
+\r
+  for (Entry = SpdList->ForwardLink; Entry != SpdList && SaData->SpdSelector != NULL; Entry = Entry->ForwardLink) {\r
+\r
+    SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
+    if (CompareSpdSelector (\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector\r
+          ) && SpdEntry->Data->Action == EfiIPsecActionProtect) {\r
+      SadEntry->Data->SpdEntry = SpdEntry;\r
+      InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);\r
+    }\r
+  }\r
+  //\r
+  // Insert the new sad entry.\r
+  //\r
+  InsertTailList (EntryInsertBefore, &SadEntry->List);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set the peer authorization configuration information for the EFI IPsec driver.\r
+\r
+  The IPsec configuration data has a unique selector/identifier separately to\r
+  identify a data entry.\r
+\r
+  @param[in]  Selector           Pointer to an entry selector on operated\r
+                                 configuration data specified by DataType.\r
+                                 A NULL Selector causes the entire specified-type\r
+                                 configuration information to be flushed.\r
+  @param[in]  Data               The data buffer to be set. The structure\r
+                                 of the data buffer should be EFI_IPSEC_PAD_DATA.\r
+  @param[in]  Context            Pointer to one entry selector that describes\r
+                                 the expected position the new data entry will\r
+                                 be added. If Context is NULL, the new entry will\r
+                                 be appended the end of database.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES  The required system resources could not be allocated.\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SetPadEntry (\r
+  IN EFI_IPSEC_CONFIG_SELECTOR       *Selector,\r
+  IN VOID                            *Data,\r
+  IN VOID                            *Context OPTIONAL\r
+  )\r
+{\r
+  IPSEC_PAD_ENTRY     *PadEntry;\r
+  EFI_IPSEC_PAD_ID    *PadId;\r
+  EFI_IPSEC_PAD_DATA  *PadData;\r
+  LIST_ENTRY          *PadList;\r
+  LIST_ENTRY          *Entry;\r
+  LIST_ENTRY          *NextEntry;\r
+  EFI_IPSEC_PAD_ID    *InsertBefore;\r
+  LIST_ENTRY          *EntryInsertBefore;\r
+  UINTN               PadEntrySize;\r
+\r
+  PadId         = (Selector == NULL) ? NULL : &Selector->PadId;\r
+  PadData       = (Data == NULL) ? NULL : (EFI_IPSEC_PAD_DATA *) Data;\r
+  InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->PadId;\r
+  PadList       = &mConfigData[IPsecConfigDataTypePad];\r
+\r
+  //\r
+  // The default behavior is to insert the node ahead of the header.\r
+  //\r
+  EntryInsertBefore = PadList;\r
+\r
+  //\r
+  // Remove the existed pad entry.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, PadList) {\r
+\r
+    PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);\r
+\r
+    if (PadId == NULL ||\r
+        ComparePadId ((EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) PadId)\r
+        ) {\r
+      //\r
+      // Record the existed entry position to keep the original order.\r
+      //\r
+      EntryInsertBefore = PadEntry->List.ForwardLink;\r
+      RemoveEntryList (&PadEntry->List);\r
+\r
+      FreePool (PadEntry);\r
+    }\r
+  }\r
+  //\r
+  // Return success here if only want to remove the pad entry\r
+  //\r
+  if (PadData == NULL || PadId == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Search the appointed entry position if InsertBefore is not NULL.\r
+  //\r
+  if (InsertBefore != NULL) {\r
+\r
+    NET_LIST_FOR_EACH (Entry, PadList) {\r
+      PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);\r
+\r
+      if (ComparePadId (\r
+            (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id,\r
+            (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore\r
+            )) {\r
+        EntryInsertBefore = Entry;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Do PADDING for different arch.\r
+  //\r
+  PadEntrySize  = ALIGN_VARIABLE (sizeof (IPSEC_PAD_ENTRY));\r
+  PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_ID));\r
+  PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_DATA));\r
+  PadEntrySize  = ALIGN_VARIABLE (PadEntrySize + (PadData->AuthData != NULL ? PadData->AuthDataSize : 0));\r
+  PadEntrySize += PadData->RevocationData != NULL ? PadData->RevocationDataSize : 0;\r
+\r
+  PadEntry      = AllocateZeroPool (PadEntrySize);\r
+\r
+  if (PadEntry == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Fix the address of Id and Data buffer and copy them, which is\r
+  // continous memory and close to the base structure of pad entry.\r
+  //\r
+  PadEntry->Id    = (EFI_IPSEC_PAD_ID *) ALIGN_POINTER ((PadEntry + 1), sizeof (UINTN));\r
+  PadEntry->Data  = (EFI_IPSEC_PAD_DATA *) ALIGN_POINTER ((PadEntry->Id + 1), sizeof (UINTN));\r
+\r
+  CopyMem (PadEntry->Id, PadId, sizeof (EFI_IPSEC_PAD_ID));\r
+\r
+  PadEntry->Data->AuthProtocol  = PadData->AuthProtocol;\r
+  PadEntry->Data->AuthMethod    = PadData->AuthMethod;\r
+  PadEntry->Data->IkeIdFlag     = PadData->IkeIdFlag;\r
+\r
+  if (PadData->AuthData != NULL) {\r
+    PadEntry->Data->AuthDataSize  = PadData->AuthDataSize;\r
+    PadEntry->Data->AuthData      = (VOID *) ALIGN_POINTER (PadEntry->Data + 1, sizeof (UINTN));\r
+    CopyMem (\r
+      PadEntry->Data->AuthData,\r
+      PadData->AuthData,\r
+      PadData->AuthDataSize\r
+      );\r
+  } else {\r
+    PadEntry->Data->AuthDataSize  = 0;\r
+    PadEntry->Data->AuthData      = NULL;\r
+  }\r
+\r
+  if (PadData->RevocationData != NULL) {\r
+    PadEntry->Data->RevocationDataSize  = PadData->RevocationDataSize;\r
+    PadEntry->Data->RevocationData      = (VOID *) ALIGN_POINTER (\r
+                                                    ((UINT8 *) (PadEntry->Data + 1) + PadData->AuthDataSize),\r
+                                                    sizeof (UINTN)\r
+                                                    );\r
+    CopyMem (\r
+      PadEntry->Data->RevocationData,\r
+      PadData->RevocationData,\r
+      PadData->RevocationDataSize\r
+      );\r
+  } else {\r
+    PadEntry->Data->RevocationDataSize  = 0;\r
+    PadEntry->Data->RevocationData      = NULL;\r
+  }\r
+  //\r
+  // Insert the new pad entry.\r
+  //\r
+  InsertTailList (EntryInsertBefore, &PadEntry->List);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function lookup the data entry from IPsec SPD. Return the configuration\r
+  value of the specified SPD Entry.\r
+\r
+  @param[in]      Selector      Pointer to an entry selector which is an identifier\r
+                                of the SPD entry.\r
+  @param[in, out] DataSize      On output the size of data returned in Data.\r
+  @param[out]     Data          The buffer to return the contents of the IPsec\r
+                                configuration data. The type of the data buffer\r
+                                is associated with the DataType.\r
+\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+  @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero.\r
+  @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.\r
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been\r
+                                updated with the size needed to complete the request.\r
+\r
+**/\r
+EFI_STATUS\r
+GetSpdEntry (\r
+  IN     EFI_IPSEC_CONFIG_SELECTOR       *Selector,\r
+  IN OUT UINTN                           *DataSize,\r
+     OUT VOID                            *Data\r
+  )\r
+{\r
+  IPSEC_SPD_ENTRY         *SpdEntry;\r
+  IPSEC_SAD_ENTRY         *SadEntry;\r
+  EFI_IPSEC_SPD_SELECTOR  *SpdSel;\r
+  EFI_IPSEC_SPD_DATA      *SpdData;\r
+  LIST_ENTRY              *SpdList;\r
+  LIST_ENTRY              *SpdSas;\r
+  LIST_ENTRY              *Entry;\r
+  UINTN                   RequiredSize;\r
+\r
+  SpdSel  = &Selector->SpdSelector;\r
+  SpdData = (EFI_IPSEC_SPD_DATA *) Data;\r
+  SpdList = &mConfigData[IPsecConfigDataTypeSpd];\r
+\r
+  NET_LIST_FOR_EACH (Entry, SpdList) {\r
+    SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
+\r
+    //\r
+    // Find the required spd entry\r
+    //\r
+    if (CompareSpdSelector (\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector\r
+          )) {\r
+\r
+      RequiredSize = IpSecGetSizeOfSpdData (SpdEntry->Data);\r
+      if (*DataSize < RequiredSize) {\r
+        *DataSize = RequiredSize;\r
+        return EFI_BUFFER_TOO_SMALL;\r
+      }\r
+\r
+      if (SpdData == NULL) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+\r
+      *DataSize = RequiredSize;\r
+\r
+      //\r
+      // Extract and fill all SaId array from the spd.sas list\r
+      //\r
+      SpdSas              = &SpdEntry->Data->Sas;\r
+      SpdData->SaIdCount  = 0;\r
+\r
+      NET_LIST_FOR_EACH (Entry, SpdSas) {\r
+        SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);\r
+        CopyMem (\r
+          &SpdData->SaId[SpdData->SaIdCount++],\r
+          SadEntry->Id,\r
+          sizeof (EFI_IPSEC_SA_ID)\r
+          );\r
+      }\r
+      //\r
+      // Fill the other fields in spd data.\r
+      //\r
+      CopyMem (SpdData->Name, SpdEntry->Data->Name, sizeof (SpdData->Name));\r
+\r
+      SpdData->PackageFlag  = SpdEntry->Data->PackageFlag;\r
+      SpdData->Action       = SpdEntry->Data->Action;\r
+\r
+      if (SpdData->Action != EfiIPsecActionProtect) {\r
+        SpdData->ProcessingPolicy = NULL;\r
+      } else {\r
+        SpdData->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ((UINT8 *) SpdData + sizeof (EFI_IPSEC_SPD_DATA) + (SpdData->SaIdCount - 1) * sizeof (EFI_IPSEC_SA_ID));\r
+\r
+        IpSecDuplicateProcessPolicy (\r
+          SpdData->ProcessingPolicy,\r
+          SpdEntry->Data->ProcessingPolicy\r
+          );\r
+      }\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This function lookup the data entry from IPsec SAD. Return the configuration\r
+  value of the specified SAD Entry.\r
+\r
+  @param[in]      Selector      Pointer to an entry selector which is an identifier\r
+                                of the SAD entry.\r
+  @param[in, out] DataSize      On output, the size of data returned in Data.\r
+  @param[out]     Data          The buffer to return the contents of the IPsec\r
+                                configuration data. The type of the data buffer\r
+                                is associated with the DataType.\r
+\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+  @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.\r
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been\r
+                                updated with the size needed to complete the request.\r
+\r
+**/\r
+EFI_STATUS\r
+GetSadEntry (\r
+  IN     EFI_IPSEC_CONFIG_SELECTOR     *Selector,\r
+  IN OUT UINTN                         *DataSize,\r
+     OUT VOID                          *Data\r
+  )\r
+{\r
+  IPSEC_SAD_ENTRY   *SadEntry;\r
+  LIST_ENTRY        *Entry;\r
+  LIST_ENTRY        *SadList;\r
+  EFI_IPSEC_SA_ID   *SaId;\r
+  EFI_IPSEC_SA_DATA *SaData;\r
+  UINTN             RequiredSize;\r
+\r
+  SaId    = &Selector->SaId;\r
+  SaData  = (EFI_IPSEC_SA_DATA *) Data;\r
+  SadList = &mConfigData[IPsecConfigDataTypeSad];\r
+\r
+  NET_LIST_FOR_EACH (Entry, SadList) {\r
+    SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);\r
+\r
+    //\r
+    // Find the required sad entry.\r
+    //\r
+    if (CompareSaId (\r
+         (EFI_IPSEC_CONFIG_SELECTOR *) SaId,\r
+         (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id\r
+         )) {\r
+      //\r
+      // Calculate the required size of the sad entry.\r
+      // Data Layout is follows:\r
+      // |EFI_IPSEC_SA_DATA\r
+      // |AuthKey\r
+      // |EncryptKey  (Optional)\r
+      // |SpdSelector (Optional)\r
+      //\r
+      RequiredSize  = ALIGN_VARIABLE (sizeof (EFI_IPSEC_SA_DATA));\r
+\r
+      if (SaId->Proto == EfiIPsecAH) {\r
+        RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength);\r
+      } else {\r
+        RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength);\r
+        RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength);\r
+      }\r
+\r
+      if (SadEntry->Data->SpdEntry != NULL) {\r
+        RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdEntry->Selector);\r
+      }\r
+\r
+\r
+\r
+      if (*DataSize < RequiredSize) {\r
+        *DataSize = RequiredSize;\r
+        return EFI_BUFFER_TOO_SMALL;\r
+      }\r
+      //\r
+      // Fill the data fields of sad entry.\r
+      //\r
+      *DataSize                 = RequiredSize;\r
+      SaData->Mode              = SadEntry->Data->Mode;\r
+      SaData->SNCount           = SadEntry->Data->SequenceNumber;\r
+      SaData->AntiReplayWindows = SadEntry->Data->AntiReplayWindowSize;\r
+\r
+      CopyMem (\r
+        &SaData->SaLifetime,\r
+        &SadEntry->Data->SaLifetime,\r
+        sizeof (EFI_IPSEC_SA_LIFETIME)\r
+        );\r
+\r
+      ZeroMem (\r
+        &SaData->AlgoInfo,\r
+        sizeof (EFI_IPSEC_ALGO_INFO)\r
+        );\r
+\r
+      if (SaId->Proto == EfiIPsecAH) {\r
+        //\r
+        // Copy AH alogrithm INFO to SaData\r
+        //\r
+        SaData->AlgoInfo.AhAlgoInfo.AuthAlgoId    = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthAlgoId;\r
+        SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength;\r
+        if (SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength != 0) {\r
+          SaData->AlgoInfo.AhAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN));\r
+          CopyMem (\r
+            SaData->AlgoInfo.AhAlgoInfo.AuthKey,\r
+            SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKey,\r
+            SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength\r
+            );\r
+        }\r
+      } else if (SaId->Proto == EfiIPsecESP) {\r
+        //\r
+        // Copy ESP alogrithem INFO to SaData\r
+        //\r
+        SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId     = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId;\r
+        SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength  = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength;\r
+        if (SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {\r
+          SaData->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN));\r
+          CopyMem (\r
+            SaData->AlgoInfo.EspAlgoInfo.AuthKey,\r
+            SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r
+            SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength\r
+            );\r
+        }\r
+\r
+        SaData->AlgoInfo.EspAlgoInfo.EncAlgoId    = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId;\r
+        SaData->AlgoInfo.EspAlgoInfo.EncKeyLength = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength;\r
+\r
+        if (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {\r
+          SaData->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (\r
+                                                          ((UINT8 *) (SaData + 1) +\r
+                                                            SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength),\r
+                                                            sizeof (UINTN)\r
+                                                            );\r
+          CopyMem (\r
+            SaData->AlgoInfo.EspAlgoInfo.EncKey,\r
+            SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,\r
+            SaData->AlgoInfo.EspAlgoInfo.EncKeyLength\r
+            );\r
+        }\r
+      }\r
+\r
+      SaData->PathMTU = SadEntry->Data->PathMTU;\r
+\r
+      //\r
+      // Fill the spd selector field of sad data\r
+      //\r
+      if (SadEntry->Data->SpdEntry != NULL) {\r
+\r
+        SaData->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) (\r
+                                (UINT8 *)SaData +\r
+                                RequiredSize -\r
+                                SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdEntry->Selector)\r
+                                );\r
+\r
+        DuplicateSpdSelector (\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdEntry->Selector,\r
+          NULL\r
+          );\r
+\r
+      } else {\r
+\r
+        SaData->SpdSelector = NULL;\r
+      }\r
+\r
+      SaData->ManualSet = SadEntry->Data->ManualSet;\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This function lookup the data entry from IPsec PAD. Return the configuration\r
+  value of the specified PAD Entry.\r
+\r
+  @param[in]      Selector      Pointer to an entry selector which is an identifier\r
+                                of the PAD entry.\r
+  @param[in, out] DataSize      On output the size of data returned in Data.\r
+  @param[out]     Data          The buffer to return the contents of the IPsec\r
+                                configuration data. The type of the data buffer\r
+                                is associated with the DataType.\r
+\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+  @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.\r
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been\r
+                                updated with the size needed to complete the request.\r
+\r
+**/\r
+EFI_STATUS\r
+GetPadEntry (\r
+  IN     EFI_IPSEC_CONFIG_SELECTOR   *Selector,\r
+  IN OUT UINTN                       *DataSize,\r
+     OUT VOID                        *Data\r
+  )\r
+{\r
+  IPSEC_PAD_ENTRY     *PadEntry;\r
+  LIST_ENTRY          *PadList;\r
+  LIST_ENTRY          *Entry;\r
+  EFI_IPSEC_PAD_ID    *PadId;\r
+  EFI_IPSEC_PAD_DATA  *PadData;\r
+  UINTN               RequiredSize;\r
+\r
+  PadId   = &Selector->PadId;\r
+  PadData = (EFI_IPSEC_PAD_DATA *) Data;\r
+  PadList = &mConfigData[IPsecConfigDataTypePad];\r
+\r
+  NET_LIST_FOR_EACH (Entry, PadList) {\r
+    PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);\r
+\r
+    //\r
+    // Find the required pad entry.\r
+    //\r
+    if (ComparePadId (\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) PadId,\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id\r
+          )) {\r
+      //\r
+      // Calculate the required size of the pad entry.\r
+      //\r
+      RequiredSize  = ALIGN_VARIABLE (sizeof (EFI_IPSEC_PAD_DATA));\r
+      RequiredSize  = ALIGN_VARIABLE (RequiredSize + PadEntry->Data->AuthDataSize);\r
+      RequiredSize += PadEntry->Data->RevocationDataSize;\r
+\r
+      if (*DataSize < RequiredSize) {\r
+        *DataSize = RequiredSize;\r
+        return EFI_BUFFER_TOO_SMALL;\r
+      }\r
+      //\r
+      // Fill the data fields of pad entry\r
+      //\r
+      *DataSize             = RequiredSize;\r
+      PadData->AuthProtocol = PadEntry->Data->AuthProtocol;\r
+      PadData->AuthMethod   = PadEntry->Data->AuthMethod;\r
+      PadData->IkeIdFlag    = PadEntry->Data->IkeIdFlag;\r
+\r
+      //\r
+      // Copy Authentication data.\r
+      //\r
+      if (PadEntry->Data->AuthData != NULL) {\r
+\r
+        PadData->AuthDataSize = PadEntry->Data->AuthDataSize;\r
+        PadData->AuthData     = (VOID *) ALIGN_POINTER ((PadData + 1), sizeof (UINTN));\r
+        CopyMem (\r
+          PadData->AuthData,\r
+          PadEntry->Data->AuthData,\r
+          PadData->AuthDataSize\r
+          );\r
+      } else {\r
+\r
+        PadData->AuthDataSize = 0;\r
+        PadData->AuthData     = NULL;\r
+      }\r
+      //\r
+      // Copy Revocation Data.\r
+      //\r
+      if (PadEntry->Data->RevocationData != NULL) {\r
+\r
+        PadData->RevocationDataSize = PadEntry->Data->RevocationDataSize;\r
+        PadData->RevocationData     = (VOID *) ALIGN_POINTER (\r
+                                                 ((UINT8 *) (PadData + 1) + PadData->AuthDataSize),\r
+                                                  sizeof (UINTN)\r
+                                                  );\r
+        CopyMem (\r
+          PadData->RevocationData,\r
+          PadEntry->Data->RevocationData,\r
+          PadData->RevocationDataSize\r
+          );\r
+      } else {\r
+\r
+        PadData->RevocationDataSize = 0;\r
+        PadData->RevocationData     = NULL;\r
+      }\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Copy Source Process Policy to the Destination Process Policy.\r
+\r
+  @param[in]  Dst                  Pointer to the Source Process Policy.\r
+  @param[in]  Src                  Pointer to the Destination Process Policy.\r
+\r
+**/\r
+VOID\r
+IpSecDuplicateProcessPolicy (\r
+  IN EFI_IPSEC_PROCESS_POLICY            *Dst,\r
+  IN EFI_IPSEC_PROCESS_POLICY            *Src\r
+  )\r
+{\r
+  //\r
+  // Firstly copy the structure content itself.\r
+  //\r
+  CopyMem (Dst, Src, sizeof (EFI_IPSEC_PROCESS_POLICY));\r
+\r
+  //\r
+  // Recursively copy the tunnel option if needed.\r
+  //\r
+  if (Dst->Mode != EfiIPsecTunnel) {\r
+    ASSERT (Dst->TunnelOption == NULL);\r
+  } else {\r
+    Dst->TunnelOption = (EFI_IPSEC_TUNNEL_OPTION *) ALIGN_POINTER ((Dst + 1), sizeof (UINTN));\r
+    CopyMem (\r
+      Dst->TunnelOption,\r
+      Src->TunnelOption,\r
+      sizeof (EFI_IPSEC_TUNNEL_OPTION)\r
+      );\r
+  }\r
+}\r
+\r
+/**\r
+  Calculate the a whole size of EFI_IPSEC_SPD_DATA, which includes the buffer size pointed\r
+  to by the pointer members.\r
+\r
+  @param[in]  SpdData             Pointer to a specified EFI_IPSEC_SPD_DATA.\r
+\r
+  @return the whole size the specified EFI_IPSEC_SPD_DATA.\r
+\r
+**/\r
+UINTN\r
+IpSecGetSizeOfEfiSpdData (\r
+  IN EFI_IPSEC_SPD_DATA               *SpdData\r
+  )\r
+{\r
+  UINTN Size;\r
+\r
+  Size = ALIGN_VARIABLE (sizeof (IPSEC_SPD_DATA));\r
+\r
+  if (SpdData->Action == EfiIPsecActionProtect) {\r
+    Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_PROCESS_POLICY));\r
+\r
+    if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) {\r
+      Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_TUNNEL_OPTION));\r
+    }\r
+  }\r
+\r
+  return Size;\r
+}\r
+\r
+/**\r
+  Calculate the a whole size of IPSEC_SPD_DATA which includes the buffer size pointed\r
+  to by the pointer members and the buffer size used by the Sa List.\r
+\r
+  @param[in]  SpdData       Pointer to the specified IPSEC_SPD_DATA.\r
+\r
+  @return the whole size of IPSEC_SPD_DATA.\r
+\r
+**/\r
+UINTN\r
+IpSecGetSizeOfSpdData (\r
+  IN IPSEC_SPD_DATA                   *SpdData\r
+  )\r
+{\r
+  UINTN       Size;\r
+  LIST_ENTRY  *Link;\r
+\r
+  Size = sizeof (EFI_IPSEC_SPD_DATA) - sizeof (EFI_IPSEC_SA_ID);\r
+\r
+  if (SpdData->Action == EfiIPsecActionProtect) {\r
+    Size += sizeof (EFI_IPSEC_PROCESS_POLICY);\r
+\r
+    if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) {\r
+      Size += sizeof (EFI_IPSEC_TUNNEL_OPTION);\r
+    }\r
+  }\r
+\r
+  NET_LIST_FOR_EACH (Link, &SpdData->Sas) {\r
+    Size += sizeof (EFI_IPSEC_SA_ID);\r
+  }\r
+\r
+  return Size;\r
+}\r
+\r
+/**\r
+  Get the IPsec Variable.\r
+\r
+  Get the all variables which start with the string contained in VaraiableName.\r
+  Since all IPsec related variable store in continual space, those kinds of\r
+  variable can be searched by the EfiGetNextVariableName. Those variables also are\r
+  returned in a continual buffer.\r
+\r
+  @param[in]      VariableName          Pointer to a specified Variable Name.\r
+  @param[in]      VendorGuid            Pointer to a specified Vendor Guid.\r
+  @param[in]      Attributes            Point to memory location to return the attributes\r
+                                        of variable. If the point is NULL, the parameter\r
+                                        would be ignored.\r
+  @param[in, out] DataSize              As input, point to the maximum size of return\r
+                                        Data-Buffer. As output, point to the actual\r
+                                        size of the returned Data-Buffer.\r
+  @param[in]      Data                  Point to return Data-Buffer.\r
+\r
+  @retval  EFI_ABORTED           If the Variable size which contained in the variable\r
+                                 structure doesn't match the variable size obtained\r
+                                 from the EFIGetVariable.\r
+  @retval  EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has\r
+                                 been updated with the size needed to complete the request.\r
+  @retval  EFI_SUCCESS           The function completed successfully.\r
+  @retval  others                Other errors found during the variable getting.\r
+**/\r
+EFI_STATUS\r
+IpSecGetVariable (\r
+  IN     CHAR16                       *VariableName,\r
+  IN     EFI_GUID                     *VendorGuid,\r
+  IN     UINT32                       *Attributes, OPTIONAL\r
+  IN OUT UINTN                        *DataSize,\r
+  IN     VOID                         *Data\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_GUID              VendorGuidI;\r
+  UINTN                 VariableNameLength;\r
+  CHAR16                *VariableNameI;\r
+  UINTN                 VariableNameISize;\r
+  UINTN                 VariableNameISizeNew;\r
+  UINTN                 VariableIndex;\r
+  UINTN                 VariableCount;\r
+  IP_SEC_VARIABLE_INFO  IpSecVariableInfo;\r
+  UINTN                 DataSizeI;\r
+\r
+  //\r
+  // The variable name constructor is "VariableName + Info/0001/0002/... + NULL".\r
+  // So the varialbe name is like "VariableNameInfo", "VariableName0001", ...\r
+  // "VariableNameNULL".\r
+  //\r
+  VariableNameLength  = StrLen (VariableName);\r
+  VariableNameISize   = (VariableNameLength + 5) * sizeof (CHAR16);\r
+  VariableNameI       = AllocateZeroPool (VariableNameISize);\r
+  ASSERT (VariableNameI != NULL);\r
+\r
+  //\r
+  // Construct the varible name of ipsecconfig meta data.\r
+  //\r
+  UnicodeSPrint (VariableNameI, VariableNameISize, L"%s%s", VariableName, L"Info");\r
+\r
+  DataSizeI = sizeof (IpSecVariableInfo);\r
+\r
+  Status = gRT->GetVariable (\r
+                  VariableNameI,\r
+                  VendorGuid,\r
+                  Attributes,\r
+                  &DataSizeI,\r
+                  &IpSecVariableInfo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (*DataSize < IpSecVariableInfo.VariableSize) {\r
+    *DataSize = IpSecVariableInfo.VariableSize;\r
+    Status    = EFI_BUFFER_TOO_SMALL;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  VariableCount     = IpSecVariableInfo.VariableCount;\r
+  VariableNameI[0]  = L'\0';\r
+\r
+  while (VariableCount != 0) {\r
+    //\r
+    // Get the variable name one by one in the variable database.\r
+    //\r
+    VariableNameISizeNew = VariableNameISize;\r
+    Status = gRT->GetNextVariableName (\r
+                    &VariableNameISizeNew,\r
+                    VariableNameI,\r
+                    &VendorGuidI\r
+                    );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      VariableNameI = ReallocatePool (\r
+                        VariableNameISize,\r
+                        VariableNameISizeNew,\r
+                        VariableNameI\r
+                        );\r
+      VariableNameISize = VariableNameISizeNew;\r
+\r
+      Status = gRT->GetNextVariableName (\r
+                      &VariableNameISizeNew,\r
+                      VariableNameI,\r
+                      &VendorGuidI\r
+                      );\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    //\r
+    // Check whether the current variable is the required "ipsecconfig".\r
+    //\r
+    if (StrnCmp (VariableNameI, VariableName, VariableNameLength) == 0 ||\r
+        CompareGuid (VendorGuid, &VendorGuidI)\r
+        ) {\r
+      //\r
+      // Parse the variable count of the current ipsecconfig data.\r
+      //\r
+      VariableIndex = StrDecimalToUintn (VariableNameI + VariableNameLength);\r
+      if (VariableIndex!= 0 && VariableIndex <= IpSecVariableInfo.VariableCount) {\r
+        //\r
+        // Get the variable size of the current ipsecconfig data.\r
+        //\r
+        DataSizeI = 0;\r
+        Status = gRT->GetVariable (\r
+                        VariableNameI,\r
+                        VendorGuid,\r
+                        Attributes,\r
+                        &DataSizeI,\r
+                        NULL\r
+                        );\r
+        ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+        //\r
+        // Validate the variable count and variable size.\r
+        //\r
+        if (VariableIndex != IpSecVariableInfo.VariableCount) {\r
+          //\r
+          // If the varaibe is not the last one, its size should be the max\r
+          // size of the single variable.\r
+          //\r
+          if (DataSizeI != IpSecVariableInfo.SingleVariableSize) {\r
+            return EFI_ABORTED;\r
+          }\r
+        } else {\r
+          if (DataSizeI != IpSecVariableInfo.VariableSize % IpSecVariableInfo.SingleVariableSize) {\r
+            return EFI_ABORTED;\r
+          }\r
+        }\r
+        //\r
+        // Get the variable data of the current ipsecconfig data and\r
+        // store it into user buffer continously.\r
+        //\r
+        Status = gRT->GetVariable (\r
+                        VariableNameI,\r
+                        VendorGuid,\r
+                        Attributes,\r
+                        &DataSizeI,\r
+                        (UINT8 *) Data + (VariableIndex - 1) * IpSecVariableInfo.SingleVariableSize\r
+                        );\r
+        ASSERT_EFI_ERROR (Status);\r
+        VariableCount--;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // The VariableCount in "VariableNameInfo" varaible should have the correct\r
+  // numbers of variables which name starts with VariableName.\r
+  //\r
+  if (VariableCount != 0) {\r
+    Status = EFI_ABORTED;\r
+  }\r
+\r
+ON_EXIT:\r
+  FreePool (VariableNameI);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the IPsec variables.\r
+\r
+  Set all IPsec variables which start with the specified variable name. Those variables\r
+  are set one by one.\r
+\r
+  @param[in]  VariableName  The name of the vendor's variable. It is a\r
+                            Null-Terminated Unicode String.\r
+  @param[in]  VendorGuid    Unify identifier for vendor.\r
+  @param[in]  Attributes    Point to memory location to return the attributes of\r
+                            variable. If the point is NULL, the parameter would be ignored.\r
+  @param[in]  DataSize      The size in bytes of Data-Buffer.\r
+  @param[in]  Data          Points to the content of the variable.\r
+\r
+  @retval  EFI_SUCCESS      The firmware successfully stored the variable and its data, as\r
+                            defined by the Attributes.\r
+  @retval  others           Storing the variables failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecSetVariable (\r
+  IN CHAR16                           *VariableName,\r
+  IN EFI_GUID                         *VendorGuid,\r
+  IN UINT32                           Attributes,\r
+  IN UINTN                            DataSize,\r
+  IN VOID                             *Data\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  CHAR16                *VariableNameI;\r
+  UINTN                 VariableNameSize;\r
+  UINTN                 VariableIndex;\r
+  IP_SEC_VARIABLE_INFO  IpSecVariableInfo;\r
+  UINT64                MaximumVariableStorageSize;\r
+  UINT64                RemainingVariableStorageSize;\r
+  UINT64                MaximumVariableSize;\r
+\r
+  Status = gRT->QueryVariableInfo (\r
+                  Attributes,\r
+                  &MaximumVariableStorageSize,\r
+                  &RemainingVariableStorageSize,\r
+                  &MaximumVariableSize\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // "VariableName + Info/0001/0002/... + NULL"\r
+  //\r
+  VariableNameSize  = (StrLen (VariableName) + 5) * sizeof (CHAR16);\r
+  VariableNameI     = AllocateZeroPool (VariableNameSize);\r
+\r
+  if (VariableNameI == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Construct the variable of ipsecconfig general information. Like the total\r
+  // numbers of the Ipsecconfig variables, the total size of all ipsecconfig variables.\r
+  //\r
+  UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%s", VariableName, L"Info");\r
+  MaximumVariableSize -= VariableNameSize;\r
+\r
+  IpSecVariableInfo.VariableCount       = (UINT32) ((DataSize + (UINTN) MaximumVariableSize - 1) / (UINTN) MaximumVariableSize);\r
+  IpSecVariableInfo.VariableSize        = (UINT32) DataSize;\r
+  IpSecVariableInfo.SingleVariableSize  = (UINT32) MaximumVariableSize;\r
+\r
+  //\r
+  // Set the variable of ipsecconfig general information.\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  VariableNameI,\r
+                  VendorGuid,\r
+                  Attributes,\r
+                  sizeof (IpSecVariableInfo),\r
+                  &IpSecVariableInfo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Error set ipsecconfig meta data with %r\n", Status));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  for (VariableIndex = 0; VariableIndex < IpSecVariableInfo.VariableCount; VariableIndex++) {\r
+    //\r
+    // Construct and set the variable of ipsecconfig data one by one.\r
+    // The index of variable name begin from 0001, and the varaible name\r
+    // likes "VariableName0001", "VaraiableName0002"....\r
+    //\r
+    UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%04d", VariableName, VariableIndex + 1);\r
+    Status = gRT->SetVariable (\r
+                    VariableNameI,\r
+                    VendorGuid,\r
+                    Attributes,\r
+                    (VariableIndex == IpSecVariableInfo.VariableCount - 1) ?\r
+                    (DataSize % (UINTN) MaximumVariableSize) :\r
+                    (UINTN) MaximumVariableSize,\r
+                    (UINT8 *) Data + VariableIndex * (UINTN) MaximumVariableSize\r
+                    );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "Error set ipsecconfig variable data with %r\n", Status));\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+  if (VariableNameI != NULL) {\r
+    FreePool (VariableNameI);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Return the configuration value for the EFI IPsec driver.\r
+\r
+  This function lookup the data entry from IPsec database or IKEv2 configuration\r
+  information. The expected data type and unique identification are described in\r
+  DataType and Selector parameters.\r
+\r
+  @param[in]      This          Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.\r
+  @param[in]      DataType      The type of data to retrieve.\r
+  @param[in]      Selector      Pointer to an entry selector that is an identifier of the IPsec\r
+                                configuration data entry.\r
+  @param[in, out] DataSize      On output the size of data returned in Data.\r
+  @param[out]     Data          The buffer to return the contents of the IPsec configuration data.\r
+                                The type of the data buffer associated with the DataType.\r
+\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+  @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:\r
+                                - This is NULL.\r
+                                - Selector is NULL.\r
+                                - DataSize is NULL.\r
+                                - Data is NULL and *DataSize is not zero\r
+  @retval EFI_NOT_FOUND         The configuration data specified by Selector is not found.\r
+  @retval EFI_UNSUPPORTED       The specified DataType is not supported.\r
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the result. DataSize has been\r
+                                updated with the size needed to complete the request.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIpSecConfigGetData (\r
+  IN     EFI_IPSEC_CONFIG_PROTOCOL    *This,\r
+  IN     EFI_IPSEC_CONFIG_DATA_TYPE   DataType,\r
+  IN     EFI_IPSEC_CONFIG_SELECTOR    *Selector,\r
+  IN OUT UINTN                        *DataSize,\r
+     OUT VOID                         *Data\r
+  )\r
+{\r
+  if (This == NULL || Selector == NULL || DataSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*DataSize != 0 && Data == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (DataType >= IPsecConfigDataTypeMaximum) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return mGetPolicyEntry[DataType](Selector, DataSize, Data);\r
+}\r
+\r
+/**\r
+  Set the security association, security policy and peer authorization configuration\r
+  information for the EFI IPsec driver.\r
+\r
+  This function is used to set the IPsec configuration information of type DataType for\r
+  the EFI IPsec driver.\r
+  The IPsec configuration data has a unique selector/identifier separately to identify\r
+  a data entry. The selector structure depends on DataType's definition.\r
+  Using SetData() with a Data of NULL causes the IPsec configuration data entry identified\r
+  by DataType and Selector to be deleted.\r
+\r
+  @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.\r
+  @param[in] DataType           The type of data to be set.\r
+  @param[in] Selector           Pointer to an entry selector on operated configuration data\r
+                                specified by DataType. A NULL Selector causes the entire\r
+                                specified-type configuration information to be flushed.\r
+  @param[in] Data               The data buffer to be set. The structure of the data buffer is\r
+                                associated with the DataType.\r
+  @param[in] InsertBefore       Pointer to one entry selector which describes the expected\r
+                                position the new data entry will be added. If InsertBefore is NULL,\r
+                                the new entry will be appended to the end of the database.\r
+\r
+  @retval EFI_SUCCESS           The specified configuration entry data was set successfully.\r
+  @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:\r
+                                - This is NULL.\r
+  @retval EFI_UNSUPPORTED       The specified DataType is not supported.\r
+  @retval EFI_OUT_OF_RESOURCED  The required system resource could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIpSecConfigSetData (\r
+  IN EFI_IPSEC_CONFIG_PROTOCOL        *This,\r
+  IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *Selector,\r
+  IN VOID                             *Data,\r
+  IN EFI_IPSEC_CONFIG_SELECTOR        *InsertBefore OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (DataType >= IPsecConfigDataTypeMaximum) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = mSetPolicyEntry[DataType](Selector, Data, InsertBefore);\r
+\r
+  if (!EFI_ERROR (Status) && !mSetBySelf) {\r
+    //\r
+    // Save the updated config data into variable.\r
+    //\r
+    IpSecConfigSave ();\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Enumerates the current selector for IPsec configuration data entry.\r
+\r
+  This function is called multiple times to retrieve the entry Selector in IPsec\r
+  configuration database. On each call to GetNextSelector(), the next entry\r
+  Selector are retrieved into the output interface.\r
+\r
+  If the entire IPsec configuration database has been iterated, the error\r
+  EFI_NOT_FOUND is returned.\r
+  If the Selector buffer is too small for the next Selector copy, an\r
+  EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect\r
+  the size of buffer needed.\r
+\r
+  On the initial call to GetNextSelector() to start the IPsec configuration database\r
+  search, a pointer to the buffer with all zero value is passed in Selector. Calls\r
+  to SetData() between calls to GetNextSelector may produce unpredictable results.\r
+\r
+  @param[in]      This          Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.\r
+  @param[in]      DataType      The type of IPsec configuration data to retrieve.\r
+  @param[in, out] SelectorSize  The size of the Selector buffer.\r
+  @param[in, out] Selector      On input, supplies the pointer to last Selector that was\r
+                                returned by GetNextSelector().\r
+                                On output, returns one copy of the current entry Selector\r
+                                of a given DataType.\r
+\r
+  @retval EFI_SUCCESS           The specified configuration data was obtained successfully.\r
+  @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:\r
+                                - This is NULL.\r
+                                - SelectorSize is NULL.\r
+                                - Selector is NULL.\r
+  @retval EFI_NOT_FOUND         The next configuration data entry was not found.\r
+  @retval EFI_UNSUPPORTED       The specified DataType is not supported.\r
+  @retval EFI_BUFFER_TOO_SMALL  The SelectorSize is too small for the result. This parameter\r
+                                has been updated with the size needed to complete the search\r
+                                request.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIpSecConfigGetNextSelector (\r
+  IN     EFI_IPSEC_CONFIG_PROTOCOL    *This,\r
+  IN     EFI_IPSEC_CONFIG_DATA_TYPE   DataType,\r
+  IN OUT UINTN                        *SelectorSize,\r
+  IN OUT EFI_IPSEC_CONFIG_SELECTOR    *Selector\r
+  )\r
+{\r
+  LIST_ENTRY                *Link;\r
+  IPSEC_COMMON_POLICY_ENTRY *CommonEntry;\r
+  BOOLEAN                   IsFound;\r
+\r
+  if (This == NULL || Selector == NULL || SelectorSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (DataType >= IPsecConfigDataTypeMaximum) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  IsFound = FALSE;\r
+\r
+  NET_LIST_FOR_EACH (Link, &mConfigData[DataType]) {\r
+    CommonEntry = BASE_CR (Link, IPSEC_COMMON_POLICY_ENTRY, List);\r
+\r
+    if (IsFound || mIsZeroSelector[DataType](Selector)) {\r
+      //\r
+      // If found the appointed entry, then duplicate the next one and return,\r
+      // or if the appointed entry is zero, then return the first one directly.\r
+      //\r
+      return mDuplicateSelector[DataType](Selector, CommonEntry->Selector, SelectorSize);\r
+    } else {\r
+      //\r
+      // Set the flag if find the appointed entry.\r
+      //\r
+      IsFound = mCompareSelector[DataType](Selector, CommonEntry->Selector);\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Register an event that is to be signaled whenever a configuration process on the\r
+  specified IPsec configuration information is done.\r
+\r
+  The register function is not surpport now and always returns EFI_UNSUPPORTED.\r
+\r
+  @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.\r
+  @param[in] DataType           The type of data to be registered the event for.\r
+  @param[in] Event              The event to be registered.\r
+\r
+  @retval EFI_SUCCESS           The event is registered successfully.\r
+  @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
+  @retval EFI_ACCESS_DENIED     The Event is already registered for the DataType.\r
+  @retval EFI_UNSUPPORTED       The notify registration is unsupported, or the specified\r
+                                DataType is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIpSecConfigRegisterNotify (\r
+  IN EFI_IPSEC_CONFIG_PROTOCOL        *This,\r
+  IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,\r
+  IN EFI_EVENT                        Event\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Remove the specified event that was previously registered on the specified IPsec\r
+  configuration data.\r
+\r
+  This function is not support now and alwasy return EFI_UNSUPPORTED.\r
+\r
+  @param[in] This               Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.\r
+  @param[in] DataType           The configuration data type to remove the registered event for.\r
+  @param[in] Event              The event to be unregistered.\r
+\r
+  @retval EFI_SUCCESS           The event was removed successfully.\r
+  @retval EFI_NOT_FOUND         The Event specified by DataType could not be found in the\r
+                                database.\r
+  @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
+  @retval EFI_UNSUPPORTED       The notify registration is unsupported, or the specified\r
+                                DataType is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIpSecConfigUnregisterNotify (\r
+  IN EFI_IPSEC_CONFIG_PROTOCOL        *This,\r
+  IN EFI_IPSEC_CONFIG_DATA_TYPE       DataType,\r
+  IN EFI_EVENT                        Event\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Copy whole data in specified EFI_SIPEC_CONFIG_SELECTOR and the Data to a buffer.\r
+\r
+  This function is a caller defined function, and it is called by the IpSecVisitConfigData().\r
+  The orignal caller is IpSecConfigSave(), which calls the IpsecVisitConfigData() to\r
+  copy all types of IPsec Config datas into one buffer and store this buffer into firmware in\r
+  the form of several variables.\r
+\r
+  @param[in]      Type              A specified IPSEC_CONFIG_DATA_TYPE.\r
+  @param[in]      Selector          Points to a EFI_IPSEC_CONFIG_SELECTOR to be copied\r
+                                    to the buffer.\r
+  @param[in]      Data              Points to data to be copied to the buffer. The\r
+                                    Data type is related to the Type.\r
+  @param[in]      SelectorSize      The size of the Selector.\r
+  @param[in]      DataSize          The size of the Data.\r
+  @param[in, out] Buffer            The buffer to store the Selector and Data.\r
+\r
+  @retval EFI_SUCCESS            Copy the Selector and Data to a buffer successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCopyPolicyEntry (\r
+  IN     EFI_IPSEC_CONFIG_DATA_TYPE   Type,\r
+  IN     EFI_IPSEC_CONFIG_SELECTOR    *Selector,\r
+  IN     VOID                         *Data,\r
+  IN     UINTN                        SelectorSize,\r
+  IN     UINTN                        DataSize,\r
+  IN OUT IPSEC_VARIABLE_BUFFER        *Buffer\r
+  )\r
+{\r
+  IPSEC_VAR_ITEM_HEADER SelectorHeader;\r
+  IPSEC_VAR_ITEM_HEADER DataHeader;\r
+  UINTN                 EntrySize;\r
+  UINT8                 *TempPoint;\r
+\r
+  if (Type == IPsecConfigDataTypeSad) {\r
+    //\r
+    // Don't save automatically-generated sa entry into variable.\r
+    //\r
+    if (((EFI_IPSEC_SA_DATA *) Data)->ManualSet == FALSE) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  //\r
+  // Increase the capacity size of the buffer if needed.\r
+  //\r
+  EntrySize  = ALIGN_VARIABLE (sizeof (SelectorHeader));\r
+  EntrySize  = ALIGN_VARIABLE (EntrySize + SelectorSize);\r
+  EntrySize  = ALIGN_VARIABLE (EntrySize + sizeof (SelectorHeader));\r
+  EntrySize  = ALIGN_VARIABLE (EntrySize + DataSize);\r
+\r
+  //EntrySize = SelectorSize + DataSize + 2 * sizeof (SelectorHeader);\r
+  if (Buffer->Capacity - Buffer->Size < EntrySize) {\r
+    //\r
+    // Calculate the required buffer\r
+    //\r
+    Buffer->Capacity += EntrySize;\r
+    TempPoint         = AllocatePool (Buffer->Capacity);\r
+\r
+    if (Buffer->Ptr == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // Copy the old Buffer to new buffer and free the old one.\r
+    //\r
+    CopyMem (TempPoint, Buffer->Ptr, Buffer->Size);\r
+    FreePool (Buffer->Ptr);\r
+\r
+    Buffer->Ptr       =  TempPoint;\r
+  }\r
+\r
+  mFixPolicyEntry[Type](Selector, Data);\r
+\r
+  //\r
+  // Fill the selector header and copy it into buffer.\r
+  //\r
+  SelectorHeader.Type = (UINT8) (Type | IPSEC_VAR_ITEM_HEADER_LOGO_BIT);\r
+  SelectorHeader.Size = (UINT16) SelectorSize;\r
+\r
+  CopyMem (\r
+    Buffer->Ptr + Buffer->Size,\r
+    &SelectorHeader,\r
+    sizeof (SelectorHeader)\r
+    );\r
+  Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + sizeof (SelectorHeader));\r
+\r
+  //\r
+  // Copy the selector into buffer.\r
+  //\r
+  CopyMem (\r
+    Buffer->Ptr + Buffer->Size,\r
+    Selector,\r
+    SelectorSize\r
+    );\r
+  Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + SelectorSize);\r
+\r
+  //\r
+  // Fill the data header and copy it into buffer.\r
+  //\r
+  DataHeader.Type = (UINT8) Type;\r
+  DataHeader.Size = (UINT16) DataSize;\r
+\r
+  CopyMem (\r
+    Buffer->Ptr + Buffer->Size,\r
+    &DataHeader,\r
+    sizeof (DataHeader)\r
+    );\r
+  Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + sizeof (DataHeader));\r
+  //\r
+  // Copy the data into buffer.\r
+  //\r
+  CopyMem (\r
+    Buffer->Ptr + Buffer->Size,\r
+    Data,\r
+    DataSize\r
+    );\r
+  Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + DataSize);\r
+\r
+  mUnfixPolicyEntry[Type](Selector, Data);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Visit all IPsec Configurations of specified Type and call the caller defined\r
+  interface.\r
+\r
+  @param[in]  DataType          The specified IPsec Config Data Type.\r
+  @param[in]  Routine           The function defined by the caller.\r
+  @param[in]  Context           The data passed to the Routine.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated\r
+  @retval EFI_SUCCESS            This function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecVisitConfigData (\r
+  IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,\r
+  IN IPSEC_COPY_POLICY_ENTRY    Routine,\r
+  IN VOID                       *Context\r
+  )\r
+{\r
+  EFI_STATUS                GetNextStatus;\r
+  EFI_STATUS                GetDataStatus;\r
+  EFI_STATUS                RoutineStatus;\r
+  EFI_IPSEC_CONFIG_SELECTOR *Selector;\r
+  VOID                      *Data;\r
+  UINTN                     SelectorSize;\r
+  UINTN                     DataSize;\r
+  UINTN                     SelectorBufferSize;\r
+  UINTN                     DataBufferSize;\r
+  BOOLEAN                   FirstGetNext;\r
+\r
+  FirstGetNext        = TRUE;\r
+  DataBufferSize      = 0;\r
+  Data                = NULL;\r
+  SelectorBufferSize  = sizeof (EFI_IPSEC_CONFIG_SELECTOR);\r
+  Selector            = AllocateZeroPool (SelectorBufferSize);\r
+\r
+  if (Selector == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  while (TRUE) {\r
+    //\r
+    // Get the real size of the selector.\r
+    //\r
+    SelectorSize = SelectorBufferSize;\r
+    GetNextStatus = EfiIpSecConfigGetNextSelector (\r
+                      &mIpSecConfigInstance,\r
+                      DataType,\r
+                      &SelectorSize,\r
+                      Selector\r
+                      );\r
+    if (GetNextStatus == EFI_BUFFER_TOO_SMALL) {\r
+      FreePool (Selector);\r
+      SelectorBufferSize = SelectorSize;\r
+      //\r
+      // Allocate zero pool for the first selector, while store the last\r
+      // selector content for the other selectors.\r
+      //\r
+      if (FirstGetNext) {\r
+        Selector = AllocateZeroPool (SelectorBufferSize);\r
+      } else {\r
+        Selector = AllocateCopyPool (SelectorBufferSize, Selector);\r
+      }\r
+\r
+      if (Selector == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      //\r
+      // Get the content of the selector.\r
+      //\r
+      GetNextStatus = EfiIpSecConfigGetNextSelector (\r
+                        &mIpSecConfigInstance,\r
+                        DataType,\r
+                        &SelectorSize,\r
+                        Selector\r
+                        );\r
+    }\r
+\r
+    if (EFI_ERROR (GetNextStatus)) {\r
+      break;\r
+    }\r
+\r
+    FirstGetNext = FALSE;\r
+\r
+    //\r
+    // Get the real size of the policy entry according to the selector.\r
+    //\r
+    DataSize = DataBufferSize;\r
+    GetDataStatus = EfiIpSecConfigGetData (\r
+                      &mIpSecConfigInstance,\r
+                      DataType,\r
+                      Selector,\r
+                      &DataSize,\r
+                      Data\r
+                      );\r
+    if (GetDataStatus == EFI_BUFFER_TOO_SMALL) {\r
+      if (Data != NULL) {\r
+        FreePool (Data);\r
+      }\r
+\r
+      DataBufferSize  = DataSize;\r
+      Data            = AllocateZeroPool (DataBufferSize);\r
+\r
+      if (Data == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      //\r
+      // Get the content of the policy entry according to the selector.\r
+      //\r
+      GetDataStatus = EfiIpSecConfigGetData (\r
+                        &mIpSecConfigInstance,\r
+                        DataType,\r
+                        Selector,\r
+                        &DataSize,\r
+                        Data\r
+                        );\r
+    }\r
+\r
+    if (EFI_ERROR (GetDataStatus)) {\r
+      break;\r
+    }\r
+    //\r
+    // Prepare the buffer of updated policy entry, which is stored in\r
+    // the continous memory, and then save into variable later.\r
+    //\r
+    RoutineStatus = Routine (\r
+                      DataType,\r
+                      Selector,\r
+                      Data,\r
+                      SelectorSize,\r
+                      DataSize,\r
+                      Context\r
+                      );\r
+    if (EFI_ERROR (RoutineStatus)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Data != NULL) {\r
+    FreePool (Data);\r
+  }\r
+\r
+  if (Selector != NULL) {\r
+    FreePool (Selector);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is the subfunction of  EFIIpSecConfigSetData.\r
+\r
+  This function call IpSecSetVaraible to set the IPsec Configuration into the firmware.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated.\r
+  @retval EFI_SUCCESS            Saved the configration successfully.\r
+  @retval Others                 Other errors were found while obtaining the variable.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecConfigSave (\r
+  VOID\r
+  )\r
+{\r
+  IPSEC_VARIABLE_BUFFER       Buffer;\r
+  EFI_STATUS                  Status;\r
+  EFI_IPSEC_CONFIG_DATA_TYPE  Type;\r
+\r
+  Buffer.Size     = 0;\r
+  Buffer.Capacity = IPSEC_DEFAULT_VARIABLE_SIZE;\r
+  Buffer.Ptr      = AllocateZeroPool (Buffer.Capacity);\r
+\r
+  if (Buffer.Ptr == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // For each policy database, prepare the contious buffer to save into variable.\r
+  //\r
+  for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) {\r
+    IpSecVisitConfigData (\r
+      Type,\r
+      (IPSEC_COPY_POLICY_ENTRY) IpSecCopyPolicyEntry,\r
+      &Buffer\r
+      );\r
+  }\r
+  //\r
+  // Save the updated policy database into variable.\r
+  //\r
+  Status = IpSecSetVariable (\r
+             IPSECCONFIG_VARIABLE_NAME,\r
+             &gEfiIpSecConfigProtocolGuid,\r
+             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+             Buffer.Size,\r
+             Buffer.Ptr\r
+             );\r
+\r
+  FreePool (Buffer.Ptr);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the all IPSec configuration variables and store those variables\r
+  to the internal data structure.\r
+\r
+  This founction is called by IpSecConfigInitialize() which is to intialize the\r
+  IPsecConfiguration Protocol.\r
+\r
+  @param[in]  Private            Point to IPSEC_PRIVATE_DATA.\r
+\r
+  @retval EFI_OUT_OF_RESOURCES   The required system resource could not be allocated\r
+  @retval EFI_SUCCESS            Restore the IPsec Configuration successfully.\r
+  @retval  others                Other errors is found while obtaining the variable.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecConfigRestore (\r
+  IN IPSEC_PRIVATE_DATA           *Private\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINTN                       BufferSize;\r
+  UINT8                       *Buffer;\r
+  IPSEC_VAR_ITEM_HEADER       *Header;\r
+  UINT8                       *Ptr;\r
+  EFI_IPSEC_CONFIG_SELECTOR   *Selector;\r
+  EFI_IPSEC_CONFIG_DATA_TYPE  Type;\r
+  VOID                        *Data;\r
+  UINT8                       Value;\r
+  UINTN                       Size;\r
+\r
+  Value       = 0;\r
+  Size        = sizeof (Value);\r
+  BufferSize  = 0;\r
+  Buffer      = NULL;\r
+\r
+  Status = gRT->GetVariable (\r
+                  IPSECCONFIG_STATUS_NAME,\r
+                  &gEfiIpSecConfigProtocolGuid,\r
+                  NULL,\r
+                  &Size,\r
+                  &Value\r
+             );\r
+\r
+  if (!EFI_ERROR (Status) && Value == IPSEC_STATUS_ENABLED) {\r
+    Private->IpSec.DisabledFlag = FALSE;\r
+  }\r
+  //\r
+  // Get the real size of policy database in variable.\r
+  //\r
+  Status = IpSecGetVariable (\r
+             IPSECCONFIG_VARIABLE_NAME,\r
+             &gEfiIpSecConfigProtocolGuid,\r
+             NULL,\r
+             &BufferSize,\r
+             Buffer\r
+             );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+\r
+    Buffer = AllocateZeroPool (BufferSize);\r
+    if (Buffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    //\r
+    // Get the content of policy database in variable.\r
+    //\r
+    Status = IpSecGetVariable (\r
+               IPSECCONFIG_VARIABLE_NAME,\r
+               &gEfiIpSecConfigProtocolGuid,\r
+               NULL,\r
+               &BufferSize,\r
+               Buffer\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Buffer);\r
+      return Status;\r
+    }\r
+\r
+    for (Ptr = Buffer; Ptr < Buffer + BufferSize;) {\r
+\r
+      Header  = (IPSEC_VAR_ITEM_HEADER *) Ptr;\r
+      Type    = (EFI_IPSEC_CONFIG_DATA_TYPE) (Header->Type & IPSEC_VAR_ITEM_HEADER_CONTENT_BIT);\r
+      ASSERT (((Header->Type & 0x80) == IPSEC_VAR_ITEM_HEADER_LOGO_BIT) && (Type < IPsecConfigDataTypeMaximum));\r
+\r
+      Selector  = (EFI_IPSEC_CONFIG_SELECTOR *) ALIGN_POINTER (Header + 1, sizeof (UINTN));\r
+      Header    = (IPSEC_VAR_ITEM_HEADER *) ALIGN_POINTER (\r
+                                              (UINT8 *) Selector + Header->Size,\r
+                                              sizeof (UINTN)\r
+                                              );\r
+      ASSERT (Header->Type == Type);\r
+\r
+      Data = ALIGN_POINTER (Header + 1, sizeof (UINTN));\r
+\r
+      mUnfixPolicyEntry[Type](Selector, Data);\r
+\r
+      //\r
+      // Update each policy entry according to the content in variable.\r
+      //\r
+      mSetBySelf = TRUE;\r
+      Status = EfiIpSecConfigSetData (\r
+                 &Private->IpSecConfig,\r
+                 Type,\r
+                 Selector,\r
+                 Data,\r
+                 NULL\r
+                 );\r
+      mSetBySelf = FALSE;\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        FreePool (Buffer);\r
+        return Status;\r
+      }\r
+\r
+      Ptr =  ALIGN_POINTER ((UINT8 *) Data + Header->Size, sizeof (UINTN));\r
+    }\r
+\r
+    FreePool (Buffer);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Install and Initialize IPsecConfig protocol\r
+\r
+  @param[in, out]  Private   Pointer to IPSEC_PRIVATE_DATA. After this function finish,\r
+                             the pointer of IPsecConfig Protocol implementation will copy\r
+                             into its IPsecConfig member.\r
+\r
+  @retval     EFI_SUCCESS    Initialized the IPsecConfig Protocol successfully.\r
+  @retval     Others         Initializing the IPsecConfig Protocol failed.\r
+**/\r
+EFI_STATUS\r
+IpSecConfigInitialize (\r
+  IN OUT IPSEC_PRIVATE_DATA        *Private\r
+  )\r
+{\r
+  EFI_IPSEC_CONFIG_DATA_TYPE  Type;\r
+\r
+  CopyMem (\r
+    &Private->IpSecConfig,\r
+    &mIpSecConfigInstance,\r
+    sizeof (EFI_IPSEC_CONFIG_PROTOCOL)\r
+    );\r
+\r
+  //\r
+  // Initialize the list head of policy database.\r
+  //\r
+  for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) {\r
+    InitializeListHead (&mConfigData[Type]);\r
+  }\r
+  //\r
+  // Restore the content of policy database according to the variable.\r
+  //\r
+  IpSecConfigRestore (Private);\r
+\r
+  return gBS->InstallMultipleProtocolInterfaces (\r
+                &Private->Handle,\r
+                &gEfiIpSecConfigProtocolGuid,\r
+                &Private->IpSecConfig,\r
+                NULL\r
+                );\r
+}\r