]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/IpSecDxe/IpSecConfigImpl.c
ArmPkg/GenericWatchdogDxe: clean up the code
[mirror_edk2.git] / NetworkPkg / IpSecDxe / IpSecConfigImpl.c
index e671e42e27af1230f804c4eb625d87047c846d9d..8893d49a9fe37a2d53eff453a5afc83025d4355d 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The implementation of IPSEC_CONFIG_PROTOCOL.\r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2018, 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
@@ -20,7 +20,7 @@ LIST_ENTRY                mConfigData[IPsecConfigDataTypeMaximum];
 BOOLEAN                   mSetBySelf = FALSE;\r
 \r
 //\r
-// Common CompareSelector routine entry for spd/sad/pad.\r
+// Common CompareSelector routine entry for SPD/SAD/PAD.\r
 //\r
 IPSEC_COMPARE_SELECTOR    mCompareSelector[] = {\r
   (IPSEC_COMPARE_SELECTOR) CompareSpdSelector,\r
@@ -29,7 +29,7 @@ IPSEC_COMPARE_SELECTOR    mCompareSelector[] = {
 };\r
 \r
 //\r
-// Common IsZeroSelector routine entry for spd/sad/pad.\r
+// Common IsZeroSelector routine entry for SPD/SAD/PAD.\r
 //\r
 IPSEC_IS_ZERO_SELECTOR    mIsZeroSelector[] = {\r
   (IPSEC_IS_ZERO_SELECTOR) IsZeroSpdSelector,\r
@@ -38,7 +38,7 @@ IPSEC_IS_ZERO_SELECTOR    mIsZeroSelector[] = {
 };\r
 \r
 //\r
-// Common DuplicateSelector routine entry for spd/sad/pad.\r
+// Common DuplicateSelector routine entry for SPD/SAD/PAD.\r
 //\r
 IPSEC_DUPLICATE_SELECTOR  mDuplicateSelector[] = {\r
   (IPSEC_DUPLICATE_SELECTOR) DuplicateSpdSelector,\r
@@ -47,7 +47,7 @@ IPSEC_DUPLICATE_SELECTOR  mDuplicateSelector[] = {
 };\r
 \r
 //\r
-// Common FixPolicyEntry routine entry for spd/sad/pad.\r
+// Common FixPolicyEntry routine entry for SPD/SAD/PAD.\r
 //\r
 IPSEC_FIX_POLICY_ENTRY    mFixPolicyEntry[] = {\r
   (IPSEC_FIX_POLICY_ENTRY) FixSpdEntry,\r
@@ -56,7 +56,7 @@ IPSEC_FIX_POLICY_ENTRY    mFixPolicyEntry[] = {
 };\r
 \r
 //\r
-// Common UnfixPolicyEntry routine entry for spd/sad/pad.\r
+// Common UnfixPolicyEntry routine entry for SPD/SAD/PAD.\r
 //\r
 IPSEC_FIX_POLICY_ENTRY    mUnfixPolicyEntry[] = {\r
   (IPSEC_FIX_POLICY_ENTRY) UnfixSpdEntry,\r
@@ -65,7 +65,7 @@ IPSEC_FIX_POLICY_ENTRY    mUnfixPolicyEntry[] = {
 };\r
 \r
 //\r
-// Common SetPolicyEntry routine entry for spd/sad/pad.\r
+// Common SetPolicyEntry routine entry for SPD/SAD/PAD.\r
 //\r
 IPSEC_SET_POLICY_ENTRY    mSetPolicyEntry[] = {\r
   (IPSEC_SET_POLICY_ENTRY) SetSpdEntry,\r
@@ -74,7 +74,7 @@ IPSEC_SET_POLICY_ENTRY    mSetPolicyEntry[] = {
 };\r
 \r
 //\r
-// Common GetPolicyEntry routine entry for spd/sad/pad.\r
+// Common GetPolicyEntry routine entry for SPD/SAD/PAD.\r
 //\r
 IPSEC_GET_POLICY_ENTRY    mGetPolicyEntry[] = {\r
   (IPSEC_GET_POLICY_ENTRY) GetSpdEntry,\r
@@ -130,8 +130,23 @@ IsInAddressInfoList(
   IN UINT32                           AddressCount\r
   )\r
 {\r
-  UINT8  Index;\r
+  UINT8           Index;\r
+  EFI_IP_ADDRESS  ZeroAddress;\r
 \r
+  ZeroMem(&ZeroAddress, sizeof (EFI_IP_ADDRESS));\r
+\r
+  //\r
+  // Zero Address means any address is matched.\r
+  //\r
+  if (AddressCount == 1) {\r
+    if (CompareMem (\r
+          &AddressInfoList[0].Address,\r
+          &ZeroAddress,\r
+          sizeof (EFI_IP_ADDRESS)\r
+          ) == 0) {\r
+      return TRUE;\r
+    }\r
+  }\r
   for (Index = 0; Index < AddressCount ; Index++) {\r
     if (CompareMem (\r
           AddressInfo,\r
@@ -196,7 +211,7 @@ CompareSpdSelector (
   }\r
 \r
   //\r
-  // Compare the all LocalAddress fields in the two Spdselectors.\r
+  // Compare the all LocalAddress and RemoteAddress 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
@@ -309,6 +324,143 @@ CompareSpdSelector (
   return IsMatch;\r
 }\r
 \r
+/**\r
+  Find if the two SPD Selectors has subordinative.\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    The first SPD Selector is subordinate Selector of second SPD Selector.\r
+  @retval  FALSE   The first SPD Selector is not subordinate Selector of second\r
+                   SPD Selector.\r
+\r
+**/\r
+BOOLEAN\r
+IsSubSpdSelector (\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->RemoteAddressCount > SpdSel2->RemoteAddressCount ||\r
+      (SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) ||\r
+      (SpdSel1->LocalPort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0)||\r
+      (SpdSel1->LocalPortRange > SpdSel2->LocalPortRange && SpdSel1->LocalPort != 0)||\r
+      (SpdSel1->RemotePort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0) ||\r
+      (SpdSel1->RemotePortRange > SpdSel2->RemotePortRange && SpdSel2->RemotePort != 0)\r
+      ) {\r
+    IsMatch = FALSE;\r
+  }\r
+\r
+  //\r
+  // Compare the all LocalAddress and RemoteAddress 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
+  if (IsMatch) {\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
+\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
+  }\r
+  if (IsMatch) {\r
+    return IsMatch;\r
+  }\r
+\r
+  //\r
+  //\r
+  // The SPD selector in SPD entry is two way.\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
+  IsMatch = TRUE;\r
+  if (SpdSel1->LocalAddressCount > SpdSel2->RemoteAddressCount ||\r
+      SpdSel1->RemoteAddressCount > SpdSel2->LocalAddressCount ||\r
+      (SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) ||\r
+      (SpdSel1->LocalPort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0)||\r
+      (SpdSel1->LocalPortRange > SpdSel2->RemotePortRange && SpdSel1->RemotePort != 0)||\r
+      (SpdSel1->RemotePort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0) ||\r
+      (SpdSel1->RemotePortRange > SpdSel2->LocalPortRange && SpdSel2->LocalPort != 0)\r
+      ) {\r
+    IsMatch = FALSE;\r
+    return IsMatch;\r
+  }\r
+\r
+  //\r
+  // Compare the all LocalAddress and RemoteAddress fields in the two Spdselectors.\r
+  // First, SpdSel1->LocalAddress to SpdSel2->RemoteAddress && Compare\r
+  // SpdSel1->RemoteAddress to SpdSel2->LocalAddress. If all match, return\r
+  // TRUE.\r
+  //\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 < 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
+  }\r
+  return IsMatch;\r
+\r
+}\r
+\r
 /**\r
   Compare two SA IDs.\r
 \r
@@ -435,16 +587,14 @@ IsZeroSaId (
   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector\r
   )\r
 {\r
-  EFI_IP_ADDRESS  *DestAddr;\r
-  EFI_IP_ADDRESS  ZeroAddr;\r
-  BOOLEAN         IsZero;\r
+  BOOLEAN                   IsZero;\r
+  EFI_IPSEC_CONFIG_SELECTOR ZeroSelector;\r
 \r
-  DestAddr  = &Selector->SaId.DestAddress;\r
   IsZero    = FALSE;\r
 \r
-  ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS));\r
+  ZeroMem (&ZeroSelector, sizeof (EFI_IPSEC_CONFIG_SELECTOR));\r
 \r
-  if (CompareMem (DestAddr, &ZeroAddr, sizeof (EFI_IP_ADDRESS)) == 0) {\r
+  if (CompareMem (&ZeroSelector, Selector, sizeof (EFI_IPSEC_CONFIG_SELECTOR)) == 0) {\r
     IsZero = TRUE;\r
   }\r
 \r
@@ -520,12 +670,12 @@ DuplicateSpdSelector (
     return EFI_BUFFER_TOO_SMALL;\r
   }\r
   //\r
-  // Copy the base structure of spd selector.\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
+  // Copy the local address array of SPD selector.\r
   //\r
   Dst->LocalAddress = (EFI_IP_ADDRESS_INFO *) (Dst + 1);\r
   CopyMem (\r
@@ -535,7 +685,7 @@ DuplicateSpdSelector (
     );\r
 \r
   //\r
-  // Copy the remote address array of spd selector.\r
+  // Copy the remote address array of SPD selector.\r
   //\r
   Dst->RemoteAddress = Dst->LocalAddress + Dst->LocalAddressCount;\r
   CopyMem (\r
@@ -650,7 +800,7 @@ FixSpdEntry (
   )\r
 {\r
   //\r
-  // It assumes that all ref buffers in spd selector and data are\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
@@ -681,11 +831,11 @@ FixSpdEntry (
 VOID\r
 FixSadEntry (\r
   IN     EFI_IPSEC_SA_ID                  *SaId,\r
-  IN OUT EFI_IPSEC_SA_DATA                *Data\r
+  IN OUT EFI_IPSEC_SA_DATA2                *Data\r
   )\r
 {\r
   //\r
-  // It assumes that all ref buffers in sad selector and data are\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
@@ -756,7 +906,7 @@ UnfixSpdEntry (
   )\r
 {\r
   //\r
-  // It assumes that all ref buffers in spd selector and data are\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
@@ -784,11 +934,11 @@ UnfixSpdEntry (
 VOID\r
 UnfixSadEntry (\r
   IN OUT EFI_IPSEC_SA_ID                     *SaId,\r
-  IN OUT EFI_IPSEC_SA_DATA                   *Data\r
+  IN OUT EFI_IPSEC_SA_DATA2                   *Data\r
   )\r
 {\r
   //\r
-  // It assumes that all ref buffers in sad selector and data are\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
@@ -868,6 +1018,8 @@ UnfixPadEntry (
                                      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
+                                   - SadEntry requied to be set into new SpdEntry's Sas has\r
+                                     been found but it is invalid.\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
@@ -887,8 +1039,9 @@ SetSpdEntry (
   LIST_ENTRY              *SpdSas;\r
   LIST_ENTRY              *EntryInsertBefore;\r
   LIST_ENTRY              *Entry;\r
-  LIST_ENTRY              *NextEntry;\r
   LIST_ENTRY              *Entry2;\r
+  LIST_ENTRY              *NextEntry;\r
+  LIST_ENTRY              *NextEntry2;\r
   IPSEC_SPD_ENTRY         *SpdEntry;\r
   IPSEC_SAD_ENTRY         *SadEntry;\r
   UINTN                   SpdEntrySize;\r
@@ -926,7 +1079,7 @@ SetSpdEntry (
   EntryInsertBefore = SpdList;\r
 \r
   //\r
-  // Remove the existed spd entry.\r
+  // Remove the existed SPD entry.\r
   //\r
   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SpdList) {\r
 \r
@@ -942,21 +1095,37 @@ SetSpdEntry (
       RemoveEntryList (&SpdEntry->List);\r
 \r
       //\r
-      // Update the reverse ref of sad entry in the spd.sas list.\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
+      // Remove the related SAs from Sas(SadEntry->BySpd). If the SA entry is established by\r
+      // IKE, remove from mConfigData list(SadEntry->List) and then free it directly since its\r
+      // SpdEntry will be freed later.\r
+      //\r
+      NET_LIST_FOR_EACH_SAFE (Entry2, NextEntry2, SpdSas) {\r
+        SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry2);\r
+\r
+        if (SadEntry->Data->SpdEntry != NULL) {\r
+          RemoveEntryList (&SadEntry->BySpd);\r
+          SadEntry->Data->SpdEntry = NULL;\r
+        }\r
+\r
+        if (!(SadEntry->Data->ManualSet)) {\r
+          RemoveEntryList (&SadEntry->List);\r
+          FreePool (SadEntry);\r
+        }\r
       }\r
+\r
       //\r
-      // Free the existed spd entry\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
+  // Return success here if only want to remove the SPD entry.\r
   //\r
   if (SpdData == NULL || SpdSel == NULL) {\r
     return EFI_SUCCESS;\r
@@ -983,7 +1152,7 @@ SetSpdEntry (
   // 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  = ALIGN_VARIABLE (SpdEntrySize + SIZE_OF_SPD_SELECTOR (SpdSel));\r
   SpdEntrySize += IpSecGetSizeOfEfiSpdData (SpdData);\r
 \r
   SpdEntry = AllocateZeroPool (SpdEntrySize);\r
@@ -993,7 +1162,7 @@ SetSpdEntry (
   }\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
+  // 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
@@ -1012,12 +1181,13 @@ SetSpdEntry (
     SpdData->Name,\r
     sizeof (SpdData->Name)\r
     );\r
-  SpdEntry->Data->PackageFlag = SpdData->PackageFlag;\r
-  SpdEntry->Data->Action      = SpdData->Action;\r
+  SpdEntry->Data->PackageFlag      = SpdData->PackageFlag;\r
+  SpdEntry->Data->TrafficDirection = SpdData->TrafficDirection;\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
+  // memory and close to the base structure of SAD data.\r
   //\r
   if (SpdData->Action != EfiIPsecActionProtect) {\r
     SpdEntry->Data->ProcessingPolicy = NULL;\r
@@ -1029,7 +1199,7 @@ SetSpdEntry (
     IpSecDuplicateProcessPolicy (SpdEntry->Data->ProcessingPolicy, SpdData->ProcessingPolicy);\r
   }\r
   //\r
-  // Update the sas list of the new spd entry.\r
+  // Update the sas list of the new SPD entry.\r
   //\r
   InitializeListHead (&SpdEntry->Data->Sas);\r
 \r
@@ -1038,19 +1208,32 @@ SetSpdEntry (
   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
+      for (Index = 0; Index < SpdData->SaIdCount; Index++) {\r
+        if (CompareSaId (\r
+              (EFI_IPSEC_CONFIG_SELECTOR *) &SpdData->SaId[Index],\r
+              (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id\r
+              )) {\r
+          //\r
+          // Check whether the found SadEntry is vaild.\r
+          //\r
+          if (IsSubSpdSelector (\r
+                (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,\r
+                (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector\r
+                )) {\r
+            if (SadEntry->Data->SpdEntry != NULL) {\r
+              RemoveEntryList (&SadEntry->BySpd);\r
+            }\r
+            InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);\r
+            SadEntry->Data->SpdEntry = SpdEntry;\r
+          } else {\r
+            return EFI_INVALID_PARAMETER;\r
+          }\r
+        }\r
       }\r
-    }\r
   }\r
+\r
   //\r
-  // Insert the new spd entry.\r
+  // Insert the new SPD entry.\r
   //\r
   InsertTailList (EntryInsertBefore, &SpdEntry->List);\r
 \r
@@ -1092,13 +1275,13 @@ SetSadEntry (
   LIST_ENTRY        *SadList;\r
   LIST_ENTRY        *SpdList;\r
   EFI_IPSEC_SA_ID   *SaId;\r
-  EFI_IPSEC_SA_DATA *SaData;\r
+  EFI_IPSEC_SA_DATA2 *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
+  SaData        = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA2 *) Data;\r
   InsertBefore  = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SaId;\r
   SadList       = &mConfigData[IPsecConfigDataTypeSad];\r
 \r
@@ -1108,7 +1291,7 @@ SetSadEntry (
   EntryInsertBefore = SadList;\r
 \r
   //\r
-  // Remove the existed sad entry.\r
+  // Remove the existed SAD entry.\r
   //\r
   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SadList) {\r
 \r
@@ -1125,7 +1308,7 @@ SetSadEntry (
       EntryInsertBefore = SadEntry->List.ForwardLink;\r
 \r
       //\r
-      // Update the related sad.byspd field.\r
+      // Update the related SAD.byspd field.\r
       //\r
       if (SadEntry->Data->SpdEntry != NULL) {\r
         RemoveEntryList (&SadEntry->BySpd);\r
@@ -1136,7 +1319,7 @@ SetSadEntry (
     }\r
   }\r
   //\r
-  // Return success here if only want to remove the sad entry\r
+  // Return success here if only want to remove the SAD entry\r
   //\r
   if (SaData == NULL || SaId == NULL) {\r
     return EFI_SUCCESS;\r
@@ -1163,16 +1346,19 @@ SetSadEntry (
   // 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 (EFI_IPSEC_SA_ID));\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
+    SadEntrySize += ALIGN_VARIABLE (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength);\r
   }\r
 \r
+  if (SaData->SpdSelector != NULL) {\r
+    SadEntrySize += SadEntrySize + SIZE_OF_SPD_SELECTOR (SaData->SpdSelector);\r
+  }\r
   SadEntry      = AllocateZeroPool (SadEntrySize);\r
 \r
   if (SadEntry == NULL) {\r
@@ -1180,7 +1366,7 @@ SetSadEntry (
   }\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
+  // 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
@@ -1238,28 +1424,52 @@ SetSadEntry (
     );\r
 \r
   SadEntry->Data->PathMTU     = SaData->PathMTU;\r
-  SadEntry->Data->SpdEntry    = NULL;\r
+  SadEntry->Data->SpdSelector = 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
+  // Copy Tunnel Source/Destination Address\r
+  //\r
+  if (SaData->Mode == EfiIPsecTunnel) {\r
+    CopyMem (\r
+      &SadEntry->Data->TunnelDestAddress,\r
+      &SaData->TunnelDestinationAddress,\r
+      sizeof (EFI_IP_ADDRESS)\r
+      );\r
+    CopyMem (\r
+      &SadEntry->Data->TunnelSourceAddress,\r
+      &SaData->TunnelSourceAddress,\r
+      sizeof (EFI_IP_ADDRESS)\r
+      );\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
+    if (IsSubSpdSelector (\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector\r
           ) && SpdEntry->Data->Action == EfiIPsecActionProtect) {\r
       SadEntry->Data->SpdEntry = SpdEntry;\r
+      SadEntry->Data->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *)((UINT8 *)SadEntry +\r
+                                                                SadEntrySize -\r
+                                                                SIZE_OF_SPD_SELECTOR (SaData->SpdSelector)\r
+                                                                );\r
+      DuplicateSpdSelector (\r
+       (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,\r
+       (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,\r
+       NULL\r
+       );\r
       InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);\r
     }\r
   }\r
   //\r
-  // Insert the new sad entry.\r
+  // Insert the new SAD entry.\r
   //\r
   InsertTailList (EntryInsertBefore, &SadEntry->List);\r
 \r
@@ -1462,7 +1672,7 @@ GetSpdEntry (
     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
 \r
     //\r
-    // Find the required spd entry\r
+    // Find the required SPD entry\r
     //\r
     if (CompareSpdSelector (\r
           (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,\r
@@ -1482,7 +1692,7 @@ GetSpdEntry (
       *DataSize = RequiredSize;\r
 \r
       //\r
-      // Extract and fill all SaId array from the spd.sas list\r
+      // Extract and fill all SaId array from the SPD.sas list\r
       //\r
       SpdSas              = &SpdEntry->Data->Sas;\r
       SpdData->SaIdCount  = 0;\r
@@ -1496,12 +1706,13 @@ GetSpdEntry (
           );\r
       }\r
       //\r
-      // Fill the other fields in spd data.\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
+      SpdData->PackageFlag      = SpdEntry->Data->PackageFlag;\r
+      SpdData->TrafficDirection = SpdEntry->Data->TrafficDirection;\r
+      SpdData->Action           = SpdEntry->Data->Action;\r
 \r
       if (SpdData->Action != EfiIPsecActionProtect) {\r
         SpdData->ProcessingPolicy = NULL;\r
@@ -1549,32 +1760,32 @@ GetSadEntry (
   LIST_ENTRY        *Entry;\r
   LIST_ENTRY        *SadList;\r
   EFI_IPSEC_SA_ID   *SaId;\r
-  EFI_IPSEC_SA_DATA *SaData;\r
+  EFI_IPSEC_SA_DATA2 *SaData;\r
   UINTN             RequiredSize;\r
 \r
   SaId    = &Selector->SaId;\r
-  SaData  = (EFI_IPSEC_SA_DATA *) Data;\r
+  SaData  = (EFI_IPSEC_SA_DATA2 *) 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
+    // 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
+      // 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
+      RequiredSize  = ALIGN_VARIABLE (sizeof (EFI_IPSEC_SA_DATA2));\r
 \r
       if (SaId->Proto == EfiIPsecAH) {\r
         RequiredSize  = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength);\r
@@ -1583,18 +1794,17 @@ GetSadEntry (
         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
+      if (SadEntry->Data->SpdSelector != NULL) {\r
+        RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector);\r
       }\r
 \r
-\r
-\r
       if (*DataSize < RequiredSize) {\r
         *DataSize = RequiredSize;\r
         return EFI_BUFFER_TOO_SMALL;\r
       }\r
+\r
       //\r
-      // Fill the data fields of sad entry.\r
+      // Fill the data fields of SAD entry.\r
       //\r
       *DataSize                 = RequiredSize;\r
       SaData->Mode              = SadEntry->Data->Mode;\r
@@ -1661,19 +1871,34 @@ GetSadEntry (
       SaData->PathMTU = SadEntry->Data->PathMTU;\r
 \r
       //\r
-      // Fill the spd selector field of sad data\r
+      // Fill Tunnel Address if it is Tunnel Mode\r
       //\r
-      if (SadEntry->Data->SpdEntry != NULL) {\r
+      if (SadEntry->Data->Mode == EfiIPsecTunnel) {\r
+        CopyMem (\r
+          &SaData->TunnelDestinationAddress,\r
+          &SadEntry->Data->TunnelDestAddress,\r
+          sizeof (EFI_IP_ADDRESS)\r
+          );\r
+        CopyMem (\r
+          &SaData->TunnelSourceAddress,\r
+          &SadEntry->Data->TunnelSourceAddress,\r
+          sizeof (EFI_IP_ADDRESS)\r
+          );\r
+      }\r
+      //\r
+      // Fill the spd selector field of SAD data\r
+      //\r
+      if (SadEntry->Data->SpdSelector != NULL) {\r
 \r
         SaData->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) (\r
                                 (UINT8 *)SaData +\r
                                 RequiredSize -\r
-                                SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdEntry->Selector)\r
+                                SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector)\r
                                 );\r
 \r
         DuplicateSpdSelector (\r
           (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,\r
-          (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdEntry->Selector,\r
+          (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,\r
           NULL\r
           );\r
 \r
@@ -1950,7 +2175,10 @@ IpSecGetVariable (
   VariableNameLength  = StrLen (VariableName);\r
   VariableNameISize   = (VariableNameLength + 5) * sizeof (CHAR16);\r
   VariableNameI       = AllocateZeroPool (VariableNameISize);\r
-  ASSERT (VariableNameI != NULL);\r
+  if (VariableNameI == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
 \r
   //\r
   // Construct the varible name of ipsecconfig meta data.\r
@@ -1995,6 +2223,10 @@ IpSecGetVariable (
                         VariableNameISizeNew,\r
                         VariableNameI\r
                         );\r
+      if (VariableNameI == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        break;\r
+      }\r
       VariableNameISize = VariableNameISizeNew;\r
 \r
       Status = gRT->GetNextVariableName (\r
@@ -2071,7 +2303,9 @@ IpSecGetVariable (
   }\r
 \r
 ON_EXIT:\r
-  FreePool (VariableNameI);\r
+  if (VariableNameI != NULL) {\r
+    FreePool (VariableNameI);\r
+  }\r
   return Status;\r
 }\r
 \r
@@ -2365,7 +2599,7 @@ EfiIpSecConfigGetNextSelector (
   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
+    if (IsFound || (BOOLEAN)(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
@@ -2477,9 +2711,9 @@ IpSecCopyPolicyEntry (
 \r
   if (Type == IPsecConfigDataTypeSad) {\r
     //\r
-    // Don't save automatically-generated sa entry into variable.\r
+    // Don't save automatically-generated SA entry into variable.\r
     //\r
-    if (((EFI_IPSEC_SA_DATA *) Data)->ManualSet == FALSE) {\r
+    if (((EFI_IPSEC_SA_DATA2 *) Data)->ManualSet == FALSE) {\r
       return EFI_SUCCESS;\r
     }\r
   }\r
@@ -2499,7 +2733,7 @@ IpSecCopyPolicyEntry (
     Buffer->Capacity += EntrySize;\r
     TempPoint         = AllocatePool (Buffer->Capacity);\r
 \r
-    if (Buffer->Ptr == NULL) {\r
+    if (TempPoint == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
     //\r