]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add IPsec/Ikev2 support.
authorqianouyang <qianouyang@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 31 Dec 2010 10:43:54 +0000 (10:43 +0000)
committerqianouyang <qianouyang@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 31 Dec 2010 10:43:54 +0000 (10:43 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11219 6f19259b-4bc3-4df7-8a09-765794883524

31 files changed:
NetworkPkg/IpSecDxe/IetfConstants.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ike.h [new file with mode: 0644]
NetworkPkg/IpSecDxe/IkeCommon.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/IkeCommon.h [new file with mode: 0644]
NetworkPkg/IpSecDxe/IkePacket.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/IkePacket.h [new file with mode: 0644]
NetworkPkg/IpSecDxe/IkeService.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/IkeService.h [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/ChildSa.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/Exchange.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/Ikev2.h [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/Info.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/Payload.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/Payload.h [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/Sa.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/Utility.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/Ikev2/Utility.h [new file with mode: 0644]
NetworkPkg/IpSecDxe/IpSecConfigImpl.c
NetworkPkg/IpSecDxe/IpSecConfigImpl.h
NetworkPkg/IpSecDxe/IpSecCryptIo.c
NetworkPkg/IpSecDxe/IpSecCryptIo.h
NetworkPkg/IpSecDxe/IpSecDebug.c
NetworkPkg/IpSecDxe/IpSecDebug.h
NetworkPkg/IpSecDxe/IpSecDriver.c
NetworkPkg/IpSecDxe/IpSecDxe.inf
NetworkPkg/IpSecDxe/IpSecImpl.c
NetworkPkg/IpSecDxe/IpSecImpl.h
NetworkPkg/IpSecDxe/IpSecMain.c [new file with mode: 0644]
NetworkPkg/IpSecDxe/IpSecSaEngine.c [deleted file]
NetworkPkg/NetworkPkg.dec
NetworkPkg/NetworkPkg.dsc

diff --git a/NetworkPkg/IpSecDxe/IetfConstants.c b/NetworkPkg/IpSecDxe/IetfConstants.c
new file mode 100644 (file)
index 0000000..7bd5c81
--- /dev/null
@@ -0,0 +1,388 @@
+/** @file\r
+  Cryptographic Parameter Constant Definitions from IETF;\r
+  \r
+  Copyright (c) 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 "Ike.h"\r
+\r
+//\r
+// "First Oakley Default Group" from RFC2409, section 6.1.\r
+//\r
+//  The prime is: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp768Modulus[] = {\r
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,\r
+  0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,\r
+  0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,\r
+  0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,\r
+  0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,\r
+  0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,\r
+  0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,\r
+  0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF\r
+  };\r
+\r
+//\r
+// "Second Oakley Default Group" from RFC2409, section 6.2.\r
+//\r
+//  The prime is: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp1024Modulus[] = {\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,\r
+  0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,\r
+  0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,\r
+  0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,\r
+  0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,\r
+  0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,\r
+  0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,\r
+  0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,\r
+  0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,\r
+  0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\r
+  };\r
+\r
+//\r
+// "1536-bit MODP Group" from RFC3526, Section 2.\r
+//\r
+// The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp1536Modulus[]={\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,\r
+  0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,\r
+  0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,\r
+  0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,\r
+  0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,\r
+  0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,\r
+  0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,\r
+  0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,\r
+  0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,\r
+  0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,\r
+  0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,\r
+  0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,\r
+  0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,\r
+  0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,\r
+  0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,\r
+  0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\r
+  };\r
+\r
+//\r
+// "2048-bit MODP Group" from RFC3526, Section 3.\r
+//\r
+//  The prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp2048Modulus[]={\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,\r
+  0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,\r
+  0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,\r
+  0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,\r
+  0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,\r
+  0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,\r
+  0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,\r
+  0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,\r
+  0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,\r
+  0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,\r
+  0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,\r
+  0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,\r
+  0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,\r
+  0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,\r
+  0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,\r
+  0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,\r
+  0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,\r
+  0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,\r
+  0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,\r
+  0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,\r
+  0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,\r
+  0xFF,0xFF,0xFF,0xFF,\r
+  };\r
+\r
+//\r
+// "3072-bit MODP Group" from RFC3526, Section 4.\r
+//\r
+//  The prime is: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp3072Modulus[]={\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,\r
+  0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,\r
+  0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,\r
+  0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,\r
+  0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,\r
+  0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,\r
+  0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,\r
+  0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,\r
+  0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,\r
+  0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,\r
+  0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,\r
+  0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,\r
+  0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,\r
+  0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,\r
+  0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,\r
+  0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,\r
+  0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,\r
+  0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,\r
+  0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,\r
+  0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,\r
+  0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,\r
+  0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,\r
+  0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,\r
+  0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,\r
+  0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,\r
+  0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,\r
+  0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,\r
+  0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,\r
+  0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,\r
+  0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,\r
+  0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,\r
+  0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\r
+  };\r
+\r
+//\r
+// "4096-bit MODP Group" from RFC3526, Section 5.\r
+//\r
+//  The prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp4096Modulus[]={\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,\r
+  0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,\r
+  0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,\r
+  0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,\r
+  0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,\r
+  0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,\r
+  0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,\r
+  0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,\r
+  0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,\r
+  0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,\r
+  0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,\r
+  0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,\r
+  0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,\r
+  0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,\r
+  0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,\r
+  0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,\r
+  0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,\r
+  0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,\r
+  0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,\r
+  0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,\r
+  0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,\r
+  0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,\r
+  0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,\r
+  0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,\r
+  0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,\r
+  0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,\r
+  0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,\r
+  0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,\r
+  0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,\r
+  0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,\r
+  0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,\r
+  0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,\r
+  0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,\r
+  0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,\r
+  0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB,\r
+  0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,\r
+  0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,\r
+  0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,\r
+  0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76,\r
+  0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,\r
+  0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,\r
+  0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\r
+  };\r
+\r
+//\r
+// "6144-bit MODP Group" from RFC3526, Section 6.\r
+//\r
+//  The prime is: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp6144Modulus[]={\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,\r
+  0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,\r
+  0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,\r
+  0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,\r
+  0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,\r
+  0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,\r
+  0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,\r
+  0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,\r
+  0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,\r
+  0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,\r
+  0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,\r
+  0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,\r
+  0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,\r
+  0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,\r
+  0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,\r
+  0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,\r
+  0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,\r
+  0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,\r
+  0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,\r
+  0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,\r
+  0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,\r
+  0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,\r
+  0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,\r
+  0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,\r
+  0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,\r
+  0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,\r
+  0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,\r
+  0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,\r
+  0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,\r
+  0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,\r
+  0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,\r
+  0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,\r
+  0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,\r
+  0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,\r
+  0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB,\r
+  0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,\r
+  0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,\r
+  0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,\r
+  0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76,\r
+  0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,\r
+  0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,\r
+  0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,\r
+  0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,0xC1,0xD4,0xDC,0xB2,\r
+  0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,\r
+  0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,\r
+  0x41,0x30,0x01,0xAE,0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,\r
+  0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,0xDA,0x3E,0xDB,0xEB,\r
+  0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,\r
+  0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,\r
+  0x2B,0xD7,0xAF,0x42,0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,\r
+  0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,0xF0,0x32,0xEA,0x15,\r
+  0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,\r
+  0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,\r
+  0x90,0x0B,0x1C,0x9E,0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,\r
+  0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,0x0F,0x1D,0x45,0xB7,\r
+  0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,\r
+  0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,\r
+  0x0F,0x80,0x37,0xE0,0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,\r
+  0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,0xF5,0x50,0xAA,0x3D,\r
+  0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,\r
+  0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,\r
+  0x6E,0x3C,0x04,0x68,0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,\r
+  0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,0xE6,0x94,0xF9,0x1E,\r
+  0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\r
+  };\r
+\r
+//\r
+// "8192-bit MODP Group" from RFC3526, Section 7.\r
+//\r
+//  The prime is: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp8192Modulus[]={\r
+  0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,\r
+  0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,\r
+  0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,\r
+  0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,\r
+  0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,\r
+  0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,\r
+  0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,\r
+  0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,\r
+  0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,\r
+  0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,\r
+  0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,\r
+  0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,\r
+  0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,\r
+  0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,\r
+  0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,\r
+  0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,\r
+  0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,\r
+  0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,\r
+  0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,\r
+  0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,\r
+  0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,\r
+  0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,\r
+  0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,\r
+  0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,\r
+  0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,\r
+  0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,\r
+  0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,\r
+  0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,\r
+  0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,\r
+  0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,\r
+  0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,\r
+  0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,\r
+  0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,\r
+  0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,\r
+  0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB,\r
+  0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,\r
+  0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,\r
+  0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,\r
+  0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76,\r
+  0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,\r
+  0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,\r
+  0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,\r
+  0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,0xC1,0xD4,0xDC,0xB2,\r
+  0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,\r
+  0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,\r
+  0x41,0x30,0x01,0xAE,0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,\r
+  0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,0xDA,0x3E,0xDB,0xEB,\r
+  0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,\r
+  0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,\r
+  0x2B,0xD7,0xAF,0x42,0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,\r
+  0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,0xF0,0x32,0xEA,0x15,\r
+  0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,\r
+  0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,\r
+  0x90,0x0B,0x1C,0x9E,0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,\r
+  0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,0x0F,0x1D,0x45,0xB7,\r
+  0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,\r
+  0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,\r
+  0x0F,0x80,0x37,0xE0,0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,\r
+  0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,0xF5,0x50,0xAA,0x3D,\r
+  0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,\r
+  0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,\r
+  0x6E,0x3C,0x04,0x68,0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,\r
+  0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,0xE6,0x94,0xF9,0x1E,\r
+  0x6D,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4,\r
+  0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,\r
+  0x73,0xB9,0x31,0xBA,0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,\r
+  0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED,0x25,0x76,0xF6,0x93,\r
+  0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68,\r
+  0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,\r
+  0xE3,0x9D,0x65,0x2D,0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,\r
+  0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07,0x13,0xEB,0x57,0xA8,\r
+  0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B,\r
+  0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,\r
+  0xA2,0xC0,0x87,0xE8,0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,\r
+  0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6,0x6D,0x2A,0x13,0xF8,\r
+  0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36,\r
+  0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,\r
+  0x08,0x46,0x85,0x1D,0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,\r
+  0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73,0xFA,0xF3,0x6B,0xC3,\r
+  0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92,\r
+  0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,\r
+  0xD5,0xEE,0x38,0x2B,0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,\r
+  0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA,0x9E,0x30,0x50,0xE2,\r
+  0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71,\r
+  0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,\r
+  0xFF,0xFF,0xFF,0xFF,\r
+  };\r
+\r
+//\r
+// Pre-defined Oakley MODP Groups\r
+//\r
+#define DH_GENERATOR_2              2\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST MODP_GROUP OakleyModpGroup[] = {\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {OakleyGroupModp768,  768,  Modp768Modulus,  DH_GENERATOR_2},\r
+  {OakleyGroupModp1024, 1024, Modp1024Modulus, DH_GENERATOR_2},\r
+  {0,                     0,    NULL,             0},    // For ECC. UnSupported\r
+  {0,                     0,    NULL,             0},    // For ECC. Unsupported\r
+  {OakleyGroupModp1536, 1536, Modp1536Modulus, DH_GENERATOR_2},\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {0,                     0,    NULL,             0},    //Undefined\r
+  {OakleyGroupModp2048, 2048, Modp2048Modulus, DH_GENERATOR_2},\r
+  {OakleyGroupModp3072, 3072, Modp3072Modulus, DH_GENERATOR_2},\r
+  {OakleyGroupModp4096, 4096, Modp4096Modulus, DH_GENERATOR_2},\r
+  {OakleyGroupModp6144, 6144, Modp6144Modulus, DH_GENERATOR_2},\r
+  {OakleyGroupModp8192, 8192, Modp8192Modulus, DH_GENERATOR_2},\r
+};\r
diff --git a/NetworkPkg/IpSecDxe/Ike.h b/NetworkPkg/IpSecDxe/Ike.h
new file mode 100644 (file)
index 0000000..48c21cf
--- /dev/null
@@ -0,0 +1,266 @@
+/** @file\r
+  The common definition of IPsec Key Exchange (IKE).\r
+\r
+  Copyright (c) 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
+\r
+#ifndef _IKE_H_\r
+#define _IKE_H_\r
+\r
+#include <Library/UdpIoLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include "IpSecImpl.h"\r
+\r
+#define IKE_VERSION_MAJOR_MASK  0xf0\r
+#define IKE_VERSION_MINOR_MASK  0x0f\r
+\r
+#define IKE_MAJOR_VERSION(v)    (((v) & IKE_VERSION_MAJOR_MASK) >> 4)\r
+#define IKE_MINOR_VERSION(v)    ((v) & IKE_VERSION_MINOR_MASK)\r
+\r
+//\r
+// Protocol Value Use in IKEv1 and IKEv2\r
+//\r
+#define IPSEC_PROTO_ISAKMP    1\r
+#define IPSEC_PROTO_IPSEC_AH  2\r
+#define IPSEC_PROTO_IPSEC_ESP 3\r
+#define IPSEC_PROTO_IPCOMP    4 // For IKEv1 this value is reserved\r
+\r
+//\r
+//  For Algorithm search in support list.Last two types are for IKEv2 only.\r
+//\r
+#define IKE_ENCRYPT_TYPE      0\r
+#define IKE_AUTH_TYPE         1\r
+#define IKE_PRF_TYPE          2\r
+#define IKE_DH_TYPE           3\r
+\r
+//\r
+// Encryption Algorithm present in IKEv1 phasrs2 and IKEv2 transform payload (Transform Type 1)\r
+//\r
+#define IPSEC_ESP_DES_IV64            1\r
+#define IPSEC_ESP_DES                 2\r
+#define IPSEC_ESP_3DES                3\r
+#define IPSEC_ESP_RC5                 4\r
+#define IPSEC_ESP_IDEA                5\r
+#define IPSEC_ESP_CAST                6\r
+#define IPSEC_ESP_BLOWFISH            7\r
+#define IPSEC_ESP_3IDEA               8\r
+#define IPSEC_ESP_DES_IV32            9\r
+#define IPSEC_ESP_RC4                 10  // It's reserved in IKEv2 \r
+#define IPSEC_ESP_NULL                11\r
+#define IPSEC_ESP_AES                 12\r
+\r
+#define IKE_XCG_TYPE_NONE             0\r
+#define IKE_XCG_TYPE_BASE             1\r
+#define IKE_XCG_TYPE_IDENTITY_PROTECT 2\r
+#define IKE_XCG_TYPE_AUTH_ONLY        3\r
+#define IKE_XCG_TYPE_AGGR             4\r
+#define IKE_XCG_TYPE_INFO             5\r
+#define IKE_XCG_TYPE_QM               32\r
+#define IKE_XCG_TYPE_NGM              33\r
+#define IKE_XCG_TYPE_SA_INIT          34\r
+#define IKE_XCG_TYPE_AUTH             35\r
+#define IKE_XCG_TYPE_CREATE_CHILD_SA  36\r
+#define IKE_XCG_TYPE_INFO2            37\r
+\r
+#define IKE_LIFE_TYPE_SECONDS         1\r
+#define IKE_LIFE_TYPE_KILOBYTES       2\r
+\r
+//\r
+// Deafult IKE SA lifetime and CHILD SA lifetime\r
+//\r
+#define IKE_SA_DEFAULT_LIFETIME       1200\r
+#define CHILD_SA_DEFAULT_LIFETIME     3600\r
+\r
+//\r
+// Next payload type presented within Proposal payload\r
+//\r
+#define IKE_PROPOSAL_NEXT_PAYLOAD_MORE  2\r
+#define IKE_PROPOSAL_NEXT_PAYLOAD_NONE  0\r
+\r
+//\r
+// Next payload type presented within Transform payload\r
+//\r
+#define IKE_TRANSFORM_NEXT_PAYLOAD_MORE 3\r
+#define IKE_TRANSFORM_NEXT_PAYLOAD_NONE 0\r
+\r
+//
+// Max size of the SA attribute
+//
+#define MAX_SA_ATTRS_SIZE     48
+#define SA_ATTR_FORMAT_BIT    0x8000\r
+//\r
+// The definition for Information Message ID.\r
+//\r
+#define INFO_MID_SIGNATURE    SIGNATURE_32 ('I', 'N', 'F', 'M')\r
+\r
+//\r
+// Type for the IKE SESSION COMMON\r
+//\r
+typedef enum {\r
+  IkeSessionTypeIkeSa,\r
+  IkeSessionTypeChildSa,\r
+  IkeSessionTypeInfo,\r
+  IkeSessionTypeMax\r
+} IKE_SESSION_TYPE;\r
+\r
+//\r
+// The DH Group ID defined RFC3526 and RFC 2409\r
+//\r
+typedef enum {\r
+  OakleyGroupModp768  = 1,\r
+  OakleyGroupModp1024 = 2,\r
+  OakleyGroupGp155    = 3,  // Unsupported Now.\r
+  OakleyGroupGp185    = 4,  // Unsupported Now.\r
+  OakleyGroupModp1536 = 5,\r
+\r
+  OakleyGroupModp2048 = 14,\r
+  OakleyGroupModp3072 = 15,\r
+  OakleyGroupModp4096 = 16,\r
+  OakleyGroupModp6144 = 17,\r
+  OakleyGroupModp8192 = 18,\r
+  OakleyGroupMax\r
+} OAKLEY_GROUP_ID;\r
+\r
+//\r
+// IKE Header\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT64  InitiatorCookie;\r
+  UINT64  ResponderCookie;\r
+  UINT8   NextPayload;\r
+  UINT8   Version;\r
+  UINT8   ExchangeType;\r
+  UINT8   Flags;\r
+  UINT32  MessageId;\r
+  UINT32  Length;\r
+} IKE_HEADER;\r
+#pragma pack()\r
+\r
+typedef union {\r
+  UINT16  AttrLength;\r
+  UINT16  AttrValue;\r
+} IKE_SA_ATTR_UNION; \r
+\r
+//\r
+// SA Attribute present in Transform Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT16            AttrType;\r
+  IKE_SA_ATTR_UNION Attr;\r
+} IKE_SA_ATTRIBUTE;\r
+#pragma pack()\r
+\r
+//\r
+// Contains the IKE packet information. \r
+//\r
+typedef struct {\r
+  UINTN               RefCount;\r
+  BOOLEAN             IsHdrExt;\r
+  IKE_HEADER          *Header;\r
+  BOOLEAN             IsPayloadsBufExt;\r
+  UINT8               *PayloadsBuf; // The whole IkePakcet trimed the IKE header.\r
+  UINTN               PayloadTotalSize;\r
+  LIST_ENTRY          PayloadList;\r
+  EFI_IP_ADDRESS      RemotePeerIp;\r
+  BOOLEAN             IsEncoded;    // whether HTON is done when sending the packet\r
+  UINT32              Spi;          // For the Delete Information Exchange\r
+  BOOLEAN             IsDeleteInfo; // For the Delete Information Exchange\r
+  IPSEC_PRIVATE_DATA  *Private;     // For the Delete Information Exchange\r
+} IKE_PACKET;\r
+\r
+//\r
+// The generic structure to all kinds of IKE payloads.\r
+//\r
+typedef struct {\r
+  UINT32      Signature;\r
+  BOOLEAN     IsPayloadBufExt;\r
+  UINT8       PayloadType;\r
+  UINT8       *PayloadBuf;\r
+  UINTN       PayloadSize;\r
+  LIST_ENTRY  ByPacket;\r
+} IKE_PAYLOAD;\r
+\r
+//\r
+// Udp Service\r
+//\r
+typedef struct {\r
+  UINT32          Signature;\r
+  UINT8           IpVersion;\r
+  LIST_ENTRY      List;\r
+  LIST_ENTRY      *ListHead;\r
+  EFI_HANDLE      NicHandle;\r
+  EFI_HANDLE      ImageHandle;\r
+  UDP_IO          *Input;\r
+  UDP_IO          *Output;\r
+  EFI_IP_ADDRESS  DefaultAddress;\r
+  BOOLEAN         IsConfigured;\r
+} IKE_UDP_SERVICE;\r
+\r
+//\r
+// Each IKE session has its own Key sets for local peer and remote peer.\r
+//\r
+typedef struct {\r
+  EFI_IPSEC_ALGO_INFO LocalPeerInfo;\r
+  EFI_IPSEC_ALGO_INFO RemotePeerInfo;\r
+} SA_KEYMATS;\r
+\r
+//\r
+// Each algorithm has its own Id, Guid, BlockSize and KeyLength.\r
+// This struct contains these information for each algorithm. It is generic structure\r
+// for both encryption and authentication algorithm. \r
+// For authentication algorithm, the AlgSize means IcvSize. For encryption algorithm,\r
+// it means IvSize.\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8     AlgorithmId;       // Encryption or Authentication Id used by ESP/AH\r
+  EFI_GUID  *AlgGuid;\r
+  UINT8     AlgSize;     // IcvSize or IvSize\r
+  UINT8     BlockSize;\r
+  UINTN     KeyMateLen;\r
+} IKE_ALG_GUID_INFO;   // For IPsec Authentication and Encryption Algorithm.\r
+#pragma pack()\r
+\r
+//\r
+// Structure used to store the DH group\r
+//\r
+typedef struct {\r
+  UINT8 GroupId;\r
+  UINTN Size;\r
+  UINT8 *Modulus;\r
+  UINTN GroupGenerator;\r
+} MODP_GROUP;\r
+\r
+/**\r
+  This is prototype definition of general interface to phase the payloads\r
+  after/before the decode/encode.\r
+\r
+  @param[in]  SessionCommon    Point to the SessionCommon\r
+  @param[in]  PayloadBuf       Point to the buffer of Payload.\r
+  @param[in]  PayloadSize      The size of the PayloadBuf in bytes.\r
+  @param[in]  PayloadType      The type of Payload.\r
+\r
+**/\r
+typedef\r
+VOID\r
+(*IKE_ON_PAYLOAD_FROM_NET) (\r
+  IN UINT8    *SessionCommon,\r
+  IN UINT8    *PayloadBuf,\r
+  IN UINTN    PayloadSize,\r
+  IN UINT8    PayloadType\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/NetworkPkg/IpSecDxe/IkeCommon.c b/NetworkPkg/IpSecDxe/IkeCommon.c
new file mode 100644 (file)
index 0000000..7f56365
--- /dev/null
@@ -0,0 +1,255 @@
+/** @file\r
+  Common operation of the IKE\r
+  \r
+  Copyright (c) 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 "Ike.h"\r
+#include "IkeCommon.h"\r
+#include "IpSecConfigImpl.h"\r
+#include "IpSecDebug.h"\r
+\r
+//\r
+// Initial the SPI\r
+//\r
+UINT32            mNextSpi  = IKE_SPI_BASE;\r
+EFI_GUID          mZeroGuid = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };\r
+\r
+/**\r
+  Call Crypto Lib to generate a random value with eight-octet length.\r
+  \r
+  @return the 64 byte vaule.\r
+\r
+**/\r
+UINT64\r
+IkeGenerateCookie (\r
+  VOID\r
+  )\r
+{\r
+  UINT64     Cookie;\r
+  EFI_STATUS Status;\r
+\r
+  Status = IpSecCryptoIoGenerateRandomBytes ((UINT8 *)&Cookie, sizeof (UINT64));\r
+  if (EFI_ERROR (Status)) {\r
+    return 0;\r
+  } else {\r
+    return Cookie;\r
+  }\r
+}\r
+\r
+/**\r
+  Generate the random data for Nonce payload.\r
+\r
+  @param[in]  NonceSize      Size of the data in bytes.\r
+  \r
+  @return Buffer which contains the random data of the spcified size. \r
+\r
+**/\r
+UINT8 *\r
+IkeGenerateNonce (\r
+  IN UINTN              NonceSize\r
+  )\r
+{\r
+  UINT8                  *Nonce;\r
+  EFI_STATUS             Status;\r
+\r
+  Nonce = AllocateZeroPool (NonceSize);\r
+  if (Nonce == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Status = IpSecCryptoIoGenerateRandomBytes (Nonce, NonceSize);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Nonce);\r
+    return NULL;\r
+  } else {\r
+    return Nonce;\r
+  }\r
+}\r
+\r
+/**\r
+  Convert the IKE Header from Network order to Host order.\r
+\r
+  @param[in, out]  Header    The pointer of the IKE_HEADER.\r
+\r
+**/\r
+VOID\r
+IkeHdrNetToHost (\r
+  IN OUT IKE_HEADER *Header\r
+  )\r
+{\r
+  Header->InitiatorCookie = NTOHLL (Header->InitiatorCookie);\r
+  Header->ResponderCookie = NTOHLL (Header->ResponderCookie);\r
+  Header->MessageId       = NTOHL (Header->MessageId);\r
+  Header->Length          = NTOHL (Header->Length);\r
+}\r
+\r
+/**\r
+  Convert the IKE Header from Host order to Network order.\r
+\r
+  @param[in, out] Header     The pointer of the IKE_HEADER.\r
+\r
+**/\r
+VOID\r
+IkeHdrHostToNet (\r
+  IN OUT IKE_HEADER *Header\r
+  )\r
+{\r
+  Header->InitiatorCookie = HTONLL (Header->InitiatorCookie);\r
+  Header->ResponderCookie = HTONLL (Header->ResponderCookie);\r
+  Header->MessageId       = HTONL (Header->MessageId);\r
+  Header->Length          = HTONL (Header->Length);\r
+}\r
+\r
+/**\r
+  Allocate a buffer of IKE_PAYLOAD and set its Signature.\r
+\r
+  @return A buffer of IKE_PAYLOAD.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+IkePayloadAlloc (\r
+  VOID\r
+  )\r
+{\r
+  IKE_PAYLOAD *IkePayload;\r
+\r
+  IkePayload            = (IKE_PAYLOAD *) AllocateZeroPool (sizeof (IKE_PAYLOAD));\r
+  if (IkePayload == NULL) {\r
+    return NULL;\r
+  }\r
+  \r
+  IkePayload->Signature = IKE_PAYLOAD_SIGNATURE;\r
+\r
+  return IkePayload;\r
+}\r
+\r
+/**\r
+  Free a specified IKE_PAYLOAD buffer.\r
+\r
+  @param[in]  IkePayload   Pointer of IKE_PAYLOAD to be freed.\r
+\r
+**/\r
+VOID\r
+IkePayloadFree (\r
+  IN IKE_PAYLOAD *IkePayload\r
+  )\r
+{\r
+  if (IkePayload == NULL) {\r
+    return;\r
+  }\r
+  //\r
+  // If this IkePayload is not referred by others, free it.\r
+  //\r
+  if (!IkePayload->IsPayloadBufExt && (IkePayload->PayloadBuf != NULL)) {\r
+    FreePool (IkePayload->PayloadBuf);\r
+  }\r
+\r
+  FreePool (IkePayload);\r
+}\r
+\r
+/**\r
+  Generate an new SPI.\r
+\r
+  @return a SPI in 4 bytes.\r
+\r
+**/\r
+UINT32\r
+IkeGenerateSpi (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // TODO: should generate SPI randomly to avoid security issue\r
+  //\r
+  return mNextSpi++;\r
+}\r
+\r
+/**\r
+  Generate a random data for IV\r
+\r
+  @param[in]  IvBuffer  The pointer of the IV buffer.\r
+  @param[in]  IvSize    The IV size.\r
+\r
+  @retval     EFI_SUCCESS  Create a random data for IV.\r
+  @retval     otherwise    Failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IkeGenerateIv (\r
+  IN UINT8                           *IvBuffer,\r
+  IN UINTN                           IvSize\r
+  )\r
+{\r
+  return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);\r
+}\r
+\r
+\r
+/**
+  Find SPD entry by a specified SPD selector.
+
+  @param[in] SpdSel       Point to SPD Selector to be searched for.\r
+
+  @retval Point to SPD Entry if the SPD entry found.\r
+  @retval NULL if not found.
+
+**/
+IPSEC_SPD_ENTRY *
+IkeSearchSpdEntry (\r
+  IN EFI_IPSEC_SPD_SELECTOR             *SpdSel
+  )
+{
+  IPSEC_SPD_ENTRY *SpdEntry;
+  LIST_ENTRY      *SpdList;
+  LIST_ENTRY      *Entry;
+
+  SpdList = &mConfigData[IPsecConfigDataTypeSpd];
+
+  NET_LIST_FOR_EACH (Entry, SpdList) {
+    SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
+
+    //
+    // Find the required SPD entry\r
+    //
+    if (CompareSpdSelector (
+          (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
+          (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
+          )) {
+      return SpdEntry;
+    }
+
+  }
+
+  return NULL;
+}\r
+\r
+/**\r
+  Get the IKE Version from the IKE_SA_SESSION.\r
+\r
+  @param[in]  Session  Pointer of the IKE_SA_SESSION.\r
+\r
+**/\r
+UINT8\r
+IkeGetVersionFromSession (\r
+  IN UINT8    *Session\r
+  )\r
+{\r
+  if (*(UINT32 *) Session == IKEV2_SA_SESSION_SIGNATURE) {\r
+    return ((IKEV2_SA_SESSION *) Session)->SessionCommon.IkeVer;\r
+  } else {\r
+    //\r
+    // Add IKEv1 support here.\r
+    //\r
+    return 0;\r
+  }\r
+}\r
+\r
diff --git a/NetworkPkg/IpSecDxe/IkeCommon.h b/NetworkPkg/IpSecDxe/IkeCommon.h
new file mode 100644 (file)
index 0000000..6041675
--- /dev/null
@@ -0,0 +1,191 @@
+/** @file\r
+  Common operation of the IKE.\r
+\r
+  Copyright (c) 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
+#ifndef _IKE_COMMON_H_\r
+#define _IKE_COMMON_H_\r
+\r
+#include <Protocol/Udp4.h>\r
+#include <Protocol/Udp6.h>\r
+#include <Protocol/Ip4Config.h>\r
\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UdpIoLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+\r
+#include "Ikev2/Ikev2.h"\r
+#include "IpSecImpl.h"\r
+#include "IkePacket.h"\r
+#include "IpSecCryptIo.h"\r
+\r
+\r
+#define IKE_DEFAULT_PORT              500\r
+#define IKE_DEFAULT_TIMEOUT_INTERVAL  10000 // 10s\r
+#define IKE_NONCE_SIZE                16\r
+#define IKE_MAX_RETRY                 4\r
+#define IKE_SPI_BASE                  0x10000\r
+#define PRF_HMAC_SHA1_GUID            &gEfiCryptAlgorithmSha1Guid\r
+#define IKE_PAYLOAD_SIGNATURE         SIGNATURE_32('I','K','E','P')\r
+#define IKE_PAYLOAD_BY_PACKET(a)      CR(a,IKE_PAYLOAD,ByPacket,IKE_PAYLOAD_SIGNATURE)\r
+\r
+\r
+#define IKE_PACKET_APPEND_PAYLOAD(IkePacket,IkePayload)                 \\r
+  do {                                                                  \\r
+    InsertTailList(&(IkePacket)->PayloadList, &(IkePayload)->ByPacket); \\r
+  } while (0)\r
+\r
+#define IKE_PACKET_REMOVE_PAYLOAD(IkePacket,IkePayload)                 \\r
+  do {                                                                  \\r
+    RemoveEntryList(&(IkePayload)->ByPacket);                           \\r
+  } while (0)\r
+\r
+#define IKE_PACKET_END_PAYLOAD(IkePacket, Node)                        \\r
+  Node = GetFirstNode (&(IkePacket)->PayloadList);                      \\r
+  while (!IsNodeAtEnd (&(IkePacket)->PayloadList, Node)) {             \\r
+    Node = GetNextNode (&(IkePacket)->PayloadList, Node);              \\r
+  }                                                                     \\r
+\r
+/**\r
+  Call Crypto Lib to generate a random value with eight-octet length.\r
+  \r
+  @return the 64 byte vaule.\r
+\r
+**/\r
+UINT64\r
+IkeGenerateCookie (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Generate the random data for Nonce payload.\r
+\r
+  @param[in]  NonceSize      Size of the data in bytes.\r
+  \r
+  @return Buffer which contains the random data of the spcified size. \r
+\r
+**/\r
+UINT8 *\r
+IkeGenerateNonce (\r
+  IN UINTN              NonceSize\r
+  );\r
+\r
+/**\r
+  Convert the IKE Header from Network order to Host order.\r
+\r
+  @param[in, out]  Header    The pointer of the IKE_HEADER.\r
+\r
+**/\r
+VOID\r
+IkeHdrNetToHost (\r
+  IN OUT IKE_HEADER *Header\r
+  );\r
+\r
+\r
+/**\r
+  Convert the IKE Header from Host order to Network order.\r
+\r
+  @param[in, out] Header     The pointer of the IKE_HEADER.\r
+\r
+**/\r
+VOID\r
+IkeHdrHostToNet (\r
+  IN OUT IKE_HEADER *Header\r
+  );\r
+\r
+/**\r
+  Allocate a buffer of IKE_PAYLOAD and set its Signature.\r
+\r
+  @return A buffer of IKE_PAYLOAD.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+IkePayloadAlloc (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Free a specified IKE_PAYLOAD buffer.\r
+\r
+  @param[in]  IkePayload   Pointer of IKE_PAYLOAD to be freed.\r
+\r
+**/\r
+VOID\r
+IkePayloadFree (\r
+  IN IKE_PAYLOAD *IkePayload\r
+  );\r
+\r
+/**\r
+  Generate an unused SPI\r
+\r
+  @return a SPI in 4 bytes.\r
+\r
+**/\r
+UINT32\r
+IkeGenerateSpi (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Generate a random data for IV\r
+\r
+  @param[in]  IvBuffer  The pointer of the IV buffer.\r
+  @param[in]  IvSize    The IV size.\r
+\r
+  @retval     EFI_SUCCESS  Create a random data for IV.\r
+  @retval     otherwise    Failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IkeGenerateIv (\r
+  IN UINT8                           *IvBuffer,\r
+  IN UINTN                           IvSize\r
+  );\r
+\r
+/**\r
+  Get the IKE Version from the IKE_SA_SESSION.\r
+\r
+  @param[in]  Session  Pointer of the IKE_SA_SESSION.\r
+\r
+**/\r
+UINT8\r
+IkeGetVersionFromSession (\r
+  IN UINT8                    *Session\r
+  );\r
+\r
+/**
+  Find SPD entry by a specified SPD selector.
+
+  @param[in] SpdSel       Point to SPD Selector to be searched for.\r
+
+  @retval Point to Spd Entry if the SPD entry found.
+  @retval NULL if not found.
+
+**/
+IPSEC_SPD_ENTRY *
+IkeSearchSpdEntry (\r
+  IN EFI_IPSEC_SPD_SELECTOR             *SpdSel
+  );\r
+\r
+extern EFI_GUID               mZeroGuid;\r
+extern MODP_GROUP             OakleyModpGroup[];\r
+extern IKE_ALG_GUID_INFO      mIPsecEncrAlgInfo[];\r
+extern IKE_ALG_GUID_INFO      mIPsecAuthAlgInfo[];\r
+\r
+#endif\r
+\r
diff --git a/NetworkPkg/IpSecDxe/IkePacket.c b/NetworkPkg/IpSecDxe/IkePacket.c
new file mode 100644 (file)
index 0000000..fa29d54
--- /dev/null
@@ -0,0 +1,257 @@
+/** @file\r
+  IKE Packet related operation.\r
+\r
+  Copyright (c) 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 "IpSecDebug.h"\r
+#include "Ikev2/Utility.h"\r
+\r
+/**\r
+  Allocate a buffer for the IKE_PACKET and intitalize its Header and payloadlist.\r
+\r
+  @return The pointer of the IKE_PACKET.\r
+\r
+**/\r
+IKE_PACKET *\r
+IkePacketAlloc (\r
+  VOID\r
+  )\r
+{\r
+  IKE_PACKET  *IkePacket;\r
+\r
+  IkePacket = (IKE_PACKET *) AllocateZeroPool (sizeof (IKE_PACKET));\r
+  if (IkePacket == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  IkePacket->RefCount = 1;\r
+  InitializeListHead (&IkePacket->PayloadList);\r
+  \r
+  IkePacket->Header = (IKE_HEADER *) AllocateZeroPool (sizeof (IKE_HEADER));\r
+  if (IkePacket->Header == NULL) {\r
+    FreePool (IkePacket);\r
+    return NULL;\r
+  }\r
+  return IkePacket;\r
+}\r
+\r
+/**\r
+  Free the IkePacket by the specified IKE_PACKET pointer.\r
+\r
+  @param[in]  IkePacket  The pointer of the IKE_PACKET to be freed.\r
+\r
+**/\r
+VOID\r
+IkePacketFree (\r
+  IN IKE_PACKET *IkePacket\r
+  )\r
+{\r
+  LIST_ENTRY  *Entry;\r
+  IKE_PAYLOAD *IkePayload;\r
+\r
+  if (IkePacket == NULL) {\r
+    return;\r
+  }\r
+  //\r
+  // Check if the Packet is referred by others.\r
+  //\r
+  if (--IkePacket->RefCount == 0) {\r
+    //\r
+    // Free IkePacket header\r
+    //\r
+    if (!IkePacket->IsHdrExt && IkePacket->Header != NULL) {\r
+      FreePool (IkePacket->Header);\r
+    }\r
+    //\r
+    // Free the PayloadsBuff\r
+    //\r
+    if (!IkePacket->IsPayloadsBufExt && IkePacket->PayloadsBuf != NULL) {\r
+      FreePool (IkePacket->PayloadsBuf);\r
+    }\r
+    //\r
+    // Iterate payloadlist and free all payloads\r
+    //\r
+    for (Entry = (IkePacket)->PayloadList.ForwardLink; Entry != &(IkePacket)->PayloadList;) {\r
+      IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+      Entry       = Entry->ForwardLink;\r
+\r
+      IkePayloadFree (IkePayload);\r
+    }\r
+\r
+    FreePool (IkePacket);\r
+  }\r
+}\r
+\r
+/**\r
+  Callback funtion of NetbufFromExt()\r
+  \r
+  @param[in]  Arg  The data passed from the NetBufFromExe(). \r
+\r
+**/\r
+VOID\r
+IkePacketNetbufFree (\r
+  IN VOID  *Arg\r
+  )\r
+{\r
+  //\r
+  // TODO: add something if need.\r
+  //\r
+}\r
+\r
+/**\r
+  Copy the NetBuf into a IKE_PACKET sturcture.\r
+  \r
+  Create a IKE_PACKET and fill the received IKE header into the header of IKE_PACKET \r
+  and copy the recieved packet without IKE HEADER to the PayloadBuf of IKE_PACKET.\r
+\r
+  @param[in]  Netbuf      The pointer of the Netbuf which contains the whole received \r
+                          IKE packet.\r
+\r
+  @return The pointer of the IKE_PACKET which contains the received packet.\r
+\r
+**/\r
+IKE_PACKET *\r
+IkePacketFromNetbuf (\r
+  IN NET_BUF *Netbuf\r
+  )\r
+{\r
+  IKE_PACKET  *IkePacket;\r
+\r
+  IkePacket = NULL;\r
+  if (Netbuf->TotalSize < sizeof (IKE_HEADER)) {\r
+    goto Error;\r
+  }\r
+\r
+  IkePacket = IkePacketAlloc ();\r
+  if (IkePacket == NULL) {\r
+    return NULL;\r
+  }\r
+  //\r
+  // Copy the IKE header from Netbuf to IkePacket->Hdr\r
+  //\r
+  NetbufCopy (Netbuf, 0, sizeof (IKE_HEADER), (UINT8 *) IkePacket->Header);\r
+  //\r
+  // Net order to host order\r
+  //\r
+  IkeHdrNetToHost (IkePacket->Header);\r
+  if (IkePacket->Header->Length < Netbuf->TotalSize) {\r
+    goto Error;\r
+  }\r
+\r
+  IkePacket->PayloadTotalSize = IkePacket->Header->Length - sizeof (IKE_HEADER);\r
+  IkePacket->PayloadsBuf      = (UINT8 *) AllocateZeroPool (IkePacket->PayloadTotalSize);\r
+\r
+  if (IkePacket->PayloadsBuf == NULL) {\r
+    goto Error;\r
+  }\r
+  //\r
+  // Copy the IKE packet without the header into the IkePacket->PayloadsBuf.\r
+  //\r
+  NetbufCopy (Netbuf, sizeof (IKE_HEADER), (UINT32) IkePacket->PayloadTotalSize, IkePacket->PayloadsBuf);\r
+  return IkePacket;\r
+\r
+Error:\r
+  if (IkePacket != NULL) {\r
+    IkePacketFree (IkePacket);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Convert the format from IKE_PACKET to NetBuf.\r
+\r
+  @param[in]  SessionCommon  Pointer of related IKE_COMMON_SESSION\r
+  @param[in]  IkePacket      Pointer of IKE_PACKET to be copy to NetBuf\r
+  @param[in]  IkeType        The IKE type to pointer the packet is for which IKE \r
+                             phase. Now it supports IKE_SA_TYPE, IKE_CHILDSA_TYPE, \r
+                             IKE_INFO_TYPE.\r
+\r
+  @return a pointer of Netbuff which contains the IKE_PACKE in network order.\r
+  \r
+**/\r
+NET_BUF *\r
+IkeNetbufFromPacket (\r
+  IN UINT8               *SessionCommon,\r
+  IN IKE_PACKET          *IkePacket,\r
+  IN UINTN               IkeType\r
+  )\r
+{\r
+  NET_BUF       *Netbuf;\r
+  NET_FRAGMENT  *Fragments;\r
+  UINTN         Index;\r
+  UINTN         NumPayloads;\r
+  LIST_ENTRY    *PacketEntry;\r
+  LIST_ENTRY    *Entry;\r
+  IKE_PAYLOAD   *IkePayload;\r
+\r
+  if (!IkePacket->IsEncoded) {\r
+    IkePacket->IsEncoded = TRUE;\r
+    //\r
+    // Convert Host order to Network order for IKE_PACKET header and payloads\r
+    // Encryption payloads if needed\r
+    //\r
+    if (((IKEV2_SESSION_COMMON *) SessionCommon)->IkeVer == 2) {\r
+      Ikev2EncodePacket ((IKEV2_SESSION_COMMON *) SessionCommon, IkePacket, IkeType);\r
+    } else {\r
+      //\r
+      //If IKEv1 support, check it here.\r
+      //\r
+      return NULL;\r
+    }\r
+  }\r
+\r
+  NumPayloads = 0;\r
+  //\r
+  // Get the number of the payloads\r
+  //\r
+  NET_LIST_FOR_EACH (PacketEntry, &(IkePacket)->PayloadList) {\r
+  \r
+    NumPayloads++;\r
+  }\r
+  //\r
+  // Allocate the Framgents according to the numbers of the IkePayload\r
+  //\r
+  Fragments = (NET_FRAGMENT *) AllocateZeroPool ((1 + NumPayloads) * sizeof (NET_FRAGMENT));\r
+  if (Fragments == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Fragments[0].Bulk = (UINT8 *) IkePacket->Header;\r
+  Fragments[0].Len  = sizeof (IKE_HEADER);\r
+  Index             = 0;\r
+\r
+  //\r
+  // Set payloads to the Framgments.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {\r
+    IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);\r
+\r
+    Fragments[Index + 1].Bulk = IkePayload->PayloadBuf;\r
+    Fragments[Index + 1].Len  = (UINT32) IkePayload->PayloadSize;\r
+    Index++;\r
+  }\r
+\r
+  Netbuf = NetbufFromExt (\r
+             Fragments,\r
+             (UINT32) (NumPayloads + 1),\r
+             0,\r
+             0,\r
+             IkePacketNetbufFree,\r
+             NULL\r
+             );\r
+  \r
+  FreePool (Fragments);\r
+  return Netbuf;\r
+}\r
+\r
diff --git a/NetworkPkg/IpSecDxe/IkePacket.h b/NetworkPkg/IpSecDxe/IkePacket.h
new file mode 100644 (file)
index 0000000..053d659
--- /dev/null
@@ -0,0 +1,82 @@
+/** @file\r
+  IKE Packet related definitions and function declarations.\r
+\r
+  Copyright (c) 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
+#ifndef _IKE_V1_PACKET_H_\r
+#define _IKE_V1_PACKET_H_\r
+\r
+#include "Ike.h"\r
+\r
+#define IKE_PACKET_REF(p) ((p)->RefCount++)\r
+\r
+/**\r
+  Allocate a buffer for the IKE_PACKET and intitalize its Header and payloadlist.\r
+\r
+  @return The pointer of the IKE_PACKET.\r
+\r
+**/\r
+IKE_PACKET *\r
+IkePacketAlloc (\r
+  VOID\r
+  );\r
+\r
+\r
+/**\r
+  Free the IkePacket by the specified IKE_PACKET pointer.\r
+\r
+  @param[in]  IkePacket  The pointer of the IKE_PACKET to be freed.\r
+\r
+**/\r
+VOID\r
+IkePacketFree (\r
+  IN IKE_PACKET *IkePacket\r
+  );\r
+\r
+\r
+/**\r
+  Copy the NetBuf into a IKE_PACKET sturcture.\r
+  \r
+  Create a IKE_PACKET and fill the received IKE header into the header of IKE_PACKET \r
+  and copy the recieved packet without IKE HEADER to the PayloadBuf of IKE_PACKET.\r
+\r
+  @param[in]  Netbuf      The pointer of the Netbuf which contains the whole received \r
+                          IKE packet.\r
+\r
+  @return The pointer of the IKE_PACKET which contains the received packet.\r
+\r
+**/\r
+IKE_PACKET *\r
+IkePacketFromNetbuf (\r
+  IN NET_BUF *Netbuf\r
+  );\r
+\r
+/**\r
+  Convert the format from IKE_PACKET to NetBuf.\r
+\r
+  @param[in]  SessionCommon  Pointer of related IKE_COMMON_SESSION\r
+  @param[in]  IkePacket      Pointer of IKE_PACKET to be copy to NetBuf\r
+  @param[in]  IkeType        The IKE type to pointer the packet is for which IKE \r
+                             phase. Now it supports IKE_SA_TYPE, IKE_CHILDSA_TYPE, \r
+                             IKE_INFO_TYPE.\r
+\r
+  @return A pointer of Netbuff which contains the contents of the IKE_PACKE in network order.\r
+**/\r
+NET_BUF *\r
+IkeNetbufFromPacket (\r
+  IN UINT8               *SessionCommon,\r
+  IN IKE_PACKET          *IkePacket,\r
+  IN UINTN               IkeType\r
+  );\r
+\r
+#endif\r
diff --git a/NetworkPkg/IpSecDxe/IkeService.c b/NetworkPkg/IpSecDxe/IkeService.c
new file mode 100644 (file)
index 0000000..0550534
--- /dev/null
@@ -0,0 +1,769 @@
+/** @file\r
+  Provide IPsec Key Exchange (IKE) service general interfaces.\r
+  \r
+  Copyright (c) 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 "IkeService.h"\r
+#include "IpSecConfigImpl.h"\r
+#include "Ikev2/Utility.h"\r
+\r
+IKE_EXCHANGE_INTERFACE  *mIkeExchange[] = {\r
+  &mIkev1Exchange,\r
+  &mIkev2Exchange\r
+};\r
+\r
+EFI_UDP4_CONFIG_DATA    mUdp4Conf = {\r
+  FALSE,\r
+  FALSE,\r
+  FALSE,\r
+  TRUE,\r
+  //\r
+  // IO parameters\r
+  //\r
+  0,\r
+  64,\r
+  FALSE,\r
+  0,\r
+  1000000,\r
+  FALSE,\r
+  {0,0,0,0},\r
+  {0,0,0,0},\r
+  IKE_DEFAULT_PORT,\r
+  {0,0,0,0},\r
+  0\r
+};\r
+\r
+EFI_UDP6_CONFIG_DATA    mUdp6Conf = {\r
+  FALSE,\r
+  FALSE,\r
+  TRUE,\r
+  //\r
+  // IO parameters\r
+  //\r
+  0,\r
+  128,\r
+  0,\r
+  1000000,\r
+  //Access Point\r
+  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\r
+  IKE_DEFAULT_PORT,\r
+  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\r
+  0\r
+};\r
+\r
+/**\r
+  Check if the NIC handle is binded to a Udp service.\r
+\r
+  @param[in]  Private    Pointer of IPSEC_PRIVATE_DATA.\r
+  @param[in]  NicHandle  The Handle of the NIC card.\r
+  @param[in]  IpVersion  The version of the IP stack.\r
+\r
+  @return a pointer of IKE_UDP_SERVICE.\r
+\r
+**/\r
+IKE_UDP_SERVICE *\r
+IkeLookupUdp (\r
+  IN IPSEC_PRIVATE_DATA     *Private,\r
+  IN EFI_HANDLE             Handle,\r
+  IN UINT8                  IpVersion\r
+  )\r
+{\r
+  LIST_ENTRY      *Head;\r
+  LIST_ENTRY      *Entry;\r
+  LIST_ENTRY      *Next;\r
+  IKE_UDP_SERVICE *Udp;\r
+\r
+  Udp   = NULL;\r
+  Head  = (IpVersion == IP_VERSION_4) ? &Private->Udp4List : &Private->Udp6List;\r
+\r
+  NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
+\r
+    Udp = IPSEC_UDP_SERVICE_FROM_LIST (Entry);\r
+    //\r
+    // Find the right udp service which installed on the appointed NIC handle.\r
+    //\r
+    if (Handle == Udp->NicHandle) {\r
+      break;\r
+    } else {\r
+      Udp = NULL;\r
+    }\r
+  }\r
+\r
+  return Udp;\r
+}\r
+\r
+/**\r
+  Configure a UDPIO's UDP4 instance.\r
+  \r
+  This fuction is called by the UdpIoCreateIo() to configures a \r
+  UDP4 instance.\r
+    \r
+  @param[in] UdpIo         The UDP_IO to be configured.\r
+  @param[in] Context       User-defined data when calling UdpIoCreateIo().\r
+  \r
+  @retval EFI_SUCCESS      The configuration succeeded.\r
+  @retval Others           The UDP4 instance fails to configure.\r
+\r
+**/\r
+EFI_STATUS\r
+IkeConfigUdp4 (\r
+  IN UDP_IO                 *UdpIo,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  EFI_UDP4_CONFIG_DATA  Udp4Cfg;\r
+  EFI_UDP4_PROTOCOL     *Udp4;\r
+\r
+  ZeroMem (&Udp4Cfg, sizeof (EFI_UDP4_CONFIG_DATA));\r
+\r
+  Udp4 = UdpIo->Protocol.Udp4;\r
+  CopyMem (\r
+    &Udp4Cfg,\r
+    &mUdp4Conf,\r
+    sizeof (EFI_UDP4_CONFIG_DATA)\r
+    );\r
+\r
+  if (Context != NULL) {\r
+    //\r
+    // Configure udp4 io with local default address.\r
+    //\r
+    Udp4Cfg.UseDefaultAddress = TRUE;\r
+  }\r
+\r
+  return Udp4->Configure (Udp4, &Udp4Cfg);\r
+}\r
+\r
+/**\r
+  Configure a UDPIO's UDP6 instance.\r
+  \r
+  This fuction is called by the UdpIoCreateIo()to configure a \r
+  UDP6 instance.\r
+    \r
+  @param[in] UdpIo         The UDP_IO to be configured.\r
+  @param[in] Context       User-defined data when calling UdpIoCreateIo().\r
+  \r
+  @retval EFI_SUCCESS      The configuration succeeded.\r
+  @retval Others           The configuration fails.\r
+\r
+**/\r
+EFI_STATUS\r
+IkeConfigUdp6 (\r
+  IN UDP_IO                 *UdpIo,\r
+  IN VOID                   *Context\r
+  )\r
+{\r
+  EFI_UDP6_PROTOCOL     *Udp6;\r
+  EFI_UDP6_CONFIG_DATA  Udp6Cfg;\r
+\r
+  ZeroMem (&Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));\r
+\r
+  Udp6 = UdpIo->Protocol.Udp6;\r
+  CopyMem (\r
+    &Udp6Cfg,\r
+    &mUdp6Conf,\r
+    sizeof (EFI_UDP6_CONFIG_DATA)\r
+    );\r
+\r
+  if (Context != NULL) {\r
+    //\r
+    // Configure instance with a destination address to start source address\r
+    // selection, and then get the configure data from the mode data to store\r
+    // the source address.\r
+    //\r
+    CopyMem (\r
+      &Udp6Cfg.RemoteAddress,\r
+      Context,\r
+      sizeof (EFI_IPv6_ADDRESS)\r
+      );\r
+  }\r
+\r
+  return Udp6->Configure (Udp6, &Udp6Cfg);\r
+}\r
+\r
+/**\r
+  Open and configure the related output UDPIO for IKE packet sending.\r
+  \r
+  If the UdpService is not configured, this fuction calls UdpIoCreatIo() to \r
+  create UDPIO to bind this UdpService for IKE packet sending. If the UdpService\r
+  has already been configured, then return.\r
+  \r
+  @param[in] UdpService     The UDP_IO to be configured.\r
+  @param[in] RemoteIp       User-defined data when calling UdpIoCreateIo().\r
+  \r
+  @retval EFI_SUCCESS      The configuration is successful.\r
+  @retval Others           The configuration fails.\r
+\r
+**/\r
+EFI_STATUS\r
+IkeOpenOutputUdp (\r
+  IN IKE_UDP_SERVICE           *UdpService,\r
+  IN EFI_IP_ADDRESS            *RemoteIp\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_IP4_CONFIG_PROTOCOL *Ip4Cfg;\r
+  EFI_IP4_IPCONFIG_DATA   *Ip4CfgData;\r
+  UINTN                   BufSize;\r
+  EFI_IP6_MODE_DATA       Ip6ModeData;\r
+  EFI_UDP6_PROTOCOL       *Udp6;\r
+\r
+  Status      = EFI_SUCCESS;\r
+  Ip4CfgData  = NULL;\r
+  BufSize     = 0;\r
+\r
+  //\r
+  // Check whether the input and output udp io are both configured.\r
+  //\r
+  if (UdpService->IsConfigured) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (UdpService->IpVersion == UDP_IO_UDP4_VERSION) {\r
+    //\r
+    // Handle ip4config protocol to get local default address.\r
+    //\r
+    Status = gBS->HandleProtocol (\r
+                    UdpService->NicHandle,\r
+                    &gEfiIp4ConfigProtocolGuid,\r
+                    (VOID **) &Ip4Cfg\r
+                    );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Status = Ip4Cfg->GetData (Ip4Cfg, &BufSize, NULL);\r
+\r
+    if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Ip4CfgData = AllocateZeroPool (BufSize);\r
+\r
+    if (Ip4CfgData == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Status = Ip4Cfg->GetData (Ip4Cfg, &BufSize, Ip4CfgData);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    CopyMem (\r
+      &UdpService->DefaultAddress.v4,\r
+      &Ip4CfgData->StationAddress,\r
+      sizeof (EFI_IPv4_ADDRESS)\r
+      );\r
+\r
+    //\r
+    // Create udp4 io for output with local default address.\r
+    //\r
+    UdpService->Output = UdpIoCreateIo (\r
+                           UdpService->NicHandle,\r
+                           UdpService->ImageHandle,\r
+                           IkeConfigUdp4,\r
+                           UDP_IO_UDP4_VERSION,\r
+                           &UdpService->DefaultAddress\r
+                           );\r
+\r
+    if (UdpService->Output == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+  } else {\r
+    //\r
+    // Create udp6 io for output with remote address.\r
+    //\r
+    UdpService->Output = UdpIoCreateIo (\r
+                           UdpService->NicHandle,\r
+                           UdpService->ImageHandle,\r
+                           IkeConfigUdp6,\r
+                           UDP_IO_UDP6_VERSION,\r
+                           RemoteIp\r
+                           );\r
+\r
+    if (UdpService->Output == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_EXIT;\r
+    }\r
+    //\r
+    // Get ip6 mode data to get the result of source address selection.\r
+    //\r
+    ZeroMem (&Ip6ModeData, sizeof (EFI_IP6_MODE_DATA));\r
+\r
+    Udp6    = UdpService->Output->Protocol.Udp6;\r
+    Status  = Udp6->GetModeData (Udp6, NULL, &Ip6ModeData, NULL, NULL);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      UdpIoFreeIo (UdpService->Output);\r
+      goto ON_EXIT;\r
+    }\r
+    //\r
+    // Reconfigure udp6 io without remote address.\r
+    //\r
+    Udp6->Configure (Udp6, NULL);\r
+    Status = IkeConfigUdp6 (UdpService->Output, NULL);\r
+\r
+    //\r
+    // Record the selected source address for ipsec process later.\r
+    //\r
+    CopyMem (\r
+      &UdpService->DefaultAddress.v6,\r
+      &Ip6ModeData.ConfigData.StationAddress,\r
+      sizeof (EFI_IPv6_ADDRESS)\r
+      );\r
+  }\r
+\r
+  UdpService->IsConfigured = TRUE;\r
+\r
+ON_EXIT:\r
+  if (Ip4CfgData != NULL) {\r
+    FreePool (Ip4CfgData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Open and configure a UDPIO of Udp4 for IKE packet receiving.\r
+  \r
+  This function is called at the IPsecDriverBinding start. IPsec create a UDP4 and \r
+  UDP4 IO for each NIC handle.\r
+  \r
+  @param[in] Private        Point to IPSEC_PRIVATE_DATA\r
+  @param[in] Controller     Handler for NIC card.\r
+  \r
+  @retval EFI_SUCCESS             The Operation is successful.\r
+  @retval EFI_OUT_OF_RESOURCE     The required system resource can't be allocated.\r
+  \r
+**/\r
+EFI_STATUS\r
+IkeOpenInputUdp4 (\r
+  IN IPSEC_PRIVATE_DATA           *Private,\r
+  IN EFI_HANDLE                   Controller\r
+  )\r
+{\r
+  IKE_UDP_SERVICE *Udp4Srv;\r
+\r
+  //\r
+  // Check whether udp4 io of the controller has already been opened.\r
+  //\r
+  Udp4Srv = IkeLookupUdp (Private, Controller, IP_VERSION_4);\r
+\r
+  if (Udp4Srv != NULL) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  Udp4Srv = AllocateZeroPool (sizeof (IKE_UDP_SERVICE));\r
+\r
+  if (Udp4Srv == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Create udp4 io for iutput.\r
+  //\r
+  Udp4Srv->Input = UdpIoCreateIo (\r
+                     Controller,\r
+                     Private->ImageHandle,\r
+                     IkeConfigUdp4,\r
+                     UDP_IO_UDP4_VERSION,\r
+                     NULL\r
+                     );\r
+\r
+  if (Udp4Srv->Input == NULL) {\r
+    FreePool (Udp4Srv);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Udp4Srv->NicHandle    = Controller;\r
+  Udp4Srv->ImageHandle  = Private->ImageHandle;\r
+  Udp4Srv->ListHead     = &(Private->Udp4List);\r
+  Udp4Srv->IpVersion    = UDP_IO_UDP4_VERSION;\r
+  Udp4Srv->IsConfigured = FALSE;\r
+\r
+  ZeroMem (&Udp4Srv->DefaultAddress, sizeof (EFI_IP_ADDRESS));\r
+\r
+  //\r
+  // Insert the udp4 io into the list and increase the count.\r
+  //\r
+  InsertTailList (&Private->Udp4List, &Udp4Srv->List);\r
+\r
+  Private->Udp4Num++;\r
+\r
+  UdpIoRecvDatagram (Udp4Srv->Input, IkeDispatch, Udp4Srv, 0);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Open and configure a UDPIO of Udp6 for IKE packet receiving.\r
+  \r
+  This function is called at the IPsecDriverBinding start. IPsec create a UDP6 and UDP6\r
+  IO for each NIC handle.\r
+  \r
+  @param[in] Private        Point to IPSEC_PRIVATE_DATA\r
+  @param[in] Controller     Handler for NIC card.\r
+  \r
+  @retval EFI_SUCCESS             The Operation is successful.\r
+  @retval EFI_OUT_OF_RESOURCE     The required system resource can't be allocated.\r
+  \r
+**/\r
+EFI_STATUS\r
+IkeOpenInputUdp6 (\r
+  IN IPSEC_PRIVATE_DATA           *Private,\r
+  IN EFI_HANDLE                   Controller\r
+  )\r
+{\r
+  IKE_UDP_SERVICE *Udp6Srv;\r
+\r
+  Udp6Srv = IkeLookupUdp (Private, Controller, IP_VERSION_6);\r
+\r
+  if (Udp6Srv != NULL) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  Udp6Srv = AllocateZeroPool (sizeof (IKE_UDP_SERVICE));\r
+\r
+  if (Udp6Srv == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Create udp6 io for input.\r
+  //\r
+  Udp6Srv->Input = UdpIoCreateIo (\r
+                     Controller,\r
+                     Private->ImageHandle,\r
+                     IkeConfigUdp6,\r
+                     UDP_IO_UDP6_VERSION,\r
+                     NULL\r
+                     );\r
+\r
+  if (Udp6Srv->Input == NULL) {\r
+    FreePool (Udp6Srv);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Udp6Srv->NicHandle    = Controller;\r
+  Udp6Srv->ImageHandle  = Private->ImageHandle;\r
+  Udp6Srv->ListHead     = &(Private->Udp6List);\r
+  Udp6Srv->IpVersion    = UDP_IO_UDP6_VERSION;\r
+  Udp6Srv->IsConfigured = FALSE;\r
+\r
+  ZeroMem (&Udp6Srv->DefaultAddress, sizeof (EFI_IP_ADDRESS));\r
+\r
+  //\r
+  // Insert the udp6 io into the list and increase the count.\r
+  //\r
+  InsertTailList (&Private->Udp6List, &Udp6Srv->List);\r
+\r
+  Private->Udp6Num++;\r
+\r
+  UdpIoRecvDatagram (Udp6Srv->Input, IkeDispatch, Udp6Srv, 0);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The general interface of starting IPsec Key Exchange.\r
+  \r
+  This function is called when a IKE negotiation to start getting a Key.\r
+  \r
+  @param[in] UdpService   Point to IKE_UDP_SERVICE which will be used for \r
+                          IKE packet sending.\r
+  @param[in] SpdEntry     Point to the SPD entry related to the IKE negotiation.\r
+  @param[in] RemoteIp     Point to EFI_IP_ADDRESS related to the IKE negotiation.\r
+  \r
+  @retval EFI_SUCCESS            The Operation is successful.\r
+  @retval EFI_ACCESS_DENIED      No related PAD entry was found.\r
+  @retval EFI_INVALID_PARAMETER  The IKE version is not supported.\r
+  \r
+**/\r
+EFI_STATUS\r
+IkeNegotiate (\r
+  IN IKE_UDP_SERVICE       *UdpService,\r
+  IN IPSEC_SPD_ENTRY       *SpdEntry,\r
+  IN EFI_IP_ADDRESS        *RemoteIp\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  UINT8                    *IkeSaSession;\r
+  IKE_EXCHANGE_INTERFACE   *Exchange;\r
+  IPSEC_PRIVATE_DATA       *Private;\r
+  IPSEC_PAD_ENTRY          *PadEntry;\r
+  UINT8                    IkeVersion;\r
+\r
+  Private = (UdpService->IpVersion == IP_VERSION_4) ?\r
+             IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :\r
+             IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);\r
+\r
+  //\r
+  // Try to open udp io for output if it hasn't.\r
+  //\r
+  Status = IkeOpenOutputUdp (UdpService, RemoteIp);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Try to find the IKE SA session in the IKEv1 and IKEv2 established SA session list.\r
+  //  \r
+  IkeSaSession = (UINT8 *) Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, RemoteIp);    \r
+\r
+\r
+  if (IkeSaSession == NULL) {\r
+    //\r
+    // Find the pad entry by the remote ip address.\r
+    //\r
+    PadEntry = IpSecLookupPadEntry (UdpService->IpVersion, RemoteIp);\r
+    if (PadEntry == NULL) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+    //\r
+    // Determine the IKE exchange instance by the auth protocol in pad entry.\r
+    //\r
+    ASSERT (PadEntry->Data->AuthProtocol < EfiIPsecAuthProtocolMaximum);\r
+    if (PadEntry->Data->AuthProtocol == EfiIPsecAuthProtocolIKEv1) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    Exchange = mIkeExchange[PadEntry->Data->AuthProtocol];\r
+    //\r
+    // Start the main mode stage to negotiate IKE SA.\r
+    //\r
+    Status = Exchange->NegotiateSa (UdpService, SpdEntry, PadEntry, RemoteIp);\r
+  } else {\r
+    //\r
+    // Determine the IKE exchange instance by the IKE version in IKE SA session.\r
+    //\r
+    IkeVersion = IkeGetVersionFromSession (IkeSaSession);\r
+    if (IkeVersion != 2) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+   \r
+    Exchange = mIkeExchange[IkeVersion - 1];\r
+    //\r
+    // Start the quick mode stage to negotiate child SA.\r
+    //\r
+    Status = Exchange->NegotiateChildSa (IkeSaSession, SpdEntry, NULL);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The generic interface when receive a IKE packet.\r
+  \r
+  This function is called when UDP IO receives a IKE packet.\r
+  \r
+  @param[in] Packet       Point to received IKE packet.\r
+  @param[in] EndPoint     Point to UDP_END_POINT which contains the information of \r
+                          Remote IP and Port.\r
+  @param[in] IoStatus     The Status of Recieve Token.\r
+  @param[in] Context      Point to data passed from the caller.\r
+    \r
+**/\r
+VOID\r
+IkeDispatch (\r
+  IN NET_BUF                        *Packet,\r
+  IN UDP_END_POINT                  *EndPoint,\r
+  IN EFI_STATUS                     IoStatus,\r
+  IN VOID                           *Context\r
+  )\r
+{\r
+  IPSEC_PRIVATE_DATA                *Private;\r
+  IKE_PACKET                        *IkePacket;\r
+  IKE_HEADER                        *IkeHdr;\r
+  IKE_UDP_SERVICE                   *UdpService;\r
+  IKE_EXCHANGE_INTERFACE            *Exchange;\r
+  EFI_STATUS                        Status;\r
+\r
+  UdpService = (IKE_UDP_SERVICE *) Context;\r
+  IkePacket  = NULL;\r
+  Private    = (UdpService->IpVersion == IP_VERSION_4) ?\r
+               IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :\r
+               IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);\r
+\r
+  if (EFI_ERROR (IoStatus)) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Check whether the ipsec is enabled or not.\r
+  //\r
+  if (Private->IpSec.DisabledFlag == TRUE) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (EndPoint->RemotePort != IKE_DEFAULT_PORT) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Build IKE packet from the received netbuf.\r
+  //\r
+  IkePacket = IkePacketFromNetbuf (Packet);\r
+\r
+  if (IkePacket == NULL) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Get the remote address from the IKE packet.\r
+  //\r
+  if (UdpService->IpVersion == IP_VERSION_4) {\r
+    *(UINT32 *) IkePacket->RemotePeerIp.Addr = HTONL ((*(UINT32 *) EndPoint->RemoteAddr.Addr));\r
+  } else {\r
+    CopyMem (\r
+      &IkePacket->RemotePeerIp,\r
+      NTOHLLL (&EndPoint->RemoteAddr.v6),\r
+      sizeof (EFI_IPv6_ADDRESS)\r
+      );\r
+  }\r
+  //\r
+  // Try to open udp io for output if hasn't.\r
+  //\r
+  Status = IkeOpenOutputUdp (UdpService, &IkePacket->RemotePeerIp);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  IkeHdr = IkePacket->Header;\r
+\r
+  //\r
+  // Determine the IKE exchange instance by the IKE version in IKE header.\r
+  //\r
+  if (IKE_MAJOR_VERSION (IkeHdr->Version) == 2) {\r
+    Exchange = mIkeExchange[IKE_MAJOR_VERSION (IkeHdr->Version) - 1];\r
+  } else {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  switch (IkeHdr->ExchangeType) {\r
+  case IKE_XCG_TYPE_IDENTITY_PROTECT:\r
+  case IKE_XCG_TYPE_SA_INIT:\r
+  case IKE_XCG_TYPE_AUTH:\r
+    Exchange->HandleSa (UdpService, IkePacket);\r
+    break;\r
+\r
+  case IKE_XCG_TYPE_QM:\r
+  case IKE_XCG_TYPE_CREATE_CHILD_SA:\r
+    Exchange->HandleChildSa (UdpService, IkePacket);\r
+    break;\r
+\r
+  case IKE_XCG_TYPE_INFO:\r
+  case IKE_XCG_TYPE_INFO2:\r
+    Exchange->HandleInfo (UdpService, IkePacket);\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+ON_EXIT:\r
+  if (IkePacket != NULL) {\r
+    IkePacketFree (IkePacket);\r
+  }\r
+\r
+  if (Packet != NULL) {\r
+    NetbufFree (Packet);\r
+  }\r
+\r
+  UdpIoRecvDatagram (UdpService->Input, IkeDispatch, UdpService, 0);\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Delete all established IKE SAs and related Child SAs.\r
+  \r
+  This function is the subfunction of the IpSecCleanupAllSa(). It first calls  \r
+  IkeDeleteChildSa() to delete all Child SAs then send out the related \r
+  Information packet.\r
+\r
+  @param[in]  Private  Pointer of the IPSEC_PRIVATE_DATA\r
+\r
+**/\r
+VOID\r
+IkeDeleteAllSas (\r
+  IN IPSEC_PRIVATE_DATA  *Private\r
+  )\r
+{\r
+  LIST_ENTRY             *Entry;\r
+  LIST_ENTRY             *NextEntry;\r
+  IKEV2_SA_SESSION       *Ikev2SaSession;\r
+  UINT8                  Value;\r
+  EFI_STATUS             Status;\r
+  IKE_EXCHANGE_INTERFACE *Exchange;\r
+  UINT8                  IkeVersion;\r
+\r
+  Exchange = NULL;\r
+\r
+  //\r
+  // If the IKEv1 is supported, first deal with the Ikev1Estatblished list.\r
+  //\r
+\r
+  //\r
+  // If IKEv2 SAs are under establishing, delete it directly.\r
+  //\r
+  if (!IsListEmpty (&Private->Ikev2SessionList)) {\r
+    NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Ikev2SessionList) {\r
+      Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);  \r
+      RemoveEntryList (Entry);\r
+      Ikev2SaSessionFree (Ikev2SaSession);\r
+    }\r
+  }\r
+  \r
+  //\r
+  // If there is no existing established IKE SA, set the Ipsec DisableFlag to TRUE\r
+  // and turn off the IsIPsecDisabling flag.\r
+  //\r
+  if (IsListEmpty (&Private->Ikev2EstablishedList)) {\r
+    Value = IPSEC_STATUS_DISABLED;\r
+    Status = gRT->SetVariable (\r
+               IPSECCONFIG_STATUS_NAME,\r
+               &gEfiIpSecConfigProtocolGuid,\r
+               EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+               sizeof (Value),\r
+               &Value\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      Private->IpSec.DisabledFlag = TRUE;\r
+      Private->IsIPsecDisabling   = FALSE;\r
+      return ;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Delete established IKEv2 SAs.\r
+  //\r
+  if (!IsListEmpty (&Private->Ikev2EstablishedList)) {\r
+    for (Entry = Private->Ikev2EstablishedList.ForwardLink; Entry != &Private->Ikev2EstablishedList;) {\r
+      Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);\r
+      Entry = Entry->ForwardLink;\r
+    \r
+      Ikev2SaSession->SessionCommon.State = IkeStateSaDeleting;\r
+\r
+      //\r
+      // Call for Information Exchange.\r
+      //\r
+      IkeVersion = IkeGetVersionFromSession ((UINT8*)Ikev2SaSession);\r
+      if (IkeVersion == 2) {\r
+        Exchange = mIkeExchange[IkeVersion - 1];\r
+        Exchange->NegotiateInfo((UINT8*)Ikev2SaSession, NULL);\r
+      }      \r
+    }\r
+  }\r
+  \r
+}\r
+\r
+\r
+\r
diff --git a/NetworkPkg/IpSecDxe/IkeService.h b/NetworkPkg/IpSecDxe/IkeService.h
new file mode 100644 (file)
index 0000000..cbd58cc
--- /dev/null
@@ -0,0 +1,254 @@
+/** @file\r
+  Prototypes definitions of IKE service.\r
+  \r
+  Copyright (c) 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
+#ifndef _IKE_SERVICE_H_\r
+#define _IKE_SERVICE_H_\r
+\r
+#include "Ike.h"\r
+#include "IpSecImpl.h"\r
+#include "IkeCommon.h"\r
+\r
+#define IPSEC_CRYPTO_LIB_MEMORY 128 * 1024\r
+\r
+/**\r
+  This is prototype definition of general interface to intialize a IKE negotiation.\r
+\r
+  @param[in]  UdpService      Point to Udp Servcie used for the IKE packet sending.\r
+  @param[in]  SpdEntry        Point to SPD entry related to this IKE negotiation.\r
+  @param[in]  PadEntry        Point to PAD entry related to this IKE negotiation.\r
+  @param[in]  RemoteIp        Point to IP Address which the remote peer to negnotiate.\r
+\r
+  @retval EFI_SUCCESS     The operation is successful.\r
+  @return Otherwise       The operation is failed.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(*IKE_NEGOTIATE_SA) (\r
+  IN IKE_UDP_SERVICE                * UdpService,\r
+  IN IPSEC_SPD_ENTRY                * SpdEntry,\r
+  IN IPSEC_PAD_ENTRY                * PadEntry,\r
+  IN EFI_IP_ADDRESS                 * RemoteIp\r
+  );\r
+\r
+/**\r
+  This is prototype definition fo general interface to start a IKE negotiation at Quick Mode. \r
+\r
+  This function will be called when the related IKE SA is existed and start to\r
+  create a Child SA.\r
+\r
+  @param[in]  IkeSaSession    Point to IKE SA Session related to this Negotiation.\r
+  @param[in]  SpdEntry        Point to SPD entry related to this Negotiation.\r
+  @param[in]  Context         Point to data passed from the caller.\r
+\r
+  @retval EFI_SUCCESS     The operation is successful.\r
+  @retval Otherwise       The operation is failed.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(*IKE_NEGOTIATE_CHILD_SA) (\r
+  IN UINT8                          *IkeSaSession,\r
+  IN IPSEC_SPD_ENTRY                *SpdEntry,\r
+  IN UINT8                          *Context\r
+  );\r
+\r
+/**\r
+  This is prototype definition of the general interface when initialize a Inforamtion\r
+  Exchange.\r
+\r
+  @param[in]  IkeSaSession      Point to IKE SA Session related to.\r
+  @param[in]  Context           Point to data passed from caller.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(*IKE_NEGOTIATE_INFO) (\r
+  IN UINT8                          *IkeSaSession,\r
+  IN UINT8                          *Context\r
+  );\r
+\r
+/**\r
+  This is prototype definition of the general interface when recived a IKE Pakcet \r
+  for the IKE SA establishing.\r
+\r
+  @param[in]  UdpService      Point to UDP service used to send IKE Packet.\r
+  @param[in]  IkePacket       Point to received IKE packet.\r
+\r
+**/\r
+typedef\r
+VOID\r
+(*IKE_HANDLE_SA) (\r
+  IN IKE_UDP_SERVICE                *UdpService,\r
+  IN IKE_PACKET                     *IkePacket\r
+  );\r
+\r
+/**\r
+  This is prototyp definition of the general interface when recived a IKE Packet\r
+  xfor the Child SA establishing. \r
\r
+  @param[in]  UdpService      Point to UDP service used to send IKE packet.\r
+  @param[in]  IkePacket       Point to received IKE packet.\r
+\r
+**/\r
+typedef\r
+VOID\r
+(*IKE_HANDLE_CHILD_SA) (\r
+  IN IKE_UDP_SERVICE                *UdpService,\r
+  IN IKE_PACKET                     *IkePacket\r
+  );\r
+\r
+/**\r
+  This is prototype definition of the general interface when received a IKE \r
+  information Packet.\r
+\r
+  @param[in]  UdpService      Point to UDP service used to send IKE packet.\r
+  @param[in]  IkePacket       Point to received IKE packet.\r
+\r
+**/\r
+typedef\r
+VOID\r
+(*IKE_HANDLE_INFO) (\r
+  IN IKE_UDP_SERVICE                *UdpService,\r
+  IN IKE_PACKET                     *IkePacket\r
+  );\r
+\r
+typedef struct _IKE_EXCHANGE_INTERFACE {\r
+  UINT8                   IkeVer;\r
+  IKE_NEGOTIATE_SA        NegotiateSa;\r
+  IKE_NEGOTIATE_CHILD_SA  NegotiateChildSa;\r
+  IKE_NEGOTIATE_INFO      NegotiateInfo;\r
+  IKE_HANDLE_SA           HandleSa;\r
+  IKE_HANDLE_CHILD_SA     HandleChildSa;\r
+  IKE_HANDLE_INFO         HandleInfo;\r
+} IKE_EXCHANGE_INTERFACE;\r
+\r
+/**\r
+  Open and configure a UDPIO of Udp4 for IKE packet receiving.\r
+  \r
+  This function is called at the IPsecDriverBinding start. IPsec create a UDP4 and  \r
+  a UDP4 IO for each NIC handle.\r
+  \r
+  @param[in] Private        Point to IPSEC_PRIVATE_DATA\r
+  @param[in] Controller     Handler for NIC card.\r
+  \r
+  @retval EFI_SUCCESS             The Operation is successful.\r
+  @retval EFI_OUT_OF_RESOURCE     The required system resource can't be allocated.\r
+  \r
+**/\r
+EFI_STATUS\r
+IkeOpenInputUdp4 (\r
+  IN IPSEC_PRIVATE_DATA             *Private,\r
+  IN EFI_HANDLE                     Controller\r
+  );\r
+\r
+/**\r
+  Open and configure a UDPIO of Udp6 for IKE packet receiving.\r
+  \r
+  This function is called at the IPsecDriverBinding start. IPsec create a UDP6 and UDP6\r
+  IO for each NIC handle.\r
+  \r
+  @param[in] Private        Point to IPSEC_PRIVATE_DATA\r
+  @param[in] Controller     Handler for NIC card.\r
+  \r
+  @retval EFI_SUCCESS             The Operation is successful.\r
+  @retval EFI_OUT_OF_RESOURCE     The required system resource can't be allocated.\r
+  \r
+**/\r
+EFI_STATUS\r
+IkeOpenInputUdp6 (\r
+  IN IPSEC_PRIVATE_DATA             *Private,\r
+  IN EFI_HANDLE                     Controller\r
+  );\r
+\r
+/**\r
+  The general interface of starting IPsec Key Exchange.\r
+  \r
+  This function is called when start a IKE negotiation to get a Key.\r
+  \r
+  @param[in] UdpService   Point to IKE_UDP_SERVICE which will be used for \r
+                          IKE packet sending.\r
+  @param[in] SpdEntry     Point to the SPD entry related to the IKE negotiation.\r
+  @param[in] RemoteIp     Point to EFI_IP_ADDRESS related to the IKE negotiation.\r
+  \r
+  @retval EFI_SUCCESS          The Operation is successful.\r
+  @retval EFI_ACCESS_DENIED    No related PAD entry was found.\r
+  \r
+**/\r
+EFI_STATUS\r
+IkeNegotiate (\r
+  IN IKE_UDP_SERVICE                *UdpService,\r
+  IN IPSEC_SPD_ENTRY                *SpdEntry,\r
+  IN EFI_IP_ADDRESS                 *RemoteIp\r
+  );\r
+\r
+/**\r
+  The general interface when receive a IKE packet.\r
+  \r
+  This function is called when UDP IO receives a IKE packet.\r
+  \r
+  @param[in] Packet       Point to received IKE packet.\r
+  @param[in] EndPoint     Point to UDP_END_POINT which contains the information of \r
+                          Remote IP and Port.\r
+  @param[in] IoStatus     The Status of Recieve Token.\r
+  @param[in] Context      Point to data passed from the caller.\r
+    \r
+**/\r
+VOID\r
+IkeDispatch (\r
+  IN NET_BUF                        *Packet,\r
+  IN UDP_END_POINT                  *EndPoint,\r
+  IN EFI_STATUS                     IoStatus,\r
+  IN VOID                           *Context\r
+  );\r
+\r
+/**\r
+  Check if the NIC handle is binded to a Udp service.\r
+\r
+  @param[in]  Private    Pointer of IPSEC_PRIVATE_DATA\r
+  @param[in]  NicHandle  The Handle of the NIC card\r
+  @param[in]  IpVersion  The version of the IP stack.\r
+\r
+  @return a pointer of IKE_UDP_SERVICE.\r
+\r
+**/\r
+IKE_UDP_SERVICE *\r
+IkeLookupUdp (\r
+  IN IPSEC_PRIVATE_DATA             *Private,\r
+  IN EFI_HANDLE                     Handle,\r
+  IN UINT8                          IpVersion\r
+  );\r
+\r
+\r
+/**\r
+  Delete all established IKE SAs and related Child SAs.\r
+  \r
+  This function is the subfunction of the IpSecCleanupAllSa(). It first calls  \r
+  IkeDeleteChildSa() to delete all Child SAs then send out the related \r
+  Information packet.\r
+\r
+  @param[in]  Private  Pointer of the IPSEC_PRIVATE_DATA.\r
+\r
+**/\r
+VOID\r
+IkeDeleteAllSas (\r
+  IN IPSEC_PRIVATE_DATA             *Private\r
+  );\r
+\r
+\r
+extern IKE_EXCHANGE_INTERFACE       mIkev1Exchange;\r
+extern IKE_EXCHANGE_INTERFACE       mIkev2Exchange;\r
+\r
+#endif\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c b/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c
new file mode 100644 (file)
index 0000000..d3859e2
--- /dev/null
@@ -0,0 +1,192 @@
+/** @file\r
+  The operations for Child SA.\r
+\r
+  Copyright (c) 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 "Utility.h"\r
+\r
+/**\r
+  Generate IKE Packet for CREATE_CHILD_SA exchange.  \r
+\r
+  This IKE Packet would be the packet for creating new CHILD SA, or the packet for\r
+  rekeying existing IKE SA, or the packet for existing CHILD SA.\r
+  \r
+  @param[in] SaSession   Pointer to related SA session. \r
+  @param[in] Context     The data passed by the caller.\r
+\r
+  return a pointer of IKE packet.\r
+\r
+**/\r
+IKE_PACKET *\r
+Ikev2CreateChildGenerator (\r
+  IN UINT8               *SaSession,\r
+  IN VOID                *Context\r
+  )\r
+{\r
+\r
+  IKEV2_CHILD_SA_SESSION  *ChildSaSession;\r
+  IKEV2_SA_SESSION        *IkeSaSession;\r
+  IKE_PACKET              *IkePacket;\r
+  IKE_PAYLOAD             *NotifyPayload;\r
+  UINT32                  *MessageId;\r
+  \r
+  ChildSaSession  = (IKEV2_CHILD_SA_SESSION *) SaSession;\r
+  IkePacket       = IkePacketAlloc();\r
+  MessageId       = NULL;\r
+\r
+  if (IkePacket == NULL) {\r
+    return NULL;\r
+  }\r
+  if (ChildSaSession == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  if (Context != NULL) {\r
+    MessageId = (UINT32 *) Context;\r
+  }\r
+  \r
+  IkePacket->Header->Version      = (UINT8) (2 << 4);\r
+  IkePacket->Header->NextPayload  = IKEV2_PAYLOAD_TYPE_NOTIFY;\r
+  IkePacket->Header->ExchangeType = IKE_XCG_TYPE_CREATE_CHILD_SA;\r
+  \r
+  if (ChildSaSession->SessionCommon.IkeSessionType == IkeSessionTypeChildSa) {\r
+    //\r
+    // 1.a Fill the IkePacket->Hdr\r
+    //    \r
+    IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie;\r
+    IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie;\r
+    \r
+    if (MessageId != NULL) {\r
+      IkePacket->Header->MessageId     = *MessageId;\r
+    } else {\r
+      IkePacket->Header->MessageId     = ChildSaSession->MessageId;\r
+    }    \r
+    \r
+    if (ChildSaSession->SessionCommon.IsInitiator) {\r
+      IkePacket->Header->Flags = IKE_HEADER_FLAGS_CHILD_INIT;\r
+    } else {\r
+      IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;\r
+    }\r
+      \r
+  } else {\r
+    IkeSaSession  = (IKEV2_SA_SESSION *) SaSession;\r
+    //\r
+    // 1.a Fill the IkePacket->Hdr\r
+    //\r
+    IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;\r
+    IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;\r
+\r
+    if (MessageId != NULL) {\r
+      IkePacket->Header->MessageId     = *MessageId;\r
+    } else {\r
+      IkePacket->Header->MessageId     = IkeSaSession->MessageId;\r
+    }    \r
+    \r
+    if (IkeSaSession->SessionCommon.IsInitiator) {\r
+      IkePacket->Header->Flags = IKE_HEADER_FLAGS_CHILD_INIT;\r
+    } else {\r
+      IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;\r
+    }\r
+  } \r
+   \r
+  //\r
+  // According to RFC4306, Chapter 4.\r
+  // A minimal implementation may support the CREATE_CHILD_SA exchange only to\r
+  // recognize requests and reject them with a Notify payload of type NO_ADDITIONAL_SAS.\r
+  //\r
+  NotifyPayload = Ikev2GenerateNotifyPayload (\r
+                    0,\r
+                    IKEV2_PAYLOAD_TYPE_NONE,\r
+                    0,                  \r
+                    IKEV2_NOTIFICATION_NO_ADDITIONAL_SAS,\r
+                    NULL,\r
+                    NULL,\r
+                    0\r
+                    );\r
+                        \r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);\r
+  //\r
+  // TODO: Support the CREATE_CHILD_SA exchange. \r
+  // \r
+  return IkePacket;\r
+}\r
+\r
+/**\r
+  Parse the IKE packet of CREATE_CHILD_SA exchange.\r
+  \r
+  This function parse the IKE packet and save the related information to further\r
+  calculation. \r
+  \r
+  @param[in] SaSession   Pointer to IKEv2_CHILD_SA_SESSION related to this Exchange.\r
+  @param[in] IkePacket   Received packet to be parsed.\r
\r
+\r
+  @retval EFI_SUCCESS       The IKE Packet is acceptable.\r
+  @retval EFI_UNSUPPORTED   Not support the CREATE_CHILD_SA request.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2CreateChildParser (\r
+  IN UINT8                        *SaSession,\r
+  IN IKE_PACKET                   *IkePacket\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Routine process before the payload decoding.\r
+\r
+  @param[in] SessionCommon  Pointer to ChildSa SessionCommon.\r
+  @param[in] PayloadBuf     Pointer to the payload.\r
+  @param[in] PayloadSize    Size of PayloadBuf in byte.\r
+  @param[in] PayloadType    Type of Payload.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaBeforeDecodePayload (\r
+  IN UINT8              *SessionCommon,\r
+  IN UINT8              *PayloadBuf,\r
+  IN UINTN              PayloadSize,\r
+  IN UINT8              PayloadType\r
+  )\r
+{\r
+\r
+}\r
+\r
+/**\r
+  Routine Process after the payload encoding.\r
+\r
+  @param[in] SessionCommon  Pointer to ChildSa SessionCommon.\r
+  @param[in] PayloadBuf     Pointer to the payload.\r
+  @param[in] PayloadSize    Size of PayloadBuf in byte.\r
+  @param[in] PayloadType    Type of Payload.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaAfterEncodePayload (\r
+  IN UINT8              *SessionCommon,\r
+  IN UINT8              *PayloadBuf,\r
+  IN UINTN              PayloadSize,\r
+  IN UINT8              PayloadType\r
+  )\r
+{\r
+}\r
+\r
+IKEV2_PACKET_HANDLER  mIkev2CreateChild = {\r
+  //\r
+  // Create Child\r
+  //\r
+  Ikev2CreateChildParser,\r
+  Ikev2CreateChildGenerator\r
+};\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Exchange.c b/NetworkPkg/IpSecDxe/Ikev2/Exchange.c
new file mode 100644 (file)
index 0000000..94bdd86
--- /dev/null
@@ -0,0 +1,803 @@
+/** @file\r
+  The general interfaces of the IKEv2.\r
+\r
+  Copyright (c) 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 "Utility.h"\r
+#include "IpSecDebug.h"\r
+#include "IkeService.h"\r
+#include "IpSecConfigImpl.h"\r
+\r
+/**\r
+  General interface to intialize a IKEv2 negotiation.\r
+\r
+  @param[in]  UdpService      Point to Udp Servcie used for the IKE packet sending.\r
+  @param[in]  SpdEntry        Point to SPD entry related to this IKE negotiation.\r
+  @param[in]  PadEntry        Point to PAD entry related to this IKE negotiation.\r
+  @param[in]  RemoteIp        Point to IP Address which the remote peer to negnotiate.\r
+\r
+  @retval EFI_SUCCESS           The operation is successful.\r
+  @retval EFI_OUT_OF_RESOURCES  The required system resource can't be allocated.\r
+  @retval EFI_INVALID_PARAMETER If UdpService or RemoteIp is NULL.\r
+  @return Others                The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2NegotiateSa (\r
+  IN IKE_UDP_SERVICE         *UdpService,\r
+  IN IPSEC_SPD_ENTRY         *SpdEntry,\r
+  IN IPSEC_PAD_ENTRY         *PadEntry,\r
+  IN EFI_IP_ADDRESS          *RemoteIp\r
+  )\r
+{\r
+  IPSEC_PRIVATE_DATA        *Private;\r
+  IKEV2_SA_SESSION          *IkeSaSession;\r
+  IKEV2_SESSION_COMMON      *SessionCommon;\r
+  IKEV2_PACKET_HANDLER      Handler;\r
+  IKE_PACKET                *IkePacket;\r
+  EFI_STATUS                Status;\r
+  \r
+  if (UdpService == NULL || RemoteIp == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  IkePacket = NULL;\r
+  Private   = (UdpService->IpVersion == IP_VERSION_4) ?\r
+               IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :\r
+               IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);\r
+\r
+  //\r
+  // Lookup the remote ip address in the processing IKE SA session list.\r
+  //\r
+  IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2SessionList, RemoteIp);\r
+  if (IkeSaSession != NULL) {\r
+    //\r
+    // Drop the packet if already in process.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // Create a new IkeSaSession and initiate the common parameters.\r
+  //\r
+  IkeSaSession = Ikev2SaSessionAlloc (Private, UdpService);\r
+  if (IkeSaSession == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Set the specific parameters and state(IKE_STATE_INIT).\r
+  //\r
+  IkeSaSession->Spd            = SpdEntry;\r
+  IkeSaSession->Pad            = PadEntry;  \r
+  SessionCommon                = &IkeSaSession->SessionCommon;\r
+  SessionCommon->IsInitiator   = TRUE;\r
+  SessionCommon->State         = IkeStateInit;\r
+  //\r
+  // TODO: Get the prefer DH Group from the IPsec Configuration, after the IPsecconfig application update\r
+  // to support it.\r
+  //\r
+  SessionCommon->PreferDhGroup = IKEV2_TRANSFORM_ID_DH_1024MODP;\r
+  \r
+  CopyMem (\r
+    &SessionCommon->RemotePeerIp,\r
+    RemoteIp,\r
+    sizeof (EFI_IP_ADDRESS)\r
+    );\r
+  \r
+  CopyMem (\r
+    &SessionCommon->LocalPeerIp,\r
+    &UdpService->DefaultAddress,\r
+    sizeof (EFI_IP_ADDRESS)\r
+    );\r
+\r
+  IKEV2_DUMP_STATE (SessionCommon->State, IkeStateInit);\r
+\r
+  //\r
+  // Initiate the SAD data of the IkeSaSession.\r
+  //\r
+  IkeSaSession->SaData = Ikev2InitializeSaData (SessionCommon);\r
+  if (IkeSaSession->SaData == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Generate an IKE request packet and send it out.\r
+  //\r
+  Handler   = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][SessionCommon->State];\r
+  IkePacket = Handler.Generator ((UINT8 *) IkeSaSession, NULL);\r
+  if (IkePacket == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = Ikev2SendIkePacket (UdpService, (UINT8 *) SessionCommon, IkePacket, 0);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Insert the current IkeSaSession into the processing IKE SA list.\r
+  //\r
+  Ikev2SaSessionInsert (&Private->Ikev2SessionList, IkeSaSession, RemoteIp);\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+\r
+  if (IkePacket != NULL) {\r
+    IkePacketFree (IkePacket);\r
+  }\r
+  Ikev2SaSessionFree (IkeSaSession);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  It is general interface to negotiate the Child SA.\r
+\r
+  There are three situations which will invoke this function. First, create a CHILD \r
+  SA if the input Context is NULL. Second, rekeying the existing IKE SA if the Context \r
+  is a IKEv2_SA_SESSION. Third, rekeying the existing CHILD SA if the context is a \r
+  IKEv2_CHILD_SA_SESSION.\r
+\r
+  @param[in] IkeSaSession  Pointer to IKEv2_SA_SESSION related to this operation.\r
+  @param[in] SpdEntry      Pointer to IPSEC_SPD_ENTRY related to this operation.\r
+  @param[in] Context       The data pass from the caller.\r
+  \r
+  @retval EFI_SUCCESS          The operation is successful.\r
+  @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.\r
+  @retval EFI_UNSUPPORTED      The condition is not support yet.\r
+  @return Others               The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2NegotiateChildSa (\r
+  IN UINT8           *IkeSaSession,\r
+  IN IPSEC_SPD_ENTRY *SpdEntry,\r
+  IN UINT8           *Context\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  IKEV2_SA_SESSION          *SaSession;\r
+  IKEV2_CHILD_SA_SESSION    *ChildSaSession;\r
+  IKEV2_SESSION_COMMON      *ChildSaCommon;\r
+  IKE_PACKET                *IkePacket;\r
+  IKE_UDP_SERVICE           *UdpService;\r
+\r
+  SaSession  = (IKEV2_SA_SESSION*) IkeSaSession;\r
+  UdpService = SaSession->SessionCommon.UdpService;\r
+  IkePacket  = NULL;\r
+\r
+  //\r
+  // 1. Create another child SA session if context is null.\r
+  // 2. Rekeying the IKE SA session if the context is IKE SA session.\r
+  // 3. Rekeying the child SA session if the context is child SA session.\r
+  //\r
+  if (Context == NULL) {\r
+    //\r
+    // Create a new ChildSaSession and initiate the common parameters.\r
+    //\r
+    ChildSaSession = Ikev2ChildSaSessionAlloc (UdpService, SaSession);\r
+\r
+    if (ChildSaSession == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // Set the specific parameters and state as IKE_STATE_CREATE_CHILD.\r
+    //\r
+    ChildSaSession->Spd         = SpdEntry;\r
+    ChildSaCommon               = &ChildSaSession->SessionCommon;\r
+    ChildSaCommon->IsInitiator  = TRUE;\r
+    ChildSaCommon->State        = IkeStateCreateChild;\r
+\r
+    IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateCreateChild);\r
+\r
+    if (SpdEntry->Selector->NextLayerProtocol != EFI_IPSEC_ANY_PROTOCOL) {\r
+      ChildSaSession->ProtoId = SpdEntry->Selector->NextLayerProtocol;\r
+    }\r
+\r
+    if (SpdEntry->Selector->LocalPort != EFI_IPSEC_ANY_PORT) {\r
+      ChildSaSession->LocalPort = SpdEntry->Selector->LocalPort;\r
+    }\r
+\r
+    if (SpdEntry->Selector->RemotePort != EFI_IPSEC_ANY_PORT) {\r
+      ChildSaSession->RemotePort = SpdEntry->Selector->RemotePort;\r
+    }\r
+    //\r
+    // Initiate the SAD data parameters of the ChildSaSession.\r
+    //\r
+    ChildSaSession->SaData = Ikev2InitializeSaData (ChildSaCommon);\r
+    if (ChildSaSession->SaData == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_ERROR;\r
+    }\r
+    //\r
+    // Generate an IKE request packet and send it out.\r
+    //\r
+    IkePacket = mIkev2CreateChild.Generator ((UINT8 *) ChildSaSession, NULL);\r
+\r
+    if (IkePacket == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Status = Ikev2SendIkePacket (UdpService, (UINT8 *) ChildSaCommon, IkePacket, 0);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+    \r
+    //\r
+    // Insert the ChildSaSession into processing child SA list.\r
+    //\r
+    Ikev2ChildSaSessionInsert (&SaSession->ChildSaSessionList, ChildSaSession);\r
+  } else {\r
+    //\r
+    // TODO: Rekeying IkeSaSession or ChildSaSession, NOT support yet.\r
+    //\r
+    // Rekey IkeSa, set IkeSaSession->State and pass over IkeSaSession\r
+    // Rekey ChildSa, set ChildSaSession->State and pass over ChildSaSession\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+\r
+  if (ChildSaSession->SaData != NULL) {\r
+    FreePool (ChildSaSession->SaData);\r
+  }\r
+\r
+  if (ChildSaSession->SessionCommon.TimeoutEvent != NULL) {\r
+    gBS->CloseEvent (ChildSaSession->SessionCommon.TimeoutEvent);\r
+  }\r
+\r
+  if (IkePacket != NULL) {\r
+    IkePacketFree (IkePacket);\r
+  }\r
+\r
+  Ikev2ChildSaSessionFree (ChildSaSession);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  It is general interface to start the Information Exchange.\r
+\r
+  There are three situations which will invoke this function. First, deliver a Delete Information\r
+  to delete the IKE SA if the input Context is NULL and the state of related IkeSaSeesion's is on \r
+  deleting.Second, deliver a Notify Information without the contents if the input Context is NULL. \r
+  Third, deliver a Notify Information if the input Context is not NULL.\r
+\r
+  @param[in] IkeSaSession  Pointer to IKEv2_SA_SESSION related to this operation.\r
+  @param[in] Context       Data passed by caller.\r
+\r
+  @retval EFI_SUCCESS          The operation is successful.\r
+  @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.\r
+  @retval EFI_UNSUPPORTED      The condition is not support yet.\r
+  @return Otherwise            The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2NegotiateInfo (\r
+  IN UINT8           *IkeSaSession,\r
+  IN UINT8           *Context\r
+  )\r
+{\r
+  \r
+  EFI_STATUS                Status;\r
+  IKEV2_SA_SESSION          *Ikev2SaSession;\r
+  IKEV2_CHILD_SA_SESSION    *ChildSaSession;\r
+  IKEV2_SESSION_COMMON      *SaCommon;\r
+  IKE_PACKET                *IkePacket;\r
+  IKE_UDP_SERVICE           *UdpService;\r
+  LIST_ENTRY                *Entry;\r
+  LIST_ENTRY                *NextEntry;\r
+\r
+  Ikev2SaSession = (IKEV2_SA_SESSION *) IkeSaSession;\r
+  UdpService     = Ikev2SaSession->SessionCommon.UdpService;\r
+  SaCommon       = &Ikev2SaSession->SessionCommon;\r
+  IkePacket      = NULL;\r
+  Status         = EFI_SUCCESS;\r
+\r
+  //\r
+  // Delete the IKE SA.\r
+  //\r
+  if (Ikev2SaSession->SessionCommon.State == IkeStateSaDeleting && Context == NULL) {\r
+\r
+    //\r
+    // The IKE SA Session should be initiator if it triggers the deleting.\r
+    //\r
+    Ikev2SaSession->SessionCommon.IsInitiator = TRUE;\r
+\r
+    //\r
+    // Generate Information Packet which contains the Delete Payload.\r
+    //\r
+    IkePacket = mIkev2Info.Generator ((UINT8 *) Ikev2SaSession, NULL);\r
+    if (IkePacket == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    //\r
+    // Send out the Packet\r
+    //\r
+    Status = Ikev2SendIkePacket (UdpService, (UINT8 *) SaCommon, IkePacket, 0);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+  } else if (!IsListEmpty (&Ikev2SaSession->DeleteSaList)) {\r
+    //\r
+    // Iterate all Deleting Child SAs.\r
+    //\r
+    NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Ikev2SaSession->DeleteSaList) {\r
+      ChildSaSession                      = IKEV2_CHILD_SA_SESSION_BY_DEL_SA (Entry);\r
+      ChildSaSession->SessionCommon.State = IkeStateSaDeleting;\r
+\r
+      //\r
+      // Generate Information Packet which contains the Child SA Delete Payload.\r
+      //\r
+      IkePacket = mIkev2Info.Generator ((UINT8 *) ChildSaSession, NULL);\r
+      if (IkePacket == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto ON_ERROR;\r
+      }\r
+\r
+      //\r
+      // Send out the Packet\r
+      //\r
+      Status = Ikev2SendIkePacket (UdpService, (UINT8 *) &ChildSaSession->SessionCommon, IkePacket, 0);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_ERROR;\r
+      }\r
+    }\r
+  }  else if (Context == NULL) {\r
+    //\r
+    // TODO: Deliver null notification message.\r
+    //\r
+  }  else if (Context != NULL) {\r
+    //\r
+    // TODO: Send out the Information Exchange which contains the Notify Payload.\r
+    //\r
+  }\r
+ON_ERROR:\r
+  if (IkePacket != NULL) {\r
+    IkePacketFree (IkePacket);\r
+  }\r
+  return Status;\r
+\r
+}\r
+\r
+/**\r
+  The general interface when received a IKEv2 packet for the IKE SA establishing.\r
+\r
+  This function first find the related IKE SA Session according to the IKE packet's \r
+  remote IP. Then call the corresponding function to handle this IKE packet according\r
+  to the related IKE SA Session's State. \r
+\r
+  @param[in] UdpService    Pointer of related UDP Service.\r
+  @param[in] IkePacket     Data passed by caller.\r
+\r
+**/\r
+VOID\r
+Ikev2HandleSa (\r
+  IN IKE_UDP_SERVICE     *UdpService,\r
+  IN IKE_PACKET          *IkePacket\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  IKEV2_SA_SESSION        *IkeSaSession;\r
+  IKEV2_CHILD_SA_SESSION  *ChildSaSession;\r
+  IKEV2_SESSION_COMMON    *IkeSaCommon;\r
+  IKEV2_SESSION_COMMON    *ChildSaCommon;\r
+  IKEV2_PACKET_HANDLER    Handler;\r
+  IKE_PACKET              *Reply;\r
+  IPSEC_PAD_ENTRY         *PadEntry;\r
+  IPSEC_PRIVATE_DATA      *Private;\r
+  BOOLEAN                 IsNewSession;\r
+\r
+  Private = (UdpService->IpVersion == IP_VERSION_4) ? \r
+             IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :\r
+             IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);\r
+\r
+  ChildSaSession = NULL;\r
+  ChildSaCommon  = NULL;\r
+  \r
+  //\r
+  // Lookup the remote ip address in the processing IKE SA session list.\r
+  //\r
+  IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2SessionList, &IkePacket->RemotePeerIp);\r
+  IsNewSession = FALSE;\r
+\r
+  if (IkeSaSession == NULL) {\r
+    //\r
+    // Lookup the remote ip address in the pad.\r
+    //\r
+    PadEntry = IpSecLookupPadEntry (UdpService->IpVersion, &IkePacket->RemotePeerIp);\r
+    if (PadEntry == NULL) {\r
+      //\r
+      // Drop the packet if no pad entry matched, this is the request from RFC 4301.\r
+      //\r
+      return ;\r
+    }\r
+\r
+    //\r
+    // Create a new IkeSaSession and initiate the common parameters.\r
+    //\r
+    IkeSaSession             = Ikev2SaSessionAlloc (Private, UdpService);\r
+    if (IkeSaSession == NULL) {\r
+      return;\r
+    }\r
+    IkeSaSession->Pad        = PadEntry;\r
+    IkeSaCommon              = &IkeSaSession->SessionCommon;\r
+    IkeSaCommon->IsInitiator = FALSE;\r
+    IkeSaCommon->State       = IkeStateInit;\r
+\r
+    IKEV2_DUMP_STATE (IkeSaCommon->State, IkeStateInit);\r
+\r
+    CopyMem (\r
+      &IkeSaCommon->RemotePeerIp,\r
+      &IkePacket->RemotePeerIp,\r
+      sizeof (EFI_IP_ADDRESS)\r
+      );\r
+\r
+    CopyMem (\r
+      &IkeSaCommon->LocalPeerIp,\r
+      &UdpService->DefaultAddress,\r
+      sizeof (EFI_IP_ADDRESS)\r
+      );\r
+    \r
+    IsNewSession = TRUE;\r
+  }\r
+\r
+  //\r
+  // Validate the IKE packet header.\r
+  //\r
+  Status = Ikev2ValidateHeader (IkeSaSession, IkePacket->Header);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Drop the packet if invalid IKE header.\r
+    //\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Decode all the payloads in the IKE packet.\r
+  //\r
+  IkeSaCommon = &IkeSaSession->SessionCommon;\r
+  Status      = Ikev2DecodePacket (IkeSaCommon, IkePacket, IkeSessionTypeIkeSa);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Try to reate the first ChildSa Session of that IkeSaSession.\r
+  // If the IkeSaSession is responder, here will create the first ChildSaSession.\r
+  //\r
+  if (IkeSaCommon->State == IkeStateAuth && IsListEmpty(&IkeSaSession->ChildSaSessionList)) {\r
+    //\r
+    // Generate a piggyback child SA in IKE_STATE_AUTH state.\r
+    //\r
+    ASSERT (IsListEmpty (&IkeSaSession->ChildSaSessionList) &&\r
+            IsListEmpty (&IkeSaSession->ChildSaEstablishSessionList));\r
+\r
+    ChildSaSession = Ikev2ChildSaSessionCreate (IkeSaSession, UdpService);\r
+    ChildSaCommon  = &ChildSaSession->SessionCommon;\r
+  }\r
+\r
+  //\r
+  // Parse the IKE request packet according to the auth method and current state.\r
+  //\r
+  Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][IkeSaCommon->State];\r
+  Status  = Handler.Parser ((UINT8 *)IkeSaSession, IkePacket);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  //\r
+  // Try to reate the first ChildSa Session of that IkeSaSession.\r
+  // If the IkeSaSession is initiator, here will create the first ChildSaSession.\r
+  //\r
+  if (IkeSaCommon->State == IkeStateAuth && IsListEmpty(&IkeSaSession->ChildSaSessionList)) {\r
+    //\r
+    // Generate a piggyback child SA in IKE_STATE_AUTH state.\r
+    //\r
+    ASSERT (IsListEmpty (&IkeSaSession->ChildSaSessionList) && \r
+            IsListEmpty (&IkeSaSession->ChildSaEstablishSessionList));\r
+    \r
+    ChildSaSession = Ikev2ChildSaSessionCreate (IkeSaSession, UdpService);\r
+    ChildSaCommon  = &ChildSaSession->SessionCommon;\r
+\r
+    //\r
+    // Initialize the SA data for Child SA.\r
+    //    \r
+    ChildSaSession->SaData = Ikev2InitializeSaData (ChildSaCommon);\r
+  }\r
+\r
+  //\r
+  // Generate the IKE response packet and send it out if not established.\r
+  //\r
+  if (IkeSaCommon->State != IkeStateIkeSaEstablished) {\r
+    Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][IkeSaCommon->State];\r
+    Reply   = Handler.Generator ((UINT8 *) IkeSaSession, NULL);\r
+    if (Reply == NULL) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    Status = Ikev2SendIkePacket (UdpService, (UINT8 *) IkeSaCommon, Reply, 0);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+    if (!IkeSaCommon->IsInitiator) {\r
+      IkeSaCommon->State ++;\r
+      IKEV2_DUMP_STATE (IkeSaCommon->State - 1, IkeSaCommon->State);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Insert the new IkeSaSession into the Private processing IkeSaSession List.\r
+  //\r
+  if (IsNewSession) {\r
+    Ikev2SaSessionInsert (&Private->Ikev2SessionList, IkeSaSession, &IkePacket->RemotePeerIp);\r
+  }\r
+\r
+  //\r
+  // Register the IkeSaSession and remove it from processing list.\r
+  //\r
+  if (IkeSaCommon->State == IkeStateIkeSaEstablished) {\r
+\r
+    //\r
+    // Remove the Established IKE SA Session from the IKE SA Session Negotiating list\r
+    // and insert it into IKE SA Session Established list.\r
+    //\r
+    Ikev2SaSessionRemove (&Private->Ikev2SessionList, &IkePacket->RemotePeerIp);\r
+    Ikev2SaSessionReg (IkeSaSession, Private);\r
+\r
+    //\r
+    // Remove the Established Child SA Session from the IkeSaSession->ChildSaSessionList\r
+    // ,insert it into IkeSaSession->ChildSaEstablishSessionList and save this Child SA \r
+    // into SAD.\r
+    //\r
+    ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (IkeSaSession->ChildSaSessionList.BackLink);\r
+    Ikev2ChildSaSessionRemove (\r
+      &IkeSaSession->ChildSaSessionList,\r
+      ChildSaSession->LocalPeerSpi,\r
+      IKEV2_ESTABLISHING_CHILDSA_LIST\r
+      );\r
+    Ikev2ChildSaSessionReg (ChildSaSession, Private);\r
+  }\r
+\r
+  return ;\r
+\r
+ON_ERROR:\r
+  if (ChildSaSession != NULL) {\r
+    //\r
+    // Remove the ChildSa from the list (Established list or Negotiating list).\r
+    //\r
+    RemoveEntryList (&ChildSaSession->ByIkeSa);\r
+    Ikev2ChildSaSessionFree (ChildSaSession);\r
+  }\r
+\r
+  if (IsNewSession && IkeSaSession != NULL) {\r
+    //\r
+    // Remove the IkeSa from the list (Established list or Negotiating list).\r
+    //\r
+    if ((&IkeSaSession->BySessionTable)->ForwardLink != NULL &&\r
+        !IsListEmpty (&IkeSaSession->BySessionTable\r
+       )){\r
+      RemoveEntryList (&IkeSaSession->BySessionTable);\r
+    }\r
+    Ikev2SaSessionFree (IkeSaSession);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+\r
+  The general interface when received a IKEv2 packet for the IKE Child SA establishing \r
+  or IKE SA/CHILD SA rekeying.\r
+\r
+  This function first find the related IKE SA Session according to the IKE packet's \r
+  remote IP. Then call the corresponding function to handle this IKE packet according\r
+  to the related IKE Child Session's State. \r
+\r
+  @param[in] UdpService    Pointer of related UDP Service.\r
+  @param[in] IkePacket     Data passed by caller.\r
+\r
+**/\r
+VOID\r
+Ikev2HandleChildSa (\r
+  IN IKE_UDP_SERVICE  *UdpService,\r
+  IN IKE_PACKET       *IkePacket\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  IKEV2_SA_SESSION                 *IkeSaSession;\r
+  IKEV2_CREATE_CHILD_REQUEST_TYPE  RequestType;\r
+  IKE_PACKET                       *Reply;\r
+  IPSEC_PRIVATE_DATA               *Private;\r
+  \r
+  Private = (UdpService->IpVersion == IP_VERSION_4) ? \r
+             IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :\r
+             IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);\r
+\r
+  Reply   = NULL;\r
+\r
+  //\r
+  // Lookup the remote ip address in the processing IKE SA session list.\r
+  //\r
+  IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, &IkePacket->RemotePeerIp);\r
+\r
+  if (IkeSaSession == NULL) {\r
+    //\r
+    // Drop the packet if no IKE SA associated.\r
+    //\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Validate the IKE packet header.\r
+  //\r
+  if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) {\r
+    //\r
+    // Drop the packet if invalid IKE header.\r
+    //\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Decode all the payloads in the IKE packet.\r
+  //\r
+  Status = Ikev2DecodePacket (&IkeSaSession->SessionCommon, IkePacket, IkeSessionTypeIkeSa);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Get the request type: CreateChildSa/RekeyChildSa/RekeyIkeSa.\r
+  //  \r
+  RequestType = Ikev2ChildExchangeRequestType (IkePacket);\r
+\r
+  switch (RequestType) {\r
+  case IkeRequestTypeCreateChildSa:\r
+  case IkeRequestTypeRekeyChildSa: \r
+  case IkeRequestTypeRekeyIkeSa: \r
+    //\r
+    // Parse the IKE request packet. Not support CREATE_CHILD_SA exchange yet, so\r
+    // only EFI_UNSUPPORTED will be returned and that will trigger a reply with a \r
+    // Notify payload of type NO_ADDITIONAL_SAS.\r
+    //\r
+    Status = mIkev2CreateChild.Parser ((UINT8 *) IkeSaSession, IkePacket);\r
+    if (EFI_ERROR (Status)) {     \r
+      goto ON_REPLY;\r
+    }\r
+\r
+  default:\r
+    //\r
+    // No support.\r
+    //\r
+    return ;\r
+  }\r
+  \r
+ON_REPLY:\r
+  //\r
+  // Generate the reply packet if needed and send it out.\r
+  //\r
+  if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) {\r
+    Reply = mIkev2CreateChild.Generator ((UINT8 *) IkeSaSession, &IkePacket->Header->MessageId);\r
+    if (Reply != NULL) {\r
+      Status = Ikev2SendIkePacket (UdpService, (UINT8 *) &(IkeSaSession->SessionCommon), Reply, 0);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        //  Delete Reply payload.\r
+        //\r
+        if (Reply != NULL) {\r
+          IkePacketFree (Reply);\r
+        }\r
+      }\r
+    }\r
+  }  \r
+  return ;\r
+}\r
+\r
+/**\r
+\r
+  It is general interface to handle IKEv2 information Exchange.\r
+  \r
+  @param[in] UdpService  Point to IKE UPD Service related to this information exchange.  \r
+  @param[in] IkePacket   The IKE packet to be parsed.\r
+\r
+**/\r
+VOID\r
+Ikev2HandleInfo (\r
+  IN IKE_UDP_SERVICE  *UdpService,\r
+  IN IKE_PACKET       *IkePacket\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  IKEV2_SESSION_COMMON    *SessionCommon;\r
+  IKEV2_SA_SESSION        *IkeSaSession;\r
+  IPSEC_PRIVATE_DATA      *Private;\r
+\r
+  Private = (UdpService->IpVersion == IP_VERSION_4) ? \r
+             IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : \r
+             IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);\r
+\r
+  //\r
+  // Lookup the remote ip address in the processing IKE SA session list.\r
+  //\r
+  IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, &IkePacket->RemotePeerIp);\r
+  \r
+  if (IkeSaSession == NULL) {\r
+    //\r
+    // Drop the packet if no IKE SA associated.\r
+    //\r
+    return ;\r
+  }\r
+  //\r
+  // Validate the IKE packet header.\r
+  //\r
+  if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) {\r
+  \r
+    //\r
+    // Drop the packet if invalid IKE header.\r
+    //\r
+    return;\r
+  }  \r
+\r
+  SessionCommon = &IkeSaSession->SessionCommon;\r
+\r
+  //\r
+  // Decode all the payloads in the IKE packet.\r
+  //\r
+  Status = Ikev2DecodePacket (SessionCommon, IkePacket, IkeSessionTypeIkeSa);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  Status = mIkev2Info.Parser ((UINT8 *)IkeSaSession, IkePacket);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Drop the packet if fail to parse.\r
+    //\r
+    return;\r
+  }    \r
+}\r
+\r
+IKE_EXCHANGE_INTERFACE  mIkev1Exchange = {
+  1,
+  NULL, //Ikev1NegotiateSa\r
+  NULL, //Ikev1NegotiateChildSa\r
+  NULL,
+  NULL, //Ikev1HandleSa,\r
+  NULL, //Ikev1HandleChildSa\r
+  NULL, //Ikev1HandleInfo\r
+};\r
+\r
+IKE_EXCHANGE_INTERFACE  mIkev2Exchange = {\r
+  2,\r
+  Ikev2NegotiateSa,\r
+  Ikev2NegotiateChildSa,\r
+  Ikev2NegotiateInfo,\r
+  Ikev2HandleSa,\r
+  Ikev2HandleChildSa,\r
+  Ikev2HandleInfo\r
+};\r
+\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h b/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h
new file mode 100644 (file)
index 0000000..a2b733a
--- /dev/null
@@ -0,0 +1,258 @@
+/** @file\r
+  IKEv2 related definitions.\r
+\r
+  Copyright (c) 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
+#ifndef _IKE_V2_H_\r
+#define _IKE_V2_H_\r
+\r
+#include "Ike.h"\r
+#include "Payload.h"\r
+\r
+#define IKEV2_TS_ANY_PORT                     0xffff\r
+#define IKEV2_TS_ANY_PROTOCOL                 0\r
+\r
+#define IKEV2_DELET_CHILDSA_LIST              0\r
+#define IKEV2_ESTABLISHING_CHILDSA_LIST       1\r
+#define IKEV2_ESTABLISHED_CHILDSA_LIST        2\r
+\r
+#define IKEV2_SA_SESSION_SIGNATURE            SIGNATURE_32 ('I', 'K', 'E', 'I')\r
+#define IKEV2_SA_SESSION_FROM_COMMON(a)       CR (a, IKEV2_SA_SESSION, SessionCommon, IKEV2_SA_SESSION_SIGNATURE)\r
+#define IKEV2_SA_SESSION_BY_SESSION(a)        CR (a, IKEV2_SA_SESSION, BySessionTable, IKEV2_SA_SESSION_SIGNATURE)\r
+#define IKEV2_SA_SESSION_BY_ESTABLISHED(a)    CR (a, IKEV2_SA_SESSION, ByEstablishedTable, IKEV2_SA_SESSION_SIGNATURE)\r
+\r
+#define IKEV2_CHILD_SA_SESSION_SIGNATURE      SIGNATURE_32 ('I', 'K', 'E', 'C')\r
+#define IKEV2_CHILD_SA_SESSION_FROM_COMMON(a) CR (a, IKEV2_CHILD_SA_SESSION, SessionCommon, IKEV2_CHILD_SA_SESSION_SIGNATURE)\r
+#define IKEV2_CHILD_SA_SESSION_BY_IKE_SA(a)   CR (a, IKEV2_CHILD_SA_SESSION, ByIkeSa, IKEV2_CHILD_SA_SESSION_SIGNATURE)\r
+#define IKEV2_CHILD_SA_SESSION_BY_DEL_SA(a)   CR (a, IKEV2_CHILD_SA_SESSION, ByDelete, IKEV2_CHILD_SA_SESSION_SIGNATURE)\r
+\r
+#define IS_IKEV2_SA_SESSION(s)                ((s)->Common.IkeSessionType == IkeSessionTypeIkeSa)\r
+#define IKEV2_SA_FIRST_PROPOSAL(Sa)           (IKEV2_PROPOSAL *)((IKEV2_SA *)(Sa)+1)\r
+#define IKEV2_NEXT_TRANSFORM_WITH_SIZE(Transform,TransformSize)         \\r
+        (IKEV2_TRANSFORM *) ((UINT8 *)(Transform) + (TransformSize))\r
+\r
+#define IKEV2_NEXT_PROPOSAL_WITH_SIZE(Proposal, ProposalSize)           \\r
+        (IKEV2_PROPOSAL *) ((UINT8 *)(Proposal) + (ProposalSize))\r
+\r
+#define IKEV2_PROPOSAL_FIRST_TRANSFORM(Proposal)                        \\r
+        (IKEV2_TRANSFORM *)((UINT8 *)((IKEV2_PROPOSAL *)(Proposal)+1) + \\r
+                      (((IKEV2_PROPOSAL *)(Proposal))->SpiSize))\r
+#define IKEV2_PROPOSAL_FIRST_TRANSFORM(Proposal)                        \\r
+        (IKEV2_TRANSFORM *)((UINT8 *)((IKEV2_PROPOSAL *)(Proposal)+1) + \\r
+                      (((IKEV2_PROPOSAL *)(Proposal))->SpiSize))\r
+\r
+typedef enum {\r
+  IkeStateInit,\r
+  IkeStateAuth,\r
+  IkeStateIkeSaEstablished,\r
+  IkeStateCreateChild,\r
+  IkeStateSaRekeying,\r
+  IkeStateChildSaEstablished,\r
+  IkeStateSaDeleting,\r
+  IkeStateMaximum\r
+} IKEV2_SESSION_STATE;\r
+\r
+typedef enum {\r
+  IkeRequestTypeCreateChildSa,\r
+  IkeRequestTypeRekeyChildSa,\r
+  IkeRequestTypeRekeyIkeSa,\r
+  IkeRequestTypeMaximum\r
+} IKEV2_CREATE_CHILD_REQUEST_TYPE;\r
+\r
+typedef struct {\r
+  UINT8            *GxBuffer;\r
+  UINTN            GxSize;\r
+  UINT8            *GyBuffer;\r
+  UINTN            GySize;\r
+  UINT8            *GxyBuffer;\r
+  UINTN            GxySize;\r
+  UINT8            *DhContext;\r
+} IKEV2_DH_BUFFER;\r
+\r
+typedef struct {\r
+  IKEV2_DH_BUFFER   *DhBuffer;\r
+  UINT8             *SkdKey;\r
+  UINTN             SkdKeySize;\r
+  UINT8             *SkAiKey;\r
+  UINTN             SkAiKeySize;\r
+  UINT8             *SkArKey;\r
+  UINTN             SkArKeySize;\r
+  UINT8             *SkEiKey;\r
+  UINTN             SkEiKeySize;\r
+  UINT8             *SkErKey;\r
+  UINTN             SkErKeySize;\r
+  UINT8             *SkPiKey;\r
+  UINTN             SkPiKeySize;\r
+  UINT8             *SkPrKey;\r
+  UINTN             SkPrKeySize;\r
+} IKEV2_SESSION_KEYS;\r
+\r
+typedef struct {\r
+  UINT16  LifeType;\r
+  UINT64  LifeDuration;\r
+  UINT16  EncAlgId;\r
+  UINTN   EnckeyLen;\r
+  UINT16  Prf;\r
+  UINT16  IntegAlgId;\r
+  UINTN   IntegKeyLen;\r
+  UINT16  DhGroup;\r
+  UINT8   ExtSeq;\r
+} IKEV2_SA_PARAMS;\r
+\r
+//\r
+// Internal Payload\r
+//\r
+typedef struct {\r
+  IKEV2_SA  SaHeader;\r
+  UINTN     NumProposals;\r
+  //\r
+  // IKE_PROPOSAL_DATA  Proposals[1];\r
+  //\r
+} IKEV2_SA_DATA;\r
+\r
+typedef struct {\r
+  UINT8 ProposalIndex;\r
+  UINT8 ProtocolId;\r
+  UINT8 *Spi;\r
+  UINT8 NumTransforms;\r
+  //\r
+  // IKE_TRANSFORM_DATA Transforms[1];\r
+  //\r
+} IKEV2_PROPOSAL_DATA;\r
+\r
+typedef struct {\r
+  UINT8             TransformIndex;\r
+  UINT8             TransformType;\r
+  UINT16            TransformId;\r
+  IKE_SA_ATTRIBUTE  Attribute;\r
+} IKEV2_TRANSFORM_DATA;\r
+\r
+typedef struct {\r
+  UINT8                   IkeVer;\r
+  IKE_SESSION_TYPE        IkeSessionType;\r
+  BOOLEAN                 IsInitiator;\r
+  BOOLEAN                 IsOnDeleting;  // Flag to indicate whether the SA is on deleting.\r
+  IKEV2_SESSION_STATE     State;\r
+  EFI_EVENT               TimeoutEvent;\r
+  UINT64                  TimeoutInterval;\r
+  UINTN                   RetryCount;\r
+  IKE_PACKET              *LastSentPacket;\r
+  IKEV2_SA_PARAMS         *SaParams;\r
+  UINT16                  PreferDhGroup;\r
+  EFI_IP_ADDRESS          RemotePeerIp;\r
+  EFI_IP_ADDRESS          LocalPeerIp;\r
+  IKE_ON_PAYLOAD_FROM_NET BeforeDecodePayload;\r
+  IKE_ON_PAYLOAD_FROM_NET AfterEncodePayload;\r
+  IKE_UDP_SERVICE         *UdpService;\r
+  IPSEC_PRIVATE_DATA      *Private;\r
+} IKEV2_SESSION_COMMON;\r
+\r
+typedef struct {\r
+  UINT32                Signature;\r
+  IKEV2_SESSION_COMMON  SessionCommon;\r
+  UINT64                InitiatorCookie;\r
+  UINT64                ResponderCookie;\r
+  //\r
+  // Initiator: SA proposals to be sent\r
+  // Responder: SA proposals to be matched\r
+  //\r
+  IKEV2_SA_DATA         *SaData; // SA Private struct used for SA payload generation\r
+  IKEV2_SESSION_KEYS    *IkeKeys;\r
+  UINT8                 *NiBlock;\r
+  UINTN                 NiBlkSize;\r
+  UINT8                 *NrBlock;\r
+  UINTN                 NrBlkSize;\r
+  UINT8                 *NCookie;                     // Buffer Contains the Notify Cookie\r
+  UINTN                 NCookieSize;                  // Size of NCookie\r
+  IPSEC_PAD_ENTRY       *Pad;\r
+  IPSEC_SPD_ENTRY       *Spd;                         // SPD that requested the negotiation, TODO: better use SPD selector\r
+  LIST_ENTRY            ChildSaSessionList;\r
+  LIST_ENTRY            ChildSaEstablishSessionList;  // For Establish Child SA.\r
+  LIST_ENTRY            InfoMIDList;                  // For Information MID\r
+  LIST_ENTRY            DeleteSaList;                 // For deteling Child SA.\r
+  UINT8                 *InitPacket;\r
+  UINTN                 InitPacketSize;\r
+  UINT8                 *RespPacket;\r
+  UINTN                 RespPacketSize;\r
+  UINT32                MessageId;\r
+  LIST_ENTRY            BySessionTable;               // Use for all IkeSaSession Links\r
+} IKEV2_SA_SESSION;\r
+\r
+typedef struct {\r
+  UINT32                 Signature;\r
+  IKEV2_SESSION_COMMON   SessionCommon;\r
+  IKEV2_SA_SESSION       *IkeSaSession;\r
+  UINT32                 MessageId;\r
+  IKEV2_SA_DATA          *SaData;\r
+  UINT8                  IpsecProtocol;\r
+  UINT32                 LocalPeerSpi;\r
+  UINT32                 RemotePeerSpi;\r
+  UINT8                  *NiBlock;\r
+  UINTN                  NiBlkSize;\r
+  UINT8                  *NrBlock;\r
+  UINTN                  NrBlkSize;\r
+  SA_KEYMATS             ChildKeymats;\r
+  IKEV2_DH_BUFFER        *DhBuffer;    //New DH exchnaged by CREATE_CHILD_SA\r
+  IPSEC_SPD_ENTRY        *Spd;\r
+  EFI_IPSEC_SPD_SELECTOR *SpdSelector;\r
+  UINT16                 ProtoId;\r
+  UINT16                 RemotePort;\r
+  UINT16                 LocalPort;\r
+  LIST_ENTRY             ByIkeSa;\r
+  LIST_ENTRY             ByDelete;\r
+} IKEV2_CHILD_SA_SESSION;\r
+\r
+typedef enum {\r
+  Ikev2InfoNotify,\r
+  Ikev2InfoDelete,\r
+  Ikev2InfoLiveCheck\r
+} IKEV2_INFO_TYPE;\r
+\r
+//\r
+// This struct is used to pass the detail infromation to the InfoGenerator() for\r
+// the response Information Exchange Message creatation.\r
+//\r
+typedef struct {\r
+  UINT32               MessageId;\r
+  IKEV2_INFO_TYPE      InfoType;\r
+} IKEV2_INFO_EXCHANGE_CONTEXT;\r
+\r
+typedef struct {\r
+  UINTN DataSize;\r
+  UINT8 *Data;\r
+} PRF_DATA_FRAGMENT;\r
+\r
+typedef \r
+IKE_PACKET *\r
+(*IKEV2_PACKET_GENERATOR) (\r
+  IN UINT8                             *SaSession,\r
+  IN VOID                              *Context\r
+);\r
+\r
+typedef\r
+EFI_STATUS\r
+(*IKEV2_PACKET_PARSER) (\r
+  IN UINT8                             *SaSession,\r
+  IN IKE_PACKET                        *IkePacket\r
+);\r
+\r
+typedef struct {\r
+  IKEV2_PACKET_PARSER                  Parser;\r
+  IKEV2_PACKET_GENERATOR               Generator;\r
+} IKEV2_PACKET_HANDLER;\r
+\r
+extern IKEV2_PACKET_HANDLER            mIkev2Initial[][2];\r
+extern IKEV2_PACKET_HANDLER            mIkev2CreateChild;\r
+extern IKEV2_PACKET_HANDLER            mIkev2Info;\r
+\r
+#endif\r
+\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Info.c b/NetworkPkg/IpSecDxe/Ikev2/Info.c
new file mode 100644 (file)
index 0000000..d297564
--- /dev/null
@@ -0,0 +1,401 @@
+/** @file\r
+  The Implementations for Information Exchange.\r
+\r
+  Copyright (c) 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 "Utility.h"\r
+#include "IpSecDebug.h"\r
+#include "IpSecConfigImpl.h"\r
+\r
+/**\r
+  Generate Information Packet.\r
+\r
+  The information Packet may contain one Delete Payload, or Notify Payload, which \r
+  dependes on the Context's parameters.\r
+\r
+  @param[in]  SaSession   Pointer to IKE SA Session or Child SA Session which is \r
+                          related to the information Exchange.\r
+  @param[in]  Context     The Data passed from the caller. If the Context is not NULL\r
+                          it should contain the information for Notification Data.\r
+                          \r
+  @retval     Pointer of IKE_PACKET generated.\r
+\r
+**/\r
+IKE_PACKET *\r
+Ikev2InfoGenerator (\r
+  IN UINT8                         *SaSession,\r
+  IN VOID                          *Context\r
+  )\r
+{\r
+  IKEV2_SA_SESSION            *IkeSaSession;\r
+  IKEV2_CHILD_SA_SESSION      *ChildSaSession;\r
+  IKE_PACKET                  *IkePacket;\r
+  IKE_PAYLOAD                 *IkePayload;\r
+  IKEV2_INFO_EXCHANGE_CONTEXT *InfoContext;\r
+\r
+  InfoContext  = NULL;\r
+  IkeSaSession = (IKEV2_SA_SESSION *) SaSession;\r
+  IkePacket    = IkePacketAlloc ();\r
+  ASSERT (IkePacket != NULL);\r
+\r
+  //\r
+  // Fill IkePacket Header.\r
+  //\r
+  IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_INFO;\r
+  IkePacket->Header->Version         = (UINT8) (2 << 4); \r
+\r
+  if (Context != NULL) {\r
+    InfoContext = (IKEV2_INFO_EXCHANGE_CONTEXT *) Context;\r
+  }\r
+\r
+  //\r
+  // For Liveness Check\r
+  //\r
+  if (InfoContext != NULL && \r
+      (InfoContext->InfoType == Ikev2InfoLiveCheck || InfoContext->InfoType == Ikev2InfoNotify) \r
+    ) {\r
+    IkePacket->Header->MessageId       = InfoContext->MessageId;\r
+    IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;\r
+    IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;\r
+    IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_NONE;\r
+    IkePacket->Header->Flags           = IKE_HEADER_FLAGS_RESPOND;\r
+    //\r
+    // TODO: add Notify Payload for Notification Information.\r
+    //\r
+    return IkePacket;\r
+  }\r
+  \r
+  //\r
+  // For delete SAs\r
+  //  \r
+  if (IkeSaSession->SessionCommon.IkeSessionType == IkeSessionTypeIkeSa) {\r
+\r
+    IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;\r
+    IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;\r
+\r
+    //\r
+    // If the information message is response message,the MessageId should\r
+    // be same as the request MessageId which passed through the Context.\r
+    //\r
+    if (InfoContext != NULL) {\r
+      IkePacket->Header->MessageId     = InfoContext->MessageId;\r
+    } else {\r
+      IkePacket->Header->MessageId     = IkeSaSession->MessageId;\r
+      Ikev2SaSessionIncreaseMessageId (IkeSaSession);\r
+    }\r
+    //\r
+    // If the state is on deleting generate a Delete Payload for it.\r
+    //\r
+    if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting ) {\r
+      IkePayload = Ikev2GenerateDeletePayload (\r
+                     IkeSaSession, \r
+                     IKEV2_PAYLOAD_TYPE_NONE, \r
+                     0, \r
+                     0, \r
+                     NULL\r
+                     );  \r
+      if (IkePayload == NULL) {\r
+        goto ERROR_EXIT;\r
+      }\r
+      //\r
+      // Fill the next payload in IkePacket's Header.\r
+      //\r
+      IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_DELETE;\r
+      IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);\r
+      IkePacket->Private           = IkeSaSession->SessionCommon.Private;\r
+      IkePacket->Spi               = 0;\r
+      IkePacket->IsDeleteInfo      = TRUE;\r
+            \r
+    } else if (Context != NULL) {\r
+      //\r
+      // TODO: If contest is not NULL Generate a Notify Payload.\r
+      //\r
+    } else {\r
+      //\r
+      // The input parameter is not correct.\r
+      //\r
+      goto ERROR_EXIT;\r
+    } \r
+  } else {\r
+    //\r
+    // Delete the Child SA Information Exchagne\r
+    //\r
+    ChildSaSession                     = (IKEV2_CHILD_SA_SESSION *) SaSession;\r
+    IkeSaSession                       = ChildSaSession->IkeSaSession;\r
+    IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie;\r
+    IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie;\r
+\r
+    //\r
+    // If the information message is response message,the MessageId should\r
+    // be same as the request MessageId which passed through the Context.\r
+    //\r
+    if (InfoContext != NULL && InfoContext->MessageId != 0) {\r
+      IkePacket->Header->MessageId     = InfoContext->MessageId;\r
+    } else {\r
+      IkePacket->Header->MessageId     = ChildSaSession->IkeSaSession->MessageId;\r
+      Ikev2SaSessionIncreaseMessageId (IkeSaSession);\r
+    }\r
+    \r
+    IkePayload     = Ikev2GenerateDeletePayload (\r
+                       ChildSaSession->IkeSaSession,\r
+                       IKEV2_PAYLOAD_TYPE_DELETE,\r
+                       4,\r
+                       1,\r
+                       (UINT8 *)&ChildSaSession->LocalPeerSpi\r
+                       );\r
+    if (IkePayload == NULL) {\r
+      goto ERROR_EXIT;\r
+    }\r
+    //\r
+    // Fill the Next Payload in IkePacket's Header.\r
+    //\r
+    IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_DELETE;\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);\r
+\r
+    IkePacket->Private      = IkeSaSession->SessionCommon.Private;\r
+    IkePacket->Spi          = ChildSaSession->LocalPeerSpi;\r
+    IkePacket->IsDeleteInfo = TRUE;\r
+\r
+    if (!ChildSaSession->SessionCommon.IsInitiator) {\r
+      //\r
+      // If responder, use the MessageId fromt the initiator.\r
+      //\r
+      IkePacket->Header->MessageId = ChildSaSession->MessageId;\r
+    }\r
+\r
+    //\r
+    // Change the IsOnDeleting Flag\r
+    //\r
+    ChildSaSession->SessionCommon.IsOnDeleting = TRUE;\r
+  }\r
+\r
+  if (InfoContext == NULL) {\r
+    IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;\r
+  } else {\r
+    IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;\r
+  }\r
+  return IkePacket;\r
+\r
+ERROR_EXIT:\r
+   if (IkePacket != NULL) {\r
+     FreePool (IkePacket);\r
+   }\r
+   return NULL;\r
+\r
+}\r
+\r
+/**\r
+  Parse the Info Exchange.\r
+\r
+  @param[in]  SaSession   Pointer to IKEV2_SA_SESSION.\r
+  @param[in]  IkePacket   Pointer to IkePacket related to the Information Exchange.\r
+\r
+  @retval  EFI_SUCCESS    The operation finised successed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2InfoParser (\r
+  IN UINT8                         *SaSession,\r
+  IN IKE_PACKET                    *IkePacket\r
+  )\r
+{\r
+  IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
+  IKEV2_SA_SESSION       *IkeSaSession;\r
+  IKE_PAYLOAD            *NotifyPayload;\r
+  IKE_PAYLOAD            *DeletePayload;\r
+  IKE_PAYLOAD            *IkePayload;\r
+  IKEV2_DELETE           *Delete;\r
+  LIST_ENTRY             *Entry;\r
+  LIST_ENTRY             *ListEntry;\r
+  UINT8                  Index;\r
+  UINT32                 Spi;\r
+  UINT8                  *SpiBuffer;\r
+  IPSEC_PRIVATE_DATA     *Private;\r
+  UINT8                  Value;\r
+  EFI_STATUS             Status;\r
+  IKE_PACKET             *RespondPacket;\r
+  \r
+  IKEV2_INFO_EXCHANGE_CONTEXT Context;\r
+  \r
+  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;\r
+\r
+  NotifyPayload  = NULL;\r
+  DeletePayload  = NULL;\r
+  Private        = NULL;\r
+  RespondPacket  = NULL;\r
+  Status         = EFI_SUCCESS;\r
+  \r
+  //\r
+  // For Liveness Check\r
+  //\r
+  if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE &&\r
+      (IkePacket->PayloadTotalSize == 0)\r
+      ) {\r
+    if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {\r
+      //\r
+      // If it is Liveness check request, reply it.\r
+      //\r
+      Context.InfoType  = Ikev2InfoLiveCheck;\r
+      Context.MessageId = IkePacket->Header->MessageId;\r
+      RespondPacket     = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);\r
+\r
+      if (RespondPacket == NULL) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        return Status;\r
+      }\r
+      Status = Ikev2SendIkePacket (\r
+                 IkeSaSession->SessionCommon.UdpService,\r
+                 (UINT8 *)(&IkeSaSession->SessionCommon),\r
+                 RespondPacket,\r
+                 0\r
+                 );\r
+\r
+    } else {\r
+      //\r
+      // Todo: verify the liveness check response packet.\r
+      //\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // For SA Delete\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {   \r
+\r
+  //\r
+  // Iterate payloads to find the Delete/Notify Payload.\r
+  //\r
+    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+    \r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_DELETE) {\r
+      DeletePayload = IkePayload;\r
+      Delete = (IKEV2_DELETE *)DeletePayload->PayloadBuf;\r
+\r
+      if (Delete->SpiSize == 0) {\r
+        //\r
+        // Delete IKE SA.\r
+        //\r
+        if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) {\r
+          RemoveEntryList (&IkeSaSession->BySessionTable);\r
+          Ikev2SaSessionFree (IkeSaSession);\r
+          //\r
+          // Checking the Private status.\r
+          //\r
+          //\r
+          // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec\r
+          // status should be changed.\r
+          //\r
+          Private = IkeSaSession->SessionCommon.Private;\r
+          if (Private != NULL && Private->IsIPsecDisabling) {\r
+            //\r
+            // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in\r
+            // IPsec status variable.\r
+            //\r
+            if (IsListEmpty (&Private->Ikev1EstablishedList) && \r
+                (IsListEmpty (&Private->Ikev2EstablishedList))\r
+               ) {\r
+              Value  = IPSEC_STATUS_DISABLED;\r
+              Status = gRT->SetVariable (\r
+                         IPSECCONFIG_STATUS_NAME,\r
+                         &gEfiIpSecConfigProtocolGuid,\r
+                         EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                         sizeof (Value),\r
+                         &Value\r
+                         );\r
+              if (!EFI_ERROR (Status)) {\r
+                //\r
+                // Set the DisabledFlag in Private data.\r
+                //\r
+                Private->IpSec.DisabledFlag = TRUE;\r
+                Private->IsIPsecDisabling   = FALSE;\r
+              }\r
+            }\r
+          }\r
+        } else {\r
+          IkeSaSession->SessionCommon.State = IkeStateSaDeleting;\r
+          Context.InfoType                  = Ikev2InfoDelete;\r
+          Context.MessageId                 = IkePacket->Header->MessageId;\r
+\r
+          RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);\r
+          if (RespondPacket == NULL) {\r
+            Status = EFI_INVALID_PARAMETER;\r
+            return Status;\r
+          }\r
+          Status = Ikev2SendIkePacket (\r
+                     IkeSaSession->SessionCommon.UdpService, \r
+                     (UINT8 *)(&IkeSaSession->SessionCommon), \r
+                     RespondPacket, \r
+                     0\r
+                     );\r
+        }\r
+      } else if (Delete->SpiSize == 4) {\r
+        //\r
+        // Move the Child SAs to DeleteList\r
+        //\r
+        SpiBuffer = (UINT8 *)(Delete + 1);\r
+        for (Index = 0; Index < Delete->NumSpis; Index++) {\r
+          Spi = ReadUnaligned32 ((UINT32 *)SpiBuffer);\r
+          for (ListEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;\r
+               ListEntry != &IkeSaSession->ChildSaEstablishSessionList;\r
+          ) {\r
+            ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ListEntry);\r
+            ListEntry = ListEntry->ForwardLink;\r
+\r
+            if (ChildSaSession->RemotePeerSpi == HTONL(Spi)) {\r
+              if (ChildSaSession->SessionCommon.State != IkeStateSaDeleting) {\r
+\r
+                //\r
+                // Insert the ChildSa Session into Delete List.\r
+                //\r
+                InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete);\r
+                ChildSaSession->SessionCommon.State       = IkeStateSaDeleting;\r
+                ChildSaSession->SessionCommon.IsInitiator = FALSE;\r
+                ChildSaSession->MessageId                 = IkePacket->Header->MessageId;\r
+\r
+                Context.InfoType = Ikev2InfoDelete;\r
+                Context.MessageId = IkePacket->Header->MessageId;\r
+          \r
+                RespondPacket = Ikev2InfoGenerator ((UINT8 *)ChildSaSession, &Context);\r
+                if (RespondPacket == NULL) {\r
+                  Status = EFI_INVALID_PARAMETER;\r
+                  return Status;\r
+                }\r
+                Status = Ikev2SendIkePacket (\r
+                           ChildSaSession->SessionCommon.UdpService,\r
+                           (UINT8 *)(&ChildSaSession->SessionCommon),\r
+                           RespondPacket, \r
+                           0\r
+                           );\r
+              } else {\r
+                //\r
+                // Delete the Child SA.\r
+                //\r
+                Ikev2ChildSaSilentDelete (IkeSaSession, Spi);\r
+                RemoveEntryList (&ChildSaSession->ByDelete);\r
+              }\r
+            }\r
+          }\r
+          SpiBuffer = SpiBuffer + sizeof (Spi);\r
+        }\r
+      }\r
+    }\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER  mIkev2Info = {\r
+  Ikev2InfoParser,\r
+  Ikev2InfoGenerator\r
+};\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Payload.c b/NetworkPkg/IpSecDxe/Ikev2/Payload.c
new file mode 100644 (file)
index 0000000..35bebf7
--- /dev/null
@@ -0,0 +1,3227 @@
+/** @file\r
+  The implementation of Payloads Creation.\r
+\r
+  Copyright (c) 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 "Utility.h"\r
+#include "IpSecDebug.h"\r
+#include "IpSecConfigImpl.h"\r
+#include "IpSecCryptIo.h"\r
+\r
+//\r
+// The Constant String of "Key Pad for IKEv2" for Authentication Payload generation. \r
+//\r
+#define CONSTANT_KEY_SIZE     17\r
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mConstantKey[CONSTANT_KEY_SIZE] = \r
+{\r
+  'K', 'e', 'y', ' ', 'P', 'a', 'd', ' ', 'f', 'o', 'r', ' ', 'I', 'K', 'E', 'v', '2'\r
+};\r
+\r
+/**\r
+  Generate Ikev2 SA payload according to SessionSaData\r
+\r
+  @param[in] SessionSaData   The data used in SA payload.\r
+  @param[in] NextPayload     The payload type presented in NextPayload field of \r
+                             SA Payload header.\r
+  @param[in] Type            The SA type. It MUST be neither (1) for IKE_SA or\r
+                             (2) for CHILD_SA or (3) for INFO.\r
+\r
+  @retval a Pointer to SA IKE payload.\r
+  \r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateSaPayload (\r
+  IN IKEV2_SA_DATA    *SessionSaData,\r
+  IN UINT8            NextPayload,\r
+  IN IKE_SESSION_TYPE Type\r
+  )\r
+{\r
+  IKE_PAYLOAD   *SaPayload;\r
+  IKEV2_SA_DATA *SaData;\r
+  UINTN         SaDataSize;\r
+\r
+  SaPayload = IkePayloadAlloc ();\r
+  ASSERT (SaPayload != NULL);\r
+  //\r
+  // TODO: Get the Proposal Number and Transform Number from IPsec Config,\r
+  // after the Ipsecconfig Application is support it.\r
+  //\r
+  \r
+  if (Type == IkeSessionTypeIkeSa) {\r
+    SaDataSize = sizeof (IKEV2_SA_DATA) + \r
+                 SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) +\r
+                 sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 4;\r
+  } else {\r
+    SaDataSize = sizeof (IKEV2_SA_DATA) + \r
+                 SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) +\r
+                 sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 3;\r
+             \r
+  }\r
+\r
+  SaData = AllocateZeroPool (SaDataSize);\r
+  ASSERT (SaData != NULL);\r
+\r
+  CopyMem (SaData, SessionSaData, SaDataSize);\r
+  SaData->SaHeader.Header.NextPayload = NextPayload;\r
+  SaPayload->PayloadType              = IKEV2_PAYLOAD_TYPE_SA;\r
+  SaPayload->PayloadBuf               = (UINT8 *) SaData;\r
+\r
+  return SaPayload;\r
+}\r
+\r
+/**\r
+  Generate a Nonce payload containing the input parameter NonceBuf.\r
+\r
+  @param[in]  NonceBuf      The nonce buffer contains the whole Nonce payload block \r
+                            except the payload header.\r
+  @param[in]  NonceSize     The buffer size of the NonceBuf\r
+  @param[in]  NextPayload   The payload type presented in the NextPayload field \r
+                            of Nonce Payload header.\r
+\r
+  @retval Pointer to Nonce IKE paload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateNoncePayload (\r
+  IN UINT8            *NonceBuf,\r
+  IN UINTN            NonceSize,\r
+  IN UINT8            NextPayload\r
+  )\r
+{\r
+  IKE_PAYLOAD *NoncePayload;\r
+  IKEV2_NONCE *Nonce;\r
+  UINTN       Size;\r
+  UINT8       *NonceBlock;\r
+\r
+  //                           1                   2                   3\r
+  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    !                                                               !\r
+  //    ~                            Nonce Data                         ~\r
+  //    !                                                               !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+  Size        = sizeof (IKEV2_NONCE) + NonceSize;\r
+  NonceBlock  = NonceBuf;\r
+\r
+  Nonce       = AllocateZeroPool (Size);\r
+  ASSERT (Nonce != NULL);\r
+  CopyMem (Nonce + 1, NonceBlock, Size - sizeof (IKEV2_NONCE));\r
+\r
+  Nonce->Header.NextPayload   = NextPayload;\r
+  Nonce->Header.PayloadLength = (UINT16) Size;\r
+  NoncePayload                = IkePayloadAlloc ();\r
+\r
+  ASSERT (NoncePayload != NULL);\r
+  NoncePayload->PayloadType = IKEV2_PAYLOAD_TYPE_NONCE;\r
+  NoncePayload->PayloadBuf  = (UINT8 *) Nonce;\r
+  NoncePayload->PayloadSize = Size;\r
+\r
+  return NoncePayload;\r
+}\r
+\r
+/**\r
+  Generate a Key Exchange payload according to the DH group type and save the \r
+  public Key into IkeSaSession IkeKey field.\r
+\r
+  @param[in, out] IkeSaSession    Pointer of the IKE_SA_SESSION.\r
+  @param[in]      NextPayload     The payload type presented in the NextPayload field of Key \r
+                                  Exchange Payload header.\r
+\r
+  @retval Pointer to Key IKE payload.\r
+\r
+**/\r
+IKE_PAYLOAD*\r
+Ikev2GenerateKePayload (\r
+  IN OUT IKEV2_SA_SESSION *IkeSaSession,\r
+  IN     UINT8            NextPayload\r
+  )\r
+{\r
+  IKE_PAYLOAD         *KePayload;\r
+  IKEV2_KEY_EXCHANGE  *Ke;\r
+  UINTN               KeSize;\r
+  IKEV2_SESSION_KEYS  *IkeKeys;\r
+\r
+  //\r
+  //                        1                   2                   3\r
+  //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   ! Next Payload  !C!  RESERVED   !         Payload Length        !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   !          DH Group #           !           RESERVED            !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   !                                                               !\r
+  //   ~                       Key Exchange Data                       ~\r
+  //   !                                                               !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+  IkeKeys = IkeSaSession->IkeKeys;\r
+\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize;\r
+  } else {\r
+    KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize;\r
+  }\r
+  \r
+  //\r
+  // Allocate buffer for Key Exchange\r
+  //\r
+  Ke = AllocateZeroPool (KeSize);\r
+  ASSERT (Ke != NULL);\r
+\r
+  Ke->Header.NextPayload    = NextPayload;\r
+  Ke->Header.PayloadLength  = (UINT16) KeSize;\r
+  Ke->DhGroup               = IkeSaSession->SessionCommon.PreferDhGroup;\r
+\r
+  CopyMem (Ke + 1, IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize);\r
+  \r
+  //\r
+  // Create IKE_PAYLOAD to point to Key Exchange payload  \r
+  //  \r
+  KePayload = IkePayloadAlloc ();\r
+  ASSERT (KePayload != NULL);\r
+  \r
+  KePayload->PayloadType = IKEV2_PAYLOAD_TYPE_KE;\r
+  KePayload->PayloadBuf  = (UINT8 *) Ke;\r
+  KePayload->PayloadSize = KeSize;\r
+  return KePayload;\r
+}\r
+\r
+/**\r
+  Generate a ID payload.\r
+\r
+  @param[in] CommonSession   Pointer to IKEV2_SESSION_COMMON related to ID payload.\r
+  @param[in] NextPayload     The payload type presented in the NextPayload field \r
+                             of ID Payload header.\r
+\r
+  @retval Pointer to ID IKE payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateIdPayload (\r
+  IN IKEV2_SESSION_COMMON *CommonSession,\r
+  IN UINT8                NextPayload\r
+  )\r
+{\r
+  IKE_PAYLOAD    *IdPayload;\r
+  IKEV2_ID       *Id;\r
+  UINTN          IdSize;\r
+  UINT8          IpVersion;\r
+  UINT8          AddrSize;\r
+\r
+  //\r
+  // ID payload\r
+  //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   ! Next Payload  !   RESERVED    !         Payload Length        !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   !   ID Type     !             RESERVED                          !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   !                                                               !\r
+  //   ~                   Identification Data                         ~\r
+  //   !                                                               !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+  \r
+  IpVersion = CommonSession->UdpService->IpVersion;\r
+  AddrSize  = (UINT8) ((IpVersion == IP_VERSION_4) ? sizeof(EFI_IPv4_ADDRESS) : sizeof(EFI_IPv6_ADDRESS));\r
+  IdSize    = sizeof (IKEV2_ID) + AddrSize;\r
+\r
+  Id = (IKEV2_ID *) AllocateZeroPool (IdSize);\r
+  ASSERT (Id != NULL);\r
+\r
+  IdPayload = IkePayloadAlloc ();\r
+  ASSERT (IdPayload != NULL);\r
+\r
+  IdPayload->PayloadType  = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP);\r
+  IdPayload->PayloadBuf   = (UINT8 *) Id;\r
+  IdPayload->PayloadSize  = IdSize;\r
+\r
+  //\r
+  // Set generic header of identification payload \r
+  //\r
+  Id->Header.NextPayload    = NextPayload;\r
+  Id->Header.PayloadLength  = (UINT16) IdSize;\r
+  Id->IdType                = (UINT8) ((IpVersion == IP_VERSION_4) ? IKEV2_ID_TYPE_IPV4_ADDR : IKEV2_ID_TYPE_IPV6_ADDR);\r
+  CopyMem (Id + 1, &CommonSession->LocalPeerIp, AddrSize);\r
+\r
+  return IdPayload;\r
+}\r
+\r
+/**\r
+  Generate a ID payload.\r
+\r
+  @param[in] CommonSession   Pointer to IKEV2_SESSION_COMMON related to ID payload.\r
+  @param[in] NextPayload     The payload type presented in the NextPayload field \r
+                             of ID Payload header.\r
+  @param[in] InCert          Pointer to the Certificate which distinguished name\r
+                             will be added into the Id payload.\r
+  @param[in] CertSize        Size of the Certificate.\r
+\r
+  @retval Pointer to ID IKE payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateCertIdPayload (\r
+  IN IKEV2_SESSION_COMMON *CommonSession,\r
+  IN UINT8                NextPayload,\r
+  IN UINT8                *InCert,\r
+  IN UINTN                CertSize\r
+  )\r
+{\r
+  IKE_PAYLOAD    *IdPayload;\r
+  IKEV2_ID       *Id;\r
+  UINTN          IdSize;\r
+  UINT8          IpVersion;\r
+  UINTN          SubjectSize;\r
+  UINT8          *CertSubject;\r
+  \r
+  //\r
+  // ID payload\r
+  //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   ! Next Payload  !   RESERVED    !         Payload Length        !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   !   ID Type     !             RESERVED                          !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   !                                                               !\r
+  //   ~                   Identification Data                         ~\r
+  //   !                                                               !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+\r
+  SubjectSize = 0;\r
+  CertSubject = NULL;\r
+  IpVersion = CommonSession->UdpService->IpVersion;\r
+  IpSecCryptoIoGetSubjectFromCert (\r
+    InCert,\r
+    CertSize,\r
+    &CertSubject,\r
+    &SubjectSize\r
+    );\r
+\r
+  IdSize = sizeof (IKEV2_ID) + SubjectSize;\r
+\r
+  Id = (IKEV2_ID *) AllocateZeroPool (IdSize);\r
+  ASSERT (Id != NULL);\r
+\r
+  IdPayload = IkePayloadAlloc ();\r
+  ASSERT (IdPayload != NULL);\r
+\r
+  IdPayload->PayloadType  = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP);\r
+  IdPayload->PayloadBuf   = (UINT8 *) Id;\r
+  IdPayload->PayloadSize  = IdSize;\r
+\r
+  //\r
+  // Set generic header of identification payload \r
+  //\r
+  Id->Header.NextPayload    = NextPayload;\r
+  Id->Header.PayloadLength  = (UINT16) IdSize;\r
+  Id->IdType                = 9;\r
+  CopyMem (Id + 1, CertSubject, SubjectSize);\r
+\r
+  if (CertSubject != NULL) {\r
+    FreePool (CertSubject);\r
+  }\r
+  return IdPayload;\r
+}\r
+\r
+/**\r
+  Generate a Authentication Payload.\r
+\r
+  This function is used for both Authentication generation and verification. When the \r
+  IsVerify is TRUE, it create a Auth Data for verification. This function choose the \r
+  related IKE_SA_INIT Message for Auth data creation according to the IKE Session's type\r
+  and the value of IsVerify parameter.\r
+\r
+  @param[in]  IkeSaSession  Pointer to IKEV2_SA_SESSION related to.\r
+  @param[in]  IdPayload     Pointer to the ID payload to be used for Authentication \r
+                            payload generation.\r
+  @param[in]  NextPayload   The type filled into the Authentication Payload next \r
+                            payload field.\r
+  @param[in]  IsVerify      If it is TURE, the Authentication payload is used for\r
+                            verification.\r
+\r
+  @return pointer to IKE Authentication payload for Pre-shared key method.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2PskGenerateAuthPayload (\r
+  IN IKEV2_SA_SESSION *IkeSaSession,\r
+  IN IKE_PAYLOAD      *IdPayload,\r
+  IN UINT8            NextPayload,\r
+  IN BOOLEAN          IsVerify\r
+  )\r
+{\r
+  UINT8              *Digest;\r
+  UINTN              DigestSize;\r
+  PRF_DATA_FRAGMENT  Fragments[3];\r
+  UINT8              *KeyBuf;\r
+  UINTN              KeySize;\r
+  IKE_PAYLOAD        *AuthPayload;\r
+  IKEV2_AUTH         *PayloadBuf;\r
+  EFI_STATUS         Status;\r
+\r
+  //\r
+  // Auth = Prf(Prf(Secret,"Key Pad for IKEv2),IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))\r
+  //\r
+  //                           1                   2                   3\r
+  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Auth Method   !                RESERVED                       !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    !                                                               !\r
+  //    ~                      Authentication Data                      ~\r
+  //    !                                                               !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
\r
+  KeyBuf      = NULL;\r
+  AuthPayload = NULL;\r
+  Digest      = NULL;\r
+  \r
+  DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf);\r
+  Digest     = AllocateZeroPool (DigestSize);\r
+\r
+  if (Digest == NULL) {\r
+    return NULL;\r
+  }\r
+  if (IdPayload == NULL) {\r
+    return NULL;\r
+  }\r
+  //\r
+  // Calcualte Prf(Seceret, "Key Pad for IKEv2");\r
+  //\r
+  Fragments[0].Data     = (UINT8 *) mConstantKey;\r
+  Fragments[0].DataSize = CONSTANT_KEY_SIZE;\r
+\r
+  Status = IpSecCryptoIoHmac (\r
+             (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,\r
+             IkeSaSession->Pad->Data->AuthData,\r
+             IkeSaSession->Pad->Data->AuthDataSize,             \r
+             (HASH_DATA_FRAGMENT *)Fragments,\r
+             1,\r
+             Digest,\r
+             DigestSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Store the AuthKey into KeyBuf\r
+  //\r
+  KeyBuf = AllocateZeroPool (DigestSize);\r
+  ASSERT (KeyBuf != NULL);\r
+  CopyMem (KeyBuf, Digest, DigestSize);\r
+  KeySize = DigestSize;\r
+\r
+  //\r
+  // Calculate Prf(SK_Pi/r, IDi/r)\r
+  //\r
+  Fragments[0].Data     = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER);\r
+  Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);\r
+\r
+  if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||\r
+      (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)\r
+     ) {\r
+     Status = IpSecCryptoIoHmac (\r
+                (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,\r
+                IkeSaSession->IkeKeys->SkPrKey,\r
+                IkeSaSession->IkeKeys->SkPrKeySize,\r
+                (HASH_DATA_FRAGMENT *) Fragments,\r
+                1,\r
+                Digest,\r
+                DigestSize\r
+                );\r
+  } else {\r
+    Status = IpSecCryptoIoHmac (\r
+               (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,\r
+               IkeSaSession->IkeKeys->SkPiKey,\r
+               IkeSaSession->IkeKeys->SkPiKeySize,\r
+               (HASH_DATA_FRAGMENT *) Fragments,\r
+               1,\r
+               Digest,\r
+               DigestSize\r
+               );\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Copy data to Fragments.\r
+  //\r
+  if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||\r
+      (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)\r
+     )  {\r
+    Fragments[0].Data     = IkeSaSession->RespPacket;\r
+    Fragments[0].DataSize = IkeSaSession->RespPacketSize;\r
+    Fragments[1].Data     = IkeSaSession->NiBlock;\r
+    Fragments[1].DataSize = IkeSaSession->NiBlkSize;\r
+  } else {\r
+    Fragments[0].Data     = IkeSaSession->InitPacket;\r
+    Fragments[0].DataSize = IkeSaSession->InitPacketSize;\r
+    Fragments[1].Data     = IkeSaSession->NrBlock;\r
+    Fragments[1].DataSize = IkeSaSession->NrBlkSize;\r
+  }\r
+\r
+  //\r
+  // Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2].\r
+  // \r
+  Fragments[2].Data     = AllocateZeroPool (DigestSize);\r
+  Fragments[2].DataSize = DigestSize;\r
+  CopyMem (Fragments[2].Data, Digest, DigestSize);\r
+\r
+  //\r
+  // Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))\r
+  //\r
+  Status = IpSecCryptoIoHmac (\r
+             (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,\r
+             KeyBuf,\r
+             KeySize,\r
+             (HASH_DATA_FRAGMENT *) Fragments,\r
+             3,\r
+             Digest,\r
+             DigestSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer for Auth Payload\r
+  //\r
+  AuthPayload               = IkePayloadAlloc ();\r
+  ASSERT (AuthPayload != NULL);\r
+\r
+  AuthPayload->PayloadSize  = sizeof (IKEV2_AUTH) + DigestSize;\r
+  PayloadBuf                = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize);\r
+  ASSERT (PayloadBuf != NULL);\r
+  //\r
+  // Fill in Auth payload.\r
+  //\r
+  PayloadBuf->Header.NextPayload   = NextPayload;\r
+  PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize);\r
+  if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodPreSharedSecret) {\r
+    //\r
+    // Only support Shared Key Message Integrity\r
+    //\r
+    PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_SKMI;\r
+  } else {\r
+    //\r
+    // Not support other Auth method.\r
+    //\r
+    Status = EFI_UNSUPPORTED;\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth\r
+  // payload block.\r
+  //\r
+  CopyMem (\r
+    PayloadBuf + 1,\r
+    Digest,\r
+    DigestSize\r
+    );\r
+  \r
+  //\r
+  // Fill in IKE_PACKET\r
+  //\r
+  AuthPayload->PayloadBuf   = (UINT8 *) PayloadBuf;\r
+  AuthPayload->PayloadType  = IKEV2_PAYLOAD_TYPE_AUTH;\r
+\r
+EXIT:\r
+  if (KeyBuf != NULL) {\r
+    FreePool (KeyBuf);\r
+  }\r
+  if (Digest != NULL) {\r
+    FreePool (Digest);\r
+  }\r
+  if (Fragments[2].Data != NULL) {\r
+    //\r
+    // Free the buffer which contains the result of Prf(SK_Pr, IDi/r)\r
+    //     \r
+    FreePool (Fragments[2].Data);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (AuthPayload != NULL) {\r
+      IkePayloadFree (AuthPayload);\r
+    }\r
+    return NULL;\r
+  } else {\r
+    return AuthPayload;\r
+  }\r
+}\r
+\r
+/**\r
+  Generate a Authentication Payload for Certificate Auth method.  \r
+\r
+  This function has two functions. One is creating a local Authentication \r
+  Payload for sending and other is creating the remote Authentication data \r
+  for verification when the IsVerify is TURE.\r
+\r
+  @param[in]  IkeSaSession      Pointer to IKEV2_SA_SESSION related to.\r
+  @param[in]  IdPayload         Pointer to the ID payload to be used for Authentication \r
+                                payload generation.\r
+  @param[in]  NextPayload       The type filled into the Authentication Payload \r
+                                next payload field.\r
+  @param[in]  IsVerify          If it is TURE, the Authentication payload is used \r
+                                for verification.\r
+  @param[in]  UefiPrivateKey    Pointer to the UEFI private key. Ignore it when \r
+                                verify the authenticate payload.\r
+  @param[in]  UefiPrivateKeyLen The size of UefiPrivateKey in bytes. Ignore it \r
+                                when verify the authenticate payload.\r
+  @param[in]  UefiKeyPwd        Pointer to the password of UEFI private key. \r
+                                Ignore it when verify the authenticate payload.\r
+  @param[in]  UefiKeyPwdLen     The size of UefiKeyPwd in bytes.Ignore it when \r
+                                verify the authenticate payload.\r
+\r
+  @return pointer to IKE Authentication payload for Cerifitcation method.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2CertGenerateAuthPayload (\r
+  IN IKEV2_SA_SESSION *IkeSaSession,\r
+  IN IKE_PAYLOAD      *IdPayload,\r
+  IN UINT8            NextPayload,\r
+  IN BOOLEAN          IsVerify,\r
+  IN UINT8            *UefiPrivateKey,\r
+  IN UINTN            UefiPrivateKeyLen,\r
+  IN UINT8            *UefiKeyPwd,\r
+  IN UINTN            UefiKeyPwdLen\r
+  )\r
+{\r
+  UINT8              *Digest;\r
+  UINTN              DigestSize;\r
+  PRF_DATA_FRAGMENT  Fragments[3];\r
+  UINT8              *KeyBuf;\r
+  UINTN              KeySize;\r
+  IKE_PAYLOAD        *AuthPayload;\r
+  IKEV2_AUTH         *PayloadBuf;\r
+  EFI_STATUS         Status;\r
+  UINT8              *Signature;\r
+  UINTN              SigSize;\r
+\r
+  //\r
+  // Auth = Prf(Scert,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))\r
+  //\r
+  //                           1                   2                   3\r
+  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Auth Method   !                RESERVED                       !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    !                                                               !\r
+  //    ~                      Authentication Data                      ~\r
+  //    !                                                               !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+  //\r
+  // Initial point\r
+  //\r
+  KeyBuf      = NULL;\r
+  AuthPayload = NULL;\r
+  Digest      = NULL;\r
+  Signature   = NULL;\r
+  SigSize     = 0;\r
+\r
+  if (IdPayload == NULL) {\r
+    return NULL;\r
+  }\r
+  DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf);\r
+  Digest     = AllocateZeroPool (DigestSize);\r
+\r
+  if (Digest == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Store the AuthKey into KeyBuf\r
+  //\r
+  KeyBuf  = AllocateZeroPool (DigestSize);\r
+  ASSERT (KeyBuf != NULL);\r
+\r
+  CopyMem (KeyBuf, Digest, DigestSize);\r
+  KeySize = DigestSize;\r
+\r
+  //\r
+  // Calculate Prf(SK_Pi/r, IDi/r)\r
+  //\r
+  Fragments[0].Data     = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER);\r
+  Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);\r
+\r
+  IpSecDumpBuf ("RestofIDPayload", Fragments[0].Data, Fragments[0].DataSize);\r
+\r
+  if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||\r
+      (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)\r
+     ) {\r
+     Status = IpSecCryptoIoHmac(\r
+                (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,\r
+                IkeSaSession->IkeKeys->SkPrKey,\r
+                IkeSaSession->IkeKeys->SkPrKeySize,\r
+                (HASH_DATA_FRAGMENT *) Fragments,\r
+                1,\r
+                Digest,\r
+                DigestSize\r
+                );\r
+    IpSecDumpBuf ("MACedIDForR", Digest, DigestSize);\r
+  } else {\r
+    Status = IpSecCryptoIoHmac (\r
+               (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,\r
+               IkeSaSession->IkeKeys->SkPiKey,\r
+               IkeSaSession->IkeKeys->SkPiKeySize,\r
+               (HASH_DATA_FRAGMENT *) Fragments,\r
+               1,\r
+               Digest,\r
+               DigestSize\r
+               );\r
+    IpSecDumpBuf ("MACedIDForI", Digest, DigestSize);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Copy data to Fragments.\r
+  //\r
+  if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||\r
+      (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)\r
+     )  {\r
+    Fragments[0].Data     = IkeSaSession->RespPacket;\r
+    Fragments[0].DataSize = IkeSaSession->RespPacketSize;\r
+    Fragments[1].Data     = IkeSaSession->NiBlock;\r
+    Fragments[1].DataSize = IkeSaSession->NiBlkSize;\r
+    IpSecDumpBuf ("RealMessage2", Fragments[0].Data, Fragments[0].DataSize);\r
+    IpSecDumpBuf ("NonceIDdata", Fragments[1].Data, Fragments[1].DataSize);\r
+  } else {\r
+    Fragments[0].Data     = IkeSaSession->InitPacket;\r
+    Fragments[0].DataSize = IkeSaSession->InitPacketSize;\r
+    Fragments[1].Data     = IkeSaSession->NrBlock;\r
+    Fragments[1].DataSize = IkeSaSession->NrBlkSize;\r
+    IpSecDumpBuf ("RealMessage1", Fragments[0].Data, Fragments[0].DataSize);\r
+    IpSecDumpBuf ("NonceRDdata", Fragments[1].Data, Fragments[1].DataSize);\r
+  }\r
+  \r
+  //\r
+  // Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2].\r
+  // \r
+  Fragments[2].Data     = AllocateZeroPool (DigestSize);\r
+  Fragments[2].DataSize = DigestSize;\r
+  CopyMem (Fragments[2].Data, Digest, DigestSize);\r
+\r
+  //\r
+  // Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))\r
+  //\r
+  Status = IpSecCryptoIoHash (\r
+             (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,\r
+             (HASH_DATA_FRAGMENT *) Fragments,\r
+             3,\r
+             Digest,\r
+             DigestSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto EXIT;\r
+  }\r
+\r
+  IpSecDumpBuf ("HashSignedOctects", Digest, DigestSize);\r
+  //\r
+  // Sign the data by the private Key  \r
+  //\r
+  if (!IsVerify) {\r
+    IpSecCryptoIoAuthDataWithCertificate (\r
+      Digest,\r
+      DigestSize,\r
+      UefiPrivateKey,\r
+      UefiPrivateKeyLen,\r
+      UefiKeyPwd,\r
+      UefiKeyPwdLen,\r
+      &Signature,\r
+      &SigSize\r
+      );\r
+\r
+    if (SigSize == 0) {\r
+      goto EXIT;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Allocate buffer for Auth Payload\r
+  //\r
+  AuthPayload = IkePayloadAlloc ();\r
+  ASSERT (AuthPayload != NULL);\r
+\r
+  if (!IsVerify) {\r
+    AuthPayload->PayloadSize  = sizeof (IKEV2_AUTH) + SigSize;\r
+  } else {\r
+    AuthPayload->PayloadSize  = sizeof (IKEV2_AUTH) + DigestSize;\r
+  }\r
+\r
+  PayloadBuf = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize);\r
+  ASSERT (PayloadBuf != NULL);\r
+  //\r
+  // Fill in Auth payload.\r
+  //\r
+  PayloadBuf->Header.NextPayload   = NextPayload;\r
+  PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize);\r
+  if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodCertificates) {\r
+      PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_RSA;\r
+  } else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto EXIT;\r
+  }\r
+\r
+  //\r
+  // Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth\r
+  // payload block.\r
+  //\r
+  if (!IsVerify) {\r
+    CopyMem (PayloadBuf + 1, Signature, SigSize);\r
+  } else {\r
+    CopyMem (PayloadBuf + 1, Digest, DigestSize);\r
+  }\r
+\r
+  //\r
+  // Fill in IKE_PACKET\r
+  //\r
+  AuthPayload->PayloadBuf   = (UINT8 *) PayloadBuf;\r
+  AuthPayload->PayloadType  = IKEV2_PAYLOAD_TYPE_AUTH;\r
+\r
+EXIT:\r
+  if (KeyBuf != NULL) {\r
+    FreePool (KeyBuf);\r
+  }\r
+  if (Digest != NULL) {\r
+    FreePool (Digest);\r
+  }\r
+  if (Signature != NULL) {\r
+    FreePool (Signature);\r
+  }\r
+  if (Fragments[2].Data != NULL) {\r
+    //\r
+    // Free the buffer which contains the result of Prf(SK_Pr, IDi/r)\r
+    //     \r
+    FreePool (Fragments[2].Data);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (AuthPayload != NULL) {\r
+      IkePayloadFree (AuthPayload);\r
+    }\r
+    return NULL;\r
+  } else {\r
+    return AuthPayload;\r
+  }\r
+}\r
+\r
+/**\r
+  Generate TS payload.\r
+\r
+  This function generates TSi or TSr payload according to type of next payload.\r
+  If the next payload is Responder TS, gereate TSi Payload. Otherwise, generate\r
+  TSr payload.\r
+  \r
+  @param[in] ChildSa        Pointer to IKEV2_CHILD_SA_SESSION related to this TS payload.\r
+  @param[in] NextPayload    The payload type presented in the NextPayload field \r
+                            of ID Payload header.\r
+  @param[in] IsTunnel       It indicates that if the Ts Payload is after the CP payload.\r
+                            If yes, it means the Tsi and Tsr payload should be with\r
+                            Max port range and address range and protocol is marked\r
+                            as zero.\r
+\r
+  @retval Pointer to Ts IKE payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateTsPayload (\r
+  IN IKEV2_CHILD_SA_SESSION *ChildSa,\r
+  IN UINT8                  NextPayload,\r
+  IN BOOLEAN                IsTunnel\r
+  )\r
+{\r
+  IKE_PAYLOAD        *TsPayload;\r
+  IKEV2_TS           *TsPayloadBuf;\r
+  TRAFFIC_SELECTOR   *TsSelector;\r
+  UINTN              SelectorSize;\r
+  UINTN              TsPayloadSize;\r
+  UINT8              IpVersion;\r
+  UINT8              AddrSize;\r
+\r
+  //\r
+  //                           1                   2                   3\r
+  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Number of TSs !                 RESERVED                      !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    !                                                               !\r
+  //    ~                       <Traffic Selectors>                     ~\r
+  //    !                                                               !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+\r
+  TsPayload    = IkePayloadAlloc();\r
+  ASSERT (TsPayload != NULL);\r
+\r
+  IpVersion    = ChildSa->SessionCommon.UdpService->IpVersion;\r
+  //\r
+  // The Starting Address and Ending Address is variable length depends on \r
+  // is IPv4 or IPv6\r
+  //\r
+  AddrSize      = (UINT8)((IpVersion == IP_VERSION_4) ? sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS));\r
+  SelectorSize  = sizeof (TRAFFIC_SELECTOR) + 2 * AddrSize;\r
+  TsPayloadSize = sizeof (IKEV2_TS) + SelectorSize;\r
+  TsPayloadBuf = AllocateZeroPool (TsPayloadSize);\r
+  ASSERT (TsPayloadBuf != NULL);\r
+\r
+  TsPayload->PayloadBuf = (UINT8 *) TsPayloadBuf;\r
+  TsSelector            = (TRAFFIC_SELECTOR*)(TsPayloadBuf + 1);\r
+\r
+  TsSelector->TSType = (UINT8)((IpVersion == IP_VERSION_4) ? IKEV2_TS_TYPE_IPV4_ADDR_RANGE : IKEV2_TS_TYPS_IPV6_ADDR_RANGE);\r
+\r
+  //\r
+  // For tunnel mode \r
+  //\r
+  if (IsTunnel) {\r
+    TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL;\r
+    TsSelector->SelecorLen   = (UINT16) SelectorSize;\r
+    TsSelector->StartPort    = 0;\r
+    TsSelector->EndPort      = IKEV2_TS_ANY_PORT;\r
+    ZeroMem ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR), AddrSize);\r
+    SetMem  ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize, AddrSize, 0xff);\r
+\r
+  } else {\r
+    //\r
+    // TODO: Support port range and address range\r
+    //\r
+    if (NextPayload == IKEV2_PAYLOAD_TYPE_TS_RSP){\r
+      //\r
+      // Create initiator Traffic Selector \r
+      //      \r
+      TsSelector->SelecorLen   = (UINT16)SelectorSize;\r
+\r
+      //\r
+      // Currently only support the port range from 0~0xffff. Don't support other\r
+      // port range.\r
+      // TODO: support Port range\r
+      //\r
+      if (ChildSa->SessionCommon.IsInitiator) {\r
+        if (ChildSa->Spd->Selector->LocalPort != 0 &&\r
+            ChildSa->Spd->Selector->LocalPortRange == 0) {\r
+          //  \r
+          // For not port range.\r
+          //\r
+          TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort;\r
+          TsSelector->EndPort   = ChildSa->Spd->Selector->LocalPort;\r
+        } else if (ChildSa->Spd->Selector->LocalPort == 0){\r
+          //\r
+          // For port from 0~0xffff\r
+          //\r
+          TsSelector->StartPort = 0;\r
+          TsSelector->EndPort   = IKEV2_TS_ANY_PORT;\r
+        } else {\r
+          //\r
+          // Not support now.\r
+          //\r
+          goto ON_ERROR;\r
+        }\r
+      } else {\r
+        if (ChildSa->Spd->Selector->RemotePort != 0 && \r
+            ChildSa->Spd->Selector->RemotePortRange == 0) {\r
+          //\r
+          // For not port range.\r
+          //\r
+          TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort;\r
+          TsSelector->EndPort   = ChildSa->Spd->Selector->RemotePort;\r
+        } else if (ChildSa->Spd->Selector->RemotePort == 0) {\r
+          //\r
+          // For port from 0~0xffff\r
+          //\r
+          TsSelector->StartPort = 0;\r
+          TsSelector->EndPort   = IKEV2_TS_ANY_PORT;\r
+        } else {\r
+          //\r
+          // Not support now.\r
+          //\r
+          goto ON_ERROR;\r
+        }\r
+      }\r
+      //\r
+      // Copy Address.Currently the address range is not supported.\r
+      // The Starting address is same as Ending address\r
+      // TODO: Support Address Range. \r
+      //\r
+      CopyMem (\r
+        (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR),\r
+        ChildSa->SessionCommon.IsInitiator ?\r
+        ChildSa->Spd->Selector->LocalAddress :\r
+        ChildSa->Spd->Selector->RemoteAddress,\r
+        AddrSize\r
+        );\r
+      CopyMem (\r
+        (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize,\r
+        ChildSa->SessionCommon.IsInitiator ?\r
+        ChildSa->Spd->Selector->LocalAddress :\r
+        ChildSa->Spd->Selector->RemoteAddress,\r
+        AddrSize\r
+        );\r
+      //\r
+      // If the Next Payload is not TS responder, this TS payload type is the TS responder.\r
+      //\r
+      TsPayload->PayloadType             = IKEV2_PAYLOAD_TYPE_TS_INIT;\r
+    }else{\r
+        //\r
+        // Create responder Traffic Selector\r
+        //      \r
+        TsSelector->SelecorLen   = (UINT16)SelectorSize;\r
+        \r
+        //\r
+        // Currently only support the port range from 0~0xffff. Don't support other\r
+        // port range.\r
+        // TODO: support Port range\r
+        //\r
+        if (!ChildSa->SessionCommon.IsInitiator) {\r
+          if (ChildSa->Spd->Selector->LocalPort != 0 &&\r
+              ChildSa->Spd->Selector->LocalPortRange == 0) {\r
+            //\r
+            // For not port range.\r
+            //\r
+            TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort;\r
+            TsSelector->EndPort   = ChildSa->Spd->Selector->LocalPort;\r
+          } else if (ChildSa->Spd->Selector->LocalPort == 0){\r
+            //\r
+            // For port from 0~0xffff\r
+            //\r
+            TsSelector->StartPort = 0;\r
+            TsSelector->EndPort   = IKEV2_TS_ANY_PORT;\r
+          } else {\r
+            //\r
+            // Not support now.\r
+            //\r
+            goto ON_ERROR;\r
+          }\r
+        } else {\r
+          if (ChildSa->Spd->Selector->RemotePort != 0 &&\r
+              ChildSa->Spd->Selector->RemotePortRange == 0) {\r
+            //\r
+            // For not port range.\r
+            //\r
+            TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort;\r
+            TsSelector->EndPort   = ChildSa->Spd->Selector->RemotePort;\r
+          } else if (ChildSa->Spd->Selector->RemotePort == 0){\r
+            //\r
+            // For port from 0~0xffff\r
+            //\r
+            TsSelector->StartPort = 0;\r
+            TsSelector->EndPort   = IKEV2_TS_ANY_PORT;\r
+          } else {\r
+            //\r
+            // Not support now.\r
+            //\r
+            goto ON_ERROR;\r
+          }\r
+        }\r
+        //\r
+        // Copy Address.Currently the address range is not supported.\r
+        // The Starting address is same as Ending address\r
+        // TODO: Support Address Range. \r
+        //\r
+        CopyMem (\r
+          (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR),\r
+          ChildSa->SessionCommon.IsInitiator ?\r
+          ChildSa->Spd->Selector->RemoteAddress :\r
+          ChildSa->Spd->Selector->LocalAddress,\r
+          AddrSize\r
+          );\r
+        CopyMem (\r
+          (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize,\r
+          ChildSa->SessionCommon.IsInitiator ?\r
+          ChildSa->Spd->Selector->RemoteAddress :\r
+          ChildSa->Spd->Selector->LocalAddress,\r
+          AddrSize\r
+          );\r
+        //\r
+        // If the Next Payload is not TS responder, this TS payload type is the TS responder.\r
+        //\r
+        TsPayload->PayloadType          = IKEV2_PAYLOAD_TYPE_TS_RSP;\r
+      }\r
+    }\r
+\r
+    if (ChildSa->Spd->Selector->NextLayerProtocol != 0xffff) {\r
+      TsSelector->IpProtocolId = (UINT8)ChildSa->Spd->Selector->NextLayerProtocol;\r
+    } else {\r
+      TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL;\r
+    } \r
+    \r
+  TsPayloadBuf->Header.NextPayload    = NextPayload;\r
+  TsPayloadBuf->Header.PayloadLength  = (UINT16)TsPayloadSize;\r
+  TsPayloadBuf->TSNumbers             = 1;\r
+  TsPayload->PayloadSize              = TsPayloadSize;\r
+  goto ON_EXIT;\r
+\r
+ON_ERROR:\r
+  if (TsPayload != NULL) {\r
+    IkePayloadFree (TsPayload);  \r
+    TsPayload = NULL;\r
+  }\r
+ON_EXIT: \r
+  return TsPayload;\r
+}\r
+\r
+/**\r
+  Generate the Notify payload.\r
+\r
+  Since the structure of Notify payload which defined in RFC 4306 is simple, so\r
+  there is no internal data structure for Notify payload. This function generate \r
+  Notify payload defined in RFC 4306, but all the fields in this payload are still \r
+  in host order and need call Ikev2EncodePayload() to convert those fields from \r
+  the host order to network order beforing sending it.\r
+\r
+  @param[in]  ProtocolId        The protocol type ID. For IKE_SA it MUST be one (1).\r
+                                For IPsec SAs it MUST be neither (2) for AH or (3)\r
+                                for ESP.\r
+  @param[in]  NextPayload       The next paylaod type in NextPayload field of \r
+                                the Notify payload.\r
+  @param[in]  SpiSize           Size of the SPI in SPI size field of the Notify Payload.  \r
+  @param[in]  MessageType       The message type in NotifyMessageType field of the \r
+                                Notify Payload.\r
+  @param[in]  SpiBuf            Pointer to buffer contains the SPI value.\r
+  @param[in]  NotifyData        Pointer to buffer contains the notification data.\r
+  @param[in]  NotifyDataSize    The size of NotifyData in bytes.\r
+  \r
+\r
+  @retval Pointer to IKE Notify Payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateNotifyPayload (\r
+  IN UINT8            ProtocolId,\r
+  IN UINT8            NextPayload,\r
+  IN UINT8            SpiSize,\r
+  IN UINT16           MessageType,\r
+  IN UINT8            *SpiBuf,\r
+  IN UINT8            *NotifyData,\r
+  IN UINTN            NotifyDataSize\r
+  )\r
+{\r
+  IKE_PAYLOAD         *NotifyPayload;\r
+  IKEV2_NOTIFY        *Notify;\r
+  UINT16              NotifyPayloadLen;\r
+  UINT8               *MessageData;\r
+\r
+  //                       1                   2                   3\r
+  //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //  ! Next Payload  !C!  RESERVED   !         Payload Length        !\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //  !  Protocol ID  !   SPI Size    !      Notify Message Type      !\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //  !                                                               !\r
+  //  ~                Security Parameter Index (SPI)                 ~\r
+  //  !                                                               !\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //  !                                                               !\r
+  //  ~                       Notification Data                       ~\r
+  //  !                                                               !\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+  //\r
+  NotifyPayloadLen  = (UINT16) (sizeof (IKEV2_NOTIFY) + NotifyDataSize + SpiSize);\r
+  Notify            = (IKEV2_NOTIFY *) AllocateZeroPool (NotifyPayloadLen);\r
+  ASSERT (Notify != NULL);\r
+\r
+  //\r
+  // Set Delete Payload's Generic Header\r
+  //\r
+  Notify->Header.NextPayload    = NextPayload;\r
+  Notify->Header.PayloadLength  = NotifyPayloadLen;\r
+  Notify->SpiSize               = SpiSize;\r
+  Notify->ProtocolId            = ProtocolId;\r
+  Notify->MessageType           = MessageType;\r
+\r
+  //\r
+  // Copy Spi , for Cookie Notify, there is no SPI.\r
+  //\r
+  if (SpiBuf != NULL && SpiSize != 0 ) {\r
+    CopyMem (Notify + 1, SpiBuf, SpiSize);\r
+  }\r
+\r
+  MessageData = ((UINT8 *) (Notify + 1)) + SpiSize;\r
+\r
+  //\r
+  // Copy Notification Data\r
+  //\r
+  if (NotifyDataSize != 0) {\r
+    CopyMem (MessageData, NotifyData, NotifyDataSize);\r
+  }\r
+\r
+  //\r
+  // Create Payload for and set type as IKEV2_PAYLOAD_TYPE_NOTIFY\r
+  //\r
+  NotifyPayload = IkePayloadAlloc ();\r
+  ASSERT (NotifyPayload != NULL);\r
+  NotifyPayload->PayloadType  = IKEV2_PAYLOAD_TYPE_NOTIFY;\r
+  NotifyPayload->PayloadBuf   = (UINT8 *) Notify;\r
+  NotifyPayload->PayloadSize  = NotifyPayloadLen;\r
+  return NotifyPayload;\r
+}\r
+\r
+/**\r
+  Generate the Delete payload.\r
+\r
+  Since the structure of Delete payload which defined in RFC 4306 is simple, \r
+  there is no internal data structure for Delete payload. This function generate \r
+  Delete payload defined in RFC 4306, but all the fields in this payload are still \r
+  in host order and need call Ikev2EncodePayload() to convert those fields from \r
+  the host order to network order beforing sending it.\r
+\r
+  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used of Delete payload generation.\r
+  @param[in]  NextPayload       The next paylaod type in NextPayload field of \r
+                                the Delete payload.\r
+  @param[in]  SpiSize           Size of the SPI in SPI size field of the Delete Payload.\r
+  @param[in]  SpiNum            Number of SPI in NumofSPIs field of the Delete Payload.\r
+  @param[in]  SpiBuf            Pointer to buffer contains the SPI value.\r
+\r
+  @retval a Pointer of IKE Delete Payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateDeletePayload (\r
+  IN IKEV2_SA_SESSION  *IkeSaSession,\r
+  IN UINT8             NextPayload,\r
+  IN UINT8             SpiSize,\r
+  IN UINT16            SpiNum,\r
+  IN UINT8             *SpiBuf\r
+  \r
+  )\r
+{\r
+  IKE_PAYLOAD  *DelPayload;\r
+  IKEV2_DELETE *Del;\r
+  UINT16       SpiBufSize;\r
+  UINT16       DelPayloadLen;\r
+\r
+  //                         1                   2                   3\r
+  //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //  ! Next Payload  !C!  RESERVED   !         Payload Length        !\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //  ! Protocol ID   !   SPI Size    !           # of SPIs           !\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //  !                                                               !\r
+  //  ~               Security Parameter Index(es) (SPI)              ~\r
+  //  !                                                               !\r
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+  SpiBufSize    = (UINT16) (SpiSize * SpiNum);\r
+  DelPayloadLen = (UINT16) (sizeof (IKEV2_DELETE) + SpiBufSize);\r
+\r
+  Del           = AllocateZeroPool (DelPayloadLen);\r
+  ASSERT (Del != NULL);\r
+  \r
+  //\r
+  // Set Delete Payload's Generic Header\r
+  //\r
+  Del->Header.NextPayload   = NextPayload;\r
+  Del->Header.PayloadLength = DelPayloadLen;\r
+  Del->NumSpis              = SpiNum;\r
+  Del->SpiSize              = SpiSize;\r
+\r
+  if (SpiSize == 4) {\r
+    //\r
+    // TODO: should consider the AH if needs to support.\r
+    //\r
+    Del->ProtocolId = IPSEC_PROTO_IPSEC_ESP;\r
+  } else {\r
+    Del->ProtocolId = IPSEC_PROTO_ISAKMP;\r
+  }\r
+\r
+  //\r
+  // Set Del Payload's Idntification Data\r
+  //\r
+  CopyMem (Del + 1, SpiBuf, SpiBufSize);\r
+  DelPayload = IkePayloadAlloc ();\r
+  ASSERT (DelPayload != NULL);\r
+  DelPayload->PayloadType = IKEV2_PAYLOAD_TYPE_DELETE;\r
+  DelPayload->PayloadBuf  = (UINT8 *) Del;\r
+  DelPayload->PayloadSize = DelPayloadLen;\r
+  return DelPayload;\r
+}\r
+\r
+/**\r
+  Generate the Configuration payload.\r
+\r
+  This function generate configuration payload defined in RFC 4306, but all the \r
+  fields in this payload are still in host order and need call Ikev2EncodePayload() \r
+  to convert those fields from the host order to network order beforing sending it.\r
+\r
+  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used for Delete payload \r
+                                generation.\r
+  @param[in]  NextPayload       The next paylaod type in NextPayload field of \r
+                                the Delete payload.\r
+  @param[in]  CfgType           The attribute type in the Configuration attribute.\r
+\r
+  @retval Pointer to IKE CP Payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateCpPayload (\r
+  IN IKEV2_SA_SESSION  *IkeSaSession,\r
+  IN UINT8             NextPayload,\r
+  IN UINT8             CfgType\r
+  )\r
+{\r
+  IKE_PAYLOAD           *CpPayload;\r
+  IKEV2_CFG             *Cfg;\r
+  UINT16                PayloadLen;\r
+  IKEV2_CFG_ATTRIBUTES  *CfgAttributes;\r
+\r
+  //\r
+  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Next Payload  !C! RESERVED    !         Payload Length        !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    !   CFG Type    !                    RESERVED                   !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    !                                                               !\r
+  //    ~                   Configuration Attributes                    ~\r
+  //    !                                                               !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+\r
+  PayloadLen = (UINT16) (sizeof (IKEV2_CFG) + sizeof (IKEV2_CFG_ATTRIBUTES));\r
+  Cfg        = (IKEV2_CFG *) AllocateZeroPool (PayloadLen);\r
+\r
+  if (Cfg == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  CfgAttributes = (IKEV2_CFG_ATTRIBUTES *)((UINT8 *)Cfg + sizeof (IKEV2_CFG));\r
+\r
+  //\r
+  // Only generate the configuration payload with an empty INTERNAL_IP4_ADDRESS \r
+  // or INTERNAL_IP6_ADDRESS. \r
+  //\r
+\r
+  Cfg->Header.NextPayload   = NextPayload;\r
+  Cfg->Header.PayloadLength = PayloadLen;\r
+  Cfg->CfgType              = IKEV2_CFG_TYPE_REQUEST;\r
+\r
+  CfgAttributes->AttritType  = CfgType;\r
+  CfgAttributes->ValueLength = 0;\r
+\r
+  CpPayload = IkePayloadAlloc ();\r
+  if (CpPayload == NULL) {\r
+    if (Cfg != NULL) {\r
+      FreePool (Cfg);\r
+    }\r
+    return NULL;\r
+  }\r
+\r
+  CpPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CP;\r
+  CpPayload->PayloadBuf  = (UINT8 *) Cfg;\r
+  CpPayload->PayloadSize = PayloadLen;\r
+  return CpPayload;\r
+}\r
+\r
+/**\r
+  Parser the Notify Cookie payload.\r
+\r
+  This function parses the Notify Cookie payload.If the Notify ProtocolId is not\r
+  IPSEC_PROTO_ISAKMP or if the SpiSize is not zero or if the MessageType is not\r
+  the COOKIE, return EFI_INVALID_PARAMETER.\r
+\r
+  @param[in]      IkeNCookie    Pointer to the IKE_PAYLOAD which contians the \r
+                                Notify Cookie payload.\r
+                                the Notify payload.\r
+  @param[in, out] IkeSaSession  Pointer to the relevant IKE SA Session.\r
+\r
+  @retval EFI_SUCCESS           The Notify Cookie Payload is valid.\r
+  @retval EFI_INVALID_PARAMETER The Notify Cookie Payload is invalid.\r
+  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2ParserNotifyCookiePayload (\r
+  IN     IKE_PAYLOAD      *IkeNCookie,\r
+  IN OUT IKEV2_SA_SESSION *IkeSaSession\r
+  ) \r
+{\r
+  IKEV2_NOTIFY      *NotifyPayload;\r
+  UINTN             NotifyDataSize;\r
+\r
+  NotifyPayload = (IKEV2_NOTIFY *)IkeNCookie->PayloadBuf;\r
+\r
+  if ((NotifyPayload->ProtocolId != IPSEC_PROTO_ISAKMP) || \r
+      (NotifyPayload->SpiSize != 0) ||\r
+      (NotifyPayload->MessageType != IKEV2_NOTIFICATION_COOKIE)\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NotifyDataSize        = NotifyPayload->Header.PayloadLength - sizeof (IKEV2_NOTIFY);\r
+  IkeSaSession->NCookie = AllocateZeroPool (NotifyDataSize);\r
+  if (IkeSaSession->NCookie == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  IkeSaSession->NCookieSize = NotifyDataSize;\r
+\r
+  CopyMem (\r
+    IkeSaSession->NCookie, \r
+    NotifyPayload + sizeof (IKEV2_NOTIFY), \r
+    NotifyDataSize\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Generate the Certificate payload or Certificate Request Payload.\r
+\r
+  Since the Certificate Payload structure is same with Certificate Request Payload, \r
+  the only difference is that one contains the Certificate Data, other contains\r
+  the acceptable certificateion CA. This function generate Certificate payload \r
+  or Certificate Request Payload defined in RFC 4306, but all the fields \r
+  in the payload are still in host order and need call Ikev2EncodePayload() \r
+  to convert those fields from the host order to network order beforing sending it.\r
+\r
+  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used of Delete payload \r
+                                generation.\r
+  @param[in]  NextPayload       The next paylaod type in NextPayload field of \r
+                                the Delete payload.\r
+  @param[in]  Certificate       Pointer of buffer contains the certification data.\r
+  @param[in]  CertificateLen    The length of Certificate in byte.\r
+  @param[in]  EncodeType        Specified the Certificate Encodeing which is defined\r
+                                in RFC 4306.\r
+  @param[in]  IsRequest         To indicate create Certificate Payload or Certificate\r
+                                Request Payload. If it is TURE, create Certificate\r
+                                Payload. Otherwise, create Certificate Request Payload.\r
+\r
+  @retval  a Pointer to IKE Payload whose payload buffer containing the Certificate\r
+           payload or Certificated Request payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateCertificatePayload (\r
+  IN IKEV2_SA_SESSION  *IkeSaSession,\r
+  IN UINT8             NextPayload,\r
+  IN UINT8             *Certificate,\r
+  IN UINTN             CertificateLen,\r
+  IN UINT8             EncodeType,\r
+  IN BOOLEAN           IsRequest\r
+  )\r
+{\r
+  IKE_PAYLOAD           *CertPayload;\r
+  IKEV2_CERT            *Cert;\r
+  UINT16                PayloadLen;\r
+  UINT8                 *PublicKey;\r
+  UINTN                 PublicKeyLen;\r
+  HASH_DATA_FRAGMENT    Fragment[1];\r
+  UINT8                 *HashData;\r
+  UINTN                 HashDataSize;\r
+  EFI_STATUS            Status;\r
+\r
+  //\r
+  //                         1                   2                   3\r
+  //     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Next Payload  !C!  RESERVED   !         Payload Length        !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //    ! Cert Encoding !                                               !\r
+  //    +-+-+-+-+-+-+-+-+                                               !\r
+  //    ~                       Certificate Data/Authority              ~\r
+  //    !                                                               !\r
+  //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+\r
+  Status       = EFI_SUCCESS;\r
+  PublicKey    = NULL;\r
+  PublicKeyLen = 0; \r
+\r
+  if (!IsRequest) {\r
+    PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + CertificateLen);\r
+  } else {\r
+    //\r
+    // SHA1 Hash length is 20.\r
+    //\r
+    PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + 20);\r
+  }\r
+\r
+  Cert = AllocateZeroPool (PayloadLen);\r
+  if (Cert == NULL) {\r
+    return NULL;\r
+  }\r
+   \r
+  //\r
+  // Generate Certificate Payload or Certificate Request Payload.\r
+  //\r
+  Cert->Header.NextPayload   = NextPayload;\r
+  Cert->Header.PayloadLength = PayloadLen;\r
+  Cert->CertEncoding         = EncodeType;\r
+  if (!IsRequest) {\r
+    CopyMem (\r
+      ((UINT8 *)Cert) + sizeof (IKEV2_CERT),\r
+      Certificate,\r
+      CertificateLen\r
+      );\r
+  } else {\r
+    Status = IpSecCryptoIoGetPublicKeyFromCert (\r
+               Certificate,\r
+               CertificateLen,\r
+               &PublicKey,\r
+               &PublicKeyLen\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT; \r
+    }\r
+\r
+    Fragment[0].Data     = PublicKey;\r
+    Fragment[0].DataSize = PublicKeyLen;\r
+    HashDataSize      = IpSecGetHmacDigestLength (IKE_AALG_SHA1HMAC);\r
+    HashData          = AllocateZeroPool (HashDataSize);\r
+    \r
+    Status = IpSecCryptoIoHash (\r
+               IKE_AALG_SHA1HMAC,\r
+               Fragment,\r
+               1,\r
+               HashData,\r
+               HashDataSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+    \r
+    CopyMem (\r
+      ((UINT8 *)Cert) + sizeof (IKEV2_CERT),\r
+      HashData,\r
+      HashDataSize\r
+      );\r
+  }\r
+\r
+  CertPayload = IkePayloadAlloc ();\r
+  if (CertPayload == NULL) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  if (!IsRequest) {\r
+    CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERT;\r
+  } else {\r
+    CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERTREQ;\r
+  }\r
+\r
+  CertPayload->PayloadBuf  = (UINT8 *) Cert;\r
+  CertPayload->PayloadSize = PayloadLen;\r
+  return CertPayload;\r
+\r
+ON_EXIT:\r
+  if (Cert != NULL) {\r
+    FreePool (Cert);\r
+  }\r
+  if (PublicKey != NULL) {\r
+    FreePool (PublicKey);\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Remove and free all IkePayloads in the specified IkePacket.\r
+\r
+  @param[in] IkePacket   The pointer of IKE_PACKET.\r
+\r
+**/\r
+VOID\r
+ClearAllPayloads (\r
+  IN IKE_PACKET     *IkePacket\r
+  )\r
+{\r
+  LIST_ENTRY      *PayloadEntry;\r
+  IKE_PAYLOAD     *IkePayload;\r
+  //\r
+  // remove all payloads from list and free each payload.\r
+  //\r
+  while (!IsListEmpty (&IkePacket->PayloadList)) {\r
+    PayloadEntry  = IkePacket->PayloadList.ForwardLink;\r
+    IkePayload    = IKE_PAYLOAD_BY_PACKET (PayloadEntry);\r
+    IKE_PACKET_REMOVE_PAYLOAD (IkePacket, IkePayload);\r
+    IkePayloadFree (IkePayload);\r
+  }\r
+}\r
+\r
+/**\r
+  Transfer the intrnal data structure IKEV2_SA_DATA to IKEV2_SA structure defined in RFC.\r
+\r
+  @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the SA Session.\r
+  @param[in] SaData        Pointer to IKEV2_SA_DATA to be transfered.\r
+\r
+  @retval  return the pointer of IKEV2_SA.\r
+  \r
+**/\r
+IKEV2_SA*\r
+Ikev2EncodeSa (\r
+  IKEV2_SESSION_COMMON *SessionCommon,\r
+  IKEV2_SA_DATA        *SaData\r
+  )\r
+{\r
+  IKEV2_SA              *Sa;\r
+  UINTN                 SaSize;\r
+  IKEV2_PROPOSAL_DATA   *ProposalData;\r
+  IKEV2_TRANSFORM_DATA  *TransformData;\r
+  UINTN                 TotalTransforms;\r
+  UINTN                 SaAttrsSize;\r
+  UINTN                 TransformsSize;\r
+  UINTN                 TransformSize;\r
+  UINTN                 ProposalsSize;\r
+  UINTN                 ProposalSize;\r
+  UINTN                 ProposalIndex;\r
+  UINTN                 TransformIndex;\r
+  IKE_SA_ATTRIBUTE      *SaAttribute;\r
+  IKEV2_PROPOSAL        *Proposal;\r
+  IKEV2_PROPOSAL        *LastProposal;\r
+  IKEV2_TRANSFORM       *Transform;\r
+  IKEV2_TRANSFORM       *LastTransform;\r
+  \r
+  //\r
+  // Transform IKE_SA_DATA structure to IKE_SA Payload.\r
+  // Header length is host order.\r
+  // The returned IKE_SA struct should be freed by caller.\r
+  //\r
+  TotalTransforms = 0;\r
+  //\r
+  // Caculate the Proposal numbers and Transform numbers.\r
+  //\r
+  for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) {\r
+\r
+    ProposalData     = (IKEV2_PROPOSAL_DATA *) (SaData + 1) + ProposalIndex;\r
+    TotalTransforms += ProposalData->NumTransforms;\r
+\r
+  }\r
+  SaSize = sizeof (IKEV2_SA) +\r
+           SaData->NumProposals * sizeof (IKEV2_PROPOSAL) +\r
+           TotalTransforms * (sizeof (IKEV2_TRANSFORM) + MAX_SA_ATTRS_SIZE);\r
+  //\r
+  // Allocate buffer for IKE_SA.\r
+  //\r
+  Sa = AllocateZeroPool (SaSize);\r
+  ASSERT (Sa != NULL);\r
+  CopyMem (Sa, SaData, sizeof (IKEV2_SA));\r
+  Sa->Header.PayloadLength  = (UINT16) sizeof (IKEV2_SA);\r
+  ProposalsSize             = 0;\r
+  LastProposal              = NULL;\r
+  Proposal                  = (IKEV2_PROPOSAL *) (Sa + 1);\r
+\r
+  //\r
+  // Set IKE_PROPOSAL\r
+  //\r
+  ProposalData  = (IKEV2_PROPOSAL_DATA *) (SaData + 1);\r
+  for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) {\r
+    Proposal->ProposalIndex   = ProposalData->ProposalIndex;\r
+    Proposal->ProtocolId      = ProposalData->ProtocolId;\r
+    Proposal->NumTransforms   = ProposalData->NumTransforms;\r
+\r
+    if (ProposalData->Spi == 0) {\r
+      Proposal->SpiSize = 0;\r
+    } else {\r
+      Proposal->SpiSize           = 4;\r
+      *(UINT32 *) (Proposal + 1)  = HTONL (*((UINT32*)ProposalData->Spi));\r
+    }\r
+\r
+    TransformsSize  = 0;\r
+    LastTransform   = NULL;\r
+    Transform       = (IKEV2_TRANSFORM *) ((UINT8 *) (Proposal + 1) + Proposal->SpiSize);\r
+\r
+    //\r
+    // Set IKE_TRANSFORM\r
+    //\r
+    for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) {\r
+      TransformData               = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex;\r
+      Transform->TransformType    = TransformData->TransformType;\r
+      Transform->TransformId      = HTONS (TransformData->TransformId);\r
+      SaAttrsSize                 = 0;\r
+\r
+      //\r
+      // If the Encryption Algorithm is variable key length set the key length in attribute.\r
+      // Note that only a single attribute type (Key Length) is defined and it is fixed length.\r
+      //\r
+      if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_ENCR && TransformData->Attribute.Attr.AttrValue != 0) {\r
+        SaAttribute                 = (IKE_SA_ATTRIBUTE *) (Transform + 1);\r
+        SaAttribute->AttrType       = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT);\r
+        SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue);\r
+        SaAttrsSize                 = sizeof (IKE_SA_ATTRIBUTE);\r
+      }\r
+\r
+      //\r
+      // If the Integrity Algorithm is variable key length set the key length in attribute.\r
+      //\r
+      if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_INTEG && TransformData->Attribute.Attr.AttrValue != 0) {\r
+        SaAttribute                 = (IKE_SA_ATTRIBUTE *) (Transform + 1);\r
+        SaAttribute->AttrType       = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT);\r
+        SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue);\r
+        SaAttrsSize                 = sizeof (IKE_SA_ATTRIBUTE);\r
+      }\r
+\r
+      TransformSize                 = sizeof (IKEV2_TRANSFORM) + SaAttrsSize;\r
+      TransformsSize               += TransformSize;\r
+      \r
+      Transform->Header.NextPayload   = IKE_TRANSFORM_NEXT_PAYLOAD_MORE;\r
+      Transform->Header.PayloadLength = HTONS ((UINT16)TransformSize);\r
+      \r
+      if (TransformIndex == ProposalData->NumTransforms) {\r
+        LastTransform->Header.NextPayload = IKE_TRANSFORM_NEXT_PAYLOAD_NONE;\r
+      }\r
+\r
+      Transform     = (IKEV2_TRANSFORM *)((UINT8 *) Transform + TransformSize);\r
+    }\r
+    \r
+    //\r
+    // Set Proposal's Generic Header.\r
+    //\r
+    ProposalSize                   = sizeof (IKEV2_PROPOSAL) + Proposal->SpiSize + TransformsSize;\r
+    ProposalsSize                 += ProposalSize;\r
+    Proposal->Header.NextPayload   = IKE_PROPOSAL_NEXT_PAYLOAD_MORE;\r
+    Proposal->Header.PayloadLength = HTONS ((UINT16)ProposalSize);\r
+    \r
+    if (ProposalIndex == SaData->NumProposals) {\r
+      LastProposal->Header.NextPayload = IKE_PROPOSAL_NEXT_PAYLOAD_NONE;\r
+    }\r
+\r
+    //\r
+    // Point to next Proposal Payload\r
+    //\r
+    Proposal     = (IKEV2_PROPOSAL *) ((UINT8 *) Proposal + ProposalSize);\r
+    ProposalData = (IKEV2_PROPOSAL_DATA *)(((UINT8 *)ProposalData) + sizeof (IKEV2_PROPOSAL_DATA) + (TransformIndex * sizeof (IKEV2_TRANSFORM_DATA)));\r
+  }\r
+  //\r
+  // Set SA's Generic Header.\r
+  //\r
+  Sa->Header.PayloadLength = (UINT16) (Sa->Header.PayloadLength + ProposalsSize);\r
+  return Sa;\r
+}\r
+\r
+/**\r
+  Decode SA payload.\r
+\r
+  This function converts the received SA payload to internal data structure.\r
+\r
+  @param[in]  SessionCommon       Pointer to IKE Common Session used to decode the SA \r
+                                  Payload.\r
+  @param[in]  Sa                  Pointer to SA Payload\r
+\r
+  @return a Pointer to internal data structure for SA payload.\r
+\r
+**/\r
+IKEV2_SA_DATA *\r
+Ikev2DecodeSa (\r
+  IKEV2_SESSION_COMMON *SessionCommon,\r
+  IKEV2_SA             *Sa\r
+  )\r
+{\r
+  IKEV2_SA_DATA         *SaData;\r
+  EFI_STATUS            Status;\r
+  IKEV2_PROPOSAL        *Proposal;\r
+  IKEV2_TRANSFORM       *Transform;\r
+  UINTN                 TotalProposals;\r
+  UINTN                 TotalTransforms;\r
+  UINTN                 ProposalNextPayloadSum;\r
+  UINTN                 ProposalIndex;\r
+  UINTN                 TransformIndex;\r
+  UINTN                 SaRemaining;\r
+  UINT16                ProposalSize;\r
+  UINTN                 ProposalRemaining;\r
+  UINT16                TransformSize;\r
+  UINTN                 SaAttrRemaining;\r
+  IKE_SA_ATTRIBUTE      *SaAttribute;\r
+  IKEV2_PROPOSAL_DATA   *ProposalData;\r
+  IKEV2_TRANSFORM_DATA  *TransformData;\r
+  UINT8                 *Spi;\r
+\r
+  //\r
+  // Transfrom from IKE_SA payload to IKE_SA_DATA structure.\r
+  // Header length NTOH is already done\r
+  // The returned IKE_SA_DATA should be freed by caller\r
+  //\r
+  SaData    = NULL;\r
+  Status    = EFI_SUCCESS;\r
+\r
+  //\r
+  // First round sanity check and size calculae\r
+  //\r
+  TotalProposals         = 0;\r
+  TotalTransforms        = 0;\r
+  ProposalNextPayloadSum = 0;\r
+  SaRemaining            = Sa->Header.PayloadLength - sizeof (IKEV2_SA);// Point to current position in SA\r
+  Proposal               = (IKEV2_PROPOSAL *)((IKEV2_SA *)(Sa)+1);\r
+\r
+  //\r
+  // Caculate the number of Proposal payload and the total numbers of\r
+  // Transforms payload (the transforms in all proposal payload).\r
+  //\r
+  while (SaRemaining > sizeof (IKEV2_PROPOSAL)) {\r
+    ProposalSize = NTOHS (Proposal->Header.PayloadLength);\r
+    if (SaRemaining < ProposalSize) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    if (Proposal->SpiSize != 0 && Proposal->SpiSize != 4) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    TotalProposals++;\r
+    TotalTransforms        += Proposal->NumTransforms;\r
+    SaRemaining            -= ProposalSize;\r
+    ProposalNextPayloadSum += Proposal->Header.NextPayload;\r
+    Proposal                = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize);\r
+  }\r
+\r
+  //\r
+  // Check the proposal number. The Proposal Payload type is 2. Nonce Paylod is 0.\r
+  // SUM(ProposalNextPayload) = Proposal Num * 2 + Noce Payload Type (0).\r
+  //\r
+  if (TotalProposals == 0 ||\r
+      (TotalProposals - 1) * IKE_PROPOSAL_NEXT_PAYLOAD_MORE + IKE_PROPOSAL_NEXT_PAYLOAD_NONE != ProposalNextPayloadSum\r
+      ) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Second round sanity check and decode. Transform the SA payload into\r
+  // a IKE_SA_DATA structure.\r
+  //\r
+  SaData = (IKEV2_SA_DATA *) AllocateZeroPool (\r
+                               sizeof (IKEV2_SA_DATA) +\r
+                               TotalProposals * sizeof (IKEV2_PROPOSAL_DATA) +\r
+                               TotalTransforms * sizeof (IKEV2_TRANSFORM_DATA)\r
+                               );\r
+  ASSERT (SaData != NULL);\r
+  CopyMem (SaData, Sa, sizeof (IKEV2_SA));\r
+  SaData->NumProposals        = TotalProposals;\r
+  ProposalData                = (IKEV2_PROPOSAL_DATA *) (SaData + 1);\r
+\r
+  //\r
+  // Proposal Payload\r
+  //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   ! Next Payload  !   RESERVED    !         Payload Length        !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   !  Proposal #   !  Protocol-Id  !    SPI Size   !# of Transforms!\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //   !                        SPI (variable)                         !\r
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+  //\r
+  for (ProposalIndex = 0, Proposal = IKEV2_SA_FIRST_PROPOSAL (Sa);\r
+       ProposalIndex < TotalProposals;\r
+       ProposalIndex++\r
+       ) {\r
+       \r
+    //\r
+    // TODO: check ProposalId\r
+    //\r
+    ProposalData->ProposalIndex   = Proposal->ProposalIndex;\r
+    ProposalData->ProtocolId      = Proposal->ProtocolId;\r
+    if (Proposal->SpiSize == 0) {\r
+      ProposalData->Spi = 0;\r
+    } else {\r
+      //\r
+      // SpiSize == 4\r
+      //\r
+      Spi = AllocateZeroPool (Proposal->SpiSize);\r
+      ASSERT (Spi != NULL);\r
+      CopyMem (Spi, (UINT32 *) (Proposal + 1), Proposal->SpiSize);\r
+      *((UINT32*) Spi) = NTOHL (*((UINT32*) Spi));\r
+      ProposalData->Spi = Spi;\r
+    }\r
+\r
+    ProposalData->NumTransforms = Proposal->NumTransforms;\r
+    ProposalSize                = NTOHS (Proposal->Header.PayloadLength);\r
+    ProposalRemaining           = ProposalSize;\r
+    //\r
+    // Transform Payload\r
+    //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //   ! Next Payload  !   RESERVED    !         Payload Length        !\r
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //   !Transform Type !   RESERVED    !         Transform ID          !\r
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //   !                                                               !\r
+    //   ~                        SA Attributes                          ~\r
+    //   !                                                               !\r
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r
+    //\r
+    Transform = IKEV2_PROPOSAL_FIRST_TRANSFORM (Proposal);\r
+    for (TransformIndex = 0; TransformIndex < Proposal->NumTransforms; TransformIndex++) {\r
+\r
+      //\r
+      // Transfer the IKEV2_TRANSFORM structure into internal IKEV2_TRANSFORM_DATA struture.\r
+      //\r
+      TransformData                   = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex;\r
+      TransformData->TransformId      = NTOHS (Transform->TransformId);\r
+      TransformData->TransformType    = Transform->TransformType;\r
+      TransformSize                   = NTOHS (Transform->Header.PayloadLength);\r
+      //\r
+      // Check the Proposal Data is correct.\r
+      //\r
+      if (ProposalRemaining < TransformSize) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        goto Exit;\r
+      }\r
+\r
+      //\r
+      // Check if the Transform payload includes Attribution.\r
+      //\r
+      SaAttrRemaining = TransformSize - sizeof (IKEV2_TRANSFORM);\r
+\r
+      //\r
+      // According to RFC 4603, currently only the Key length attribute type is \r
+      // supported. For each Transform, there is only one attributeion.\r
+      //\r
+      if (SaAttrRemaining > 0) {\r
+        if (SaAttrRemaining != sizeof (IKE_SA_ATTRIBUTE)) {\r
+          Status = EFI_INVALID_PARAMETER;\r
+          goto Exit;\r
+        }\r
+        SaAttribute                             = (IKE_SA_ATTRIBUTE *) ((IKEV2_TRANSFORM *)(Transform) + 1);\r
+        TransformData->Attribute.AttrType       = (UINT16)((NTOHS (SaAttribute->AttrType))  & ~SA_ATTR_FORMAT_BIT);\r
+        TransformData->Attribute.Attr.AttrValue = NTOHS (SaAttribute->Attr.AttrValue);\r
+\r
+        //\r
+        // Currently, only supports the Key Length Attribution.\r
+        //\r
+        if (TransformData->Attribute.AttrType != IKEV2_ATTRIBUTE_TYPE_KEYLEN) {\r
+          Status = EFI_INVALID_PARAMETER;\r
+          goto Exit;\r
+        }        \r
+      }\r
+\r
+      //\r
+      // Move to next Transform\r
+      //      \r
+      Transform = IKEV2_NEXT_TRANSFORM_WITH_SIZE (Transform, TransformSize);\r
+    }\r
+    Proposal     = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize);\r
+    ProposalData = (IKEV2_PROPOSAL_DATA *) ((UINT8 *)(ProposalData + 1) +\r
+                                                ProposalData->NumTransforms *\r
+                                                sizeof (IKEV2_TRANSFORM_DATA));\r
+  }\r
+\r
+Exit:\r
+  if (EFI_ERROR (Status) && SaData != NULL) {\r
+    FreePool (SaData);\r
+    SaData = NULL;\r
+  }\r
+  return SaData;\r
+}\r
+\r
+/**\r
+  General interface of payload encoding.\r
+\r
+  This function encodes the internal data structure into payload which \r
+  is defined in RFC 4306. The IkePayload->PayloadBuf is used to store both the input\r
+  payload and converted payload. Only the SA payload use the interal structure\r
+  to store the attribute. Other payload use structure which is same with the RFC\r
+  defined, for this kind payloads just do host order to network order change of\r
+  some fields.\r
+\r
+  @param[in]      SessionCommon       Pointer to IKE Session Common used to encode the payload.\r
+  @param[in, out] IkePayload          Pointer to IKE payload to be encoded as input, and\r
+                                      store the encoded result as output.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Meet error when encoding the SA payload.\r
+  @retval EFI_SUCCESS            Encoded successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2EncodePayload (\r
+  IN     UINT8               *SessionCommon,\r
+  IN OUT IKE_PAYLOAD         *IkePayload\r
+  )\r
+{\r
+  IKEV2_SA_DATA               *SaData;\r
+  IKEV2_SA                    *SaPayload;\r
+  IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;\r
+  IKEV2_NOTIFY                *NotifyPayload;\r
+  IKEV2_DELETE                *DeletePayload;\r
+  IKEV2_KEY_EXCHANGE          *KeyPayload;\r
+  IKEV2_TS                    *TsPayload;\r
+  IKEV2_CFG_ATTRIBUTES        *CfgAttribute;\r
+  UINT8                       *TsBuffer;\r
+  UINT8                       Index;\r
+  TRAFFIC_SELECTOR            *TrafficSelector;\r
+\r
+  //\r
+  // Transform the Internal IKE structure to IKE payload.\r
+  // Only the SA payload use the interal structure to store the attribute.\r
+  // Other payload use structure which same with the RFC defined, so there is\r
+  // no need to tranform them to IKE payload.\r
+  //\r
+  switch (IkePayload->PayloadType) {\r
+  case IKEV2_PAYLOAD_TYPE_SA:\r
+    //\r
+    // Transform IKE_SA_DATA to IK_SA payload\r
+    //\r
+    SaData    = (IKEV2_SA_DATA *) IkePayload->PayloadBuf;\r
+    SaPayload = Ikev2EncodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, SaData);\r
+\r
+    if (SaPayload == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    if (!IkePayload->IsPayloadBufExt) {\r
+      FreePool (IkePayload->PayloadBuf);\r
+    }\r
+    IkePayload->PayloadBuf      = (UINT8 *) SaPayload;\r
+    IkePayload->IsPayloadBufExt = FALSE;\r
+    break;\r
+\r
+  case IKEV2_PAYLOAD_TYPE_NOTIFY:\r
+    NotifyPayload               = (IKEV2_NOTIFY *) IkePayload->PayloadBuf;\r
+    NotifyPayload->MessageType  = HTONS (NotifyPayload->MessageType);\r
+    break;\r
+    \r
+  case IKEV2_PAYLOAD_TYPE_DELETE:\r
+    DeletePayload           = (IKEV2_DELETE *) IkePayload->PayloadBuf;\r
+    DeletePayload->NumSpis  = HTONS (DeletePayload->NumSpis);\r
+    break;\r
+    \r
+  case IKEV2_PAYLOAD_TYPE_KE:\r
+    KeyPayload              = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf;\r
+    KeyPayload->DhGroup     = HTONS (KeyPayload->DhGroup);\r
+    break;\r
+    \r
+  case IKEV2_PAYLOAD_TYPE_TS_INIT:\r
+  case IKEV2_PAYLOAD_TYPE_TS_RSP:\r
+    TsPayload = (IKEV2_TS *) IkePayload->PayloadBuf;\r
+    TsBuffer  = IkePayload->PayloadBuf + sizeof (IKEV2_TS);\r
+\r
+    for (Index = 0; Index < TsPayload->TSNumbers; Index++) {\r
+      TrafficSelector = (TRAFFIC_SELECTOR *) TsBuffer;\r
+      TsBuffer        = TsBuffer + TrafficSelector->SelecorLen;\r
+      //\r
+      // Host order to network order\r
+      //\r
+      TrafficSelector->SelecorLen = HTONS (TrafficSelector->SelecorLen);\r
+      TrafficSelector->StartPort  = HTONS (TrafficSelector->StartPort);\r
+      TrafficSelector->EndPort    = HTONS (TrafficSelector->EndPort);\r
+      \r
+    }\r
+\r
+    break;\r
+\r
+  case IKEV2_PAYLOAD_TYPE_CP:\r
+    CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1);\r
+    CfgAttribute->AttritType  = HTONS (CfgAttribute->AttritType);\r
+    CfgAttribute->ValueLength = HTONS (CfgAttribute->ValueLength);\r
+    \r
+  case IKEV2_PAYLOAD_TYPE_ID_INIT:\r
+  case IKEV2_PAYLOAD_TYPE_ID_RSP:\r
+  case IKEV2_PAYLOAD_TYPE_AUTH:\r
+  default:\r
+    break;\r
+  }\r
+  \r
+  PayloadHdr  = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf;\r
+  IkePayload->PayloadSize = PayloadHdr->PayloadLength;\r
+  PayloadHdr->PayloadLength = HTONS (PayloadHdr->PayloadLength);\r
+  IKEV2_DUMP_PAYLOAD (IkePayload);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The general interface for decoding Payload.\r
+\r
+  This function converts the received Payload into internal structure.\r
+\r
+  @param[in]      SessionCommon     Pointer to IKE Session Common used for decoding.\r
+  @param[in, out] IkePayload        Pointer to IKE payload to be decoded as input, and\r
+                                    store the decoded result as output. \r
+\r
+  @retval EFI_INVALID_PARAMETER  Meet error when decoding the SA payload.\r
+  @retval EFI_SUCCESS            Decoded successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2DecodePayload (\r
+  IN     UINT8       *SessionCommon,\r
+  IN OUT IKE_PAYLOAD *IkePayload\r
+  )\r
+{\r
+  IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;\r
+  UINT16                      PayloadSize;\r
+  UINT8                       PayloadType;\r
+  IKEV2_SA_DATA               *SaData;\r
+  EFI_STATUS                  Status;\r
+  IKEV2_NOTIFY                *NotifyPayload;\r
+  IKEV2_DELETE                *DeletePayload;\r
+  UINT16                      TsTotalSize;\r
+  TRAFFIC_SELECTOR            *TsSelector;\r
+  IKEV2_TS                    *TsPayload;\r
+  IKEV2_KEY_EXCHANGE          *KeyPayload;\r
+  IKEV2_CFG_ATTRIBUTES        *CfgAttribute;\r
+  UINT8                       Index;\r
+\r
+  //\r
+  // Transform the IKE payload to Internal IKE structure.\r
+  // Only the SA payload and Hash Payload use the interal\r
+  // structure to store the attribute. Other payloads use\r
+  // structure which is same with the definitions in RFC, \r
+  // so there is no need to tranform them to internal IKE \r
+  // structure.\r
+  //\r
+  Status      = EFI_SUCCESS;\r
+  PayloadSize = (UINT16) IkePayload->PayloadSize;\r
+  PayloadType = IkePayload->PayloadType;\r
+  PayloadHdr  = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf;\r
+  //\r
+  // The PayloadSize is the size of whole payload.\r
+  // Replace HTONS operation to assignment statements, since the result is same.\r
+  //\r
+  PayloadHdr->PayloadLength = PayloadSize;\r
+\r
+  IKEV2_DUMP_PAYLOAD (IkePayload);\r
+  switch (PayloadType) {\r
+  case IKEV2_PAYLOAD_TYPE_SA:\r
+    if (PayloadSize < sizeof (IKEV2_SA)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    SaData = Ikev2DecodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, (IKEV2_SA *) PayloadHdr);\r
+    if (SaData == NULL) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    if (!IkePayload->IsPayloadBufExt) {\r
+      FreePool (IkePayload->PayloadBuf);\r
+    }\r
+    \r
+    IkePayload->PayloadBuf      = (UINT8 *) SaData;\r
+    IkePayload->IsPayloadBufExt = FALSE;    \r
+    break;\r
+\r
+  case IKEV2_PAYLOAD_TYPE_ID_INIT:\r
+  case IKEV2_PAYLOAD_TYPE_ID_RSP :\r
+    if (PayloadSize < sizeof (IKEV2_ID)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+    break;\r
+\r
+  case IKEV2_PAYLOAD_TYPE_NOTIFY:\r
+    if (PayloadSize < sizeof (IKEV2_NOTIFY)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    NotifyPayload               = (IKEV2_NOTIFY *) PayloadHdr;\r
+    NotifyPayload->MessageType  = NTOHS (NotifyPayload->MessageType);\r
+    break;\r
+    \r
+  case IKEV2_PAYLOAD_TYPE_DELETE:\r
+    if (PayloadSize < sizeof (IKEV2_DELETE)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    DeletePayload           = (IKEV2_DELETE *) PayloadHdr;\r
+    DeletePayload->NumSpis  = NTOHS (DeletePayload->NumSpis);\r
+    break;\r
+    \r
+  case IKEV2_PAYLOAD_TYPE_AUTH:\r
+    if (PayloadSize < sizeof (IKEV2_AUTH)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+    break;\r
+\r
+  case IKEV2_PAYLOAD_TYPE_KE:\r
+    KeyPayload              = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf;\r
+    KeyPayload->DhGroup     = HTONS (KeyPayload->DhGroup);\r
+    break;  \r
+\r
+  case IKEV2_PAYLOAD_TYPE_TS_INIT:\r
+  case IKEV2_PAYLOAD_TYPE_TS_RSP :\r
+    TsTotalSize = 0;\r
+    if (PayloadSize < sizeof (IKEV2_TS)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+    //\r
+    // Parse each traffic selector and transfer network-order to host-order\r
+    //\r
+    TsPayload   = (IKEV2_TS *) IkePayload->PayloadBuf;\r
+    TsSelector  = (TRAFFIC_SELECTOR *) (IkePayload->PayloadBuf + sizeof (IKEV2_TS));\r
+\r
+    for (Index = 0; Index < TsPayload->TSNumbers; Index++) {\r
+      TsSelector->SelecorLen  = NTOHS (TsSelector->SelecorLen);\r
+      TsSelector->StartPort   = NTOHS (TsSelector->StartPort);\r
+      TsSelector->EndPort     = NTOHS (TsSelector->EndPort);\r
+\r
+      TsTotalSize             = (UINT16) (TsTotalSize + TsSelector->SelecorLen);\r
+      TsSelector              = (TRAFFIC_SELECTOR *) ((UINT8 *) TsSelector + TsSelector->SelecorLen);\r
+    }\r
+    //\r
+    // Check if the total size of Traffic Selectors is correct.\r
+    //\r
+    if (TsTotalSize != PayloadSize - sizeof(IKEV2_TS)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+  case IKEV2_PAYLOAD_TYPE_CP:\r
+    CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1);\r
+    CfgAttribute->AttritType  = NTOHS (CfgAttribute->AttritType);\r
+    CfgAttribute->ValueLength = NTOHS (CfgAttribute->ValueLength);\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+ Exit:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Decode the IKE packet.\r
+\r
+  This function first decrypts the IKE packet if needed , then separates the whole \r
+  IKE packet from the IkePacket->PayloadBuf into IkePacket payload list.\r
+  \r
+  @param[in]      SessionCommon          Pointer to IKEV1_SESSION_COMMON containing \r
+                                         some parameter used by IKE packet decoding.\r
+  @param[in, out] IkePacket              The IKE Packet to be decoded on input, and \r
+                                         the decoded result on return.\r
+  @param[in]      IkeType                The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and\r
+                                         IKE_CHILD_TYPE are supported.\r
+\r
+  @retval         EFI_SUCCESS            The IKE packet is decoded successfully.\r
+  @retval         Otherwise              The IKE packet decoding is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2DecodePacket (\r
+  IN     IKEV2_SESSION_COMMON  *SessionCommon,\r
+  IN OUT IKE_PACKET            *IkePacket,\r
+  IN     UINTN                 IkeType\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;\r
+  UINT8                       PayloadType;\r
+  UINTN                       RemainBytes;\r
+  UINT16                      PayloadSize;\r
+  IKE_PAYLOAD                 *IkePayload;\r
+  IKE_HEADER                  *IkeHeader;\r
+  IKEV2_SA_SESSION            *IkeSaSession;\r
+\r
+  IkeHeader = NULL;\r
+  \r
+  //\r
+  // Check if the IkePacket need decrypt.\r
+  //\r
+  if (SessionCommon->State >= IkeStateAuth) {\r
+    Status = Ikev2DecryptPacket (SessionCommon, IkePacket, IkeType);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // If the IkePacket doesn't contain any payload return invalid parameter.\r
+  //\r
+  if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE) {\r
+    if ((SessionCommon->State >= IkeStateAuth) && \r
+        (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INFO)\r
+        ) {\r
+      //\r
+      // If it is Liveness check, there will be no payload load in the encrypt payload.\r
+      //\r
+      Status = EFI_SUCCESS;\r
+    } else {\r
+      Status = EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If the PayloadTotalSize < Header length, return invalid parameter.\r
+  //\r
+  RemainBytes = IkePacket->PayloadTotalSize;\r
+  if (RemainBytes < sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // If the packet is first or second message, store whole message in\r
+  // IkeSa->InitiPacket or IkeSa->RespPacket for following Auth Payload\r
+  // calculate.\r
+  //\r
+  if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) {\r
+    IkeHeader = AllocateZeroPool (sizeof (IKE_HEADER));\r
+    ASSERT (IkeHeader != NULL);\r
+    CopyMem (IkeHeader, IkePacket->Header, sizeof (IKE_HEADER));\r
+\r
+    //\r
+    // Before store the whole packet, roll back the host order to network order,\r
+    // since the header order was changed in the IkePacketFromNetbuf.\r
+    //\r
+    IkeHdrNetToHost (IkeHeader);\r
+    IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);\r
+    if (SessionCommon->IsInitiator) {\r
+      IkeSaSession->RespPacket     = AllocateZeroPool (IkePacket->Header->Length);\r
+      IkeSaSession->RespPacketSize = IkePacket->Header->Length;\r
+      CopyMem (IkeSaSession->RespPacket, IkeHeader, sizeof (IKE_HEADER));\r
+      CopyMem (\r
+        IkeSaSession->RespPacket + sizeof (IKE_HEADER),\r
+        IkePacket->PayloadsBuf,\r
+        IkePacket->Header->Length - sizeof (IKE_HEADER)\r
+        );         \r
+    } else {\r
+      IkeSaSession->InitPacket     = AllocateZeroPool (IkePacket->Header->Length);\r
+      IkeSaSession->InitPacketSize = IkePacket->Header->Length;\r
+      CopyMem (IkeSaSession->InitPacket, IkeHeader, sizeof (IKE_HEADER));\r
+      CopyMem (\r
+        IkeSaSession->InitPacket + sizeof (IKE_HEADER),\r
+        IkePacket->PayloadsBuf,\r
+        IkePacket->Header->Length - sizeof (IKE_HEADER)\r
+        );\r
+    }\r
+  }\r
+\r
+  //\r
+  // Point to the first Payload \r
+  //\r
+  PayloadHdr  = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePacket->PayloadsBuf;\r
+  PayloadType = IkePacket->Header->NextPayload;\r
+\r
+  //\r
+  // Parse each payload\r
+  //\r
+  while (RemainBytes >= sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) {\r
+    PayloadSize = NTOHS (PayloadHdr->PayloadLength);\r
+\r
+    //\r
+    //Check the size of the payload is correct.\r
+    //\r
+    if (RemainBytes < PayloadSize) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // At certain states, it should save some datas before decoding.\r
+    //\r
+    if (SessionCommon->BeforeDecodePayload != NULL) {\r
+      SessionCommon->BeforeDecodePayload (\r
+                       (UINT8 *) SessionCommon,\r
+                       (UINT8 *) PayloadHdr,\r
+                       PayloadSize,\r
+                       PayloadType\r
+                       );\r
+    }\r
+\r
+    //\r
+    // Initial IkePayload\r
+    //\r
+    IkePayload = IkePayloadAlloc ();\r
+    ASSERT (IkePayload != NULL);\r
+\r
+    IkePayload->PayloadType     = PayloadType;\r
+    IkePayload->PayloadBuf      = (UINT8 *) PayloadHdr;\r
+    IkePayload->PayloadSize     = PayloadSize;\r
+    IkePayload->IsPayloadBufExt = TRUE;\r
+\r
+    Status = Ikev2DecodePayload ((UINT8 *) SessionCommon, IkePayload);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    IPSEC_DUMP_BUF ("After Decoding Payload", IkePayload->PayloadBuf, IkePayload->PayloadSize);\r
+    //\r
+    // Add each payload into packet\r
+    // Notice, the IkePacket->Hdr->Lenght still recode the whole IkePacket length\r
+    // which is before the decoding.\r
+    //\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);\r
+\r
+    RemainBytes -= PayloadSize;\r
+    PayloadType  = PayloadHdr->NextPayload;\r
+    if (PayloadType == IKEV2_PAYLOAD_TYPE_NONE) {\r
+      break;\r
+    }\r
+\r
+    PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) ((UINT8 *) PayloadHdr + PayloadSize);\r
+  }\r
+\r
+  if (PayloadType != IKEV2_PAYLOAD_TYPE_NONE) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Exit;\r
+  }\r
+\r
+Exit:\r
+  if (EFI_ERROR (Status)) {\r
+    ClearAllPayloads (IkePacket);\r
+  }\r
+\r
+  if (IkeHeader != NULL) {\r
+    FreePool (IkeHeader);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Encode the IKE packet.\r
+\r
+  This function puts all Payloads into one payload then encrypt it if needed.\r
+\r
+  @param[in]      SessionCommon      Pointer to IKEV2_SESSION_COMMON containing \r
+                                     some parameter used during IKE packet encoding.\r
+  @param[in, out] IkePacket          Pointer to IKE_PACKET to be encoded as input, \r
+                                     and the encoded result as output.\r
+  @param[in]      IkeType            The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and\r
+                                     IKE_CHILD_TYPE are supportted.\r
+\r
+  @retval         EFI_SUCCESS        Encode IKE packet successfully.\r
+  @retval         Otherwise          Encode IKE packet failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2EncodePacket (\r
+  IN     IKEV2_SESSION_COMMON *SessionCommon,\r
+  IN OUT IKE_PACKET           *IkePacket,\r
+  IN     UINTN                IkeType\r
+  )\r
+{\r
+  IKE_PAYLOAD       *IkePayload;\r
+  UINTN             PayloadTotalSize;\r
+  LIST_ENTRY        *Entry;\r
+  EFI_STATUS        Status;\r
+  IKEV2_SA_SESSION  *IkeSaSession;\r
+\r
+  PayloadTotalSize = 0;\r
+  //\r
+  // Encode each payload\r
+  //\r
+  for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {\r
+    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+    Entry       = Entry->ForwardLink;\r
+    Status      = Ikev2EncodePayload ((UINT8 *) SessionCommon, IkePayload);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (SessionCommon->AfterEncodePayload != NULL) {\r
+      //\r
+      // For certain states, save some payload for further calculation\r
+      //\r
+      SessionCommon->AfterEncodePayload (\r
+                      (UINT8 *) SessionCommon,\r
+                      IkePayload->PayloadBuf,\r
+                      IkePayload->PayloadSize,\r
+                      IkePayload->PayloadType\r
+                      );\r
+    }\r
+\r
+    PayloadTotalSize += IkePayload->PayloadSize;\r
+  }\r
+  IkePacket->PayloadTotalSize = PayloadTotalSize;\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (SessionCommon->State >= IkeStateAuth) {\r
+    //\r
+    // Encrypt all payload and transfer IKE packet header from Host order to Network order.\r
+    //\r
+    Status = Ikev2EncryptPacket (SessionCommon, IkePacket);\r
+  } else {\r
+    //\r
+    // Fill in the lenght into IkePacket header and transfer Host order to Network order.\r
+    //\r
+    IkePacket->Header->Length = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize);\r
+    IkeHdrHostToNet (IkePacket->Header);\r
+  }\r
+\r
+  //\r
+  // If the packet is first message, store whole message in IkeSa->InitiPacket \r
+  // for following Auth Payload calculation.\r
+  //\r
+  if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) {\r
+    IkeSaSession =  IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);\r
+    if (SessionCommon->IsInitiator) {      \r
+      IkeSaSession->InitPacketSize = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER);\r
+      IkeSaSession->InitPacket     = AllocateZeroPool (IkeSaSession->InitPacketSize);\r
+      ASSERT (IkeSaSession->InitPacket != NULL);\r
+      CopyMem (IkeSaSession->InitPacket, IkePacket->Header, sizeof (IKE_HEADER));\r
+      PayloadTotalSize = 0;\r
+      for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {\r
+        IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+        Entry       = Entry->ForwardLink;\r
+        CopyMem (\r
+          IkeSaSession->InitPacket + sizeof (IKE_HEADER) + PayloadTotalSize,\r
+          IkePayload->PayloadBuf,\r
+          IkePayload->PayloadSize\r
+          );\r
+        PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize;\r
+      }\r
+    } else {      \r
+      IkeSaSession->RespPacketSize = IkePacket->PayloadTotalSize + sizeof(IKE_HEADER);\r
+      IkeSaSession->RespPacket     = AllocateZeroPool (IkeSaSession->RespPacketSize);\r
+      ASSERT (IkeSaSession->RespPacket != NULL);\r
+      CopyMem (IkeSaSession->RespPacket, IkePacket->Header, sizeof (IKE_HEADER));\r
+      PayloadTotalSize = 0;\r
+      for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {\r
+        IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+        Entry       = Entry->ForwardLink;\r
+\r
+        CopyMem (\r
+          IkeSaSession->RespPacket + sizeof (IKE_HEADER) + PayloadTotalSize,\r
+          IkePayload->PayloadBuf,\r
+          IkePayload->PayloadSize\r
+          );\r
+        PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize;\r
+      }\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Decrypt IKE packet.\r
+\r
+  This function decrypts the Encrypted IKE packet and put the result into IkePacket->PayloadBuf.\r
+\r
+  @param[in]      SessionCommon       Pointer to IKEV2_SESSION_COMMON containing \r
+                                      some parameter used during decrypting.\r
+  @param[in, out] IkePacket           Pointer to IKE_PACKET to be decrypted as input, \r
+                                      and the decrypted result as output.\r
+  @param[in, out] IkeType             The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and\r
+                                      IKE_CHILD_TYPE are supportted.\r
+\r
+  @retval EFI_INVALID_PARAMETER      If the IKE packet length is zero or the\r
+                                     IKE packet length is not aligned with Algorithm Block Size\r
+  @retval EFI_SUCCESS                Decrypt IKE packet successfully.\r
+  \r
+**/\r
+EFI_STATUS\r
+Ikev2DecryptPacket (\r
+  IN     IKEV2_SESSION_COMMON *SessionCommon,\r
+  IN OUT IKE_PACKET           *IkePacket,\r
+  IN OUT UINTN                IkeType\r
+  )\r
+{\r
+  UINT8                  CryptBlockSize;      // Encrypt Block Size\r
+  UINTN                  DecryptedSize;       // Encrypted IKE Payload Size  \r
+  UINT8                  *DecryptedBuf;       // Encrypted IKE Payload buffer\r
+  UINTN                  IntegritySize;\r
+  UINT8                  *IntegrityBuffer;\r
+  UINTN                  IvSize;              // Iv Size \r
+  UINT8                  CheckSumSize;        // Integrity Check Sum Size depends on intergrity Auth \r
+  UINT8                  *CheckSumData;       // Check Sum data\r
+  IKEV2_SA_SESSION       *IkeSaSession;\r
+  IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
+  EFI_STATUS             Status;\r
+  UINT8                  PadLen;\r
+  UINTN                  CryptKeyLength;\r
+  HASH_DATA_FRAGMENT     Fragments[1];\r
+\r
+  IvSize         = 0;\r
+  IkeSaSession   = NULL;\r
+  CryptBlockSize = 0;\r
+  CheckSumSize   = 0;\r
+  CryptKeyLength = 0;\r
+\r
+  //\r
+  // Check if the first payload is the Encrypted payload\r
+  //\r
+  if (IkePacket->Header->NextPayload != IKEV2_PAYLOAD_TYPE_ENCRYPT) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  CheckSumData    = NULL;\r
+  DecryptedBuf    = NULL;\r
+  IntegrityBuffer = NULL;\r
+\r
+  //\r
+  // Get the Block Size\r
+  //\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    \r
+    CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId);\r
+    CryptKeyLength = IpSecGetEncryptKeyLength ((UINT8) SessionCommon->SaParams->EncAlgId);\r
+    CheckSumSize   = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId);\r
+    IkeSaSession   = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);\r
+\r
+  } else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) {\r
+\r
+    ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
+    IkeSaSession   = ChildSaSession->IkeSaSession;\r
+    CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);\r
+    CryptKeyLength = IpSecGetEncryptKeyLength ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);\r
+    CheckSumSize   = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId);\r
+  } else {\r
+    //\r
+    // The type of SA Session would either be IkeSa or ChildSa.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CheckSumData = AllocateZeroPool (CheckSumSize);\r
+  ASSERT (CheckSumData != NULL);\r
+\r
+  //\r
+  // Fill in the Integrity buffer\r
+  //\r
+  IntegritySize   = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER);\r
+  IntegrityBuffer = AllocateZeroPool (IntegritySize);\r
+  ASSERT (IntegrityBuffer != NULL);\r
+  CopyMem (IntegrityBuffer, IkePacket->Header, sizeof(IKE_HEADER));\r
+  CopyMem (IntegrityBuffer + sizeof (IKE_HEADER), IkePacket->PayloadsBuf, IkePacket->PayloadTotalSize);\r
+\r
+  //\r
+  // Change Host order to Network order, since the header order was changed \r
+  // in the IkePacketFromNetbuf.\r
+  //\r
+  IkeHdrHostToNet ((IKE_HEADER *)IntegrityBuffer);\r
+\r
+  //\r
+  // Calculate the Integrity CheckSum Data\r
+  //\r
+  Fragments[0].Data     = IntegrityBuffer;\r
+  Fragments[0].DataSize = IntegritySize - CheckSumSize;\r
+\r
+  if (SessionCommon->IsInitiator) {\r
+    Status = IpSecCryptoIoHmac (\r
+               (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,\r
+               IkeSaSession->IkeKeys->SkArKey,\r
+               IkeSaSession->IkeKeys->SkArKeySize,\r
+               (HASH_DATA_FRAGMENT *) Fragments,\r
+               1,\r
+               CheckSumData,\r
+               CheckSumSize\r
+               );\r
+  } else {\r
+    Status = IpSecCryptoIoHmac (\r
+               (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,\r
+               IkeSaSession->IkeKeys->SkAiKey,\r
+               IkeSaSession->IkeKeys->SkAiKeySize,\r
+               (HASH_DATA_FRAGMENT *) Fragments,\r
+               1,\r
+               CheckSumData,\r
+               CheckSumSize\r
+               );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Compare the Integrity CheckSum Data with the one in IkePacket\r
+  //\r
+  if (CompareMem (\r
+        IkePacket->PayloadsBuf + IkePacket->PayloadTotalSize - CheckSumSize,\r
+        CheckSumData,\r
+        CheckSumSize\r
+        ) != 0) {\r
+    DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_EXIT;\r
+  }\r
\r
+  IvSize = CryptBlockSize;\r
+   \r
+  //\r
+  // Decrypt the payload with the key.\r
+  //\r
+  DecryptedSize = IkePacket->PayloadTotalSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER) - IvSize - CheckSumSize;\r
+  DecryptedBuf  = AllocateZeroPool (DecryptedSize);\r
+  ASSERT (DecryptedBuf != NULL);\r
+\r
+  CopyMem (\r
+    DecryptedBuf,\r
+    IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER) + IvSize,\r
+    DecryptedSize\r
+    );\r
+\r
+  if (SessionCommon->IsInitiator) {\r
+   Status = IpSecCryptoIoDecrypt (\r
+              (UINT8) SessionCommon->SaParams->EncAlgId,\r
+              IkeSaSession->IkeKeys->SkErKey,\r
+              IkeSaSession->IkeKeys->SkErKeySize << 3,\r
+              IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),\r
+              DecryptedBuf,\r
+              DecryptedSize,\r
+              DecryptedBuf\r
+              );\r
+  } else {\r
+    Status = IpSecCryptoIoDecrypt (\r
+               (UINT8) SessionCommon->SaParams->EncAlgId,\r
+               IkeSaSession->IkeKeys->SkEiKey,\r
+               IkeSaSession->IkeKeys->SkEiKeySize << 3,\r
+               IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),\r
+               DecryptedBuf,\r
+               DecryptedSize,\r
+               DecryptedBuf\r
+               );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Error decrypt buffer with %r\n", Status));\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Get the Padding length\r
+  //\r
+  //\r
+  PadLen = (UINT8) (*(DecryptedBuf + DecryptedSize - sizeof (IKEV2_PAD_LEN)));\r
+\r
+  //\r
+  // Save the next payload of encrypted payload into IkePacket->Hdr->NextPayload\r
+  //\r
+  IkePacket->Header->NextPayload = ((IKEV2_ENCRYPTED *) IkePacket->PayloadsBuf)->Header.NextPayload;\r
+  \r
+  //\r
+  // Free old IkePacket->PayloadBuf and point it to decrypted paylaod buffer.\r
+  //\r
+  FreePool (IkePacket->PayloadsBuf);\r
+  IkePacket->PayloadsBuf      = DecryptedBuf;\r
+  IkePacket->PayloadTotalSize = DecryptedSize - PadLen;\r
+\r
+  IPSEC_DUMP_BUF ("Decrypted Buffer", DecryptedBuf, DecryptedSize);\r
+  \r
+\r
+ON_EXIT:\r
+  if (CheckSumData != NULL) {\r
+    FreePool (CheckSumData);\r
+  }\r
+\r
+  if (EFI_ERROR (Status) && DecryptedBuf != NULL) {\r
+    FreePool (DecryptedBuf);\r
+  }\r
+\r
+  if (IntegrityBuffer != NULL) {\r
+    FreePool (IntegrityBuffer);\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Encrypt IKE packet.\r
+\r
+  This function encrypt IKE packet before sending it. The Encrypted IKE packet\r
+  is put in to IKEV2 Encrypted Payload.\r
+  \r
+  @param[in]        SessionCommon     Pointer to IKEV2_SESSION_COMMON related to the IKE packet.\r
+  @param[in, out]   IkePacket         Pointer to IKE packet to be encrypted.\r
+\r
+  @retval      EFI_SUCCESS       Operation is successful.\r
+  @retval      Others            Operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2EncryptPacket (\r
+  IN IKEV2_SESSION_COMMON *SessionCommon,\r
+  IN OUT IKE_PACKET       *IkePacket\r
+  )\r
+{\r
+  UINT8                  CryptBlockSize;      // Encrypt Block Size\r
+  UINT8                  CryptBlockSizeMask;  // Block Mask\r
+  UINTN                  EncryptedSize;       // Encrypted IKE Payload Size  \r
+  UINT8                  *EncryptedBuf;       // Encrypted IKE Payload buffer\r
+  UINT8                  *EncryptPayloadBuf;  // Contain whole Encrypted Payload\r
+  UINTN                  EncryptPayloadSize;  // Total size of the Encrypted payload\r
+  UINT8                  *IntegrityBuf;       // Buffer to be intergity \r
+  UINT32                 IntegrityBufSize;    // Buffer size of IntegrityBuf\r
+  UINT8                  *IvBuffer;           // Initialization Vector\r
+  UINT8                  IvSize;              // Iv Size \r
+  UINT8                  CheckSumSize;        // Integrity Check Sum Size depends on intergrity Auth \r
+  UINT8                  *CheckSumData;       // Check Sum data\r
+  UINTN                  Index;\r
+  IKE_PAYLOAD            *EncryptPayload;\r
+  IKEV2_SA_SESSION       *IkeSaSession;\r
+  IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
+  EFI_STATUS             Status;\r
+  LIST_ENTRY             *Entry;\r
+  IKE_PAYLOAD            *IkePayload;\r
+  UINTN                  CryptKeyLength;\r
+  HASH_DATA_FRAGMENT     Fragments[1];\r
+\r
+  //\r
+  // Initial all buffers to NULL.\r
+  //\r
+  EncryptedBuf      = NULL;\r
+  EncryptPayloadBuf = NULL;\r
+  IvBuffer          = NULL;\r
+  CheckSumData      = NULL;\r
+  IkeSaSession      = NULL;\r
+  CryptBlockSize    = 0;\r
+  CheckSumSize      = 0;\r
+  CryptKeyLength    = 0;\r
+  IntegrityBuf      = NULL;\r
+  //\r
+  // Get the Block Size\r
+  //\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+\r
+    CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId);\r
+    CryptKeyLength = IpSecGetEncryptKeyLength ((UINT8) SessionCommon->SaParams->EncAlgId);\r
+    CheckSumSize   = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId);\r
+    IkeSaSession   = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);\r
+\r
+  } else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) {\r
+\r
+    ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
+    IkeSaSession   = ChildSaSession->IkeSaSession;\r
+    CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);\r
+    CryptKeyLength = IpSecGetEncryptKeyLength ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);\r
+    CheckSumSize   = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId);\r
+  }\r
+  \r
+  //\r
+  // Calcualte the EncryptPayloadSize and the PAD length\r
+  //\r
+  CryptBlockSizeMask  = (UINT8) (CryptBlockSize - 1);\r
+  EncryptedSize       = (IkePacket->PayloadTotalSize + sizeof (IKEV2_PAD_LEN) + CryptBlockSizeMask) & ~CryptBlockSizeMask;\r
+  EncryptedBuf        = (UINT8 *) AllocateZeroPool (EncryptedSize);\r
+  ASSERT (EncryptedBuf != NULL);\r
+\r
+  //\r
+  // Copy all payload into EncryptedIkePayload\r
+  //\r
+  Index = 0;\r
+  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {\r
+    IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);\r
+\r
+    CopyMem (EncryptedBuf + Index, IkePayload->PayloadBuf, IkePayload->PayloadSize);\r
+    Index += IkePayload->PayloadSize;\r
+\r
+  };\r
+\r
+  //\r
+  // Fill in the Pading Length\r
+  //\r
+  *(EncryptedBuf + EncryptedSize - 1) = (UINT8)(EncryptedSize - IkePacket->PayloadTotalSize - 1);\r
+\r
+  //\r
+  // The IV size is equal with block size\r
+  //\r
+  IvSize    = CryptBlockSize;\r
+  IvBuffer  = (UINT8 *) AllocateZeroPool (IvSize);\r
+\r
+  //\r
+  // Generate IV\r
+  //\r
+  IkeGenerateIv (IvBuffer, IvSize);\r
+\r
+  //\r
+  // Encrypt payload buf\r
+  //\r
+  if (SessionCommon->IsInitiator) {\r
+    Status = IpSecCryptoIoEncrypt (\r
+               (UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId,\r
+               IkeSaSession->IkeKeys->SkEiKey,\r
+               IkeSaSession->IkeKeys->SkEiKeySize << 3,\r
+               IvBuffer,\r
+               EncryptedBuf,\r
+               EncryptedSize,\r
+               EncryptedBuf\r
+               );\r
+  } else {\r
+    Status = IpSecCryptoIoEncrypt (\r
+               (UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId,\r
+               IkeSaSession->IkeKeys->SkErKey,\r
+               IkeSaSession->IkeKeys->SkErKeySize << 3,\r
+               IvBuffer,\r
+               EncryptedBuf,\r
+               EncryptedSize,\r
+               EncryptedBuf\r
+               );\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Allocate the buffer for the whole IKE payload (Encrypted Payload).\r
+  //\r
+  EncryptPayloadSize = sizeof(IKEV2_ENCRYPTED) + IvSize + EncryptedSize + CheckSumSize;\r
+  EncryptPayloadBuf  = AllocateZeroPool (EncryptPayloadSize);\r
+  ASSERT (EncryptPayloadBuf != NULL);\r
+\r
+  //\r
+  // Fill in Header of  Encrypted Payload\r
+  //\r
+  ((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.NextPayload   = IkePacket->Header->NextPayload;\r
+  ((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.PayloadLength = HTONS ((UINT16)EncryptPayloadSize);\r
+\r
+  //\r
+  // Fill in Iv\r
+  //\r
+  CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED), IvBuffer, IvSize);\r
+\r
+  //\r
+  // Fill in encrypted data\r
+  //\r
+  CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED) + IvSize, EncryptedBuf, EncryptedSize);\r
+\r
+  //\r
+  // Fill in the IKE Packet header\r
+  //  \r
+  IkePacket->PayloadTotalSize    = EncryptPayloadSize;\r
+  IkePacket->Header->Length      = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize);\r
+  IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ENCRYPT;\r
+  \r
+  IntegrityBuf                   = AllocateZeroPool (IkePacket->Header->Length);\r
+  IntegrityBufSize               = IkePacket->Header->Length;\r
+  IkeHdrHostToNet (IkePacket->Header);\r
+\r
+  CopyMem (IntegrityBuf, IkePacket->Header, sizeof (IKE_HEADER));\r
+  CopyMem (IntegrityBuf + sizeof (IKE_HEADER), EncryptPayloadBuf, EncryptPayloadSize);\r
+\r
+  //\r
+  // Calcualte Integrity CheckSum\r
+  //\r
+  Fragments[0].Data     = IntegrityBuf;\r
+  Fragments[0].DataSize = EncryptPayloadSize + sizeof (IKE_HEADER) - CheckSumSize;\r
+\r
+  CheckSumData = AllocateZeroPool (CheckSumSize);\r
+  if (SessionCommon->IsInitiator) {\r
+\r
+    IpSecCryptoIoHmac (\r
+      (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,\r
+      IkeSaSession->IkeKeys->SkAiKey,\r
+      IkeSaSession->IkeKeys->SkAiKeySize,\r
+      (HASH_DATA_FRAGMENT *) Fragments,\r
+      1,\r
+      CheckSumData,\r
+      CheckSumSize\r
+      );\r
+  } else {\r
+\r
+    IpSecCryptoIoHmac (\r
+      (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,\r
+      IkeSaSession->IkeKeys->SkArKey,\r
+      IkeSaSession->IkeKeys->SkArKeySize,\r
+      (HASH_DATA_FRAGMENT *) Fragments, \r
+      1,\r
+      CheckSumData,\r
+      CheckSumSize\r
+      );\r
+  }\r
+\r
+  //\r
+  // Copy CheckSum into Encrypted Payload\r
+  //\r
+  CopyMem (EncryptPayloadBuf + EncryptPayloadSize - CheckSumSize, CheckSumData, CheckSumSize);\r
+\r
+  IPSEC_DUMP_BUF ("Encrypted payload buffer", EncryptPayloadBuf, EncryptPayloadSize);\r
+  IPSEC_DUMP_BUF ("Integrith CheckSum Data", CheckSumData, CheckSumSize);\r
+\r
+  //\r
+  // Clean all payload under IkePacket->PayloadList.\r
+  //\r
+  ClearAllPayloads (IkePacket);\r
+\r
+  //\r
+  // Create Encrypted Payload and add into IkePacket->PayloadList\r
+  //\r
+  EncryptPayload = IkePayloadAlloc ();\r
+  ASSERT (EncryptPayload != NULL);\r
+\r
+  //\r
+  // Fill the encrypted payload into the IKE_PAYLOAD structure.\r
+  //\r
+  EncryptPayload->PayloadBuf  = EncryptPayloadBuf;\r
+  EncryptPayload->PayloadSize = EncryptPayloadSize;\r
+  EncryptPayload->PayloadType = IKEV2_PAYLOAD_TYPE_ENCRYPT;\r
+  \r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, EncryptPayload);\r
+\r
+ON_EXIT:\r
+  if (EncryptedBuf != NULL) {\r
+    FreePool (EncryptedBuf);\r
+  }\r
+\r
+  if (EFI_ERROR (Status) && EncryptPayloadBuf != NULL) {\r
+    FreePool (EncryptPayloadBuf);\r
+  }\r
+\r
+  if (IvBuffer != NULL) {\r
+    FreePool (IvBuffer);\r
+  }\r
+\r
+  if (CheckSumData != NULL) {\r
+    FreePool (CheckSumData);\r
+  }\r
+\r
+  if (IntegrityBuf != NULL) {\r
+    FreePool (IntegrityBuf);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Save some useful payloads after accepting the Packet.\r
+\r
+  @param[in] SessionCommon   Pointer to IKEV2_SESSION_COMMON related to the operation.\r
+  @param[in] IkePacket       Pointer to received IkePacet.\r
+  @param[in] IkeType         The type used to indicate it is in IkeSa or ChildSa or Info\r
+                             exchange.\r
+\r
+**/\r
+VOID\r
+Ikev2OnPacketAccepted (\r
+  IN IKEV2_SESSION_COMMON *SessionCommon,\r
+  IN IKE_PACKET           *IkePacket,\r
+  IN UINT8                IkeType\r
+  )\r
+{\r
+  return;\r
+}\r
+\r
+/**\r
+\r
+  The notification function. It will be called when the related UDP_TX_TOKEN's event\r
+  is signaled.\r
+\r
+  This function frees the Net Buffer pointed to the input Packet. \r
+  \r
+  @param[in]  Packet           Pointer to Net buffer containing the sending IKE packet.\r
+  @param[in]  EndPoint         Pointer to UDP_END_POINT containing the remote and local\r
+                               address information.\r
+  @param[in]  IoStatus         The Status of the related UDP_TX_TOKEN.\r
+  @param[in]  Context          Pointer to data passed from the caller.\r
+\r
+**/\r
+VOID\r
+Ikev2OnPacketSent (\r
+  IN NET_BUF                   *Packet,\r
+  IN UDP_END_POINT             *EndPoint,\r
+  IN EFI_STATUS                IoStatus,\r
+  IN VOID                      *Context\r
+  )\r
+{\r
+ IKE_PACKET             *IkePacket;\r
+ IKEV2_SA_SESSION       *IkeSaSession;\r
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
+ UINT8                  Value;\r
+ IPSEC_PRIVATE_DATA     *Private;\r
+ EFI_STATUS             Status;\r
+\r
+ IkePacket  = (IKE_PACKET *) Context;\r
+ Private    = NULL;\r
\r
+ if (EFI_ERROR (IoStatus)) {\r
+    DEBUG ((DEBUG_ERROR, "Error send the last packet in IkeSessionTypeIkeSa with %r\n", IoStatus));\r
+  }\r
+  \r
+  NetbufFree (Packet);\r
+\r
+  if (IkePacket->IsDeleteInfo) {\r
+    //\r
+    // For each RemotePeerIP, there are only one IKESA.\r
+    //\r
+    IkeSaSession = Ikev2SaSessionLookup (\r
+                     &IkePacket->Private->Ikev2EstablishedList,\r
+                     &IkePacket->RemotePeerIp\r
+                     );\r
+    if (IkeSaSession == NULL) {\r
+      IkePacketFree (IkePacket);\r
+      return;\r
+    }\r
+
+    Private = IkePacket->Private;\r
+    if (IkePacket->Spi != 0 ) {\r
+      //\r
+      // At that time, the established Child SA still in eht ChildSaEstablishSessionList.\r
+      // And meanwhile, if the Child SA is in the the ChildSa in Delete list, \r
+      // remove it from delete list and delete it direclty.\r
+      //\r
+      ChildSaSession = Ikev2ChildSaSessionLookupBySpi (\r
+                         &IkeSaSession->ChildSaEstablishSessionList,\r
+                         IkePacket->Spi\r
+                         );\r
+      if (ChildSaSession != NULL) {\r
+        Ikev2ChildSaSessionRemove (\r
+          &IkeSaSession->DeleteSaList,\r
+          ChildSaSession->LocalPeerSpi,\r
+          IKEV2_DELET_CHILDSA_LIST\r
+          );\r
+\r
+        //\r
+        // Delete the Child SA.\r
+        //\r
+        Ikev2ChildSaSilentDelete (\r
+          IkeSaSession,\r
+          IkePacket->Spi\r
+          );\r
+      }\r
+\r
+    } else {\r
+      //\r
+      // Delete the IKE SA\r
+      //\r
+      DEBUG (\r
+        (DEBUG_INFO,\r
+        "\n------ deleted Packet (cookie_i, cookie_r):(0x%lx, 0x%lx)------\n",\r
+        IkeSaSession->InitiatorCookie,\r
+        IkeSaSession->ResponderCookie)\r
+        );\r
+
+      RemoveEntryList (&IkeSaSession->BySessionTable);\r
+      Ikev2SaSessionFree (IkeSaSession);\r
+    }\r
+  }\r
+  IkePacketFree (IkePacket);\r
+\r
+  //\r
+  // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec status \r
+  // should be changed.\r
+  //\r
+  if (Private != NULL && Private->IsIPsecDisabling) {\r
+    //
+    // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
+    // IPsec status variable.
+    //
+    if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) {\r
+      Value = IPSEC_STATUS_DISABLED;
+      Status = gRT->SetVariable (
+                 IPSECCONFIG_STATUS_NAME,
+                 &gEfiIpSecConfigProtocolGuid,
+                 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+                 sizeof (Value),
+                 &Value
+                 );
+      if (!EFI_ERROR (Status)) {
+        //
+        // Set the DisabledFlag in Private data.
+        //
+        Private->IpSec.DisabledFlag = TRUE;
+        Private->IsIPsecDisabling   = FALSE;
+      }
+    }
+  }\r
+}\r
+\r
+/**\r
+  Send out IKEV2 packet.\r
+\r
+  @param[in]  IkeUdpService     Pointer to IKE_UDP_SERVICE used to send the IKE packet.\r
+  @param[in]  SessionCommon     Pointer to IKEV1_SESSION_COMMON related to the IKE packet.\r
+  @param[in]  IkePacket         Pointer to IKE_PACKET to be sent out.\r
+  @param[in]  IkeType           The type of IKE to point what's kind of the IKE \r
+                                packet is to be sent out. IKE_SA_TYPE, IKE_INFO_TYPE \r
+                                and IKE_CHILD_TYPE are supportted.\r
+\r
+  @retval     EFI_SUCCESS       The operation complete successfully.\r
+  @retval     Otherwise         The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2SendIkePacket (\r
+  IN IKE_UDP_SERVICE     *IkeUdpService,\r
+  IN UINT8               *SessionCommon,\r
+  IN IKE_PACKET          *IkePacket,\r
+  IN UINTN               IkeType\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  NET_BUF               *IkePacketNetbuf;\r
+  UDP_END_POINT         EndPoint;\r
+  IKEV2_SESSION_COMMON  *Common;\r
+\r
+  Common = (IKEV2_SESSION_COMMON *) SessionCommon;\r
+  \r
+  //\r
+  // Set the resend interval\r
+  //\r
+  if (Common->TimeoutInterval == 0) {\r
+    Common->TimeoutInterval = IKE_DEFAULT_TIMEOUT_INTERVAL;\r
+  }\r
+\r
+  //\r
+  // Retransfer the packet if it is initial packet.\r
+  //\r
+  if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {\r
+    //\r
+    // Set timer for next retry, this will cancel previous timer\r
+    //\r
+    Status = gBS->SetTimer (\r
+                    Common->TimeoutEvent,\r
+                    TimerRelative,\r
+                    MultU64x32 (Common->TimeoutInterval, 10000) // ms->100ns\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  IKE_PACKET_REF (IkePacket);\r
+  //\r
+  // If the last sent packet is same with this round packet, the packet is resent packet. \r
+  //\r
+  if (IkePacket != Common->LastSentPacket && Common->LastSentPacket != NULL) {\r
+    IkePacketFree (Common->LastSentPacket);\r
+  }\r
+\r
+  Common->LastSentPacket = IkePacket;\r
+\r
+  //\r
+  // Transform IkePacke to NetBuf\r
+  //\r
+  IkePacketNetbuf = IkeNetbufFromPacket ((UINT8 *) SessionCommon, IkePacket, IkeType);\r
+  ASSERT (IkePacketNetbuf != NULL);\r
+\r
+  ZeroMem (&EndPoint, sizeof (UDP_END_POINT));\r
+  EndPoint.RemotePort = IKE_DEFAULT_PORT;\r
+  CopyMem (&IkePacket->RemotePeerIp, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS));\r
+  CopyMem (&EndPoint.RemoteAddr, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS));\r
+  CopyMem (&EndPoint.LocalAddr, &Common->LocalPeerIp, sizeof (EFI_IP_ADDRESS));\r
+\r
+  IPSEC_DUMP_PACKET (IkePacket, EfiIPsecOutBound, IkeUdpService->IpVersion);\r
+\r
+  if (IkeUdpService->IpVersion == IP_VERSION_4) {\r
+    EndPoint.RemoteAddr.Addr[0] = HTONL (EndPoint.RemoteAddr.Addr[0]);\r
+    EndPoint.LocalAddr.Addr[0]  = HTONL (EndPoint.LocalAddr.Addr[0]);\r
+  }\r
+\r
+  //\r
+  // Call UDPIO to send out the IKE packet.\r
+  //\r
+  Status = UdpIoSendDatagram (\r
+             IkeUdpService->Output,\r
+             IkePacketNetbuf,\r
+             &EndPoint,\r
+             NULL,\r
+             Ikev2OnPacketSent,\r
+             (VOID*)IkePacket\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Error send packet with %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Payload.h b/NetworkPkg/IpSecDxe/Ikev2/Payload.h
new file mode 100644 (file)
index 0000000..6096a3b
--- /dev/null
@@ -0,0 +1,438 @@
+/** @file\r
+  The Definitions related to IKEv2 payload.\r
+\r
+  Copyright (c) 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
+#ifndef _IKE_V2_PAYLOAD_H_\r
+#define _IKE_V2_PAYLOAD_H_\r
+\r
+//\r
+// Payload Type for IKEv2\r
+//\r
+#define IKEV2_PAYLOAD_TYPE_NONE     0\r
+#define IKEV2_PAYLOAD_TYPE_SA       33\r
+#define IKEV2_PAYLOAD_TYPE_KE       34\r
+#define IKEV2_PAYLOAD_TYPE_ID_INIT  35\r
+#define IKEV2_PAYLOAD_TYPE_ID_RSP   36\r
+#define IKEV2_PAYLOAD_TYPE_CERT     37\r
+#define IKEV2_PAYLOAD_TYPE_CERTREQ  38\r
+#define IKEV2_PAYLOAD_TYPE_AUTH     39\r
+#define IKEV2_PAYLOAD_TYPE_NONCE    40\r
+#define IKEV2_PAYLOAD_TYPE_NOTIFY   41\r
+#define IKEV2_PAYLOAD_TYPE_DELETE   42\r
+#define IKEV2_PAYLOAD_TYPE_VENDOR   43\r
+#define IKEV2_PAYLOAD_TYPE_TS_INIT  44\r
+#define IKEV2_PAYLOAD_TYPE_TS_RSP   45\r
+#define IKEV2_PAYLOAD_TYPE_ENCRYPT  46\r
+#define IKEV2_PAYLOAD_TYPE_CP       47\r
+#define IKEV2_PAYLOAD_TYPE_EAP      48\r
+\r
+//\r
+// IKE header Flag for IKEv2\r
+//\r
+#define IKE_HEADER_FLAGS_INIT       0x08\r
+#define IKE_HEADER_FLAGS_RESPOND    0x20\r
+#define IKE_HEADER_FLAGS_CHILD_INIT 0\r
+\r
+//\r
+// IKE Header Exchange Type for IKEv2\r
+//\r
+#define IKEV2_EXCHANGE_TYPE_INIT         34\r
+#define IKEV2_EXCHANGE_TYPE_AUTH         35\r
+#define IKEV2_EXCHANGE_TYPE_CREATE_CHILD 36\r
+#define IKEV2_EXCHANGE_TYPE_INFO         37\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8   NextPayload;\r
+  UINT8   Reserved;\r
+  UINT16  PayloadLength;\r
+} IKEV2_COMMON_PAYLOAD_HEADER;\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  // \r
+  // Proposals\r
+  //\r
+} IKEV2_SA;\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       ProposalIndex;\r
+  UINT8                       ProtocolId;\r
+  UINT8                       SpiSize;\r
+  UINT8                       NumTransforms;\r
+} IKEV2_PROPOSAL;\r
+#pragma pack()\r
+\r
+//\r
+// IKEv2 Transform Type Values presented within Transform Payload\r
+//\r
+#define IKEV2_TRANSFORM_TYPE_ENCR      1  // Encryption Algorithm\r
+#define IKEV2_TRANSFORM_TYPE_PRF       2  // Pseduo-Random Func\r
+#define IKEV2_TRANSFORM_TYPE_INTEG     3  // Integrity Algorithm\r
+#define IKEV2_TRANSFORM_TYPE_DH        4  // DH Group\r
+#define IKEV2_TRANSFORM_TYPE_ESN       5  // Extended Sequence Number\r
+\r
+//\r
+// IKEv2 Transform ID for Encrypt Algorithm (ENCR)\r
+// \r
+#define IKEV2_TRANSFORM_ID_ENCR_DES_IV64 1\r
+#define IKEV2_TRANSFORM_ID_ENCR_DES      2\r
+#define IKEV2_TRANSFORM_ID_ENCR_3DES     3\r
+#define IKEV2_TRANSFORM_ID_ENCR_RC5      4\r
+#define IKEV2_TRANSFORM_ID_ENCR_IDEA     5\r
+#define IKEV2_TRANSFORM_ID_ENCR_CAST     6\r
+#define IKEV2_TRANSFORM_ID_ENCR_BLOWFISH 7\r
+#define IKEV2_TRANSFORM_ID_ENCR_3IDEA    8\r
+#define IKEV2_TRANSFORM_ID_ENCR_DES_IV32 9\r
+#define IKEV2_TRANSFORM_ID_ENCR_NULL     11\r
+#define IKEV2_TRANSFORM_ID_ENCR_AES_CBC  12\r
+#define IKEV2_TRANSFORM_ID_ENCR_AES_CTR  13\r
+\r
+//\r
+// IKEv2 Transform ID for Pseudo-Random Function (PRF)\r
+//\r
+#define IKEV2_TRANSFORM_ID_PRF_HMAC_MD5     1\r
+#define IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1    2\r
+#define IKEV2_TRANSFORM_ID_PRF_HMAC_TIGER   3\r
+#define IKEV2_TRANSFORM_ID_PRF_AES128_XCBC  4\r
+\r
+//\r
+// IKEv2 Transform ID for Integrity Algorithm (INTEG)\r
+//\r
+#define IKEV2_TRANSFORM_ID_AUTH_NONE              0\r
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_MD5_96       1\r
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96      2\r
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_DES_MAC      3\r
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_KPDK_MD5     4\r
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_AES_XCBC_96  5\r
+\r
+//\r
+// IKEv2 Transform ID for Diffie-Hellman Group (DH)\r
+//\r
+#define IKEV2_TRANSFORM_ID_DH_768MODP             1\r
+#define IKEV2_TRANSFORM_ID_DH_1024MODP            2\r
+#define IKEV2_TRANSFORM_ID_DH_2048MODP            14\r
+\r
+//\r
+// IKEv2 Attribute Type Values\r
+//\r
+#define IKEV2_ATTRIBUTE_TYPE_KEYLEN               14\r
+\r
+//\r
+// Transform Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       TransformType;\r
+  UINT8                       Reserved;\r
+  UINT16                      TransformId;\r
+  //\r
+  // SA Attributes\r
+  //\r
+} IKEV2_TRANSFORM;\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT16                      DhGroup;\r
+  UINT16                      Reserved;\r
+  //\r
+  // Remaining part contains the key exchanged\r
+  //\r
+} IKEV2_KEY_EXCHANGE;\r
+#pragma pack()\r
+\r
+//\r
+// Identification Type Values presented within Ikev2 ID payload\r
+//\r
+#define IKEV2_ID_TYPE_IPV4_ADDR        1\r
+#define IKEV2_ID_TYPE_FQDN             2\r
+#define IKEV2_ID_TYPE_RFC822_ADDR      3\r
+#define IKEV2_ID_TYPE_IPV6_ADDR        5\r
+#define IKEV2_ID_TYPE_DER_ASN1_DN      9\r
+#define IKEV2_ID_TYPE_DER_ASN1_GN      10\r
+#define IKEV2_ID_TYPE_KEY_ID           11\r
+\r
+//\r
+// Identification Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       IdType;\r
+  UINT8                       Reserver1;\r
+  UINT16                      Reserver2;\r
+  //\r
+  // Identification Data\r
+  //\r
+} IKEV2_ID;\r
+#pragma pack()\r
+\r
+//\r
+// Encoding Type presented in IKEV2 Cert Payload\r
+//\r
+#define IKEV2_CERT_ENCODEING_RESERVED                  0\r
+#define IKEV2_CERT_ENCODEING_X509_CERT_WRAP            1\r
+#define IKEV2_CERT_ENCODEING_PGP_CERT                  2\r
+#define IKEV2_CERT_ENCODEING_DNS_SIGN_KEY              3\r
+#define IKEV2_CERT_ENCODEING_X509_CERT_SIGN            4\r
+#define IKEV2_CERT_ENCODEING_KERBEROS_TOKEN            6\r
+#define IKEV2_CERT_ENCODEING_REVOCATION_LIST_CERT      7\r
+#define IKEV2_CERT_ENCODEING_AUTH_REVOCATION_LIST      8\r
+#define IKEV2_CERT_ENCODEING_SPKI_CERT                 9\r
+#define IKEV2_CERT_ENCODEING_X509_CERT_ATTRIBUTE       10\r
+#define IKEV2_CERT_ENCODEING_RAW_RSA_KEY               11\r
+#define IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT 12\r
+\r
+//\r
+// IKEV2 Certificate Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       CertEncoding;\r
+  //\r
+  // Cert Data\r
+  //\r
+} IKEV2_CERT;\r
+#pragma pack()\r
+\r
+//\r
+// IKEV2 Certificate Request Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       CertEncoding;\r
+  //\r
+  // Cert Authority\r
+  //\r
+} IKEV2_CERT_REQ;\r
+#pragma pack()\r
+\r
+//\r
+// Authentication Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       AuthMethod;\r
+  UINT8                       Reserved1;\r
+  UINT16                      Reserved2;\r
+  //\r
+  // Auth Data\r
+  //\r
+} IKEV2_AUTH;\r
+#pragma pack()\r
+\r
+//\r
+// Authmethod in Authentication Payload\r
+//\r
+#define IKEV2_AUTH_METHOD_RSA        1; // RSA Digital Signature\r
+#define IKEV2_AUTH_METHOD_SKMI       2; // Shared Key Message Integrity\r
+#define IKEV2_AUTH_METHOD_DSS        3; // DSS Digital Signature\r
+\r
+//\r
+// IKEv2 Nonce Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  //\r
+  // Nonce Data\r
+  //\r
+} IKEV2_NONCE;\r
+#pragma pack()\r
+\r
+//\r
+// Notification Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       ProtocolId;\r
+  UINT8                       SpiSize;\r
+  UINT16                      MessageType;\r
+  //\r
+  // SPI and Notification Data\r
+  //\r
+} IKEV2_NOTIFY;\r
+#pragma pack()\r
+\r
+//\r
+//  Notify Message Types presented within IKEv2 Notify Payload\r
+//\r
+#define IKEV2_NOTIFICATION_UNSUPPORT_CRITICAL_PAYLOAD       1\r
+#define IKEV2_NOTIFICATION_INVALID_IKE_SPI                  4\r
+#define IKEV2_NOTIFICATION_INVALID_MAJOR_VERSION            5\r
+#define IKEV2_NOTIFICATION_INVALID_SYNTAX                   7\r
+#define IKEV2_NOTIFICATION_INVALID_MESSAGE_ID               9\r
+#define IKEV2_NOTIFICATION_INVALID_SPI                     11\r
+#define IKEV2_NOTIFICATION_NO_PROPOSAL_CHOSEN              14\r
+#define IKEV2_NOTIFICATION_INVALID_KEY_PAYLOAD             17\r
+#define IKEV2_NOTIFICATION_AUTHENTICATION_FAILED           24\r
+#define IKEV2_NOTIFICATION_SINGLE_PAIR_REQUIRED            34\r
+#define IKEV2_NOTIFICATION_NO_ADDITIONAL_SAS               35\r
+#define IKEV2_NOTIFICATION_INTERNAL_ADDRESS_FAILURE        36\r
+#define IKEV2_NOTIFICATION_FAILED_CP_REQUIRED              37\r
+#define IKEV2_NOTIFICATION_TS_UNCCEPTABLE                  38\r
+#define IKEV2_NOTIFICATION_INVALID_SELECTORS               39\r
+#define IKEV2_NOTIFICATION_COOKIE                          16390\r
+#define IKEV2_NOTIFICATION_USE_TRANSPORT_MODE              16391\r
+#define IKEV2_NOTIFICATION_REKEY_SA                        16393\r
+\r
+//\r
+// IKEv2 Protocol ID\r
+//\r
+//\r
+// IKEv2 Delete Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       ProtocolId;\r
+  UINT8                       SpiSize;\r
+  UINT16                      NumSpis;\r
+  //\r
+  // SPIs\r
+  //\r
+} IKEV2_DELETE;\r
+#pragma pack()\r
+\r
+//\r
+// Traffic Selector Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       TSNumbers;\r
+  UINT8                       Reserved1;\r
+  UINT16                      Reserved2;\r
+  //\r
+  // Traffic Selector\r
+  //\r
+} IKEV2_TS;\r
+#pragma pack()\r
+\r
+//\r
+// Traffic Selector\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8                       TSType;\r
+  UINT8                       IpProtocolId;\r
+  UINT16                      SelecorLen;\r
+  UINT16                      StartPort;\r
+  UINT16                      EndPort;\r
+  //\r
+  // Starting Address && Ending Address\r
+  //\r
+} TRAFFIC_SELECTOR;\r
+#pragma pack()\r
+\r
+//\r
+// Ts Type in Traffic Selector\r
+//\r
+#define IKEV2_TS_TYPE_IPV4_ADDR_RANGE     7\r
+#define IKEV2_TS_TYPS_IPV6_ADDR_RANGE     8\r
+\r
+//\r
+// Vendor Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  //\r
+  // Vendor ID\r
+  //\r
+} IKEV2_VENDOR;\r
+#pragma pack()\r
+\r
+//\r
+// Encrypted Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  //\r
+  // IV, Encrypted IKE Payloads, Padding, PAD length, Integrity CheckSum\r
+  //\r
+} IKEV2_ENCRYPTED;\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8 PadLength;\r
+} IKEV2_PAD_LEN;\r
+#pragma pack()\r
+\r
+//\r
+// Configuration Payload\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  IKEV2_COMMON_PAYLOAD_HEADER Header;\r
+  UINT8                       CfgType;\r
+  UINT8                       Reserve1;\r
+  UINT16                      Reserve2;\r
+  //\r
+  // Configuration Attributes\r
+  //\r
+} IKEV2_CFG;\r
+#pragma pack()\r
+\r
+//\r
+// Configuration Payload CPG type\r
+//\r
+#define IKEV2_CFG_TYPE_REQUEST    1\r
+#define IKEV2_CFG_TYPE_REPLY      2\r
+#define IKEV2_CFG_TYPE_SET        3\r
+#define IKEV2_CFG_TYPE_ACK        4\r
+\r
+//\r
+// Configuration Attributes\r
+//\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT16    AttritType;\r
+  UINT16    ValueLength;\r
+} IKEV2_CFG_ATTRIBUTES;\r
+#pragma pack()\r
+\r
+//\r
+// Configuration Attributes\r
+//\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS      1\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_NBTMASK      2\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_DNS          3\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_NBNS         4\r
+#define IKEV2_CFG_ATTR_INTERNA_ADDRESS_BXPIRY    5\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_DHCP         6\r
+#define IKEV2_CFG_ATTR_APPLICATION_VERSION       7\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS      8\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP6_DNS          10\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP6_NBNS         11\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP6_DHCP         12\r
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_SUBNET       13\r
+#define IKEV2_CFG_ATTR_SUPPORTED_ATTRIBUTES      14\r
+#define IKEV2_CFG_ATTR_IP6_SUBNET                15\r
+\r
+#endif\r
+\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Sa.c b/NetworkPkg/IpSecDxe/Ikev2/Sa.c
new file mode 100644 (file)
index 0000000..7265ca8
--- /dev/null
@@ -0,0 +1,1949 @@
+/** @file\r
+  The operations for IKEv2 SA.\r
+\r
+  Copyright (c) 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 "Utility.h"\r
+#include "IpSecDebug.h"\r
+#include "IkeService.h"\r
+#include "Ikev2.h"\r
+\r
+/**\r
+  Generates the DH Key.\r
+\r
+  This generates the DH local public key and store it in the IKEv2 SA Session's GxBuffer.\r
+  \r
+  @param[in]  IkeSaSession   Pointer to related IKE SA Session.\r
+\r
+  @retval EFI_SUCCESS        The operation succeeded.\r
+  @retval Others             The operation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2GenerateSaDhPublicKey (\r
+  IN IKEV2_SA_SESSION         *IkeSaSession\r
+  );\r
+\r
+/**\r
+  Generates the IKEv2 SA key for the furthure IKEv2 exchange.\r
+\r
+  @param[in]  IkeSaSession       Pointer to IKEv2 SA Session.\r
+  @param[in]  KePayload          Pointer to Key payload used to generate the Key.\r
+\r
+  @retval EFI_UNSUPPORTED    If the Algorithm Id is not supported.\r
+  @retval EFI_SUCCESS        The operation succeeded.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2GenerateSaKeys (\r
+  IN IKEV2_SA_SESSION       *IkeSaSession,\r
+  IN IKE_PAYLOAD            *KePayload\r
+  );\r
+\r
+/**\r
+  Generates the Keys for the furthure IPsec Protocol.\r
+\r
+  @param[in]  ChildSaSession     Pointer to IKE Child SA Session.\r
+  @param[in]  KePayload          Pointer to Key payload used to generate the Key.\r
+\r
+  @retval EFI_UNSUPPORTED    If one or more Algorithm Id is unsupported.\r
+  @retval EFI_SUCCESS        The operation succeeded.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2GenerateChildSaKeys (\r
+  IN IKEV2_CHILD_SA_SESSION     *ChildSaSession,\r
+  IN IKE_PAYLOAD                *KePayload\r
+  );\r
+\r
+/**\r
+  Gernerates IKEv2 packet for IKE_SA_INIT exchange.\r
+\r
+  @param[in] SaSession  Pointer to IKEV2_SA_SESSION related to the exchange.\r
+  @param[in] Context    Context Data passed by caller.\r
+\r
+  @retval EFI_SUCCESS   The IKEv2 packet generation succeeded.\r
+  @retval Others        The IKEv2 packet generation failed.\r
+\r
+**/\r
+IKE_PACKET *\r
+Ikev2InitPskGenerator (\r
+  IN UINT8           *SaSession,\r
+  IN VOID            *Context\r
+  )\r
+{\r
+  IKE_PACKET         *IkePacket;\r
+  IKEV2_SA_SESSION   *IkeSaSession;\r
+  IKE_PAYLOAD        *SaPayload;\r
+  IKE_PAYLOAD        *KePayload;\r
+  IKE_PAYLOAD        *NoncePayload;\r
+  IKE_PAYLOAD        *NotifyPayload;\r
+  EFI_STATUS         Status;\r
+\r
+  SaPayload      = NULL;\r
+  KePayload      = NULL;\r
+  NoncePayload   = NULL;\r
+  NotifyPayload  = NULL;\r
+\r
+  IkeSaSession = (IKEV2_SA_SESSION *) SaSession;\r
+\r
+  //\r
+  // 1. Allocate IKE packet\r
+  //\r
+  IkePacket = IkePacketAlloc ();\r
+  ASSERT (IkePacket != NULL);\r
+\r
+  //\r
+  // 1.a Fill the IkePacket->Hdr\r
+  //\r
+  IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_INIT;\r
+  IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;\r
+  IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;\r
+  IkePacket->Header->Version         = (UINT8) (2 << 4);\r
+  IkePacket->Header->MessageId       = 0;\r
+\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;\r
+  } else {\r
+    IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;\r
+  }\r
+\r
+  //\r
+  // If the NCookie is not NULL, this IKE_SA_INIT packet is resent by the NCookie\r
+  // and the NCookie payload should be the first payload in this packet.\r
+  //\r
+  if (IkeSaSession->NCookie != NULL) {\r
+    IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NOTIFY;\r
+    NotifyPayload = Ikev2GenerateNotifyPayload (\r
+                      IPSEC_PROTO_ISAKMP,\r
+                      IKEV2_PAYLOAD_TYPE_SA,\r
+                      0,\r
+                      IKEV2_NOTIFICATION_COOKIE,\r
+                      NULL,\r
+                      IkeSaSession->NCookie,\r
+                      IkeSaSession->NCookieSize\r
+                      );\r
+  } else {\r
+    IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_SA;\r
+  }\r
+\r
+  //\r
+  // 2. Generate SA Payload according to the SaData & SaParams\r
+  //\r
+  SaPayload = Ikev2GenerateSaPayload (\r
+                IkeSaSession->SaData,\r
+                IKEV2_PAYLOAD_TYPE_KE,\r
+                IkeSessionTypeIkeSa\r
+                );\r
+\r
+  //\r
+  // 3. Generate DH public key.\r
+  //    The DhPrivate Key has been generated in Ikev2InitPskParser, if the\r
+  //    IkeSaSession is responder. If resending IKE_SA_INIT with Cookie Notify\r
+  //    No need to recompute the Public key.\r
+  //\r
+  if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) {    \r
+    Status = Ikev2GenerateSaDhPublicKey (IkeSaSession);\r
+    if (EFI_ERROR (Status)) {\r
+      goto CheckError;\r
+    }\r
+  }\r
+\r
+  //\r
+  // 4. Generate KE Payload according to SaParams->DhGroup\r
+  //\r
+  KePayload = Ikev2GenerateKePayload (\r
+                IkeSaSession, \r
+                IKEV2_PAYLOAD_TYPE_NONCE\r
+                );\r
+\r
+  //\r
+  // 5. Generate Nonce Payload\r
+  //    If resending IKE_SA_INIT with Cookie Notify paylaod, no need to regenerate\r
+  //    the Nonce Payload.\r
+  //\r
+  if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) {\r
+    IkeSaSession->NiBlkSize = IKE_NONCE_SIZE;\r
+    IkeSaSession->NiBlock   = IkeGenerateNonce (IKE_NONCE_SIZE);\r
+    ASSERT (IkeSaSession->NiBlock != NULL);\r
+  }\r
+\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    NoncePayload = Ikev2GenerateNoncePayload (\r
+                     IkeSaSession->NiBlock,\r
+                     IkeSaSession->NiBlkSize,\r
+                     IKEV2_PAYLOAD_TYPE_NONE\r
+                     );\r
+  } else {\r
+    //\r
+    // The Nonce Payload has been created in Ikev2PskParser if the IkeSaSession is\r
+    // responder.\r
+    //\r
+    NoncePayload = Ikev2GenerateNoncePayload (\r
+                     IkeSaSession->NrBlock,\r
+                     IkeSaSession->NrBlkSize,\r
+                     IKEV2_PAYLOAD_TYPE_NONE\r
+                     );\r
+  }\r
+\r
+  if (NotifyPayload != NULL) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);\r
+  }\r
+  if (SaPayload != NULL) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);\r
+  }\r
+  if (KePayload != NULL) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, KePayload);\r
+  }\r
+  if (NoncePayload != NULL) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, NoncePayload);\r
+  }\r
+\r
+  return IkePacket;\r
+\r
+CheckError:\r
+  if (IkePacket != NULL) {\r
+    IkePacketFree (IkePacket);\r
+  }\r
+  if (SaPayload != NULL) {\r
+    IkePayloadFree (SaPayload);\r
+  }\r
+  return NULL;    \r
+}\r
+\r
+/**\r
+  Parses the IKEv2 packet for IKE_SA_INIT exchange.\r
+\r
+  @param[in] SaSession  Pointer to IKEV2_SA_SESSION related to the exchange.\r
+  @param[in] IkePacket  The received IKE packet to be parsed.\r
+\r
+  @retval EFI_SUCCESS            The IKEv2 packet is acceptable and the relative data is\r
+                                 saved for furthure communication.\r
+  @retval EFI_INVALID_PARAMETER  The IKEv2 packet is malformed or the SA proposal is unacceptable.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2InitPskParser (\r
+  IN UINT8            *SaSession,\r
+  IN IKE_PACKET       *IkePacket\r
+  ) \r
+{\r
+  IKEV2_SA_SESSION     *IkeSaSession;\r
+  IKE_PAYLOAD          *SaPayload;\r
+  IKE_PAYLOAD          *KeyPayload;\r
+  IKE_PAYLOAD          *IkePayload;\r
+  IKE_PAYLOAD          *NoncePayload;\r
+  IKE_PAYLOAD          *NotifyPayload;\r
+  UINT8                *NonceBuffer;\r
+  UINTN                NonceSize;\r
+  LIST_ENTRY           *Entry;\r
+  EFI_STATUS           Status;\r
+\r
+  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;\r
+  KeyPayload     = NULL;\r
+  SaPayload      = NULL;\r
+  NoncePayload   = NULL;\r
+  IkePayload     = NULL;\r
+  NotifyPayload  = NULL;\r
+\r
+  //\r
+  // Iterate payloads to find the SaPayload and KeyPayload.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {\r
+    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {\r
+      SaPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_KE) {\r
+      KeyPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NONCE) {\r
+      NoncePayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) {\r
+      NotifyPayload = IkePayload;\r
+    }\r
+  }\r
+\r
+  //\r
+  // According to RFC 4306 - 2.6. If the responder responds with the COOKIE Notify\r
+  // payload with the cookie data, initiator MUST retry the IKE_SA_INIT with a\r
+  // Notify payload of type COOKIE containing the responder suppplied cookie data\r
+  // as first payload and all other payloads unchanged.\r
+  //\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    if (NotifyPayload != NULL) {\r
+      Status = Ikev2ParserNotifyCookiePayload (NotifyPayload, IkeSaSession);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  if ((KeyPayload == NULL) || (SaPayload == NULL) || (NoncePayload == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Store NoncePayload for SKEYID computing.\r
+  //\r
+  NonceSize   = NoncePayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);\r
+  NonceBuffer = (UINT8 *) AllocatePool (NonceSize);\r
+  ASSERT (NonceBuffer != NULL);\r
+  CopyMem (\r
+    NonceBuffer,\r
+    NoncePayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),\r
+    NonceSize\r
+    );\r
+\r
+  //\r
+  // Check if IkePacket Header matches the state\r
+  //\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    //\r
+    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND\r
+    //\r
+    if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto CheckError;\r
+    }\r
+\r
+    //\r
+    // 2. Parse the SA Payload and Key Payload to find out the cryptographic\r
+    //    suite and fill in the Sa paramse into CommonSession->SaParams\r
+    //\r
+    if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto CheckError;\r
+    }\r
+\r
+    //\r
+    // 3. If Initiator, the NoncePayload is Nr_b.\r
+    //\r
+    IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateAuth);\r
+    IkeSaSession->NrBlock             = NonceBuffer;\r
+    IkeSaSession->NrBlkSize           = NonceSize;\r
+    IkeSaSession->SessionCommon.State = IkeStateAuth;\r
+    IkeSaSession->ResponderCookie     = IkePacket->Header->ResponderCookie;\r
+\r
+    //\r
+    // 4. Change the state of IkeSaSession\r
+    //\r
+    IkeSaSession->SessionCommon.State = IkeStateAuth;\r
+  } else {\r
+    //\r
+    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT\r
+    //\r
+    if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto CheckError;\r
+    }\r
+\r
+    //\r
+    // 2. Parse the SA payload and find out the perfered one\r
+    //    and fill in the SA parameters into CommonSession->SaParams and SaData into\r
+    //    IkeSaSession for the responder SA payload generation.\r
+    //\r
+    if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto CheckError;\r
+    }\r
+\r
+    //\r
+    // 3. Generat Dh Y parivate Key\r
+    //\r
+    Status = Ikev2GenerateSaDhPublicKey (IkeSaSession);\r
+    if (EFI_ERROR (Status)) {\r
+      goto CheckError;\r
+    }\r
+\r
+    //\r
+    // 4. If Responder, the NoncePayload is Ni_b and go to generate Nr_b.\r
+    //\r
+    IkeSaSession->NiBlock   = NonceBuffer;\r
+    IkeSaSession->NiBlkSize = NonceSize;\r
+\r
+    //\r
+    // 5. Generate Nr_b\r
+    //\r
+    IkeSaSession->NrBlock   = IkeGenerateNonce (IKE_NONCE_SIZE);\r
+    ASSERT_EFI_ERROR (IkeSaSession->NrBlock != NULL);\r
+    IkeSaSession->NrBlkSize = IKE_NONCE_SIZE;\r
+\r
+    //\r
+    // 6. Save the Cookies\r
+    //\r
+    IkeSaSession->InitiatorCookie = IkePacket->Header->InitiatorCookie;\r
+    IkeSaSession->ResponderCookie = IkeGenerateCookie ();\r
+  }\r
+\r
+  if (IkeSaSession->SessionCommon.PreferDhGroup != ((IKEV2_KEY_EXCHANGE *)KeyPayload->PayloadBuf)->DhGroup) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto CheckError;\r
+  }\r
+  //\r
+  // Call Ikev2GenerateSaKeys to create SKEYID, SKEYID_d, SKEYID_a, SKEYID_e.\r
+  //\r
+  Status = Ikev2GenerateSaKeys (IkeSaSession, KeyPayload);\r
+  if (EFI_ERROR(Status)) {\r
+    goto CheckError;\r
+  }\r
+  return EFI_SUCCESS;\r
+\r
+CheckError:\r
+  if (NonceBuffer != NULL) {\r
+    FreePool (NonceBuffer);\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Generates the IKEv2 packet for IKE_AUTH exchange.\r
+\r
+  @param[in] SaSession  Pointer to IKEV2_SA_SESSION.\r
+  @param[in] Context    Context data passed by caller.\r
+\r
+  @retval   Pointer to IKE Packet to be sent out.\r
+\r
+**/\r
+IKE_PACKET *\r
+Ikev2AuthPskGenerator (\r
+  IN UINT8         *SaSession,\r
+  IN VOID          *Context\r
+  )\r
+{\r
+  IKE_PACKET             *IkePacket;\r
+  IKEV2_SA_SESSION       *IkeSaSession;\r
+  IKE_PAYLOAD            *IdPayload;\r
+  IKE_PAYLOAD            *AuthPayload;\r
+  IKE_PAYLOAD            *SaPayload;\r
+  IKE_PAYLOAD            *TsiPayload;\r
+  IKE_PAYLOAD            *TsrPayload;\r
+  IKE_PAYLOAD            *NotifyPayload;\r
+  IKE_PAYLOAD            *CpPayload;\r
+  IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
+  \r
+\r
+  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;\r
+  ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));\r
+\r
+  CpPayload      = NULL;\r
+  NotifyPayload  = NULL;\r
+  \r
+  //\r
+  // 1. Allocate IKE Packet\r
+  //\r
+  IkePacket= IkePacketAlloc ();\r
+  ASSERT (IkePacket != NULL);\r
+\r
+  //\r
+  // 1.a Fill the IkePacket Header.\r
+  //\r
+  IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_AUTH;\r
+  IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;\r
+  IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;\r
+  IkePacket->Header->Version         = (UINT8)(2 << 4);\r
+  if (ChildSaSession->SessionCommon.IsInitiator) {\r
+    IkePacket->Header->NextPayload   = IKEV2_PAYLOAD_TYPE_ID_INIT;\r
+  } else {\r
+    IkePacket->Header->NextPayload   = IKEV2_PAYLOAD_TYPE_ID_RSP;\r
+  }\r
+\r
+  //\r
+  // According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should \r
+  // be always number 0 and 1;\r
+  //\r
+  IkePacket->Header->MessageId = 1;\r
+\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;\r
+  } else {\r
+    IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;\r
+  }\r
+\r
+  //\r
+  // 2. Generate ID Payload according to IP version and address.\r
+  //\r
+  IdPayload = Ikev2GenerateIdPayload (\r
+                &IkeSaSession->SessionCommon,\r
+                IKEV2_PAYLOAD_TYPE_AUTH\r
+                );\r
+\r
+  //\r
+  // 3. Generate Auth Payload\r
+  //    If it is tunnel mode, should create the configuration payload after the\r
+  //    Auth payload.\r
+  //\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {\r
+\r
+    AuthPayload = Ikev2PskGenerateAuthPayload (\r
+                    ChildSaSession->IkeSaSession,\r
+                    IdPayload,\r
+                    IKEV2_PAYLOAD_TYPE_SA,\r
+                    FALSE\r
+                    );\r
+  } else {\r
+    AuthPayload = Ikev2PskGenerateAuthPayload (\r
+                    ChildSaSession->IkeSaSession,\r
+                    IdPayload,\r
+                    IKEV2_PAYLOAD_TYPE_CP,\r
+                    FALSE\r
+                    );\r
+    if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) {\r
+      CpPayload = Ikev2GenerateCpPayload (\r
+                    ChildSaSession->IkeSaSession,\r
+                    IKEV2_PAYLOAD_TYPE_SA,\r
+                    IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS\r
+                    );\r
+    } else {\r
+      CpPayload = Ikev2GenerateCpPayload (\r
+                    ChildSaSession->IkeSaSession,\r
+                    IKEV2_PAYLOAD_TYPE_SA,\r
+                    IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS\r
+                    );\r
+    }\r
+  }\r
+\r
+  //\r
+  // 4. Generate SA Payload according to the SA Data in ChildSaSession\r
+  //\r
+  SaPayload = Ikev2GenerateSaPayload (\r
+                ChildSaSession->SaData,\r
+                IKEV2_PAYLOAD_TYPE_TS_INIT,\r
+                IkeSessionTypeChildSa\r
+                );\r
+\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {\r
+    //\r
+    // Generate Tsi and Tsr.\r
+    //\r
+    TsiPayload = Ikev2GenerateTsPayload (\r
+                   ChildSaSession,\r
+                   IKEV2_PAYLOAD_TYPE_TS_RSP,\r
+                   FALSE\r
+                   );\r
+\r
+    TsrPayload = Ikev2GenerateTsPayload (\r
+                   ChildSaSession,\r
+                   IKEV2_PAYLOAD_TYPE_NOTIFY,\r
+                   FALSE\r
+                   );\r
+\r
+    //\r
+    // Generate Notify Payload. If transport mode, there should have Notify\r
+    // payload with TRANSPORT_MODE notification.\r
+    //\r
+    NotifyPayload = Ikev2GenerateNotifyPayload (\r
+                      0,\r
+                      IKEV2_PAYLOAD_TYPE_NONE,\r
+                      0,\r
+                      IKEV2_NOTIFICATION_USE_TRANSPORT_MODE,\r
+                      NULL,\r
+                      NULL,\r
+                      0\r
+                      );\r
+  } else {\r
+    //\r
+    // Generate Tsr for Tunnel mode.\r
+    //\r
+    TsiPayload = Ikev2GenerateTsPayload (\r
+                   ChildSaSession,\r
+                   IKEV2_PAYLOAD_TYPE_TS_RSP,\r
+                   TRUE\r
+                   );\r
+    TsrPayload = Ikev2GenerateTsPayload (\r
+                   ChildSaSession,\r
+                   IKEV2_PAYLOAD_TYPE_NONE,\r
+                   FALSE\r
+                   );\r
+  }\r
+\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload);\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload);\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload);\r
+  }\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload);\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload);\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);\r
+  }\r
+\r
+  return IkePacket;\r
+}\r
+\r
+/**\r
+  Parses IKE_AUTH packet.\r
+\r
+  @param[in]  SaSession   Pointer to the IKE_SA_SESSION related to this packet.\r
+  @param[in]  IkePacket   Pointer to the IKE_AUTH packet to be parsered.\r
+\r
+  @retval     EFI_INVALID_PARAMETER   The IKE packet is malformed or the SA \r
+                                      proposal is unacceptable.\r
+  @retval     EFI_SUCCESS             The IKE packet is acceptable and the\r
+                                      relative data is saved for furthure communication.\r
+\r
+**/\r
+EFI_STATUS \r
+Ikev2AuthPskParser (\r
+  IN UINT8             *SaSession,\r
+  IN IKE_PACKET        *IkePacket\r
+  )\r
+{\r
+  IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
+  IKEV2_SA_SESSION       *IkeSaSession;\r
+  IKE_PAYLOAD            *IkePayload;\r
+  IKE_PAYLOAD            *SaPayload;\r
+  IKE_PAYLOAD            *IdiPayload;\r
+  IKE_PAYLOAD            *IdrPayload;\r
+  IKE_PAYLOAD            *AuthPayload;\r
+  IKE_PAYLOAD            *TsiPayload;\r
+  IKE_PAYLOAD            *TsrPayload;\r
+  IKE_PAYLOAD            *VerifiedAuthPayload;\r
+  LIST_ENTRY             *Entry;\r
+  EFI_STATUS             Status;\r
+\r
+  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;\r
+  ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));\r
+\r
+  SaPayload   = NULL;\r
+  IdiPayload  = NULL;\r
+  IdrPayload  = NULL;\r
+  AuthPayload = NULL;\r
+  TsiPayload  = NULL;\r
+  TsrPayload  = NULL;\r
+\r
+  //\r
+  // Iterate payloads to find the SaPayload/ID/AUTH/TS Payload.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {\r
+    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) {\r
+      IdiPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) {\r
+      IdrPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {\r
+      SaPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) {\r
+      AuthPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {\r
+      TsiPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) {\r
+      TsrPayload = IkePayload;\r
+    }\r
+  }\r
+\r
+  if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) || (TsrPayload == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if ((IdiPayload == NULL) && (IdrPayload == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check IkePacket Header is match the state\r
+  //\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    \r
+    //\r
+    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND\r
+    //\r
+    if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) ||\r
+        (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)\r
+        ) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+  } else {\r
+    //\r
+    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT\r
+    //\r
+    if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) ||\r
+        (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)\r
+        ) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // 2. Parse the SA payload and Key Payload and find out the perferable one\r
+    //    and fill in the Sa paramse into CommonSession->SaParams and SaData into\r
+    //    IkeSaSession for the responder SA payload generation.\r
+    //\r
+  }\r
+\r
+  //\r
+  // Verify the Auth Payload.\r
+  //\r
+  VerifiedAuthPayload = Ikev2PskGenerateAuthPayload (\r
+                          IkeSaSession,\r
+                          IkeSaSession->SessionCommon.IsInitiator ? IdrPayload : IdiPayload,\r
+                          IKEV2_PAYLOAD_TYPE_SA,\r
+                          TRUE\r
+                          );\r
+  if ((VerifiedAuthPayload != NULL) &&\r
+      (0 != CompareMem (\r
+              VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),\r
+              AuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),\r
+              VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER)\r
+              ))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  };\r
+\r
+  //\r
+  // 3. Parse the SA Payload to find out the cryptographic suite\r
+  //    and fill in the Sa paramse into CommonSession->SaParams. If no acceptable\r
+  //    porposal found, return EFI_INVALID_PARAMETER.\r
+  //\r
+  if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // 4. Parse TSi, TSr payloads.\r
+  //\r
+  if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId !=\r
+       ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) &&\r
+      (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) &&\r
+      (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0)\r
+      ) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!IkeSaSession->SessionCommon.IsInitiator) {\r
+    //\r
+    //TODO:check the Port range. Only support any port and one certain port here.\r
+    //\r
+    ChildSaSession->ProtoId    = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId;\r
+    ChildSaSession->LocalPort  = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;\r
+    ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;\r
+    //\r
+    // Association a SPD with this SA.\r
+    //\r
+    Status = Ikev2ChildSaAssociateSpdEntry (ChildSaSession);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // Associate the IkeSaSession's SPD to the first ChildSaSession's SPD.\r
+    //\r
+    if (ChildSaSession->IkeSaSession->Spd == NULL) {\r
+      ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd;\r
+      Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);\r
+    }\r
+  } else {\r
+    //\r
+    //TODO:check the Port range.\r
+    //\r
+    if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&\r
+        (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort)\r
+        ) {\r
+      return EFI_INVALID_PARAMETER;\r
+    } \r
+    if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&\r
+        (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort)\r
+        ) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector.\r
+    //\r
+    if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {\r
+      if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) {\r
+        //\r
+        // If it is tunnel mode, the UEFI part must be the initiator.\r
+        //\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+      //\r
+      // Get the Virtual IP address from the Tsi traffic selector. \r
+      // TODO: check the CFG reply payload\r
+      //\r
+      CopyMem (\r
+        &ChildSaSession->SpdSelector->LocalAddress[0].Address,\r
+        TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR),\r
+        (ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ?\r
+        sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)\r
+        );\r
+      }    \r
+  }\r
+\r
+  //\r
+  // 5. Generate keymats for IPsec protocol.\r
+  //\r
+  Ikev2GenerateChildSaKeys (ChildSaSession, NULL);\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    //\r
+    // 6. Change the state of IkeSaSession\r
+    //\r
+    IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished);\r
+    IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished;\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Gernerates IKEv2 packet for IKE_SA_INIT exchange.\r
+\r
+  @param[in] SaSession  Pointer to IKEV2_SA_SESSION related to the exchange.\r
+  @param[in] Context    Context Data passed by caller.\r
+\r
+  @retval EFI_SUCCESS   The IKE packet generation succeeded.\r
+  @retval Others        The IKE packet generation failed.\r
+\r
+**/\r
+IKE_PACKET*\r
+Ikev2InitCertGenerator (\r
+  IN UINT8           *SaSession,\r
+  IN VOID            *Context\r
+  ) \r
+{\r
+  IKE_PACKET         *IkePacket;\r
+  IKE_PAYLOAD        *CertReqPayload;\r
+  LIST_ENTRY         *Node;\r
+  IKE_PAYLOAD        *NoncePayload;\r
+\r
+  if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // The first two messages exchange is same between PSK and Cert.\r
+  //\r
+  IkePacket = Ikev2InitPskGenerator (SaSession, Context);\r
+\r
+  if ((IkePacket != NULL) && (!((IKEV2_SA_SESSION *)SaSession)->SessionCommon.IsInitiator)) {\r
+    //\r
+    // Add the Certification Request Payload\r
+    //\r
+    CertReqPayload = Ikev2GenerateCertificatePayload (\r
+                       (IKEV2_SA_SESSION *)SaSession,\r
+                       IKEV2_PAYLOAD_TYPE_NONE,\r
+                       (UINT8*)PcdGetPtr(UefiCaFile),\r
+                       PcdGet32(UefiCaFileSize),\r
+                       IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,\r
+                       TRUE\r
+                       );\r
+    //\r
+    // Change Nonce Payload Next payload type.\r
+    //\r
+    IKE_PACKET_END_PAYLOAD (IkePacket, Node);\r
+    NoncePayload = IKE_PAYLOAD_BY_PACKET (Node);\r
+    ((IKEV2_NONCE *)NoncePayload->PayloadBuf)->Header.NextPayload = IKEV2_PAYLOAD_TYPE_CERTREQ;\r
+\r
+    //\r
+    // Add Certification Request Payload\r
+    //\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload);\r
+  }\r
+\r
+  return IkePacket;\r
+}\r
+\r
+/**\r
+  Parses the IKEv2 packet for IKE_SA_INIT exchange.\r
+\r
+  @param[in] SaSession  Pointer to IKEV2_SA_SESSION related to the exchange.\r
+  @param[in] IkePacket  The received IKEv2 packet to be parsed.\r
+\r
+  @retval EFI_SUCCESS            The IKEv2 packet is acceptable and the relative data is\r
+                                 saved for furthure communication.\r
+  @retval EFI_INVALID_PARAMETER  The IKE packet is malformed or the SA proposal is unacceptable.                        \r
+  @retval EFI_UNSUPPORTED        The certificate authentication is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2InitCertParser (\r
+  IN UINT8            *SaSession,\r
+  IN IKE_PACKET       *IkePacket\r
+  )\r
+{\r
+  if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {\r
+    return EFI_UNSUPPORTED;\r
+  } \r
+  \r
+  //\r
+  // The first two messages exchange is same between PSK and Cert.\r
+  // Todo: Parse Certificate Request from responder Initial Exchange. \r
+  //\r
+  return Ikev2InitPskParser (SaSession, IkePacket);\r
+}\r
+\r
+/**\r
+  Generates the IKEv2 packet for IKE_AUTH exchange.\r
+\r
+  @param[in] SaSession  Pointer to IKEV2_SA_SESSION.\r
+  @param[in] Context    Context data passed by caller.\r
+\r
+  @retval Pointer to IKEv2 Packet to be sent out.\r
+\r
+**/\r
+IKE_PACKET *\r
+Ikev2AuthCertGenerator (\r
+  IN UINT8         *SaSession,\r
+  IN VOID          *Context\r
+  )\r
+{\r
+  IKE_PACKET             *IkePacket;\r
+  IKEV2_SA_SESSION       *IkeSaSession;\r
+  IKE_PAYLOAD            *IdPayload;\r
+  IKE_PAYLOAD            *AuthPayload;\r
+  IKE_PAYLOAD            *SaPayload;\r
+  IKE_PAYLOAD            *TsiPayload;\r
+  IKE_PAYLOAD            *TsrPayload;\r
+  IKE_PAYLOAD            *NotifyPayload;\r
+  IKE_PAYLOAD            *CpPayload;\r
+  IKE_PAYLOAD            *CertPayload;\r
+  IKE_PAYLOAD            *CertReqPayload;\r
+  IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
+\r
+  if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {\r
+    return NULL;\r
+  }\r
+\r
+  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;\r
+  ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));\r
+\r
+  CpPayload      = NULL;\r
+  NotifyPayload  = NULL;\r
+  CertPayload    = NULL;\r
+  CertReqPayload = NULL;\r
+\r
+  //\r
+  // 1. Allocate IKE Packet\r
+  //\r
+  IkePacket= IkePacketAlloc ();\r
+  ASSERT (IkePacket != NULL);\r
+\r
+  //\r
+  // 1.a Fill the IkePacket Header.\r
+  //\r
+  IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_AUTH;\r
+  IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;\r
+  IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;\r
+  IkePacket->Header->Version         = (UINT8)(2 << 4);\r
+  if (ChildSaSession->SessionCommon.IsInitiator) {\r
+    IkePacket->Header->NextPayload   = IKEV2_PAYLOAD_TYPE_ID_INIT;\r
+  } else {\r
+    IkePacket->Header->NextPayload   = IKEV2_PAYLOAD_TYPE_ID_RSP;\r
+  }\r
+\r
+  //\r
+  // According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should\r
+  // be always number 0 and 1;\r
+  //\r
+  IkePacket->Header->MessageId = 1;\r
+\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;\r
+  } else {\r
+    IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;\r
+  }\r
+\r
+  //\r
+  // 2. Generate ID Payload according to IP version and address.\r
+  //\r
+  IdPayload = Ikev2GenerateCertIdPayload (\r
+                &IkeSaSession->SessionCommon,\r
+                IKEV2_PAYLOAD_TYPE_CERT,\r
+                (UINT8 *)PcdGetPtr (UefiCertificate),\r
+                PcdGet32 (UefiCertificateSize)\r
+                );\r
+\r
+  //\r
+  // 3. Generate Certificate Payload\r
+  //\r
+  CertPayload = Ikev2GenerateCertificatePayload (\r
+                  IkeSaSession,\r
+                  (UINT8)(IkeSaSession->SessionCommon.IsInitiator ? IKEV2_PAYLOAD_TYPE_CERTREQ : IKEV2_PAYLOAD_TYPE_AUTH),\r
+                  (UINT8 *)PcdGetPtr (UefiCertificate),\r
+                  PcdGet32 (UefiCertificateSize),\r
+                  IKEV2_CERT_ENCODEING_X509_CERT_SIGN,\r
+                  FALSE\r
+                  );\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    CertReqPayload = Ikev2GenerateCertificatePayload (\r
+                       IkeSaSession,\r
+                       IKEV2_PAYLOAD_TYPE_AUTH,\r
+                       (UINT8 *)PcdGetPtr (UefiCertificate),\r
+                       PcdGet32 (UefiCertificateSize),\r
+                       IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,\r
+                       TRUE\r
+                       );\r
+  }\r
+\r
+  //\r
+  // 4. Generate Auth Payload\r
+  //    If it is tunnel mode, should create the configuration payload after the\r
+  //    Auth payload.\r
+  //\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {\r
+    AuthPayload = Ikev2CertGenerateAuthPayload (\r
+                    ChildSaSession->IkeSaSession,\r
+                    IdPayload,\r
+                    IKEV2_PAYLOAD_TYPE_SA,\r
+                    FALSE,\r
+                    (UINT8 *)PcdGetPtr (UefiCertificateKey),\r
+                    PcdGet32 (UefiCertificateKeySize),\r
+                    ChildSaSession->IkeSaSession->Pad->Data->AuthData,\r
+                    ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize\r
+                    );\r
+  } else {\r
+    AuthPayload = Ikev2CertGenerateAuthPayload (\r
+                    ChildSaSession->IkeSaSession,\r
+                    IdPayload,\r
+                    IKEV2_PAYLOAD_TYPE_CP,\r
+                    FALSE,\r
+                    (UINT8 *)PcdGetPtr (UefiCertificateKey),\r
+                    PcdGet32 (UefiCertificateKeySize),\r
+                    ChildSaSession->IkeSaSession->Pad->Data->AuthData,\r
+                    ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize\r
+                    );\r
+    if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) {\r
+      CpPayload = Ikev2GenerateCpPayload (\r
+                    ChildSaSession->IkeSaSession,\r
+                    IKEV2_PAYLOAD_TYPE_SA,\r
+                    IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS\r
+                    );\r
+    } else {\r
+      CpPayload = Ikev2GenerateCpPayload (\r
+                    ChildSaSession->IkeSaSession,\r
+                    IKEV2_PAYLOAD_TYPE_SA,\r
+                    IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS\r
+                    );\r
+    }\r
+  }\r
+\r
+  //\r
+  // 5. Generate SA Payload according to the Sa Data in ChildSaSession\r
+  //\r
+  SaPayload = Ikev2GenerateSaPayload (\r
+                ChildSaSession->SaData,\r
+                IKEV2_PAYLOAD_TYPE_TS_INIT,\r
+                IkeSessionTypeChildSa\r
+                );\r
+\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {\r
+    //\r
+    // Generate Tsi and Tsr.\r
+    //\r
+    TsiPayload = Ikev2GenerateTsPayload (\r
+                   ChildSaSession,\r
+                   IKEV2_PAYLOAD_TYPE_TS_RSP,\r
+                   FALSE\r
+                   );\r
+\r
+    TsrPayload = Ikev2GenerateTsPayload (\r
+                   ChildSaSession,\r
+                   IKEV2_PAYLOAD_TYPE_NOTIFY,\r
+                   FALSE\r
+                   );\r
+\r
+    //\r
+    // Generate Notify Payload. If transport mode, there should have Notify \r
+    // payload with TRANSPORT_MODE notification.\r
+    //\r
+    NotifyPayload = Ikev2GenerateNotifyPayload (\r
+                      0,\r
+                      IKEV2_PAYLOAD_TYPE_NONE,\r
+                      0,\r
+                      IKEV2_NOTIFICATION_USE_TRANSPORT_MODE,\r
+                      NULL,\r
+                      NULL,\r
+                      0\r
+                      );\r
+  } else {\r
+    //\r
+    // Generate Tsr for Tunnel mode.\r
+    //\r
+    TsiPayload = Ikev2GenerateTsPayload (\r
+                   ChildSaSession,\r
+                   IKEV2_PAYLOAD_TYPE_TS_RSP,\r
+                   TRUE\r
+                   );\r
+    TsrPayload = Ikev2GenerateTsPayload (\r
+                   ChildSaSession,\r
+                   IKEV2_PAYLOAD_TYPE_NONE,\r
+                   FALSE\r
+                   );\r
+  }\r
+\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload);\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertPayload);\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload);\r
+  }\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload);\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload);\r
+  }\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload);\r
+  IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload);\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {\r
+    IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);\r
+  }\r
+\r
+  return IkePacket;\r
+}\r
+\r
+/**\r
+  Parses IKE_AUTH packet.\r
+\r
+  @param[in]  SaSession   Pointer to the IKE_SA_SESSION related to this packet.\r
+  @param[in]  IkePacket   Pointer to the IKE_AUTH packet to be parsered.\r
+\r
+  @retval     EFI_INVALID_PARAMETER   The IKEv2 packet is malformed or the SA\r
+                                      proposal is unacceptable.\r
+  @retval     EFI_SUCCESS             The IKE packet is acceptable and the\r
+                                      relative data is saved for furthure communication.\r
+  @retval     EFI_UNSUPPORTED         The certificate authentication is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2AuthCertParser (\r
+  IN UINT8             *SaSession,\r
+  IN IKE_PACKET        *IkePacket\r
+  )\r
+{\r
+  IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
+  IKEV2_SA_SESSION       *IkeSaSession;\r
+  IKE_PAYLOAD            *IkePayload;\r
+  IKE_PAYLOAD            *SaPayload;\r
+  IKE_PAYLOAD            *IdiPayload;\r
+  IKE_PAYLOAD            *IdrPayload;\r
+  IKE_PAYLOAD            *AuthPayload;\r
+  IKE_PAYLOAD            *TsiPayload;\r
+  IKE_PAYLOAD            *TsrPayload;\r
+  IKE_PAYLOAD            *CertPayload;\r
+  IKE_PAYLOAD            *CertReqPayload;\r
+  IKE_PAYLOAD            *VerifiedAuthPayload;\r
+  LIST_ENTRY             *Entry;\r
+  EFI_STATUS             Status;\r
+\r
+  if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;\r
+  ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));\r
+\r
+  SaPayload           = NULL;\r
+  IdiPayload          = NULL;\r
+  IdrPayload          = NULL;\r
+  AuthPayload         = NULL;\r
+  TsiPayload          = NULL;\r
+  TsrPayload          = NULL;\r
+  CertPayload         = NULL;\r
+  CertReqPayload      = NULL;\r
+  VerifiedAuthPayload = NULL;\r
+  Status              = EFI_INVALID_PARAMETER;\r
+\r
+  //\r
+  // Iterate payloads to find the SaPayload/ID/AUTH/TS Payload.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {\r
+    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) {\r
+      IdiPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) {\r
+      IdrPayload = IkePayload;\r
+    }\r
+\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {\r
+      SaPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) {\r
+      AuthPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {\r
+      TsiPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) {\r
+      TsrPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERT) {\r
+      CertPayload = IkePayload;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERTREQ) {\r
+      CertReqPayload = IkePayload;\r
+    }\r
+  }\r
+\r
+  if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) || \r
+      (TsrPayload == NULL) || (CertPayload == NULL)) {\r
+    goto Exit;\r
+  }\r
+  if ((IdiPayload == NULL) && (IdrPayload == NULL)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Check IkePacket Header is match the state\r
+  //\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    \r
+    //\r
+    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND\r
+    //\r
+    if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) ||\r
+        (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) {\r
+      goto Exit;\r
+    }\r
+  } else {\r
+    //\r
+    // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT\r
+    //\r
+    if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) ||\r
+        (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) {\r
+      goto Exit;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Verify the Auth Payload.\r
+  //\r
+  VerifiedAuthPayload = Ikev2CertGenerateAuthPayload (\r
+                          IkeSaSession,\r
+                          IkeSaSession->SessionCommon.IsInitiator ? IdrPayload:IdiPayload,\r
+                          IKEV2_PAYLOAD_TYPE_SA,\r
+                          TRUE,\r
+                          NULL,\r
+                          0,\r
+                          NULL,\r
+                          0\r
+                          );\r
+\r
+  if ((VerifiedAuthPayload != NULL) &&\r
+      (!IpSecCryptoIoVerifySignDataByCertificate (\r
+          CertPayload->PayloadBuf + sizeof (IKEV2_CERT),\r
+          CertPayload->PayloadSize - sizeof (IKEV2_CERT),\r
+          (UINT8 *)PcdGetPtr (UefiCaFile),\r
+          PcdGet32 (UefiCaFileSize),\r
+          VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_AUTH),\r
+          VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_AUTH),\r
+          AuthPayload->PayloadBuf + sizeof (IKEV2_AUTH),\r
+          AuthPayload->PayloadSize - sizeof (IKEV2_AUTH)\r
+          ))) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // 3. Parse the SA Payload to find out the cryptographic suite\r
+  //    and fill in the SA paramse into CommonSession->SaParams. If no acceptable\r
+  //    porposal found, return EFI_INVALID_PARAMETER.\r
+  //\r
+  if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // 4. Parse TSi, TSr payloads.\r
+  //\r
+  if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId !=\r
+      ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) &&\r
+      (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) &&\r
+      (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0)\r
+      ) {\r
+    goto Exit;\r
+  }\r
+\r
+  if (!IkeSaSession->SessionCommon.IsInitiator) {\r
+    //\r
+    //Todo:check the Port range. Only support any port and one certain port here.\r
+    //\r
+    ChildSaSession->ProtoId    = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId;\r
+    ChildSaSession->LocalPort  = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;\r
+    ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;\r
+    //\r
+    // Association a SPD with this SA.\r
+    //\r
+    if (EFI_ERROR (Ikev2ChildSaAssociateSpdEntry (ChildSaSession))) {\r
+      goto Exit;\r
+    }\r
+    //\r
+    // Associate the IkeSaSession's SPD to the first ChildSaSession's SPD.\r
+    //\r
+    if (ChildSaSession->IkeSaSession->Spd == NULL) {\r
+      ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd;\r
+      Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);\r
+    }\r
+  } else {\r
+    //\r
+    // Todo:check the Port range.\r
+    //\r
+    if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&\r
+        (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort)\r
+        ) {\r
+      goto Exit;\r
+    } \r
+    if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&\r
+        (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort)\r
+        ) {\r
+      goto Exit;\r
+    }\r
+    //\r
+    // For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector.\r
+    //\r
+    if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {\r
+      if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) {\r
+        //\r
+        // If it is tunnel mode, the UEFI part must be the initiator.\r
+        //\r
+        goto Exit;\r
+      }\r
+      //\r
+      // Get the Virtual IP address from the Tsi traffic selector. \r
+      // TODO: check the CFG reply payload\r
+      //\r
+      CopyMem (\r
+        &ChildSaSession->SpdSelector->LocalAddress[0].Address,\r
+        TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR),\r
+        (ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ?\r
+        sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)\r
+        );\r
+    }\r
+  }\r
+  \r
+  //\r
+  // 5. Generat keymats for IPsec protocol.\r
+  //\r
+  Ikev2GenerateChildSaKeys (ChildSaSession, NULL);\r
+  if (IkeSaSession->SessionCommon.IsInitiator) {\r
+    //\r
+    // 6. Change the state of IkeSaSession\r
+    //\r
+    IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished);\r
+    IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+Exit:\r
+  if (VerifiedAuthPayload != NULL) {\r
+    IkePayloadFree (VerifiedAuthPayload);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Generates the DH Public Key.\r
+\r
+  This generates the DH local public key and store it in the IKE SA Session's GxBuffer.\r
+\r
+  @param[in]  IkeSaSession   Pointer to related IKE SA Session.\r
+\r
+  @retval EFI_SUCCESS        The operation succeeded.\r
+  @retval Others             The operation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2GenerateSaDhPublicKey (\r
+  IN IKEV2_SA_SESSION         *IkeSaSession\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+  IKEV2_SESSION_KEYS *IkeKeys;\r
+\r
+  IkeSaSession->IkeKeys = AllocateZeroPool (sizeof (IKEV2_SESSION_KEYS));\r
+  ASSERT (IkeSaSession->IkeKeys != NULL);\r
+  IkeKeys = IkeSaSession->IkeKeys;\r
+  IkeKeys->DhBuffer = AllocateZeroPool (sizeof (IKEV2_DH_BUFFER));\r
+  ASSERT (IkeKeys->DhBuffer != NULL);\r
+\r
+  //\r
+  // Init DH with the certain DH Group Description.\r
+  //\r
+  IkeKeys->DhBuffer->GxSize   = OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size >> 3;\r
+  IkeKeys->DhBuffer->GxBuffer = AllocateZeroPool (IkeKeys->DhBuffer->GxSize);\r
+  ASSERT (IkeKeys->DhBuffer->GxBuffer != NULL);\r
+\r
+  //\r
+  // Get X PublicKey\r
+  //\r
+  Status = IpSecCryptoIoDhGetPublicKey (\r
+             &IkeKeys->DhBuffer->DhContext,\r
+             OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].GroupGenerator,\r
+             OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size,\r
+             OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Modulus,\r
+             IkeKeys->DhBuffer->GxBuffer,\r
+             &IkeKeys->DhBuffer->GxSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam X public key error Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  IPSEC_DUMP_BUF ("DH Public Key (g^x) Dump", IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Computes the DH Shared/Exchange Key.\r
+\r
+  Given peer's public key, this function computes the exchanged common key and\r
+  stores it in the IKEv2 SA Session's GxyBuffer.\r
+\r
+  @param[in]  DhBuffer       Pointer to buffer of peer's puliic key.\r
+  @param[in]  KePayload      Pointer to received key payload.\r
+  \r
+  @retval EFI_SUCCESS        The operation succeeded.\r
+  @retval Otherwise          The operation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2GenerateSaDhComputeKey (\r
+  IN IKEV2_DH_BUFFER       *DhBuffer,\r
+  IN IKE_PAYLOAD            *KePayload\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  IKEV2_KEY_EXCHANGE  *Ke;\r
+  UINT8               *PubKey;\r
+  UINTN               PubKeySize;\r
+\r
+  Ke                  = (IKEV2_KEY_EXCHANGE *) KePayload->PayloadBuf;\r
+  PubKey              = (UINT8 *) (Ke + 1);\r
+  PubKeySize          = KePayload->PayloadSize - sizeof (IKEV2_KEY_EXCHANGE);\r
+  DhBuffer->GxySize   = DhBuffer->GxSize;\r
+  DhBuffer->GxyBuffer = AllocateZeroPool (DhBuffer->GxySize);\r
+  ASSERT (DhBuffer->GxyBuffer != NULL);\r
+\r
+  //\r
+  // Get GxyBuf\r
+  //\r
+  Status = IpSecCryptoIoDhComputeKey (\r
+             DhBuffer->DhContext,\r
+             PubKey,\r
+             PubKeySize,\r
+             DhBuffer->GxyBuffer,\r
+             &DhBuffer->GxySize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam Y session key error Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Create GxyBuf.\r
+  //\r
+  DhBuffer->GySize   = PubKeySize;\r
+  DhBuffer->GyBuffer = AllocateZeroPool (DhBuffer->GySize);\r
+  ASSERT (DhBuffer->GyBuffer != NULL);\r
+  CopyMem (DhBuffer->GyBuffer, PubKey, DhBuffer->GySize);\r
+\r
+  IPSEC_DUMP_BUF ("DH Public Key (g^y) Dump", DhBuffer->GyBuffer, DhBuffer->GySize);\r
+  IPSEC_DUMP_BUF ("DH Shared Key (g^xy) Dump", DhBuffer->GxyBuffer, DhBuffer->GxySize);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Generates the IKE SKEYSEED and seven other secrets. SK_d, SK_ai, SK_ar, SK_ei, SK_er,\r
+  SK_pi, SK_pr are keys for the furthure IKE exchange.\r
+\r
+  @param[in]  IkeSaSession       Pointer to IKE SA Session.\r
+  @param[in]  KePayload          Pointer to Key payload used to generate the Key.\r
+\r
+  @retval EFI_UNSUPPORTED        If one or more Algorithm Id is not supported.\r
+  @retval EFI_OUT_OF_RESOURCES   If there is no enough resource to be allocated to\r
+                                 meet the requirement.\r
+  @retval EFI_SUCCESS            The operation succeeded.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2GenerateSaKeys (\r
+  IN IKEV2_SA_SESSION       *IkeSaSession,\r
+  IN IKE_PAYLOAD            *KePayload\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  IKEV2_SA_PARAMS     *SaParams;\r
+  IPSEC_PAD_ENTRY     *Pad;\r
+  PRF_DATA_FRAGMENT   Fragments[4];\r
+  UINT64              InitiatorCookieNet;\r
+  UINT64              ResponderCookieNet;\r
+  UINT8               *KeyBuffer;\r
+  UINTN               KeyBufferSize;\r
+  UINTN               AuthAlgKeyLen;\r
+  UINTN               EncryptAlgKeyLen;\r
+  UINTN               IntegrityAlgKeyLen;\r
+  UINTN               PrfAlgKeyLen;\r
+  UINT8               *OutputKey;\r
+  UINTN               OutputKeyLength;\r
+  UINT8               *Digest;\r
+  UINTN               DigestSize;\r
+\r
+  Digest    = NULL;\r
+  OutputKey = NULL;\r
+  KeyBuffer = NULL;\r
+\r
+  //\r
+  // Generate Gxy\r
+  //\r
+  Ikev2GenerateSaDhComputeKey (IkeSaSession->IkeKeys->DhBuffer, KePayload);\r
+\r
+  Pad = IkeSaSession->Pad;\r
+\r
+  //\r
+  // Get the key length of Authenticaion, Encryption, PRF, and Integrity.\r
+  //\r
+  SaParams           = IkeSaSession->SessionCommon.SaParams;\r
+  AuthAlgKeyLen      = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);\r
+  EncryptAlgKeyLen   = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId);\r
+  IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId);\r
+  PrfAlgKeyLen       = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);\r
+\r
+  //\r
+  // If one or more algorithm is not support, return EFI_UNSUPPORTED.\r
+  //\r
+  if (AuthAlgKeyLen == 0 || \r
+      EncryptAlgKeyLen == 0 ||\r
+      IntegrityAlgKeyLen == 0 ||\r
+      PrfAlgKeyLen == 0\r
+      ) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Compute SKEYSEED = prf(Ni | Nr, g^ir)\r
+  //\r
+  KeyBufferSize = IkeSaSession->NiBlkSize + IkeSaSession->NrBlkSize;\r
+  KeyBuffer     = AllocateZeroPool (KeyBufferSize);\r
+  ASSERT (KeyBuffer != NULL);\r
+\r
+  CopyMem (KeyBuffer, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);\r
+  CopyMem (KeyBuffer + IkeSaSession->NiBlkSize, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);\r
+\r
+  Fragments[0].Data     = IkeSaSession->IkeKeys->DhBuffer->GxyBuffer;\r
+  Fragments[0].DataSize = IkeSaSession->IkeKeys->DhBuffer->GxySize;\r
+\r
+  DigestSize = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);\r
+  Digest     = AllocateZeroPool (DigestSize);\r
+\r
+  if (Digest == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Exit;\r
+  }\r
+\r
+  IpSecCryptoIoHmac (\r
+    (UINT8)SaParams->Prf,\r
+    KeyBuffer,\r
+    KeyBufferSize,\r
+    (HASH_DATA_FRAGMENT *) Fragments,\r
+    1,\r
+    Digest,\r
+    DigestSize\r
+    );\r
+\r
+  //\r
+  // {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = prf+\r
+  //               (SKEYSEED, Ni | Nr | SPIi | SPIr )\r
+  //\r
+  Fragments[0].Data     = IkeSaSession->NiBlock;\r
+  Fragments[0].DataSize = IkeSaSession->NiBlkSize;\r
+  Fragments[1].Data     = IkeSaSession->NrBlock;\r
+  Fragments[1].DataSize = IkeSaSession->NrBlkSize;\r
+  InitiatorCookieNet    = HTONLL (IkeSaSession->InitiatorCookie);\r
+  ResponderCookieNet    = HTONLL (IkeSaSession->ResponderCookie);\r
+  Fragments[2].Data     = (UINT8 *)(&InitiatorCookieNet);\r
+  Fragments[2].DataSize = sizeof (IkeSaSession->InitiatorCookie);\r
+  Fragments[3].Data     = (UINT8 *)(&ResponderCookieNet);\r
+  Fragments[3].DataSize = sizeof (IkeSaSession->ResponderCookie);\r
+\r
+  IPSEC_DUMP_BUF (">>> NiBlock", IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);\r
+  IPSEC_DUMP_BUF (">>> NrBlock", IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);\r
+  IPSEC_DUMP_BUF (">>> InitiatorCookie", (UINT8 *)&IkeSaSession->InitiatorCookie, sizeof(UINT64));\r
+  IPSEC_DUMP_BUF (">>> ResponderCookie", (UINT8 *)&IkeSaSession->ResponderCookie, sizeof(UINT64));\r
+  \r
+  OutputKeyLength = PrfAlgKeyLen + \r
+                    2 * EncryptAlgKeyLen +\r
+                    2 * AuthAlgKeyLen +\r
+                    2 * IntegrityAlgKeyLen;\r
+  OutputKey       = AllocateZeroPool (OutputKeyLength);\r
+\r
+  //\r
+  // Generate Seven Keymates.\r
+  //\r
+  Status = Ikev2SaGenerateKey (\r
+             (UINT8)SaParams->Prf,\r
+             Digest,\r
+             DigestSize,\r
+             OutputKey,\r
+             OutputKeyLength,\r
+             Fragments,\r
+             4\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Save the seven keys into KeySession.\r
+  // First, SK_d\r
+  //\r
+  IkeSaSession->IkeKeys->SkdKey     = AllocateZeroPool (PrfAlgKeyLen);\r
+  IkeSaSession->IkeKeys->SkdKeySize = PrfAlgKeyLen;\r
+  CopyMem (IkeSaSession->IkeKeys->SkdKey, OutputKey, PrfAlgKeyLen);\r
+\r
+  IPSEC_DUMP_BUF (">>> SK_D Key", IkeSaSession->IkeKeys->SkdKey, PrfAlgKeyLen);\r
+\r
+  //\r
+  // Second, Sk_ai\r
+  //\r
+  IkeSaSession->IkeKeys->SkAiKey     = AllocateZeroPool (IntegrityAlgKeyLen);\r
+  IkeSaSession->IkeKeys->SkAiKeySize = IntegrityAlgKeyLen;\r
+  CopyMem (IkeSaSession->IkeKeys->SkAiKey, OutputKey + PrfAlgKeyLen, IntegrityAlgKeyLen);\r
+  \r
+  IPSEC_DUMP_BUF (">>> SK_Ai Key", IkeSaSession->IkeKeys->SkAiKey, IkeSaSession->IkeKeys->SkAiKeySize);\r
+\r
+  //\r
+  // Third, Sk_ar\r
+  //\r
+  IkeSaSession->IkeKeys->SkArKey     = AllocateZeroPool (IntegrityAlgKeyLen);\r
+  IkeSaSession->IkeKeys->SkArKeySize = IntegrityAlgKeyLen;\r
+  CopyMem (\r
+    IkeSaSession->IkeKeys->SkArKey,\r
+    OutputKey + PrfAlgKeyLen + IntegrityAlgKeyLen,\r
+    IntegrityAlgKeyLen\r
+    );\r
+  \r
+  IPSEC_DUMP_BUF (">>> SK_Ar Key", IkeSaSession->IkeKeys->SkArKey, IkeSaSession->IkeKeys->SkArKeySize);\r
+\r
+  //\r
+  // Fourth, Sk_ei\r
+  //\r
+  IkeSaSession->IkeKeys->SkEiKey     = AllocateZeroPool (EncryptAlgKeyLen);\r
+  IkeSaSession->IkeKeys->SkEiKeySize = EncryptAlgKeyLen;\r
+  \r
+  CopyMem (\r
+    IkeSaSession->IkeKeys->SkEiKey,\r
+    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen,\r
+    EncryptAlgKeyLen\r
+    );\r
+  IPSEC_DUMP_BUF (\r
+    ">>> SK_Ei Key", \r
+    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen,\r
+    EncryptAlgKeyLen\r
+    );\r
+\r
+  //\r
+  // Fifth, Sk_er\r
+  //\r
+  IkeSaSession->IkeKeys->SkErKey     = AllocateZeroPool (EncryptAlgKeyLen);\r
+  IkeSaSession->IkeKeys->SkErKeySize = EncryptAlgKeyLen;\r
+\r
+  CopyMem (\r
+    IkeSaSession->IkeKeys->SkErKey,\r
+    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen,\r
+    EncryptAlgKeyLen\r
+    );\r
+  IPSEC_DUMP_BUF (\r
+    ">>> SK_Er Key",\r
+    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen,\r
+    EncryptAlgKeyLen\r
+    );\r
+\r
+  //\r
+  // Sixth, Sk_pi\r
+  //\r
+  IkeSaSession->IkeKeys->SkPiKey     = AllocateZeroPool (AuthAlgKeyLen);\r
+  IkeSaSession->IkeKeys->SkPiKeySize = AuthAlgKeyLen;\r
+\r
+  CopyMem (\r
+    IkeSaSession->IkeKeys->SkPiKey,\r
+    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen +  2 * EncryptAlgKeyLen,\r
+    AuthAlgKeyLen\r
+    );\r
+  IPSEC_DUMP_BUF (\r
+    ">>> SK_Pi Key",\r
+    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen +  2 * EncryptAlgKeyLen,\r
+    AuthAlgKeyLen\r
+    );\r
+\r
+  //\r
+  // Seventh, Sk_pr\r
+  //\r
+  IkeSaSession->IkeKeys->SkPrKey     = AllocateZeroPool (AuthAlgKeyLen);\r
+  IkeSaSession->IkeKeys->SkPrKeySize = AuthAlgKeyLen;\r
+\r
+  CopyMem (\r
+    IkeSaSession->IkeKeys->SkPrKey,\r
+    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen,\r
+    AuthAlgKeyLen\r
+    ); \r
+  IPSEC_DUMP_BUF (\r
+    ">>> SK_Pr Key",\r
+    OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen,\r
+    AuthAlgKeyLen\r
+    );\r
+\r
+\r
+Exit:\r
+  if (Digest != NULL) {\r
+    FreePool (Digest);\r
+  }\r
+  if (KeyBuffer != NULL) {\r
+    FreePool (KeyBuffer);\r
+  }\r
+  if (OutputKey != NULL) {\r
+    FreePool (OutputKey);\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Generates the Keys for the furthure IPsec Protocol.\r
+\r
+  @param[in]  ChildSaSession     Pointer to IKE Child SA Session.\r
+  @param[in]  KePayload          Pointer to Key payload used to generate the Key.\r
+\r
+  @retval EFI_UNSUPPORTED    If one or more Algorithm Id is not supported.\r
+  @retval EFI_SUCCESS        The operation succeeded.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2GenerateChildSaKeys (\r
+  IN IKEV2_CHILD_SA_SESSION     *ChildSaSession,\r
+  IN IKE_PAYLOAD                *KePayload\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  IKEV2_SA_PARAMS     *SaParams;\r
+  PRF_DATA_FRAGMENT   Fragments[3];\r
+  UINTN               EncryptAlgKeyLen;\r
+  UINTN               IntegrityAlgKeyLen;\r
+  UINT8*              OutputKey;\r
+  UINTN               OutputKeyLength;\r
+\r
+  if (KePayload != NULL) {\r
+    //\r
+    // Generate Gxy \r
+    //\r
+    Ikev2GenerateSaDhComputeKey (ChildSaSession->DhBuffer, KePayload);\r
+    Fragments[0].Data     = ChildSaSession->DhBuffer->GxyBuffer;\r
+    Fragments[0].DataSize = ChildSaSession->DhBuffer->GxySize;\r
+  }\r
+\r
+  Fragments[1].Data     = ChildSaSession->NiBlock;\r
+  Fragments[1].DataSize = ChildSaSession->NiBlkSize;\r
+  Fragments[2].Data     = ChildSaSession->NrBlock;\r
+  Fragments[2].DataSize = ChildSaSession->NrBlkSize;\r
+\r
+  //\r
+  // Get the key length of Authenticaion, Encryption, PRF, and Integrity.\r
+  //\r
+  SaParams           = ChildSaSession->SessionCommon.SaParams;\r
+  EncryptAlgKeyLen   = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId);\r
+  IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId);\r
+  OutputKeyLength    = 2 * EncryptAlgKeyLen + 2 * IntegrityAlgKeyLen;\r
+\r
+  if ((EncryptAlgKeyLen == 0) || (IntegrityAlgKeyLen == 0)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // \r
+  // If KePayload is not NULL, calculate KEYMAT = prf+(SK_d, g^ir (new) | Ni | Nr ),\r
+  // otherwise, KEYMAT = prf+(SK_d, Ni | Nr )\r
+  //\r
+  OutputKey = AllocateZeroPool (OutputKeyLength);\r
+\r
+  //\r
+  // Derive Key from the SkdKey Buffer.\r
+  //\r
+  Status = Ikev2SaGenerateKey (\r
+             (UINT8)ChildSaSession->IkeSaSession->SessionCommon.SaParams->Prf,\r
+             ChildSaSession->IkeSaSession->IkeKeys->SkdKey,\r
+             ChildSaSession->IkeSaSession->IkeKeys->SkdKeySize,\r
+             OutputKey,\r
+             OutputKeyLength,\r
+             KePayload == NULL ? &Fragments[1] : Fragments,\r
+             KePayload == NULL ? 2 : 3\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (OutputKey);\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Copy KEYMATE (SK_ENCRYPT_i | SK_ENCRYPT_r | SK_INTEG_i | SK_INTEG_r) to\r
+  // ChildKeyMates.\r
+  //  \r
+  if (!ChildSaSession->SessionCommon.IsInitiator) {\r
+\r
+    // \r
+    // Initiator Encryption Key\r
+    //\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId    = (UINT8)SaParams->EncAlgId;\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey       = AllocateZeroPool (EncryptAlgKeyLen);\r
+\r
+    CopyMem (\r
+      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,\r
+      OutputKey,\r
+      EncryptAlgKeyLen\r
+      );\r
+\r
+    //\r
+    // Initiator Authentication Key\r
+    //\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId    = (UINT8)SaParams->IntegAlgId;\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey       = AllocateZeroPool (IntegrityAlgKeyLen);\r
+\r
+    CopyMem (\r
+      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,\r
+      OutputKey + EncryptAlgKeyLen,\r
+      IntegrityAlgKeyLen\r
+      );\r
+\r
+    //\r
+    // Responder Encrypt Key\r
+    //\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId    = (UINT8)SaParams->EncAlgId;\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey       = AllocateZeroPool (EncryptAlgKeyLen);\r
+\r
+    CopyMem (\r
+      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,\r
+      OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen,\r
+      EncryptAlgKeyLen\r
+      );\r
+\r
+    //\r
+    // Responder Authentication Key\r
+    //\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId    = (UINT8)SaParams->IntegAlgId;\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey       = AllocateZeroPool (IntegrityAlgKeyLen);\r
+    \r
+    CopyMem (\r
+      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,\r
+      OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen,\r
+      IntegrityAlgKeyLen\r
+      );\r
+  } else {\r
+    //\r
+    // Initiator Encryption Key\r
+    //\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId    = (UINT8)SaParams->EncAlgId;\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey       = AllocateZeroPool (EncryptAlgKeyLen);\r
+\r
+    CopyMem (\r
+      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,\r
+      OutputKey,\r
+      EncryptAlgKeyLen\r
+      );\r
+\r
+    //\r
+    // Initiator Authentication Key\r
+    //\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId    = (UINT8)SaParams->IntegAlgId;\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey       = AllocateZeroPool (IntegrityAlgKeyLen);\r
+\r
+    CopyMem (\r
+      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,\r
+      OutputKey + EncryptAlgKeyLen,\r
+      IntegrityAlgKeyLen\r
+      );\r
+\r
+    //\r
+    // Responder Encryption Key\r
+    //\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId    = (UINT8)SaParams->EncAlgId;\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey       = AllocateZeroPool (EncryptAlgKeyLen);\r
+\r
+    CopyMem (\r
+      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,\r
+      OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen,\r
+      EncryptAlgKeyLen\r
+      );\r
+\r
+    //\r
+    // Responder Authentication Key\r
+    //\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId    = (UINT8)SaParams->IntegAlgId;\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;\r
+    ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey       = AllocateZeroPool (IntegrityAlgKeyLen);\r
+\r
+    CopyMem (\r
+      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,\r
+      OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen,\r
+      IntegrityAlgKeyLen\r
+      );\r
+  }\r
+\r
+  IPSEC_DUMP_BUF (\r
+      " >>> Local Encryption Key",\r
+      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,\r
+      EncryptAlgKeyLen\r
+      );\r
+  IPSEC_DUMP_BUF (\r
+      " >>> Remote Encryption Key",\r
+      ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,\r
+      EncryptAlgKeyLen\r
+      );\r
+  IPSEC_DUMP_BUF (\r
+      " >>> Local Authentication Key",\r
+      ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,\r
+      IntegrityAlgKeyLen\r
+      );\r
+  IPSEC_DUMP_BUF (\r
+    " >>> Remote Authentication Key",\r
+    ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,\r
+    IntegrityAlgKeyLen\r
+    );\r
+\r
+  FreePool (OutputKey);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER mIkev2Initial[][2] = {\r
+  { //PSK\r
+    { // IKEV2_INIT\r
+      Ikev2InitPskParser,\r
+      Ikev2InitPskGenerator\r
+    },\r
+    { //IKEV2_AUTH\r
+      Ikev2AuthPskParser,\r
+      Ikev2AuthPskGenerator\r
+    }\r
+  },\r
+  { // CERT\r
+    { // IKEV2_INIT\r
+      Ikev2InitCertParser,\r
+      Ikev2InitCertGenerator\r
+    },\r
+    { // IKEV2_AUTH\r
+      Ikev2AuthCertParser,\r
+      Ikev2AuthCertGenerator\r
+    },\r
+  },\r
+};\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Utility.c b/NetworkPkg/IpSecDxe/Ikev2/Utility.c
new file mode 100644 (file)
index 0000000..4c461b3
--- /dev/null
@@ -0,0 +1,2692 @@
+/** @file\r
+  The Common operations used by IKE Exchange Process.\r
+\r
+  Copyright (c) 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 "Utility.h"\r
+#include "IpSecDebug.h"\r
+#include "IkeService.h"\r
+#include "IpSecConfigImpl.h"\r
+\r
+UINT16 mIkev2EncryptAlgorithmList[IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM] = {\r
+  IKEV2_TRANSFORM_ID_ENCR_3DES,\r
+  IKEV2_TRANSFORM_ID_ENCR_AES_CBC, \r
+};\r
+\r
+UINT16 mIkev2PrfAlgorithmList[IKEV2_SUPPORT_PRF_ALGORITHM_NUM] = {\r
+  IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1,\r
+};\r
+\r
+UINT16 mIkev2DhGroupAlgorithmList[IKEV2_SUPPORT_DH_ALGORITHM_NUM] = {\r
+  IKEV2_TRANSFORM_ID_DH_1024MODP,\r
+  IKEV2_TRANSFORM_ID_DH_2048MODP,\r
+};\r
+\r
+UINT16 mIkev2AuthAlgorithmList[IKEV2_SUPPORT_AUTH_ALGORITHM_NUM] = {\r
+  IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96,\r
+};\r
+\r
+/**\r
+  Allocate buffer for IKEV2_SA_SESSION and initialize it.\r
+\r
+  @param[in] Private        Pointer to IPSEC_PRIVATE_DATA.\r
+  @param[in] UdpService     Pointer to IKE_UDP_SERVICE related to this IKE SA Session.\r
+\r
+  @return Pointer to IKEV2_SA_SESSION or NULL.\r
+\r
+**/\r
+IKEV2_SA_SESSION *\r
+Ikev2SaSessionAlloc (\r
+  IN IPSEC_PRIVATE_DATA       *Private,\r
+  IN IKE_UDP_SERVICE          *UdpService\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  IKEV2_SESSION_COMMON  *SessionCommon;\r
+  IKEV2_SA_SESSION      *IkeSaSession;\r
+\r
+  IkeSaSession = AllocateZeroPool (sizeof (IKEV2_SA_SESSION));\r
+  ASSERT (IkeSaSession != NULL);\r
+\r
+  //\r
+  // Initialize the fields of IkeSaSession and its SessionCommon.\r
+  //\r
+  IkeSaSession->NCookie              = NULL;\r
+  IkeSaSession->Signature            = IKEV2_SA_SESSION_SIGNATURE;\r
+  IkeSaSession->InitiatorCookie      = IkeGenerateCookie ();\r
+  IkeSaSession->ResponderCookie      = 0;\r
+  //\r
+  // BUGBUG: Message ID starts from 2 is to match the OpenSwan requirement, but it \r
+  // might not match the IPv6 Logo. In its test specification, it mentions that\r
+  // the Message ID should start from zero after the IKE_SA_INIT exchange.\r
+  //\r
+  IkeSaSession->MessageId            = 2;\r
+  SessionCommon                      = &IkeSaSession->SessionCommon;\r
+  SessionCommon->UdpService          = UdpService;\r
+  SessionCommon->Private             = Private;\r
+  SessionCommon->IkeSessionType      = IkeSessionTypeIkeSa;\r
+  SessionCommon->IkeVer              = 2;\r
+  SessionCommon->AfterEncodePayload  = NULL;\r
+  SessionCommon->BeforeDecodePayload = NULL;\r
+\r
+  //\r
+  // Create a resend notfiy event for retry.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  Ikev2ResendNotify,\r
+                  SessionCommon,\r
+                  &SessionCommon->TimeoutEvent\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (IkeSaSession);\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Initialize the lists in IkeSaSession.\r
+  //\r
+  InitializeListHead (&IkeSaSession->ChildSaSessionList);\r
+  InitializeListHead (&IkeSaSession->ChildSaEstablishSessionList);\r
+  InitializeListHead (&IkeSaSession->InfoMIDList);\r
+  InitializeListHead (&IkeSaSession->DeleteSaList);\r
+\r
+  return IkeSaSession;\r
+}\r
+\r
+/**\r
+  Register the established IKEv2 SA into Private->Ikev2EstablishedList. If there is\r
+  IKEV2_SA_SESSION with same remote peer IP, remove the old one then register the\r
+  new one.\r
+\r
+  @param[in]  IkeSaSession  Pointer to IKEV2_SA_SESSION to be registered.\r
+  @param[in]  Private       Pointer to IPSEC_PRAVATE_DATA.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionReg (\r
+  IN IKEV2_SA_SESSION          *IkeSaSession,\r
+  IN IPSEC_PRIVATE_DATA        *Private\r
+  )\r
+{\r
+  IKEV2_SESSION_COMMON         *SessionCommon;\r
+  IKEV2_SA_SESSION             *OldIkeSaSession;\r
+  EFI_STATUS                   Status;\r
+  UINT64                       Lifetime;\r
+\r
+  //\r
+  // Keep IKE SA exclusive to remote ip address.\r
+  //\r
+  SessionCommon   = &IkeSaSession->SessionCommon;\r
+  OldIkeSaSession = Ikev2SaSessionRemove (&Private->Ikev2EstablishedList, &SessionCommon->RemotePeerIp);\r
+  if (OldIkeSaSession != NULL) {\r
+    //\r
+    // TODO: It should delete all child SAs if rekey the IKE SA.\r
+    //\r
+    Ikev2SaSessionFree (OldIkeSaSession);\r
+  }\r
+\r
+  //\r
+  // Cleanup the fields of SessionCommon for processing.\r
+  // \r
+  Ikev2SessionCommonRefresh (SessionCommon);\r
+\r
+  //\r
+  // Insert the ready IKE SA session into established list.\r
+  //\r
+  Ikev2SaSessionInsert (&Private->Ikev2EstablishedList, IkeSaSession, &SessionCommon->RemotePeerIp);\r
+\r
+  //\r
+  // Create a notfiy event for the IKE SA life time counting.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  Ikev2LifetimeNotify,\r
+                  SessionCommon,\r
+                  &SessionCommon->TimeoutEvent\r
+                  );\r
+  if (EFI_ERROR(Status)){\r
+    //\r
+    // If TimerEvent creation failed, the SA will be alive untill user disable it or \r
+    // receiving a Delete Payload from peer. \r
+    //\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Start to count the lifetime of the IKE SA.\r
+  //\r
+  if (IkeSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime == 0) {\r
+    Lifetime = IKE_SA_DEFAULT_LIFETIME;\r
+  } else {\r
+    Lifetime = IkeSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime;\r
+  }\r
+  \r
+  Status = gBS->SetTimer (\r
+                  SessionCommon->TimeoutEvent,\r
+                  TimerRelative,\r
+                  MultU64x32(Lifetime, 10000000) // ms->100ns\r
+                  );\r
+  if (EFI_ERROR(Status)){\r
+    //\r
+    // If SetTimer failed, the SA will be alive untill user disable it or \r
+    // receiving a Delete Payload from peer. \r
+    //\r
+    return ;\r
+  }\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "\n------IkeSa established and start to count down %d seconds lifetime\n",\r
+    Lifetime\r
+    ));\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Find a IKEV2_SA_SESSION by the remote peer IP.\r
+\r
+  @param[in]  SaSessionList     SaSession List to be searched.\r
+  @param[in]  RemotePeerIp      Pointer to specified IP address.\r
+\r
+  @return Pointer to IKEV2_SA_SESSION if find one or NULL.\r
+\r
+**/\r
+IKEV2_SA_SESSION *\r
+Ikev2SaSessionLookup (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN EFI_IP_ADDRESS       *RemotePeerIp\r
+  )\r
+{\r
+  LIST_ENTRY        *Entry;\r
+  IKEV2_SA_SESSION  *IkeSaSession;\r
+\r
+  NET_LIST_FOR_EACH (Entry, SaSessionList) {\r
+    IkeSaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);\r
+\r
+    if (CompareMem (\r
+          &IkeSaSession->SessionCommon.RemotePeerIp,\r
+          RemotePeerIp,\r
+          sizeof (EFI_IP_ADDRESS)\r
+          ) == 0) {\r
+\r
+      return IkeSaSession;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Insert a IKE_SA_SESSION into IkeSaSession list. The IkeSaSession list is either\r
+  Private->Ikev2SaSession list or Private->Ikev2EstablishedList list.\r
+\r
+  @param[in]  SaSessionList   Pointer to list to be inserted into.\r
+  @param[in]  IkeSaSession    Pointer to IKEV2_SA_SESSION to be inserted. \r
+  @param[in]  RemotePeerIp    Pointer to EFI_IP_ADDRESSS to indicate the \r
+                              unique IKEV2_SA_SESSION.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionInsert (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN IKEV2_SA_SESSION     *IkeSaSession,\r
+  IN EFI_IP_ADDRESS       *RemotePeerIp\r
+  )\r
+{\r
+  Ikev2SaSessionRemove (SaSessionList, RemotePeerIp);\r
+  InsertTailList (SaSessionList, &IkeSaSession->BySessionTable);\r
+}\r
+\r
+/**\r
+  Remove the SA Session by Remote Peer IP.\r
+\r
+  @param[in]  SaSessionList   Pointer to list to be searched.\r
+  @param[in]  RemotePeerIp    Pointer to EFI_IP_ADDRESS to use for SA Session search.\r
+\r
+  @retval Pointer to IKEV2_SA_SESSION with the specified remote IP address or NULL. \r
+\r
+**/\r
+IKEV2_SA_SESSION *\r
+Ikev2SaSessionRemove (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN EFI_IP_ADDRESS       *RemotePeerIp\r
+  )\r
+{\r
+  LIST_ENTRY        *Entry;\r
+  IKEV2_SA_SESSION  *IkeSaSession;\r
+\r
+  NET_LIST_FOR_EACH (Entry, SaSessionList) {\r
+    IkeSaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);\r
+\r
+    if (CompareMem (\r
+          &IkeSaSession->SessionCommon.RemotePeerIp,\r
+          RemotePeerIp,\r
+          sizeof (EFI_IP_ADDRESS)\r
+          ) == 0) {\r
+\r
+      RemoveEntryList (Entry);\r
+      return IkeSaSession;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Marking a SA session as on deleting.\r
+\r
+  @param[in]  IkeSaSession  Pointer to IKEV2_SA_SESSION.\r
+\r
+  @retval     EFI_SUCCESS   Find the related SA session and marked it.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2SaSessionOnDeleting (\r
+  IN IKEV2_SA_SESSION          *IkeSaSession\r
+  )\r
+{\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free specified Seession Common. The session common would belong to a IKE SA or \r
+  a Child SA.\r
+\r
+  @param[in]   SessionCommon   Pointer to a Session Common.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionCommonFree (\r
+  IN IKEV2_SESSION_COMMON      *SessionCommon\r
+  )\r
+{\r
+\r
+  ASSERT (SessionCommon != NULL);\r
+\r
+  if (SessionCommon->LastSentPacket != NULL) {\r
+    IkePacketFree (SessionCommon->LastSentPacket);\r
+  }\r
+\r
+  if (SessionCommon->SaParams != NULL) {\r
+    FreePool (SessionCommon->SaParams);\r
+  }\r
+  if (SessionCommon->TimeoutEvent != NULL) {\r
+    gBS->CloseEvent (SessionCommon->TimeoutEvent);\r
+  }\r
+}\r
+\r
+/**\r
+  After IKE/Child SA is estiblished, close the time event and free sent packet.\r
+\r
+  @param[in]   SessionCommon   Pointer to a Session Common.\r
+\r
+**/\r
+VOID\r
+Ikev2SessionCommonRefresh (\r
+  IN IKEV2_SESSION_COMMON      *SessionCommon\r
+  )\r
+{\r
+  ASSERT (SessionCommon != NULL);\r
+\r
+  gBS->CloseEvent (SessionCommon->TimeoutEvent);\r
+  SessionCommon->TimeoutEvent     = NULL;\r
+  SessionCommon->TimeoutInterval  = 0;\r
+  SessionCommon->RetryCount       = 0;\r
+  if (SessionCommon->LastSentPacket != NULL) {\r
+    IkePacketFree (SessionCommon->LastSentPacket);\r
+    SessionCommon->LastSentPacket = NULL;\r
+  }\r
+\r
+  return ;\r
+}\r
+/**\r
+  Free specified IKEV2 SA Session. \r
+\r
+  @param[in]    IkeSaSession   Pointer to IKEV2_SA_SESSION to be freed.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionFree (\r
+  IN IKEV2_SA_SESSION         *IkeSaSession\r
+  )\r
+{\r
+  IKEV2_SESSION_KEYS      *IkeKeys;\r
+  LIST_ENTRY              *Entry;\r
+  IKEV2_CHILD_SA_SESSION  *ChildSa;\r
+  IKEV2_DH_BUFFER         *DhBuffer;\r
+\r
+  ASSERT (IkeSaSession != NULL);\r
+  \r
+  //\r
+  // Delete Common Session\r
+  //\r
+  Ikev2SaSessionCommonFree (&IkeSaSession->SessionCommon);\r
+\r
+  //\r
+  // Delete ChildSaEstablish List and SAD\r
+  //\r
+  for (Entry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;\r
+       Entry != &IkeSaSession->ChildSaEstablishSessionList;\r
+      ) {\r
+\r
+    ChildSa = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
+    Entry   = Entry->ForwardLink;\r
+    Ikev2ChildSaSilentDelete (ChildSa->IkeSaSession, ChildSa->LocalPeerSpi);\r
+\r
+  }\r
+\r
+  //\r
+  // Delete ChildSaSessionList\r
+  //\r
+  for ( Entry  = IkeSaSession->ChildSaSessionList.ForwardLink;\r
+        Entry != &IkeSaSession->ChildSaSessionList;\r
+        ){\r
+    ChildSa = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
+    Entry   = Entry->ForwardLink;\r
+    RemoveEntryList (Entry->BackLink);\r
+    Ikev2ChildSaSessionFree (ChildSa);\r
+  }\r
+\r
+  //\r
+  // Delete DhBuffer and Keys\r
+  //\r
+  if (IkeSaSession->IkeKeys != NULL) {\r
+    IkeKeys  = IkeSaSession->IkeKeys;\r
+    DhBuffer = IkeKeys->DhBuffer;\r
+\r
+    //\r
+    // Delete DhBuffer\r
+    //\r
+    Ikev2DhBufferFree (DhBuffer);\r
+\r
+    //\r
+    // Delete Keys\r
+    //    \r
+    if (IkeKeys->SkAiKey != NULL) {\r
+      FreePool (IkeKeys->SkAiKey);\r
+    }\r
+    if (IkeKeys->SkArKey != NULL) {\r
+      FreePool (IkeKeys->SkArKey);\r
+    }\r
+    if (IkeKeys->SkdKey != NULL) {\r
+      FreePool (IkeKeys->SkdKey);\r
+    }\r
+    if (IkeKeys->SkEiKey != NULL) {\r
+      FreePool (IkeKeys->SkEiKey);\r
+    }\r
+    if (IkeKeys->SkErKey != NULL) {\r
+      FreePool (IkeKeys->SkErKey);\r
+    }\r
+    if (IkeKeys->SkPiKey != NULL) {\r
+      FreePool (IkeKeys->SkPiKey);\r
+    }\r
+    if (IkeKeys->SkPrKey != NULL) {\r
+      FreePool (IkeKeys->SkPrKey);\r
+    }\r
+    FreePool (IkeKeys);\r
+  }\r
+\r
+  if (IkeSaSession->SaData != NULL) {\r
+    FreePool (IkeSaSession->SaData);\r
+  }\r
+\r
+  if (IkeSaSession->NiBlock != NULL) {\r
+    FreePool (IkeSaSession->NiBlock);\r
+  }\r
+\r
+  if (IkeSaSession->NrBlock != NULL) {\r
+    FreePool (IkeSaSession->NrBlock);\r
+  }\r
+\r
+  if (IkeSaSession->NCookie != NULL) {\r
+    FreePool (IkeSaSession->NCookie);\r
+  }\r
+\r
+  if (IkeSaSession->InitPacket != NULL) {\r
+    FreePool (IkeSaSession->InitPacket);\r
+  }\r
+\r
+  if (IkeSaSession->RespPacket != NULL) {\r
+    FreePool (IkeSaSession->RespPacket);\r
+  }\r
+\r
+  FreePool (IkeSaSession);\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Increase the MessageID in IkeSaSession.\r
+\r
+  @param[in] IkeSaSession Pointer to a specified IKEV2_SA_SESSION.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionIncreaseMessageId (\r
+  IN IKEV2_SA_SESSION         *IkeSaSession\r
+  )\r
+{\r
+  if (IkeSaSession->MessageId < 0xffffffff) {\r
+    IkeSaSession->MessageId ++;\r
+  } else {\r
+    //\r
+    // TODO: Trigger Rekey process.\r
+    //\r
+  }\r
+}\r
+\r
+/**\r
+  Allocate memory for IKEV2 Child SA Session.\r
+  \r
+  @param[in]   UdpService     Pointer to IKE_UDP_SERVICE.\r
+  @param[in]   IkeSaSession   Pointer to IKEV2_SA_SESSION related to this Child SA \r
+                              Session.\r
+\r
+  @retval  Pointer of a new created IKEV2 Child SA Session or NULL.\r
+\r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionAlloc (\r
+  IN IKE_UDP_SERVICE          *UdpService,\r
+  IN IKEV2_SA_SESSION         *IkeSaSession\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  IKEV2_CHILD_SA_SESSION      *ChildSaSession;\r
+  IKEV2_SESSION_COMMON        *ChildSaCommon;\r
+  IKEV2_SESSION_COMMON        *SaCommon;\r
+\r
+  ChildSaSession = AllocateZeroPool (sizeof (IKEV2_CHILD_SA_SESSION));\r
+  if (ChildSaSession == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Initialize the fields of ChildSaSession and its SessionCommon.\r
+  //\r
+  ChildSaSession->Signature          = IKEV2_CHILD_SA_SESSION_SIGNATURE;\r
+  ChildSaSession->IkeSaSession       = IkeSaSession;\r
+  ChildSaSession->MessageId          = IkeSaSession->MessageId;\r
+  ChildSaSession->LocalPeerSpi       = IkeGenerateSpi ();\r
+  ChildSaCommon                      = &ChildSaSession->SessionCommon;\r
+  ChildSaCommon->UdpService          = UdpService;\r
+  ChildSaCommon->Private             = IkeSaSession->SessionCommon.Private;\r
+  ChildSaCommon->IkeSessionType      = IkeSessionTypeChildSa;\r
+  ChildSaCommon->IkeVer              = 2;\r
+  ChildSaCommon->AfterEncodePayload  = Ikev2ChildSaAfterEncodePayload;\r
+  ChildSaCommon->BeforeDecodePayload = Ikev2ChildSaBeforeDecodePayload;\r
+  SaCommon = &ChildSaSession->IkeSaSession->SessionCommon;\r
+\r
+  //\r
+  // Create a resend notfiy event for retry.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  Ikev2ResendNotify,\r
+                  ChildSaCommon,\r
+                  &ChildSaCommon->TimeoutEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (ChildSaSession);\r
+    return NULL;\r
+  }\r
+\r
+  CopyMem (&ChildSaCommon->LocalPeerIp, &SaCommon->LocalPeerIp, sizeof (EFI_IP_ADDRESS));\r
+  CopyMem (&ChildSaCommon->RemotePeerIp, &SaCommon->RemotePeerIp, sizeof (EFI_IP_ADDRESS));\r
+\r
+  return ChildSaSession;\r
+}\r
+\r
+/**\r
+  Register a established IKEv2 Child SA into IkeSaSession->ChildSaEstablishSessionList. \r
+  If the there is IKEV2_CHILD_SA_SESSION with same remote peer IP, remove the old one \r
+  then register the new one.\r
+\r
+  @param[in]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION to be registered.\r
+  @param[in]  Private         Pointer to IPSEC_PRAVATE_DATA.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaSessionReg (\r
+  IN IKEV2_CHILD_SA_SESSION    *ChildSaSession,\r
+  IN IPSEC_PRIVATE_DATA        *Private\r
+  )\r
+{\r
+  IKEV2_SESSION_COMMON         *SessionCommon;\r
+  IKEV2_CHILD_SA_SESSION       *OldChildSaSession;\r
+  IKEV2_SA_SESSION             *IkeSaSession;\r
+  IKEV2_SA_PARAMS              *SaParams;\r
+  EFI_STATUS                   Status;\r
+  UINT64                       Lifetime;\r
+\r
+  //\r
+  // Keep the IKE SA exclusive.\r
+  //\r
+  SessionCommon     = &ChildSaSession->SessionCommon;\r
+  IkeSaSession      = ChildSaSession->IkeSaSession;\r
+  OldChildSaSession = Ikev2ChildSaSessionRemove (\r
+                        &IkeSaSession->ChildSaEstablishSessionList,\r
+                        ChildSaSession->LocalPeerSpi,\r
+                        IKEV2_ESTABLISHED_CHILDSA_LIST\r
+                        );\r
+  if (OldChildSaSession != NULL) {\r
+    //\r
+    // Free the old one.\r
+    //\r
+    Ikev2ChildSaSessionFree (OldChildSaSession);\r
+  }\r
+\r
+  //\r
+  // Store the ready child SA into SAD.\r
+  //\r
+  Ikev2StoreSaData (ChildSaSession);\r
+\r
+  //\r
+  // Cleanup the fields of SessionCommon for processing.\r
+  // \r
+  Ikev2SessionCommonRefresh (SessionCommon);\r
\r
+  //\r
+  // Insert the ready child SA session into established list.\r
+  //\r
+  Ikev2ChildSaSessionInsert (&IkeSaSession->ChildSaEstablishSessionList, ChildSaSession);\r
+\r
+  //\r
+  // Create a Notify event for the IKE SA life time counting.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  Ikev2LifetimeNotify,\r
+                  SessionCommon,\r
+                  &SessionCommon->TimeoutEvent\r
+                  );\r
+  if (EFI_ERROR(Status)){\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Start to count the lifetime of the IKE SA.\r
+  //\r
+  SaParams = SessionCommon->SaParams;\r
+  if (ChildSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime != 0){\r
+    Lifetime = ChildSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime;\r
+  } else {\r
+    Lifetime = CHILD_SA_DEFAULT_LIFETIME;\r
+  }\r
+\r
+  Status = gBS->SetTimer (\r
+                  SessionCommon->TimeoutEvent,\r
+                  TimerRelative,\r
+                  MultU64x32(Lifetime, 10000000) // ms->100ns\r
+                  );\r
+  if (EFI_ERROR(Status)){\r
+    return ;\r
+  }\r
+\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "\n------ChildSa established and start to count down %d seconds lifetime\n",\r
+    Lifetime\r
+    ));\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Find the ChildSaSession by it's MessagId.\r
+\r
+  @param[in] SaSessionList  Pointer to a ChildSaSession List.\r
+  @param[in] Mid            The messageId used to search ChildSaSession.\r
+\r
+  @return Pointer to IKEV2_CHILD_SA_SESSION or NULL.\r
+\r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionLookupByMid (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN UINT32               Mid\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  IKEV2_CHILD_SA_SESSION  *ChildSaSession;\r
+
+  NET_LIST_FOR_EACH (Entry, SaSessionList) {\r
+    ChildSaSession  = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
+
+    if (ChildSaSession->MessageId == Mid) {\r
+      return ChildSaSession;
+    }
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  This function find the Child SA by the specified SPI.\r
+
+  This functin find a ChildSA session by searching the ChildSaSessionlist of
+  the input IKEV2_SA_SESSION by specified MessageID.\r
+  
+  @param[in]  SaSessionList      Pointer to List to be searched.\r
+  @param[in]  Spi                Specified SPI.\r
+
+  @return Pointer to IKEV2_CHILD_SA_SESSION or NULL.\r
+\r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionLookupBySpi (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN UINT32               Spi\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  IKEV2_CHILD_SA_SESSION  *ChildSaSession;\r
+
+  NET_LIST_FOR_EACH (Entry, SaSessionList) {\r
+    ChildSaSession  = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
+
+    if (ChildSaSession->RemotePeerSpi == Spi || ChildSaSession->LocalPeerSpi == Spi) {\r
+      return ChildSaSession;
+    }
+  }
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Insert a Child SA Session into the specified ChildSa list.\r
+\r
+  @param[in]  SaSessionList   Pointer to list to be inserted in.\r
+  @param[in]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION to be inserted.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaSessionInsert (\r
+  IN LIST_ENTRY               *SaSessionList,\r
+  IN IKEV2_CHILD_SA_SESSION   *ChildSaSession\r
+  )\r
+{\r
+ InsertTailList (SaSessionList, &ChildSaSession->ByIkeSa);\r
+}\r
+\r
+/**\r
+  Remove the IKEV2_CHILD_SA_SESSION from IkeSaSessionList.\r
+  \r
+  @param[in]  SaSessionList      The SA Session List to be iterated.\r
+  @param[in]  Spi                Spi used to identified the IKEV2_CHILD_SA_SESSION.\r
+  @param[in]  ListType           The type of the List to indicate whether it is a \r
+                                 Established. \r
+\r
+  @return The point to IKEV2_CHILD_SA_SESSION or NULL.\r
+  \r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionRemove (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN UINT32               Spi, \r
+  IN UINT8                ListType\r
+  )\r
+{\r
+  LIST_ENTRY              *Entry;\r
+  LIST_ENTRY              *NextEntry;\r
+  IKEV2_CHILD_SA_SESSION  *ChildSaSession;\r
+\r
+  NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SaSessionList) {\r
+    \r
+    if (ListType == IKEV2_ESTABLISHED_CHILDSA_LIST || ListType == IKEV2_ESTABLISHING_CHILDSA_LIST) {\r
+      ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
+    } else if (ListType == IKEV2_DELET_CHILDSA_LIST) {\r
+      ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_DEL_SA (Entry);\r
+    } else {\r
+      return NULL;\r
+    }\r
+\r
+    if (ChildSaSession->RemotePeerSpi == Spi || ChildSaSession->LocalPeerSpi == Spi) {\r
+      RemoveEntryList (Entry);\r
+      return ChildSaSession;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Mark a specified Child SA Session as on deleting.\r
+\r
+  @param[in]  ChildSaSession   Pointer to IKEV2_CHILD_SA_SESSION.\r
+\r
+  @retval     EFI_SUCCESS      Operation is successful.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2ChildSaSessionOnDeleting (\r
+  IN IKEV2_CHILD_SA_SESSION   *ChildSaSession\r
+  )\r
+{\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Free the memory located for the specified IKEV2_CHILD_SA_SESSION. \r
+\r
+  @param[in]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaSessionFree (\r
+  IN IKEV2_CHILD_SA_SESSION   *ChildSaSession\r
+  )\r
+{\r
+  IKEV2_SESSION_COMMON  *SessionCommon;\r
+\r
+  SessionCommon = &ChildSaSession->SessionCommon;\r
+  if (ChildSaSession->SaData != NULL) {\r
+    FreePool (ChildSaSession->SaData);\r
+  }\r
+\r
+  if (ChildSaSession->NiBlock != NULL) {\r
+    FreePool (ChildSaSession->NiBlock);\r
+  }\r
+\r
+  if (ChildSaSession->NrBlock != NULL) {\r
+    FreePool (ChildSaSession->NrBlock);\r
+  }\r
+\r
+  if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey != NULL) {\r
+    FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey);\r
+  }\r
+\r
+  if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey != NULL) {\r
+    FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey);\r
+  }\r
+\r
+  if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey != NULL) {\r
+    FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey);\r
+  }\r
+\r
+  if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey != NULL) {\r
+    FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey);\r
+  }\r
+\r
+  //\r
+  // Delete DhBuffer\r
+  //\r
+  Ikev2DhBufferFree (ChildSaSession->DhBuffer);\r
+\r
+  //\r
+  // Delete SpdSelector\r
+  //\r
+  if (ChildSaSession->SpdSelector != NULL) {\r
+    if (ChildSaSession->SpdSelector->LocalAddress != NULL) {\r
+      FreePool (ChildSaSession->SpdSelector->LocalAddress);\r
+    }\r
+    if (ChildSaSession->SpdSelector->RemoteAddress != NULL) {\r
+      FreePool (ChildSaSession->SpdSelector->RemoteAddress);\r
+    }\r
+    FreePool (ChildSaSession->SpdSelector);\r
+  }\r
+  Ikev2SaSessionCommonFree (SessionCommon);\r
+  FreePool (ChildSaSession);\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Delete the specified established Child SA.\r
+\r
+  This function delete the Child SA directly and don't send the Information Packet to\r
+  remote peer.\r
+\r
+  @param[in]  IkeSaSession   Pointer to a IKE SA Session used to be searched for.\r
+  @param[in]  Spi            SPI used to find the Child SA.\r
+\r
+  @retval     EFI_NOT_FOUND  Pointer of IKE SA Session is NULL.\r
+  @retval     EFI_NOT_FOUND  There is no specified Child SA related with the input\r
+                             SPI under this IKE SA Session.\r
+  @retval     EFI_SUCCESS    Delete the Child SA successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2ChildSaSilentDelete (\r
+  IN IKEV2_SA_SESSION       *IkeSaSession,\r
+  IN UINT32                 Spi\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_IPSEC_CONFIG_SELECTOR *Selector;\r
+  UINTN                     SelectorSize;\r
+  BOOLEAN                   IsLocalFound;\r
+  BOOLEAN                   IsRemoteFound;\r
+  UINT32                    LocalSpi;\r
+  UINT32                    RemoteSpi;\r
+  IKEV2_CHILD_SA_SESSION    *ChildSession;\r
+  EFI_IPSEC_CONFIG_SELECTOR *LocalSelector;\r
+  EFI_IPSEC_CONFIG_SELECTOR *RemoteSelector;\r
+  IKE_UDP_SERVICE           *UdpService;\r
+  IPSEC_PRIVATE_DATA        *Private;\r
+\r
+  if (IkeSaSession == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  IsLocalFound    = FALSE;\r
+  IsRemoteFound   = FALSE;\r
+  ChildSession    = NULL;\r
+  LocalSelector   = NULL;\r
+  RemoteSelector  = NULL;\r
+  UdpService      = IkeSaSession->SessionCommon.UdpService;\r
+\r
+  Private  = (UdpService->IpVersion == IP_VERSION_4) ?\r
+             IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :\r
+             IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);\r
+\r
+  //\r
+  // Remove the Established SA from ChildSaEstablishlist.\r
+  //\r
+  ChildSession = Ikev2ChildSaSessionRemove(\r
+                   &(IkeSaSession->ChildSaEstablishSessionList),\r
+                   Spi, \r
+                   IKEV2_ESTABLISHED_CHILDSA_LIST\r
+                   );\r
+  if (ChildSession == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  LocalSpi  = ChildSession->LocalPeerSpi;\r
+  RemoteSpi = ChildSession->RemotePeerSpi;\r
+  \r
+  SelectorSize  = sizeof (EFI_IPSEC_CONFIG_SELECTOR);\r
+  Selector      = AllocateZeroPool (SelectorSize);\r
+  ASSERT (Selector != NULL);\r
+\r
+  \r
+\r
+  while (1) {\r
+    Status = EfiIpSecConfigGetNextSelector (\r
+               &Private->IpSecConfig,\r
+               IPsecConfigDataTypeSad,\r
+               &SelectorSize,\r
+               Selector\r
+               );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      FreePool (Selector);\r
+\r
+      Selector = AllocateZeroPool (SelectorSize);\r
+      Status   = EfiIpSecConfigGetNextSelector (\r
+                   &Private->IpSecConfig,\r
+                   IPsecConfigDataTypeSad,\r
+                   &SelectorSize,\r
+                   Selector\r
+                   );\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    if (Selector->SaId.Spi == RemoteSpi) {\r
+      //\r
+      // SPI is unique. There is only one SAD whose SPI is\r
+      // same with RemoteSpi.\r
+      //\r
+      IsRemoteFound   = TRUE;\r
+      RemoteSelector  = AllocateZeroPool (SelectorSize);\r
+      CopyMem (RemoteSelector, Selector, SelectorSize);\r
+    }\r
+\r
+    if (Selector->SaId.Spi == LocalSpi) {\r
+      //\r
+      // SPI is unique. There is only one SAD whose SPI is\r
+      // same with LocalSpi.\r
+      //\r
+      IsLocalFound  = TRUE;\r
+      LocalSelector = AllocateZeroPool (SelectorSize);\r
+      CopyMem (LocalSelector, Selector, SelectorSize);\r
+    }\r
+  }\r
+  //\r
+  // Delete SA from the Variable.\r
+  //\r
+  if (IsLocalFound) {\r
+    Status = EfiIpSecConfigSetData (\r
+               &Private->IpSecConfig,\r
+               IPsecConfigDataTypeSad,\r
+               LocalSelector,\r
+               NULL,\r
+               NULL\r
+               );\r
+  }\r
+\r
+  if (IsRemoteFound) {\r
+    Status = EfiIpSecConfigSetData (\r
+               &Private->IpSecConfig,\r
+               IPsecConfigDataTypeSad,\r
+               RemoteSelector,\r
+               NULL,\r
+               NULL\r
+               );\r
+\r
+  }\r
+\r
+  DEBUG (\r
+    (DEBUG_INFO,\r
+    "\n------IKEV2 deleted ChildSa(local spi, remote spi):(0x%x, 0x%x)------\n",\r
+    LocalSpi,\r
+    RemoteSpi)\r
+    );\r
+  Ikev2ChildSaSessionFree (ChildSession);\r
+\r
+  if (RemoteSelector != NULL) {\r
+    FreePool (RemoteSelector);\r
+  }\r
+\r
+  if (LocalSelector != NULL) {\r
+    FreePool (LocalSelector);\r
+  }\r
+\r
+  if (Selector != NULL) {\r
+    FreePool (Selector);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Free the specified DhBuffer.\r
+\r
+  @param[in] DhBuffer   Pointer to IKEV2_DH_BUFFER to be freed.\r
+  \r
+**/\r
+VOID\r
+Ikev2DhBufferFree (\r
+  IKEV2_DH_BUFFER *DhBuffer\r
+) \r
+{\r
+  if (DhBuffer != NULL) {\r
+    if (DhBuffer->GxBuffer != NULL) {\r
+      FreePool (DhBuffer->GxBuffer);\r
+    }\r
+    if (DhBuffer->GyBuffer != NULL) {\r
+      FreePool (DhBuffer->GyBuffer);\r
+    }\r
+    if (DhBuffer->GxyBuffer != NULL) {\r
+      FreePool (DhBuffer->GxyBuffer);\r
+    }\r
+    if (DhBuffer->DhContext != NULL) {\r
+      IpSecCryptoIoFreeDh (&DhBuffer->DhContext);\r
+    }\r
+    FreePool (DhBuffer);\r
+  }\r
+}\r
+\r
+/**\r
+  This function is to parse a request IKE packet and return its request type.\r
+  The request type is one of IKE CHILD SA creation, IKE SA rekeying and \r
+  IKE CHILD SA rekeying.\r
+\r
+  @param[in] IkePacket  IKE packet to be prased.\r
+\r
+  return the type of the IKE packet.\r
+\r
+**/\r
+IKEV2_CREATE_CHILD_REQUEST_TYPE\r
+Ikev2ChildExchangeRequestType(\r
+  IN IKE_PACKET               *IkePacket\r
+  )\r
+{\r
+  BOOLEAN       Flag;\r
+  LIST_ENTRY    *Entry;\r
+  IKE_PAYLOAD   *IkePayload;\r
+\r
+  Flag            = FALSE;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {\r
+    IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {\r
+      //\r
+      // Packet with Ts Payload means it is for either CHILD_SA_CREATE or CHILD_SA_REKEY.\r
+      //\r
+      Flag = TRUE;\r
+    }\r
+    if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) { \r
+      if (((IKEV2_NOTIFY*)IkePayload)->MessageType == IKEV2_NOTIFICATION_REKEY_SA) {\r
+        //\r
+        // If notify payload with REKEY_SA message type, the IkePacket is for \r
+        // rekeying Child SA.\r
+        //\r
+        return IkeRequestTypeRekeyChildSa;\r
+      }\r
+    }\r
+  };\r
+\r
+  if (!Flag){\r
+    //\r
+    // The Create Child Exchange is for IKE SA rekeying.\r
+    //\r
+    return IkeRequestTypeRekeyIkeSa;\r
+  } else {\r
+    //\r
+    // If the Notify payloaad with transport mode message type, the IkePacket is \r
+    // for create Child SA.\r
+    //\r
+    return IkeRequestTypeCreateChildSa;\r
+  }\r
+}\r
+\r
+/**\r
+  Associate a SPD selector to the Child SA Session.\r
+\r
+  This function is called when the Child SA is not the first child SA of its \r
+  IKE SA. It associate a SPD to this Child SA.\r
+\r
+  @param[in, out]  ChildSaSession     Pointer to the Child SA Session to be associated to \r
+                                      a SPD selector.\r
+\r
+  @retval EFI_SUCCESS        Associate one SPD selector to this Child SA Session successfully.\r
+  @retval EFI_NOT_FOUND      Can't find the related SPD selector.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2ChildSaAssociateSpdEntry (\r
+  IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession\r
+  )\r
+{\r
+  IpSecVisitConfigData (IPsecConfigDataTypeSpd, Ikev2MatchSpdEntry, ChildSaSession);\r
+  if (ChildSaSession->Spd != NULL) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function finds the SPI from Create Child SA Exchange Packet.\r
\r
+  @param[in] IkePacket       Pointer to IKE_PACKET to be searched.\r
+\r
+  @retval SPI number or 0 if it is not supported.\r
+\r
+**/\r
+UINT32\r
+Ikev2ChildExchangeRekeySpi (\r
+  IN IKE_PACKET               *IkePacket\r
+  )\r
+{\r
+  //\r
+  // Not support yet.\r
+  // \r
+  return 0;\r
+}\r
+\r
+/**\r
+  Validate the IKE header of received IKE packet.\r
+\r
+  @param[in]   IkeSaSession  Pointer to IKEV2_SA_SESSION related to this IKE packet.\r
+  @param[in]   IkeHdr        Pointer to IKE header of received IKE packet.\r
+\r
+  @retval TRUE   If the IKE header is valid.\r
+  @retval FALSE  If the IKE header is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+Ikev2ValidateHeader (\r
+  IN IKEV2_SA_SESSION         *IkeSaSession,\r
+  IN IKE_HEADER               *IkeHdr\r
+  )\r
+{\r
+\r
+  IKEV2_SESSION_STATE State;\r
+\r
+  State = IkeSaSession->SessionCommon.State;\r
+  if (State == IkeStateInit) {\r
+    //\r
+    // For the IKE Initial Exchange, the MessagId should be zero.\r
+    //\r
+    if (IkeHdr->MessageId != 0) {\r
+      return FALSE;\r
+    }\r
+  } else {\r
+    if (State == IkeStateAuth) {\r
+      if (IkeHdr->MessageId != 1) {\r
+        return FALSE;\r
+      }\r
+    }\r
+    if (IkeHdr->InitiatorCookie != IkeSaSession->InitiatorCookie ||\r
+        IkeHdr->ResponderCookie != IkeSaSession->ResponderCookie\r
+        ) {\r
+      //\r
+      // TODO: send notification INVALID-COOKIE\r
+      //\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Information Exchagne and Create Child Exchange can be started from each part.\r
+  //\r
+  if (IkeHdr->ExchangeType != IKEV2_EXCHANGE_TYPE_INFO && \r
+      IkeHdr->ExchangeType != IKEV2_EXCHANGE_TYPE_CREATE_CHILD\r
+      ) {\r
+    if (IkeSaSession->SessionCommon.IsInitiator) {\r
+      if (IkeHdr->InitiatorCookie != IkeSaSession->InitiatorCookie) {\r
+        //\r
+        // TODO: send notification INVALID-COOKIE\r
+        //\r
+        return FALSE;\r
+      }\r
+      if (IkeHdr->Flags != IKE_HEADER_FLAGS_RESPOND) {\r
+        return FALSE;\r
+      }\r
+    } else {\r
+      if (IkeHdr->Flags != IKE_HEADER_FLAGS_INIT) {\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Create and intialize IKEV2_SA_DATA for speicifed IKEV2_SESSION_COMMON.\r
+\r
+  This function will be only called by the initiator. The responder's IKEV2_SA_DATA\r
+  will be generated during parsed the initiator packet.\r
+\r
+  @param[in]  SessionCommon  Pointer to IKEV2_SESSION_COMMON related to.\r
+\r
+  @retval a Pointer to a new IKEV2_SA_DATA or NULL.\r
+\r
+**/\r
+IKEV2_SA_DATA *\r
+Ikev2InitializeSaData (\r
+  IN IKEV2_SESSION_COMMON     *SessionCommon\r
+  )\r
+{\r
+  IKEV2_CHILD_SA_SESSION      *ChildSaSession;\r
+  IKEV2_SA_DATA               *SaData;\r
+  IKEV2_PROPOSAL_DATA         *ProposalData;\r
+  IKEV2_TRANSFORM_DATA        *TransformData;\r
+  IKE_SA_ATTRIBUTE            *Attribute;\r
+\r
+  ASSERT (SessionCommon != NULL);\r
+  //\r
+  // TODO: Remove the hard code of the support Alogrithm. Those data should be\r
+  // get from the SPD/PAD data.\r
+  //\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    SaData = AllocateZeroPool (\r
+               sizeof (IKEV2_SA_DATA) +\r
+               sizeof (IKEV2_PROPOSAL_DATA) * 2 +\r
+               sizeof (IKEV2_TRANSFORM_DATA) * 4 * 2\r
+               );\r
+  } else {\r
+    SaData = AllocateZeroPool (\r
+               sizeof (IKEV2_SA_DATA) +\r
+               sizeof (IKEV2_PROPOSAL_DATA) * 2 +\r
+               sizeof (IKEV2_TRANSFORM_DATA) * 3 * 2\r
+               );\r
+  }\r
+  if (SaData == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // First proposal payload: 3DES + SHA1 + DH\r
+  //\r
+  SaData->NumProposals          = 2;\r
+  ProposalData                  = (IKEV2_PROPOSAL_DATA *) (SaData + 1);\r
+  ProposalData->ProposalIndex   = 1;\r
+\r
+  //\r
+  // If SA data for IKE_SA_INIT exchage, contains 4 transforms. If SA data for \r
+  // IKE_AUTH exchange contains 3 transforms.\r
+  //\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    ProposalData->NumTransforms   = 4;\r
+  } else {\r
+    ProposalData->NumTransforms   = 3;\r
+  }\r
+\r
+\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    ProposalData->ProtocolId    = IPSEC_PROTO_ISAKMP;\r
+  } else {\r
+    ChildSaSession              = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
+    ProposalData->ProtocolId    = IPSEC_PROTO_IPSEC_ESP;\r
+    ProposalData->Spi           = AllocateZeroPool (sizeof (ChildSaSession->LocalPeerSpi));\r
+    ASSERT (ProposalData->Spi != NULL);\r
+    CopyMem (\r
+      ProposalData->Spi,\r
+      &ChildSaSession->LocalPeerSpi,\r
+      sizeof(ChildSaSession->LocalPeerSpi)\r
+    );\r
+  }\r
+\r
+  //\r
+  // Set transform attribute for Encryption Algorithm - 3DES\r
+  //\r
+  TransformData                 = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1);\r
+  TransformData->TransformIndex = 0;\r
+  TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_ENCR;\r
+  TransformData->TransformId    = IKEV2_TRANSFORM_ID_ENCR_3DES;\r
+\r
+  //\r
+  // Set transform attribute for Integrity Algorithm - SHA1_96\r
+  //\r
+  TransformData                 = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
+  TransformData->TransformIndex = 1;\r
+  TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_INTEG;\r
+  TransformData->TransformId    = IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96;\r
+\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    //\r
+    // Set transform attribute for Pseduo-Random Function - HAMC_SHA1\r
+    //\r
+    TransformData                 = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
+    TransformData->TransformIndex = 2;\r
+    TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_PRF;\r
+    TransformData->TransformId    = IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1;\r
+  }\r
+\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    //\r
+    // Set transform attribute for DH Group - DH 1024\r
+    //\r
+    TransformData                 = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
+    TransformData->TransformIndex = 3;\r
+    TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_DH;\r
+    TransformData->TransformId    = IKEV2_TRANSFORM_ID_DH_1024MODP;\r
+  } else {\r
+    //\r
+    // Transform type for Extended Sequence Numbers. Currently not support Extended\r
+    // Sequence Number.\r
+    //\r
+    TransformData                 = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
+    TransformData->TransformIndex = 2;\r
+    TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_ESN;\r
+    TransformData->TransformId    = 0;\r
+  }\r
+\r
+  //\r
+  // Second proposal payload: 3DES + SHA1 + DH\r
+  //\r
+  ProposalData                  = (IKEV2_PROPOSAL_DATA *) (TransformData + 1);\r
+  ProposalData->ProposalIndex   = 2;\r
+\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    ProposalData->ProtocolId      = IPSEC_PROTO_ISAKMP;\r
+    ProposalData->NumTransforms   = 4;\r
+  } else {\r
+\r
+    ChildSaSession              = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
+    ProposalData->ProtocolId    = IPSEC_PROTO_IPSEC_ESP;\r
+    ProposalData->NumTransforms = 3;\r
+    ProposalData->Spi           = AllocateZeroPool (sizeof (ChildSaSession->LocalPeerSpi));\r
+    ASSERT (ProposalData->Spi != NULL);\r
+    CopyMem (\r
+      ProposalData->Spi,\r
+      &ChildSaSession->LocalPeerSpi,\r
+      sizeof(ChildSaSession->LocalPeerSpi)\r
+    );\r
+  }\r
+\r
+  //\r
+  // Set transform attribute for Encryption Algorithm - AES-CBC\r
+  //\r
+  TransformData                 = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1);\r
+  TransformData->TransformIndex = 0;\r
+  TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_ENCR;\r
+  TransformData->TransformId    = IKEV2_TRANSFORM_ID_ENCR_AES_CBC;\r
+  Attribute                     = &TransformData->Attribute;\r
+  Attribute->AttrType           = IKEV2_ATTRIBUTE_TYPE_KEYLEN;\r
+  Attribute->Attr.AttrLength    = (UINT16) (8 * IpSecGetEncryptKeyLength (IKEV2_TRANSFORM_ID_ENCR_AES_CBC));\r
+\r
+  //\r
+  // Set transform attribute for Integrity Algorithm - SHA1_96\r
+  //\r
+  TransformData                 = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
+  TransformData->TransformIndex = 1;\r
+  TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_INTEG;\r
+  TransformData->TransformId    = IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96;\r
+\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    //\r
+    // Set transform attribute for Pseduo-Random Function - HAMC_SHA1\r
+    //\r
+    TransformData                 = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
+    TransformData->TransformIndex = 2;\r
+    TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_PRF;\r
+    TransformData->TransformId    = IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1;\r
+  }\r
+\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    //\r
+    // Set transform attrbiute for DH Group - DH-1024\r
+    //\r
+    TransformData                 = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
+    TransformData->TransformIndex = 3;\r
+    TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_DH;\r
+    TransformData->TransformId    = IKEV2_TRANSFORM_ID_DH_1024MODP;\r
+  } else {\r
+    //\r
+    // Transform type for Extended Sequence Numbers. Currently not support Extended\r
+    // Sequence Number.\r
+    //\r
+    TransformData                 = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
+    TransformData->TransformIndex = 2;\r
+    TransformData->TransformType  = IKEV2_TRANSFORM_TYPE_ESN;\r
+    TransformData->TransformId    = 0;\r
+  }\r
+\r
+  return SaData;\r
+}\r
+\r
+/**\r
+  Store the SA into SAD.\r
+\r
+  @param[in]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION.\r
+\r
+**/\r
+VOID\r
+Ikev2StoreSaData (\r
+  IN IKEV2_CHILD_SA_SESSION   *ChildSaSession\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_IPSEC_SA_ID             SaId;\r
+  EFI_IPSEC_SA_DATA2           SaData;\r
+  IKEV2_SESSION_COMMON        *SessionCommon;\r
+  IPSEC_PRIVATE_DATA          *Private;\r
+  UINT32                      TempAddressCount;\r
+  EFI_IP_ADDRESS_INFO         *TempAddressInfo;\r
+\r
+  SessionCommon             = &ChildSaSession->SessionCommon;\r
+  Private                   = SessionCommon->Private;\r
+\r
+  ZeroMem (&SaId, sizeof (EFI_IPSEC_SA_ID));\r
+  ZeroMem (&SaData, sizeof (EFI_IPSEC_SA_DATA2));\r
+\r
+  //\r
+  // Create a SpdSelector. In this implementation, one SPD represents\r
+  // 2 direction traffic, so in here, there needs to reverse the local address \r
+  // and remote address for Remote Peer's SA, then reverse again for the locate\r
+  // SA. \r
+  //\r
+  TempAddressCount = ChildSaSession->SpdSelector->LocalAddressCount;\r
+  TempAddressInfo  = ChildSaSession->SpdSelector->LocalAddress;\r
+\r
+  ChildSaSession->SpdSelector->LocalAddressCount = ChildSaSession->SpdSelector->RemoteAddressCount;\r
+  ChildSaSession->SpdSelector->LocalAddress      = ChildSaSession->SpdSelector->RemoteAddress;\r
+\r
+  ChildSaSession->SpdSelector->RemoteAddress     = TempAddressInfo;\r
+  ChildSaSession->SpdSelector->RemoteAddressCount= TempAddressCount;\r
+\r
+  //\r
+  // Set the SaId and SaData.\r
+  //\r
+  SaId.Spi                 = ChildSaSession->LocalPeerSpi;\r
+  SaId.Proto               = EfiIPsecESP;\r
+  SaData.AntiReplayWindows = 16;\r
+  SaData.SNCount           = 0;\r
+  SaData.Mode              = ChildSaSession->Spd->Data->ProcessingPolicy->Mode;\r
+\r
+  //\r
+  // If it is tunnel mode, should add the TunnelDest and TunnelSource for SaData.\r
+  //\r
+  if (SaData.Mode == EfiIPsecTunnel) {\r
+    CopyMem (\r
+      &SaData.TunnelSourceAddress, \r
+      &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress,\r
+      sizeof (EFI_IP_ADDRESS)\r
+      );\r
+    CopyMem (\r
+      &SaData.TunnelDestinationAddress,\r
+      &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->LocalTunnelAddress,\r
+      sizeof (EFI_IP_ADDRESS)\r
+      );\r
+  }\r
+\r
+  CopyMem (&SaId.DestAddress, &ChildSaSession->SessionCommon.LocalPeerIp, sizeof (EFI_IP_ADDRESS));\r
+  CopyMem (&SaData.AlgoInfo, &ChildSaSession->ChildKeymats.LocalPeerInfo, sizeof (EFI_IPSEC_ALGO_INFO));\r
+  SaData.SpdSelector = ChildSaSession->SpdSelector;\r
+\r
+  //\r
+  // Store the remote SA into SAD.\r
+  //\r
+  Status = EfiIpSecConfigSetData (\r
+             &Private->IpSecConfig,\r
+             IPsecConfigDataTypeSad,\r
+             (EFI_IPSEC_CONFIG_SELECTOR *) &SaId,\r
+             &SaData,\r
+             NULL\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Store the local SA into SAD.\r
+  //  \r
+  ChildSaSession->SpdSelector->RemoteAddressCount = ChildSaSession->SpdSelector->LocalAddressCount;\r
+  ChildSaSession->SpdSelector->RemoteAddress      = ChildSaSession->SpdSelector->LocalAddress;\r
+\r
+  ChildSaSession->SpdSelector->LocalAddress       = TempAddressInfo;\r
+  ChildSaSession->SpdSelector->LocalAddressCount  = TempAddressCount;\r
+  \r
+  SaId.Spi = ChildSaSession->RemotePeerSpi;\r
+\r
+  CopyMem (&SaId.DestAddress, &ChildSaSession->SessionCommon.RemotePeerIp, sizeof (EFI_IP_ADDRESS));\r
+  CopyMem (&SaData.AlgoInfo, &ChildSaSession->ChildKeymats.RemotePeerInfo, sizeof (EFI_IPSEC_ALGO_INFO));\r
+  SaData.SpdSelector = ChildSaSession->SpdSelector;\r
+\r
+  //\r
+  // If it is tunnel mode, should add the TunnelDest and TunnelSource for SaData.\r
+  //\r
+  if (SaData.Mode == EfiIPsecTunnel) {\r
+    CopyMem (\r
+      &SaData.TunnelSourceAddress,\r
+      &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->LocalTunnelAddress,\r
+      sizeof (EFI_IP_ADDRESS)\r
+      );\r
+    CopyMem (\r
+      &SaData.TunnelDestinationAddress,\r
+      &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress,\r
+      sizeof (EFI_IP_ADDRESS)\r
+      );\r
+  }\r
+\r
+  Status = EfiIpSecConfigSetData (\r
+             &Private->IpSecConfig,\r
+             IPsecConfigDataTypeSad,\r
+             (EFI_IPSEC_CONFIG_SELECTOR *) &SaId,\r
+             &SaData,\r
+             NULL\r
+             );\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Call back function of the IKE life time is over.\r
+\r
+  This function will mark the related IKE SA Session as deleting and trigger a \r
+  Information negotiation.\r
+\r
+  @param[in]    Event     The signaled Event.\r
+  @param[in]    Context   Pointer to data passed by caller.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+Ikev2LifetimeNotify (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  IKEV2_SA_SESSION            *IkeSaSession;\r
+  IKEV2_CHILD_SA_SESSION      *ChildSaSession;\r
+  IKEV2_SESSION_COMMON        *SessionCommon;\r
+\r
+  ASSERT (Context != NULL);\r
+  SessionCommon = (IKEV2_SESSION_COMMON *) Context;\r
+\r
+  if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+    IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);\r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "\n---IkeSa Lifetime is out(cookie_i, cookie_r):(0x%lx, 0x%lx)---\n",\r
+      IkeSaSession->InitiatorCookie,\r
+      IkeSaSession->ResponderCookie\r
+      ));\r
+\r
+    //\r
+    // Change the  IKE SA Session's State to IKE_STATE_SA_DELETING.\r
+    //\r
+    IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateSaDeleting);\r
+    IkeSaSession->SessionCommon.State = IkeStateSaDeleting;\r
+\r
+  } else {\r
+    ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
+    IkeSaSession   = ChildSaSession->IkeSaSession;\r
+\r
+    //\r
+    // Link the timeout child SA to the DeleteSaList.\r
+    //\r
+    InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete);\r
+\r
+    //\r
+    // Change the Child SA Session's State to IKE_STATE_SA_DELETING.\r
+    //    \r
+    DEBUG ((\r
+      DEBUG_INFO,\r
+      "\n------ChildSa Lifetime is out(SPI):(0x%x)------\n",\r
+      ChildSaSession->LocalPeerSpi\r
+      ));\r
+  }\r
+\r
+  //\r
+  // TODO: Send the delete info packet or delete silently\r
+  //\r
+  mIkev2Exchange.NegotiateInfo ((UINT8 *) IkeSaSession, NULL);\r
+}\r
+\r
+/**\r
+  This function will be called if the TimeOut Event is signaled.\r
+\r
+  @param[in]  Event      The signaled Event.\r
+  @param[in]  Context    The data passed by caller.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ikev2ResendNotify (\r
+  IN EFI_EVENT                 Event,\r
+  IN VOID                      *Context\r
+  )\r
+{\r
+  IPSEC_PRIVATE_DATA           *Private;\r
+  IKEV2_SA_SESSION             *IkeSaSession;\r
+  IKEV2_CHILD_SA_SESSION       *ChildSaSession;\r
+  IKEV2_SESSION_COMMON         *SessionCommon;\r
+  LIST_ENTRY                   *ChildSaEntry;\r
+  UINT8                        Value;\r
+  EFI_STATUS                   Status;\r
+\r
+  ASSERT (Context != NULL); \r
+  IkeSaSession   = NULL;\r
+  ChildSaSession = NULL;\r
+  SessionCommon  = (IKEV2_SESSION_COMMON *) Context;\r
+  Private        = SessionCommon->Private;\r
+\r
+  //\r
+  // Remove the SA session from the processing list if exceed the max retry.\r
+  //\r
+  if (SessionCommon->RetryCount > IKE_MAX_RETRY) {\r
+    if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
+      IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);\r
+      if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) {\r
+\r
+        //\r
+        // If the IkeSaSession is initiator, delete all its Child SAs before removing IKE SA.\r
+        // If the IkesaSession is responder, all ChildSa has been remove in Ikev2HandleInfo();\r
+        //\r
+        for (ChildSaEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;\r
+             ChildSaEntry != &IkeSaSession->ChildSaEstablishSessionList;\r
+        ) {\r
+          ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ChildSaEntry);\r
+          //\r
+          // Move to next ChildSa Entry.\r
+          //\r
+          ChildSaEntry = ChildSaEntry->ForwardLink;\r
+          //\r
+          // Delete LocalSpi & RemoteSpi and remove the ChildSaSession from the\r
+          // EstablishedChildSaList.\r
+          //\r
+          Ikev2ChildSaSilentDelete (IkeSaSession, ChildSaSession->LocalPeerSpi);\r
+        }\r
+\r
+        //\r
+        // If the IKE SA Delete Payload wasn't sent out successfully, Delete it from the EstablishedList.\r
+        //\r
+        Ikev2SaSessionRemove (&Private->Ikev2EstablishedList, &SessionCommon->RemotePeerIp);\r
+\r
+        if (Private != NULL && Private->IsIPsecDisabling) {\r
+            //\r
+            // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in\r
+            // IPsec status variable.\r
+            //\r
+            if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) {\r
+              Value = IPSEC_STATUS_DISABLED;\r
+              Status = gRT->SetVariable (\r
+                              IPSECCONFIG_STATUS_NAME,\r
+                              &gEfiIpSecConfigProtocolGuid,\r
+                              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+                              sizeof (Value),\r
+                              &Value\r
+                              );\r
+              if (!EFI_ERROR (Status)) {\r
+                //\r
+                // Set the Disabled Flag in Private data.\r
+                //\r
+                Private->IpSec.DisabledFlag = TRUE;\r
+                Private->IsIPsecDisabling   = FALSE;\r
+              }\r
+            }\r
+          }\r
+      } else {\r
+        Ikev2SaSessionRemove (&Private->Ikev2SessionList, &SessionCommon->RemotePeerIp);\r
+      }\r
+      Ikev2SaSessionFree (IkeSaSession);\r
+\r
+    } else {\r
+\r
+      //\r
+      // If the packet sent by Child SA.\r
+      //\r
+      ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
+      IkeSaSession   = ChildSaSession->IkeSaSession;\r
+      if (ChildSaSession->SessionCommon.State == IkeStateSaDeleting) {\r
+\r
+        //\r
+        // Established Child SA should be remove from the SAD entry and \r
+        // DeleteList. The function of Ikev2DeleteChildSaSilent() will remove \r
+        // the childSA from the IkeSaSession->ChildSaEstablishedList. So there \r
+        // is no need to remove it here.\r
+        //\r
+        Ikev2ChildSaSilentDelete (IkeSaSession, ChildSaSession->LocalPeerSpi);\r
+        Ikev2ChildSaSessionRemove (\r
+          &IkeSaSession->DeleteSaList,\r
+          ChildSaSession->LocalPeerSpi,\r
+          IKEV2_DELET_CHILDSA_LIST\r
+          );\r
+      } else {\r
+        Ikev2ChildSaSessionRemove (\r
+          &IkeSaSession->ChildSaSessionList,\r
+          ChildSaSession->LocalPeerSpi,\r
+          IKEV2_ESTABLISHING_CHILDSA_LIST\r
+          );\r
+      }\r
+\r
+      Ikev2ChildSaSessionFree (ChildSaSession);\r
+    }\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Increase the retry count.\r
+  //\r
+  SessionCommon->RetryCount++;\r
+  DEBUG ((DEBUG_INFO, ">>>Resending the last packet ...\n"));\r
+\r
+  //\r
+  // Resend the last packet.\r
+  //\r
+  Ikev2SendIkePacket (\r
+    SessionCommon->UdpService,\r
+    (UINT8*)SessionCommon,\r
+    SessionCommon->LastSentPacket,\r
+    0\r
+    );\r
+}\r
+\r
+/**\r
+  Copy ChildSaSession->Spd->Selector to ChildSaSession->SpdSelector.\r
+\r
+  ChildSaSession->SpdSelector stores the real Spdselector for its SA. Sometime,\r
+  the SpdSelector in ChildSaSession is more accurated or the scope is smaller \r
+  than the one in ChildSaSession->Spd, especially for the tunnel mode.\r
+    \r
+  @param[in, out]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION related to.\r
+  \r
+**/\r
+VOID\r
+Ikev2ChildSaSessionSpdSelectorCreate (\r
+  IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession\r
+  ) \r
+{\r
+  if (ChildSaSession->Spd != NULL && ChildSaSession->Spd->Selector != NULL) {\r
+    if (ChildSaSession->SpdSelector == NULL) {\r
+      ChildSaSession->SpdSelector = AllocateZeroPool (sizeof (EFI_IPSEC_SPD_SELECTOR));\r
+      ASSERT (ChildSaSession->SpdSelector != NULL);\r
+    }\r
+    CopyMem (\r
+      ChildSaSession->SpdSelector, \r
+      ChildSaSession->Spd->Selector, \r
+      sizeof (EFI_IPSEC_SPD_SELECTOR)\r
+      );\r
+    ChildSaSession->SpdSelector->RemoteAddress = AllocateCopyPool (\r
+                                                   ChildSaSession->Spd->Selector->RemoteAddressCount * \r
+                                                   sizeof (EFI_IP_ADDRESS_INFO), \r
+                                                   ChildSaSession->Spd->Selector->RemoteAddress\r
+                                                   );\r
+    ChildSaSession->SpdSelector->LocalAddress = AllocateCopyPool (\r
+                                                  ChildSaSession->Spd->Selector->LocalAddressCount * \r
+                                                  sizeof (EFI_IP_ADDRESS_INFO), \r
+                                                  ChildSaSession->Spd->Selector->LocalAddress\r
+                                                  );\r
+\r
+    ASSERT (ChildSaSession->SpdSelector->LocalAddress != NULL);\r
+    ASSERT (ChildSaSession->SpdSelector->RemoteAddress != NULL);\r
+\r
+    ChildSaSession->SpdSelector->RemoteAddressCount = ChildSaSession->Spd->Selector->RemoteAddressCount;\r
+    ChildSaSession->SpdSelector->LocalAddressCount = ChildSaSession->Spd->Selector->LocalAddressCount; \r
+  }\r
+}\r
+\r
+/**\r
+  Generate a ChildSa Session and insert it into related IkeSaSession.\r
+\r
+  @param[in]  IkeSaSession    Pointer to related IKEV2_SA_SESSION.\r
+  @param[in]  UdpService      Pointer to related IKE_UDP_SERVICE.\r
+\r
+  @return pointer of IKEV2_CHILD_SA_SESSION.\r
+\r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionCreate (\r
+  IN IKEV2_SA_SESSION   *IkeSaSession,\r
+  IN IKE_UDP_SERVICE     *UdpService\r
+  )\r
+{\r
+  IKEV2_CHILD_SA_SESSION    *ChildSaSession;\r
+  IKEV2_SESSION_COMMON      *ChildSaCommon;\r
+\r
+  //\r
+  // Create a new ChildSaSession.Insert it into processing list and initiate the common parameters.\r
+  //\r
+  ChildSaSession = Ikev2ChildSaSessionAlloc (UdpService, IkeSaSession);\r
+  ASSERT (ChildSaSession != NULL);\r
+\r
+  //\r
+  // Set the specific parameters.\r
+  // \r
+  ChildSaSession->Spd        = IkeSaSession->Spd;\r
+  ChildSaCommon              = &ChildSaSession->SessionCommon;\r
+  ChildSaCommon->IsInitiator = IkeSaSession->SessionCommon.IsInitiator;\r
+  if (IkeSaSession->SessionCommon.State == IkeStateAuth) {\r
+    ChildSaCommon->State     = IkeStateAuth;\r
+    IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateAuth);\r
+  } else {\r
+    ChildSaCommon->State     = IkeStateCreateChild;\r
+    IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateCreateChild);\r
+  }\r
+\r
+  //\r
+  // If SPD->Selector is not NULL, copy it to the ChildSaSession->SpdSelector.\r
+  // The ChildSaSession->SpdSelector might be changed after the traffic selector\r
+  // negoniation and it will be copied into the SAData after ChildSA established.\r
+  //\r
+  Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);\r
+\r
+  //\r
+  // Copy first NiBlock and NrBlock to ChildSa Session\r
+  //\r
+  ChildSaSession->NiBlock   = AllocateZeroPool (IkeSaSession->NiBlkSize);\r
+  ASSERT (ChildSaSession->NiBlock != NULL);\r
+  ChildSaSession->NiBlkSize = IkeSaSession->NiBlkSize;\r
+  CopyMem (ChildSaSession->NiBlock, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);\r
+\r
+  ChildSaSession->NrBlock   = AllocateZeroPool (IkeSaSession->NrBlkSize);\r
+  ASSERT (ChildSaSession->NrBlock != NULL);\r
+  ChildSaSession->NrBlkSize = IkeSaSession->NrBlkSize;\r
+  CopyMem (ChildSaSession->NrBlock, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);\r
+\r
+  //\r
+  //  Only if the Create Child SA is called for the IKE_INIT Exchange and \r
+  //  IkeSaSession is initiator (Only Initiator's SPD is not NULL), Set the \r
+  //  Traffic Selectors related information here.\r
+  //\r
+  if (IkeSaSession->SessionCommon.State == IkeStateAuth && IkeSaSession->Spd != NULL) {\r
+    ChildSaSession->ProtoId = IkeSaSession->Spd->Selector->NextLayerProtocol;\r
+    ChildSaSession->LocalPort = IkeSaSession->Spd->Selector->LocalPort;\r
+    ChildSaSession->RemotePort = IkeSaSession->Spd->Selector->RemotePort;\r
+  }\r
+\r
+  //\r
+  // Insert the new ChildSaSession into processing child SA list.\r
+  //\r
+  Ikev2ChildSaSessionInsert (&IkeSaSession->ChildSaSessionList, ChildSaSession);\r
+  return ChildSaSession;\r
+}\r
+\r
+/**\r
+  Check if the SPD is related to the input Child SA Session.\r
+\r
+  This function is the subfunction of Ikev1AssociateSpdEntry(). It is the call\r
+  back function of IpSecVisitConfigData(). \r
+  \r
+\r
+  @param[in]  Type               Type of the input Config Selector.\r
+  @param[in]  Selector           Pointer to the Configure Selector to be checked. \r
+  @param[in]  Data               Pointer to the Configure Selector's Data passed \r
+                                 from the caller.\r
+  @param[in]  SelectorSize       The buffer size of Selector.\r
+  @param[in]  DataSize           The buffer size of the Data.\r
+  @param[in]  Context            The data passed from the caller. It is a Child\r
+                                 SA Session in this context.\r
+\r
+  @retval EFI_SUCCESS        The SPD Selector is not related to the Child SA Session. \r
+  @retval EFI_ABORTED        The SPD Selector is related to the Child SA session and \r
+                             set the ChildSaSession->Spd to point to this SPD Selector.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2MatchSpdEntry (\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 VOID                           *Context\r
+  )\r
+{\r
+  IKEV2_CHILD_SA_SESSION  *ChildSaSession;\r
+  EFI_IPSEC_SPD_SELECTOR  *SpdSelector;\r
+  EFI_IPSEC_SPD_DATA      *SpdData;\r
+  BOOLEAN                 IsMatch;\r
+  UINT8                   IpVersion;\r
+\r
+  ASSERT (Type == IPsecConfigDataTypeSpd);\r
+  SpdData = (EFI_IPSEC_SPD_DATA *) Data;\r
+  //\r
+  // Bypass all non-protect SPD entry first\r
+  //\r
+  if (SpdData->Action != EfiIPsecActionProtect) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ChildSaSession  = (IKEV2_CHILD_SA_SESSION *) Context;\r
+  IpVersion       = ChildSaSession->SessionCommon.UdpService->IpVersion;\r
+  SpdSelector     = (EFI_IPSEC_SPD_SELECTOR *) Selector;  \r
+  IsMatch         = TRUE;\r
+\r
+  if (SpdSelector->NextLayerProtocol == EFI_IP_PROTO_UDP &&\r
+      SpdSelector->LocalPort == IKE_DEFAULT_PORT &&\r
+      SpdSelector->LocalPortRange == 0 &&\r
+      SpdSelector->RemotePort == IKE_DEFAULT_PORT &&\r
+      SpdSelector->RemotePortRange == 0\r
+      ) {\r
+    //\r
+    // TODO: Skip IKE Policy here or set a SPD entry?\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (SpdSelector->NextLayerProtocol != EFI_IPSEC_ANY_PROTOCOL &&\r
+      SpdSelector->NextLayerProtocol != ChildSaSession->ProtoId\r
+      ) {\r
+    IsMatch = FALSE;\r
+  }\r
+\r
+  if (SpdSelector->LocalPort != EFI_IPSEC_ANY_PORT && SpdSelector->LocalPort != ChildSaSession->LocalPort) {\r
+    IsMatch = FALSE;\r
+  }\r
+\r
+  if (SpdSelector->RemotePort != EFI_IPSEC_ANY_PORT && SpdSelector->RemotePort != ChildSaSession->RemotePort) {\r
+    IsMatch = FALSE;\r
+  }\r
+\r
+  IsMatch = (BOOLEAN) (IsMatch && \r
+                       IpSecMatchIpAddress (\r
+                         IpVersion,\r
+                         &ChildSaSession->SessionCommon.LocalPeerIp,\r
+                         SpdSelector->LocalAddress,\r
+                         SpdSelector->LocalAddressCount\r
+                         ));\r
+\r
+  IsMatch = (BOOLEAN) (IsMatch && \r
+                       IpSecMatchIpAddress (\r
+                         IpVersion,\r
+                         &ChildSaSession->SessionCommon.RemotePeerIp,\r
+                         SpdSelector->RemoteAddress,\r
+                         SpdSelector->RemoteAddressCount\r
+                         ));\r
+\r
+  if (IsMatch) {\r
+    ChildSaSession->Spd = IkeSearchSpdEntry (SpdSelector);\r
+    return EFI_ABORTED;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+/**\r
+  Check if the Algorithm ID is supported.\r
+\r
+  @param[in]  AlgorithmId The specified Algorithm ID.\r
+  @param[in]  Type        The type used to indicate the Algorithm is for Encrypt or\r
+                          Authentication.\r
+\r
+  @retval     TRUE        If the Algorithm ID is supported.\r
+  @retval     FALSE       If the Algorithm ID is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+Ikev2IsSupportAlg (\r
+  IN UINT16 AlgorithmId,\r
+  IN UINT8  Type\r
+  )\r
+{\r
+  UINT8 Index;\r
+  switch (Type) {\r
+  case IKE_ENCRYPT_TYPE :\r
+    for (Index = 0; Index < IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM; Index++) {\r
+      if (mIkev2EncryptAlgorithmList[Index] == AlgorithmId) {\r
+        return TRUE;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case IKE_AUTH_TYPE :\r
+    for (Index = 0; Index < IKEV2_SUPPORT_AUTH_ALGORITHM_NUM; Index++) {\r
+      if (mIkev2AuthAlgorithmList[Index] == AlgorithmId) {\r
+        return TRUE;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case IKE_DH_TYPE :\r
+    for (Index = 0; Index < IKEV2_SUPPORT_DH_ALGORITHM_NUM; Index++) {\r
+      if (mIkev2DhGroupAlgorithmList[Index] == AlgorithmId) {\r
+        return TRUE;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case IKE_PRF_TYPE :\r
+    for (Index = 0; Index < IKEV2_SUPPORT_PRF_ALGORITHM_NUM; Index++) {\r
+      if (mIkev2PrfAlgorithmList[Index] == AlgorithmId) {\r
+        return TRUE;\r
+      }\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Get the preferred algorithm types from ProposalData.\r
+\r
+  @param[in]  ProposalData              Pointer to related IKEV2_PROPOSAL_DATA.\r
+  @param[out] PreferEncryptAlgorithm    Output of preferred encrypt algorithm.\r
+  @param[out] PreferIntegrityAlgorithm  Output of preferred integrity algorithm. \r
+  @param[out] PreferPrfAlgorithm        Output of preferred PRF algorithm. Only \r
+                                        for IKE SA.\r
+  @param[out] PreferDhGroup             Output of preferred DH group. Only for \r
+                                        IKE SA.\r
+  @param[out] PreferEncryptKeylength    Output of preferred encrypt key length \r
+                                        in bytes.\r
+  @param[out] IsSupportEsn              Output of value about the Extented Sequence\r
+                                        Number is support or not. Only for Child SA.\r
+  @param[in]  IsChildSa                 If it is ture, the ProposalData is for IKE\r
+                                        SA. Otherwise the proposalData is for Child SA.\r
+\r
+**/\r
+VOID\r
+Ikev2ParseProposalData (\r
+  IN     IKEV2_PROPOSAL_DATA  *ProposalData, \r
+     OUT UINT16               *PreferEncryptAlgorithm,\r
+     OUT UINT16               *PreferIntegrityAlgorithm,\r
+     OUT UINT16               *PreferPrfAlgorithm,\r
+     OUT UINT16               *PreferDhGroup,\r
+     OUT UINTN                *PreferEncryptKeylength,\r
+     OUT BOOLEAN              *IsSupportEsn,\r
+  IN     BOOLEAN              IsChildSa\r
+) \r
+{\r
+  IKEV2_TRANSFORM_DATA *TransformData;\r
+  UINT8                TransformIndex;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if (ProposalData == NULL ||\r
+      PreferEncryptAlgorithm == NULL || \r
+      PreferIntegrityAlgorithm == NULL ||\r
+      PreferEncryptKeylength == NULL\r
+      ) {\r
+    return;\r
+  }\r
+\r
+  if (IsChildSa) {\r
+    if (IsSupportEsn == NULL) {\r
+      return;\r
+    }\r
+  } else {\r
+    if (PreferPrfAlgorithm == NULL || PreferDhGroup == NULL) {\r
+      return;\r
+    }\r
+  }  \r
+\r
+  TransformData = (IKEV2_TRANSFORM_DATA *)(ProposalData + 1);\r
+  for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) {\r
+    switch (TransformData->TransformType) {          \r
+    //\r
+    // For IKE SA there are four algorithm types. Encryption Algorithm, Pseudo-random Function, \r
+    // Integrity Algorithm, Diffie-Hellman Group. For Child SA, there are three algorithm types. \r
+    // Encryption Algorithm, Integrity Algorithm, Extended Sequence Number.\r
+    //\r
+    case IKEV2_TRANSFORM_TYPE_ENCR:\r
+      if (*PreferEncryptAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_ENCRYPT_TYPE)) {\r
+        //\r
+        // Check the attribute value. According to RFC, only Keylength is support.\r
+        //\r
+        if (TransformData->Attribute.AttrType == IKEV2_ATTRIBUTE_TYPE_KEYLEN) {\r
+          //\r
+          // If the Keylength is not support, continue to check the next one.\r
+          //\r
+          if (IpSecGetEncryptKeyLength ((UINT8)TransformData->TransformId) != (UINTN)(TransformData->Attribute.Attr.AttrValue >> 3)){\r
+            break;\r
+          } else {\r
+            *PreferEncryptKeylength = TransformData->Attribute.Attr.AttrValue;\r
+          }\r
+        }\r
+        *PreferEncryptAlgorithm = TransformData->TransformId;\r
+      }\r
+      break;\r
+\r
+    case IKEV2_TRANSFORM_TYPE_PRF :\r
+      if (!IsChildSa) {\r
+        if (*PreferPrfAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_PRF_TYPE)) {\r
+          *PreferPrfAlgorithm = TransformData->TransformId;\r
+        }\r
+      }       \r
+      break;\r
+\r
+    case IKEV2_TRANSFORM_TYPE_INTEG :\r
+      if (*PreferIntegrityAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_AUTH_TYPE)) {\r
+        *PreferIntegrityAlgorithm = TransformData->TransformId;\r
+      }\r
+      break;\r
+      \r
+    case IKEV2_TRANSFORM_TYPE_DH :\r
+      if (!IsChildSa) {\r
+        if (*PreferDhGroup == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_DH_TYPE)) {\r
+          *PreferDhGroup = TransformData->TransformId;\r
+        }\r
+      }        \r
+      break;\r
+    \r
+    case IKEV2_TRANSFORM_TYPE_ESN :\r
+      if (IsChildSa) {\r
+        if (TransformData->TransformId != 0) {\r
+          *IsSupportEsn = TRUE;\r
+        }\r
+      }        \r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+    TransformData = (IKEV2_TRANSFORM_DATA *)(TransformData + 1);\r
+  }\r
+}\r
+\r
+/**\r
+  Parse the received Initial Exchange Packet.\r
+  \r
+  This function parse the SA Payload and Key Payload to find out the cryptographic \r
+  suite for the further IKE negotiation and fill it into the IKE SA Session's \r
+  CommonSession->SaParams.\r
+\r
+  @param[in, out]  IkeSaSession  Pointer to related IKEV2_SA_SESSION.\r
+  @param[in]       SaPayload     The received packet.\r
+  @param[in]       Type          The received packet IKE header flag. \r
+\r
+  @retval          TRUE          If the SA proposal in Packet is acceptable.\r
+  @retval          FALSE         If the SA proposal in Packet is not acceptable.\r
+\r
+**/\r
+BOOLEAN\r
+Ikev2SaParseSaPayload (\r
+  IN OUT IKEV2_SA_SESSION *IkeSaSession,\r
+  IN     IKE_PAYLOAD      *SaPayload,\r
+  IN     UINT8            Type\r
+  )\r
+{\r
+  IKEV2_PROPOSAL_DATA  *ProposalData;\r
+  UINT8                ProposalIndex;\r
+  UINT16               PreferEncryptAlgorithm;\r
+  UINT16               PreferIntegrityAlgorithm;\r
+  UINT16               PreferPrfAlgorithm;\r
+  UINT16               PreferDhGroup;\r
+  UINTN                PreferEncryptKeylength;\r
+  UINT16               EncryptAlgorithm;\r
+  UINT16               IntegrityAlgorithm;\r
+  UINT16               PrfAlgorithm;\r
+  UINT16               DhGroup;\r
+  UINTN                EncryptKeylength;\r
+  BOOLEAN              IsMatch;\r
+  UINTN                SaDataSize;\r
+\r
+  PreferPrfAlgorithm       = 0;\r
+  PreferIntegrityAlgorithm = 0;\r
+  PreferDhGroup            = 0;\r
+  PreferEncryptAlgorithm   = 0;\r
+  PreferEncryptKeylength   = 0;\r
+  PrfAlgorithm             = 0;\r
+  IntegrityAlgorithm       = 0;\r
+  DhGroup                  = 0;\r
+  EncryptAlgorithm         = 0;\r
+  EncryptKeylength         = 0;\r
+  IsMatch                  = FALSE;\r
+\r
+  if (Type == IKE_HEADER_FLAGS_INIT) {\r
+    ProposalData   = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);\r
+    for (ProposalIndex = 0; ProposalIndex < ((IKEV2_SA_DATA *)SaPayload->PayloadBuf)->NumProposals; ProposalIndex++) {\r
+      //\r
+      // Iterate each proposal to find the perfered one.\r
+      //\r
+      if (ProposalData->ProtocolId == IPSEC_PROTO_ISAKMP && ProposalData->NumTransforms >= 4) {\r
+        //\r
+        // Get the preferred algorithms.\r
+        //\r
+        Ikev2ParseProposalData (\r
+          ProposalData, \r
+          &PreferEncryptAlgorithm,\r
+          &PreferIntegrityAlgorithm,\r
+          &PreferPrfAlgorithm,\r
+          &PreferDhGroup,\r
+          &PreferEncryptKeylength,\r
+          NULL,\r
+          FALSE\r
+          );\r
+\r
+        if (PreferEncryptAlgorithm != 0 &&\r
+              PreferIntegrityAlgorithm != 0 &&\r
+              PreferPrfAlgorithm != 0 && \r
+              PreferDhGroup != 0\r
+              ) {\r
+            //\r
+            // Find the matched one. \r
+            //\r
+            IkeSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));\r
+            ASSERT (IkeSaSession->SessionCommon.SaParams != NULL);\r
+            IkeSaSession->SessionCommon.SaParams->EncAlgId   = PreferEncryptAlgorithm;\r
+            IkeSaSession->SessionCommon.SaParams->EnckeyLen  = PreferEncryptKeylength;\r
+            IkeSaSession->SessionCommon.SaParams->DhGroup    = PreferDhGroup;\r
+            IkeSaSession->SessionCommon.SaParams->Prf        = PreferPrfAlgorithm;\r
+            IkeSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;\r
+            IkeSaSession->SessionCommon.PreferDhGroup        = PreferDhGroup;\r
+\r
+            //\r
+            // Save the matched one in IKEV2_SA_DATA for furthure calculation.\r
+            //\r
+            SaDataSize           = sizeof (IKEV2_SA_DATA) +\r
+                                   sizeof (IKEV2_PROPOSAL_DATA) +\r
+                                   sizeof (IKEV2_TRANSFORM_DATA) * 4;\r
+            IkeSaSession->SaData = AllocateZeroPool (SaDataSize);\r
+            ASSERT (IkeSaSession->SaData != NULL);\r
+\r
+            IkeSaSession->SaData->NumProposals  = 1;\r
+\r
+            //\r
+            // BUGBUG: Suppose the matched proposal only has 4 transforms. If\r
+            // The matched Proposal has more than 4 transforms means it contains\r
+            // one than one transform with same type.\r
+            //\r
+            CopyMem (\r
+              (IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1), \r
+               ProposalData, \r
+               SaDataSize - sizeof (IKEV2_SA_DATA)\r
+              );\r
+\r
+            ((IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1))->ProposalIndex = 1;\r
+            return TRUE;\r
+          } else {\r
+            PreferEncryptAlgorithm   = 0;\r
+            PreferIntegrityAlgorithm = 0;\r
+            PreferPrfAlgorithm       = 0;\r
+            PreferDhGroup            = 0;\r
+            PreferEncryptKeylength   = 0;\r
+          }\r
+      }\r
+      //\r
+      // Point to next Proposal.\r
+      //\r
+      ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + \r
+                     ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));\r
+    }\r
+  } else if (Type == IKE_HEADER_FLAGS_RESPOND) {\r
+    //\r
+    // First check the SA proposal's ProtoctolID and Transform Numbers. Since it is \r
+    // the responded SA proposal, suppose it only has one proposal and the transform Numbers \r
+    // is 4. \r
+    //\r
+    ProposalData  = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *) SaPayload->PayloadBuf + 1);\r
+    if (ProposalData->ProtocolId != IPSEC_PROTO_ISAKMP || ProposalData->NumTransforms != 4) {\r
+      return FALSE;\r
+    }\r
+    //\r
+    // Get the preferred algorithms. \r
+    //\r
+    Ikev2ParseProposalData (\r
+      ProposalData,\r
+      &PreferEncryptAlgorithm,\r
+      &PreferIntegrityAlgorithm,\r
+      &PreferPrfAlgorithm,\r
+      &PreferDhGroup,\r
+      &PreferEncryptKeylength,\r
+      NULL, \r
+      FALSE\r
+      );\r
+    // \r
+    // Check if the Sa proposal data from received packet is in the IkeSaSession->SaData.\r
+    //\r
+    ProposalData = (IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1);\r
+\r
+    for (ProposalIndex = 0; ProposalIndex < IkeSaSession->SaData->NumProposals && (!IsMatch); ProposalIndex++) {\r
+      Ikev2ParseProposalData (\r
+          ProposalData, \r
+          &EncryptAlgorithm,\r
+          &IntegrityAlgorithm,\r
+          &PrfAlgorithm,\r
+          &DhGroup,\r
+          &EncryptKeylength,\r
+          NULL,\r
+          FALSE\r
+          );\r
+      if (EncryptAlgorithm == PreferEncryptAlgorithm &&\r
+          EncryptKeylength == PreferEncryptKeylength &&\r
+          IntegrityAlgorithm == PreferIntegrityAlgorithm &&\r
+          PrfAlgorithm == PreferPrfAlgorithm &&\r
+          DhGroup      == PreferDhGroup\r
+          ) {\r
+        IsMatch = TRUE;\r
+      } else {\r
+        EncryptAlgorithm   = 0;\r
+        IntegrityAlgorithm = 0;\r
+        PrfAlgorithm       = 0;\r
+        DhGroup            = 0;\r
+        EncryptKeylength   = 0; \r
+      }\r
+\r
+      ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + \r
+                     ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));    \r
+    }\r
+\r
+    if (IsMatch) {\r
+        IkeSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));\r
+        ASSERT (IkeSaSession->SessionCommon.SaParams != NULL);\r
+        IkeSaSession->SessionCommon.SaParams->EncAlgId   = PreferEncryptAlgorithm;\r
+        IkeSaSession->SessionCommon.SaParams->EnckeyLen  = PreferEncryptKeylength;\r
+        IkeSaSession->SessionCommon.SaParams->DhGroup    = PreferDhGroup;\r
+        IkeSaSession->SessionCommon.SaParams->Prf        = PreferPrfAlgorithm;\r
+        IkeSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;\r
+        IkeSaSession->SessionCommon.PreferDhGroup        = PreferDhGroup;\r
+      \r
+        return TRUE;\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Parse the received Authentication Exchange Packet.\r
+  \r
+  This function parse the SA Payload and Key Payload to find out the cryptographic\r
+  suite for the ESP and fill it into the Child SA Session's CommonSession->SaParams.\r
+  \r
+  @param[in, out]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION related to \r
+                                   this Authentication Exchange.\r
+  @param[in]       SaPayload       The received packet.\r
+  @param[in]       Type            The IKE header's flag of received packet . \r
+  \r
+  @retval          TRUE            If the SA proposal in Packet is acceptable.\r
+  @retval          FALSE           If the SA proposal in Packet is not acceptable.\r
+\r
+**/\r
+BOOLEAN\r
+Ikev2ChildSaParseSaPayload (\r
+  IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession,\r
+  IN     IKE_PAYLOAD            *SaPayload,\r
+  IN     UINT8                  Type\r
+  )\r
+{\r
+  IKEV2_PROPOSAL_DATA  *ProposalData;\r
+  UINT8                ProposalIndex;\r
+  UINT16               PreferEncryptAlgorithm;\r
+  UINT16               PreferIntegrityAlgorithm;\r
+  UINTN                PreferEncryptKeylength;\r
+  BOOLEAN              PreferIsSupportEsn;\r
+  UINT16               EncryptAlgorithm;\r
+  UINT16               IntegrityAlgorithm;\r
+  UINTN                EncryptKeylength;\r
+  BOOLEAN              IsSupportEsn;\r
+  BOOLEAN              IsMatch;\r
+  UINTN                SaDataSize;\r
+\r
+\r
+  PreferIntegrityAlgorithm = 0;\r
+  PreferEncryptAlgorithm   = 0;\r
+  PreferEncryptKeylength   = 0;\r
+  IntegrityAlgorithm       = 0;\r
+  EncryptAlgorithm         = 0;\r
+  EncryptKeylength         = 0;\r
+  IsMatch                  = TRUE;\r
+  IsSupportEsn             = FALSE;\r
+  PreferIsSupportEsn       = FALSE;\r
+\r
+  if (Type == IKE_HEADER_FLAGS_INIT) {\r
+    ProposalData   = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *) SaPayload->PayloadBuf + 1);\r
+    for (ProposalIndex = 0; ProposalIndex < ((IKEV2_SA_DATA *) SaPayload->PayloadBuf)->NumProposals; ProposalIndex++) {\r
+      //\r
+      // Iterate each proposal to find the preferred one.\r
+      //\r
+      if (ProposalData->ProtocolId == IPSEC_PROTO_IPSEC_ESP && ProposalData->NumTransforms >= 3) {\r
+        //\r
+        // Get the preferred algorithm.\r
+        //\r
+        Ikev2ParseProposalData (\r
+          ProposalData,\r
+          &PreferEncryptAlgorithm,\r
+          &PreferIntegrityAlgorithm,\r
+          NULL,\r
+          NULL,\r
+          &PreferEncryptKeylength,\r
+          &IsSupportEsn,\r
+          TRUE\r
+          );\r
+        //\r
+        // Don't support the ESN now.\r
+        //\r
+        if (PreferEncryptAlgorithm != 0 && \r
+            PreferIntegrityAlgorithm != 0 &&\r
+            !IsSupportEsn\r
+            ) {\r
+          //\r
+          // Find the matched one. \r
+          //\r
+          ChildSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));\r
+          ASSERT (ChildSaSession->SessionCommon.SaParams != NULL);\r
+          ChildSaSession->SessionCommon.SaParams->EncAlgId   = PreferEncryptAlgorithm;\r
+          ChildSaSession->SessionCommon.SaParams->EnckeyLen  = PreferEncryptKeylength;\r
+          ChildSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;\r
+          CopyMem (&ChildSaSession->RemotePeerSpi, ProposalData->Spi, sizeof (ChildSaSession->RemotePeerSpi));\r
+\r
+          //\r
+          // Save the matched one in IKEV2_SA_DATA for furthure calculation.\r
+          //\r
+          SaDataSize           = sizeof (IKEV2_SA_DATA) +\r
+                                 sizeof (IKEV2_PROPOSAL_DATA) +\r
+                                 sizeof (IKEV2_TRANSFORM_DATA) * 4;\r
+\r
+          ChildSaSession->SaData = AllocateZeroPool (SaDataSize);\r
+          ASSERT (ChildSaSession->SaData != NULL);\r
+\r
+          ChildSaSession->SaData->NumProposals  = 1;\r
+\r
+          //\r
+          // BUGBUG: Suppose there are 4 transforms in the matched proposal. If\r
+          // the matched Proposal has more than 4 transforms that means there \r
+          // are more than one transform with same type.\r
+          //\r
+          CopyMem (\r
+            (IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1),\r
+             ProposalData,\r
+             SaDataSize - sizeof (IKEV2_SA_DATA)\r
+            );\r
+\r
+          ((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->ProposalIndex = 1;\r
+\r
+          ((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->Spi = AllocateCopyPool (\r
+                                                                          sizeof (ChildSaSession->LocalPeerSpi), \r
+                                                                          &ChildSaSession->LocalPeerSpi\r
+                                                                          );\r
+          ASSERT (((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->Spi != NULL);\r
+          return TRUE;\r
+\r
+        } else {\r
+          PreferEncryptAlgorithm   = 0;\r
+          PreferIntegrityAlgorithm = 0;\r
+          IsSupportEsn             = TRUE;\r
+        }\r
+      }\r
+      //\r
+      // Point to next Proposal\r
+      //\r
+      ProposalData = (IKEV2_PROPOSAL_DATA *)((UINT8 *)(ProposalData + 1) + \r
+                     ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));\r
+    }\r
+  } else if (Type == IKE_HEADER_FLAGS_RESPOND) {\r
+    //\r
+    // First check the SA proposal's ProtoctolID and Transform Numbers. Since it is \r
+    // the responded SA proposal, suppose it only has one proposal and the transform Numbers \r
+    // is 3. \r
+    //\r
+    ProposalData  = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);\r
+    if (ProposalData->ProtocolId != IPSEC_PROTO_IPSEC_ESP || ProposalData->NumTransforms != 3) {\r
+      return FALSE;\r
+    }\r
+    //\r
+    // Get the preferred algorithms.\r
+    //\r
+    Ikev2ParseProposalData (\r
+      ProposalData,\r
+      &PreferEncryptAlgorithm,\r
+      &PreferIntegrityAlgorithm,\r
+      NULL,\r
+      NULL,\r
+      &PreferEncryptKeylength,\r
+      &PreferIsSupportEsn,\r
+      TRUE\r
+      );\r
+\r
+    ProposalData = (IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1);\r
+\r
+    for (ProposalIndex = 0; ProposalIndex < ChildSaSession->SaData->NumProposals && (!IsMatch); ProposalIndex++) {\r
+      Ikev2ParseProposalData (\r
+          ProposalData, \r
+          &EncryptAlgorithm,\r
+          &IntegrityAlgorithm,\r
+          NULL,\r
+          NULL,\r
+          &EncryptKeylength,\r
+          &IsSupportEsn,\r
+          TRUE\r
+          );\r
+      if (EncryptAlgorithm == PreferEncryptAlgorithm &&\r
+          EncryptKeylength == PreferEncryptKeylength &&\r
+          IntegrityAlgorithm == PreferIntegrityAlgorithm &&\r
+          IsSupportEsn == PreferIsSupportEsn          \r
+          ) {\r
+        IsMatch = TRUE;\r
+      } else {\r
+        PreferEncryptAlgorithm   = 0;\r
+        PreferIntegrityAlgorithm = 0;\r
+        IsSupportEsn             = TRUE;\r
+      }\r
+       ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + \r
+                     ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));  \r
+    }\r
+  \r
+    ProposalData  = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);\r
+    if (IsMatch) {\r
+        ChildSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));\r
+        ASSERT (ChildSaSession->SessionCommon.SaParams != NULL);\r
+        ChildSaSession->SessionCommon.SaParams->EncAlgId   = PreferEncryptAlgorithm;\r
+        ChildSaSession->SessionCommon.SaParams->EnckeyLen  = PreferEncryptKeylength;\r
+        ChildSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;\r
+        CopyMem (&ChildSaSession->RemotePeerSpi, ProposalData->Spi, sizeof (ChildSaSession->RemotePeerSpi));\r
+\r
+        return TRUE;\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Generate Key buffer from fragments.\r
+\r
+  If the digest length of specified HashAlgId is larger than or equal with the \r
+  required output key length, derive the key directly. Otherwise, Key Material \r
+  needs to be PRF-based concatenation according to 2.13 of RFC 4306: \r
+  prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01),\r
+  T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04)\r
+  then derive the key from this key material.\r
+  \r
+  @param[in]       HashAlgId        The Hash Algorithm ID used to generate key.\r
+  @param[in]       HashKey          Pointer to a key buffer which contains hash key.\r
+  @param[in]       HashKeyLength    The length of HashKey in bytes.\r
+  @param[in, out]  OutputKey        Pointer to buffer which is used to receive the \r
+                                    output key.\r
+  @param[in]       OutputKeyLength  The length of OutPutKey buffer.\r
+  @param[in]       Fragments        Pointer to the data to be used to generate key.\r
+  @param[in]       NumFragments     The numbers of the Fragement.\r
+\r
+  @retval EFI_SUCCESS            The operation complete successfully.\r
+  @retval EFI_INVALID_PARAMETER  If NumFragments is zero.\r
+  @retval EFI_OUT_OF_RESOURCES   If the required resource can't be allocated.\r
+  @retval Others                 The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2SaGenerateKey (\r
+  IN     UINT8                 HashAlgId,\r
+  IN     UINT8                 *HashKey,\r
+  IN     UINTN                 HashKeyLength,\r
+  IN OUT UINT8                 *OutputKey,\r
+  IN     UINTN                 OutputKeyLength,\r
+  IN     PRF_DATA_FRAGMENT    *Fragments,\r
+  IN     UINTN                 NumFragments\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  PRF_DATA_FRAGMENT   LocalFragments[3];\r
+  UINT8               *Digest;\r
+  UINTN               DigestSize;\r
+  UINTN               Round;\r
+  UINTN               Index;\r
+  UINTN               AuthKeyLength;\r
+  UINTN               FragmentsSize;\r
+  UINT8               TailData;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  if (NumFragments == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  LocalFragments[0].Data = NULL;\r
+  LocalFragments[1].Data = NULL;\r
+  LocalFragments[2].Data = NULL;\r
+\r
+  AuthKeyLength = IpSecGetHmacDigestLength (HashAlgId);\r
+  DigestSize    = AuthKeyLength;\r
+  Digest        = AllocateZeroPool (AuthKeyLength);\r
+\r
+  if (Digest == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // If the required output key length is less than the digest size,\r
+  // copy the digest into OutputKey.\r
+  //\r
+  if (OutputKeyLength <=  DigestSize) {\r
+    Status = IpSecCryptoIoHmac (\r
+               HashAlgId,\r
+               HashKey, \r
+               HashKeyLength, \r
+               (HASH_DATA_FRAGMENT *) Fragments, \r
+               NumFragments, \r
+               Digest, \r
+               DigestSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    CopyMem (OutputKey, Digest, OutputKeyLength);\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  //Otherwise, Key Material need to be PRF-based concatenation according to 2.13\r
+  //of RFC 4306: prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01),\r
+  //T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04)\r
+  //then derive the key from this key material.\r
+  //\r
+  FragmentsSize = 0;\r
+  for (Index = 0; Index < NumFragments; Index++) {\r
+    FragmentsSize = FragmentsSize + Fragments[Index].DataSize;\r
+  }\r
+\r
+  LocalFragments[1].Data     = AllocateZeroPool (FragmentsSize);\r
+  ASSERT (LocalFragments[1].Data != NULL);\r
+  LocalFragments[1].DataSize = FragmentsSize;\r
+\r
+  //\r
+  // Copy all input fragments into LocalFragments[1];\r
+  //\r
+  FragmentsSize = 0;\r
+  for (Index = 0; Index < NumFragments; Index++) {\r
+    CopyMem (\r
+      LocalFragments[1].Data + FragmentsSize, \r
+      Fragments[Index].Data,\r
+      Fragments[Index].DataSize\r
+      );\r
+    FragmentsSize = FragmentsSize + Fragments[Index].DataSize;\r
+  }\r
+\r
+  //\r
+  // Prepare 0x01 as the first tail data.\r
+  //\r
+  TailData                   = 0x01;\r
+  LocalFragments[2].Data     = &TailData;\r
+  LocalFragments[2].DataSize = sizeof (TailData);\r
+  //\r
+  // Allocate buffer for the first fragment\r
+  //\r
+  LocalFragments[0].Data     = AllocateZeroPool (AuthKeyLength);\r
+  ASSERT (LocalFragments[0].Data != NULL);\r
+  LocalFragments[0].DataSize = AuthKeyLength;\r
+\r
+  Round = (OutputKeyLength - 1) / AuthKeyLength + 1;\r
+  for (Index = 0; Index < Round; Index++) {\r
+    Status = IpSecCryptoIoHmac (\r
+               HashAlgId, \r
+               HashKey, \r
+               HashKeyLength, \r
+               (HASH_DATA_FRAGMENT *)(Index == 0 ? &LocalFragments[1] : LocalFragments),\r
+               Index == 0 ? 2 : 3, \r
+               Digest,\r
+               DigestSize\r
+               );\r
+    if (EFI_ERROR(Status)) {\r
+      goto Exit;\r
+    }\r
+    CopyMem (\r
+      LocalFragments[0].Data, \r
+      Digest, \r
+      DigestSize\r
+      );\r
+    if (OutputKeyLength > DigestSize * (Index + 1)) {\r
+      CopyMem (\r
+        OutputKey + Index * DigestSize, \r
+        Digest, \r
+        DigestSize\r
+        );\r
+      LocalFragments[0].DataSize = DigestSize;\r
+      TailData ++;\r
+    } else {\r
+      // \r
+      // The last round\r
+      //\r
+      CopyMem (\r
+        OutputKey + Index * DigestSize, \r
+        Digest, \r
+        OutputKeyLength - Index * DigestSize\r
+      );\r
+    }\r
+  }\r
+\r
+Exit:\r
+  //\r
+  // Only First and second Framgement Data need to be freed.\r
+  //\r
+  for (Index = 0 ; Index < 2; Index++) {\r
+    if (LocalFragments[Index].Data != NULL) {\r
+      FreePool (LocalFragments[Index].Data);\r
+    }\r
+  }\r
+  if (Digest != NULL) {\r
+    FreePool (Digest);\r
+  }\r
+  return Status;\r
+}\r
+\r
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Utility.h b/NetworkPkg/IpSecDxe/Ikev2/Utility.h
new file mode 100644 (file)
index 0000000..ea3e5cd
--- /dev/null
@@ -0,0 +1,1131 @@
+/** @file\r
+  The interfaces of IKE/Child session operations and payload related operations \r
+  used by IKE Exchange Process.\r
+\r
+  Copyright (c) 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
+#ifndef _IKE_V2_UTILITY_H_\r
+#define _IKE_V2_UTILITY_H_\r
+\r
+#include "Ikev2.h"\r
+#include "IkeCommon.h"\r
+#include "IpSecCryptIo.h"\r
+\r
+#include <Library/PcdLib.h>\r
+\r
+#define IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM    2\r
+#define IKEV2_SUPPORT_PRF_ALGORITHM_NUM        1\r
+#define IKEV2_SUPPORT_DH_ALGORITHM_NUM         2\r
+#define IKEV2_SUPPORT_AUTH_ALGORITHM_NUM       1\r
+\r
+/**\r
+  Allocate buffer for IKEV2_SA_SESSION and initialize it.\r
+\r
+  @param[in] Private        Pointer to IPSEC_PRIVATE_DATA.\r
+  @param[in] UdpService     Pointer to IKE_UDP_SERVICE related to this IKE SA Session.\r
+\r
+  @return Pointer to IKEV2_SA_SESSION.\r
+\r
+**/\r
+IKEV2_SA_SESSION *\r
+Ikev2SaSessionAlloc (\r
+  IN IPSEC_PRIVATE_DATA       *Private,\r
+  IN IKE_UDP_SERVICE          *UdpService\r
+  );\r
+\r
+/**\r
+  Register Establish IKEv2 SA into Private->Ikev2EstablishedList.\r
+\r
+  @param[in]  IkeSaSession  Pointer to IKEV2_SA_SESSION to be registered.\r
+  @param[in]  Private       Pointer to IPSEC_PRAVATE_DATA.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionReg (\r
+  IN IKEV2_SA_SESSION          *IkeSaSession,\r
+  IN IPSEC_PRIVATE_DATA        *Private\r
+  );\r
+\r
+/**\r
+  Find a IKEV2_SA_SESSION by the remote peer IP.\r
+\r
+  @param[in]  SaSessionList     SaSession List to be searched.\r
+  @param[in]  RemotePeerIp      Pointer to specified IP address.\r
+\r
+  @return Pointer to IKEV2_SA_SESSION if find one or NULL.\r
+\r
+**/\r
+IKEV2_SA_SESSION *\r
+Ikev2SaSessionLookup (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN EFI_IP_ADDRESS       *RemotePeerIp\r
+  );\r
+\r
+/**\r
+  Insert a IKE_SA_SESSION into IkeSaSession list. The IkeSaSession list is either\r
+  Private->Ikev2SaSession list or Private->Ikev2EstablishedList list.\r
+\r
+  @param[in]  SaSessionList   Pointer to list to be inserted into.\r
+  @param[in]  IkeSaSession    Pointer to IKEV2_SA_SESSION to be inserted. \r
+  @param[in]  RemotePeerIp    Pointer to EFI_IP_ADDRESSS to indicate the \r
+                              unique IKEV2_SA_SESSION.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionInsert (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN IKEV2_SA_SESSION     *IkeSaSession,\r
+  IN EFI_IP_ADDRESS       *RemotePeerIp\r
+  );\r
+\r
+/**\r
+  Remove the SA Session by Remote Peer IP.\r
+\r
+  @param[in]  SaSessionList   Pointer to list to be searched.\r
+  @param[in]  RemotePeerIp    Pointer to EFI_IP_ADDRESS to use for SA Session search.\r
+\r
+  @retval Pointer to IKEV2_SA_SESSION with the specified remote IP address. \r
+\r
+**/\r
+IKEV2_SA_SESSION *\r
+Ikev2SaSessionRemove (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN EFI_IP_ADDRESS       *RemotePeerIp\r
+  );\r
+\r
+\r
+/**\r
+  Marking a SA session as on deleting.\r
+\r
+  @param[in]  IkeSaSession  Pointer to IKEV2_SA_SESSION.\r
+\r
+  @retval     EFI_SUCCESS   Find the related SA session and marked it.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2SaSessionOnDeleting (\r
+  IN IKEV2_SA_SESSION          *IkeSaSession\r
+  );\r
+\r
+/**\r
+  After IKE/Child SA is estiblished, close the time event and free sent packet.\r
+\r
+  @param[in]   SessionCommon   Pointer to a Session Common.\r
+\r
+**/\r
+VOID\r
+Ikev2SessionCommonRefresh (\r
+  IN IKEV2_SESSION_COMMON      *SessionCommon\r
+  );\r
+\r
+/**\r
+  Free specified IKEV2 SA Session. \r
+\r
+  @param[in]    IkeSaSession   Pointer to IKEV2_SA_SESSION to be freed.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionFree (\r
+  IN IKEV2_SA_SESSION         *IkeSaSession\r
+  );\r
+\r
+/**\r
+  Free specified Seession Common. The session common would belong to a IKE SA or \r
+  a Child SA.\r
+\r
+  @param[in]   SessionCommon   Pointer to a Session Common.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionCommonFree (\r
+  IN IKEV2_SESSION_COMMON      *SessionCommon\r
+  );\r
+\r
+/**\r
+  Increase the MessageID in IkeSaSession.\r
+\r
+  @param[in] IkeSaSession Pointer to a specified IKEV2_SA_SESSION.\r
+\r
+**/\r
+VOID\r
+Ikev2SaSessionIncreaseMessageId (\r
+  IN IKEV2_SA_SESSION         *IkeSaSession\r
+  );\r
+\r
+/**\r
+  Allocate Momery for IKEV2 Child SA Session.\r
+  \r
+  @param[in]   UdpService     Pointer to IKE_UDP_SERVICE.\r
+  @param[in]   IkeSaSession   Pointer to IKEV2_SA_SESSION related to this Child SA \r
+                              Session.\r
+\r
+  @retval  Pointer of a new created IKEV2 Child SA Session.\r
+\r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionAlloc (\r
+  IN IKE_UDP_SERVICE          *UdpService,\r
+  IN IKEV2_SA_SESSION         *IkeSaSession\r
+  );\r
+\r
+/**\r
+  Register a established IKEv2 Child SA into IkeSaSession->ChildSaEstablishSessionList. \r
+  If the there is IKEV2_CHILD_SA_SESSION with same remote peer IP, remove the old one \r
+  then register the new one.\r
+\r
+  @param[in]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION to be registered.\r
+  @param[in]  Private         Pointer to IPSEC_PRAVATE_DATA.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaSessionReg (\r
+  IN IKEV2_CHILD_SA_SESSION    *ChildSaSession,\r
+  IN IPSEC_PRIVATE_DATA        *Private\r
+  );\r
+\r
+/**\r
+  This function find the Child SA by the specified Spi.\r
+
+  This functin find a ChildSA session by searching the ChildSaSessionlist of
+  the input IKEV2_SA_SESSION by specified MessageID.\r
+  
+  @param[in]  SaSessionList      Pointer to List to be searched.\r
+  @param[in]  Spi                Specified SPI.\r
+
+  @return Pointer to IKEV2_CHILD_SA_SESSION.\r
+\r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionLookupBySpi (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN UINT32               Spi\r
+  );\r
+\r
+/**\r
+  Find the ChildSaSession by it's MessagId.\r
+\r
+  @param[in] SaSessionList  Pointer to a ChildSaSession List.\r
+  @param[in] Mid            The messageId used to search ChildSaSession.\r
+\r
+  @return Pointer to IKEV2_CHILD_SA_SESSION.\r
+\r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionLookupByMid (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN UINT32               Mid\r
+  );\r
+\r
+/**\r
+  Insert a Child SA Session into the specified ChildSa list..\r
+\r
+  @param[in]  SaSessionList   Pointer to list to be inserted in.\r
+  @param[in]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION to be inserted.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaSessionInsert (\r
+  IN LIST_ENTRY               *SaSessionList,\r
+  IN IKEV2_CHILD_SA_SESSION   *ChildSaSession\r
+  );\r
+\r
+/**\r
+  Remove the IKEV2_CHILD_SA_SESSION from IkeSaSessionList.\r
+  \r
+  @param[in]  SaSessionList      The SA Session List to be iterated.\r
+  @param[in]  Spi                Spi used to identify the IKEV2_CHILD_SA_SESSION.\r
+  @param[in]  ListType           The type of the List to indicate whether it is a \r
+                                 Established. \r
+\r
+  @return The point to IKEV2_CHILD_SA_SESSION.\r
+  \r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionRemove (\r
+  IN LIST_ENTRY           *SaSessionList,\r
+  IN UINT32               Spi, \r
+  IN UINT8                ListType  \r
+  );\r
+\r
+/**\r
+  Mark a specified Child SA Session as on deleting.\r
+\r
+  @param[in]  ChildSaSession   Pointer to IKEV2_CHILD_SA_SESSION.\r
+\r
+  @retval     EFI_SUCCESS      Operation is successful.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2ChildSaSessionOnDeleting (\r
+  IN IKEV2_CHILD_SA_SESSION   *ChildSaSession\r
+  );\r
+\r
+/**\r
+  Free the memory located for the specified IKEV2_CHILD_SA_SESSION. \r
+\r
+  @param[in]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaSessionFree (\r
+  IN IKEV2_CHILD_SA_SESSION   *ChildSaSession\r
+  );\r
+\r
+/**\r
+  Free the specified DhBuffer.\r
+\r
+  @param[in] DhBuffer   Pointer to IKEV2_DH_BUFFER to be freed.\r
+  \r
+**/\r
+VOID\r
+Ikev2DhBufferFree (\r
+  IN IKEV2_DH_BUFFER *DhBuffer\r
+  );\r
+\r
+/**\r
+  Delete the specified established Child SA.\r
+\r
+  This function delete the Child SA directly and dont send the Information Packet to\r
+  remote peer.\r
+\r
+  @param[in]  IkeSaSession   Pointer to a IKE SA Session used to be searched for.\r
+  @param[in]  Spi            SPI used to find the Child SA.\r
+\r
+  @retval     EFI_NOT_FOUND  Pointer of IKE SA Session is NULL.\r
+  @retval     EFI_NOT_FOUND  There is no specified Child SA related with the input\r
+                             SPI under this IKE SA Session.\r
+  @retval     EFI_SUCCESS    Delete the Child SA successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2ChildSaSilentDelete (\r
+  IN IKEV2_SA_SESSION       *IkeSaSession,\r
+  IN UINT32                 Spi\r
+  );\r
+\r
+/**\r
+  This function is to parse a request IKE packet and return its request type.\r
+  The request type is one of IKE CHILD SA creation, IKE SA rekeying and \r
+  IKE CHILD SA rekeying.\r
+\r
+  @param[in] IkePacket  IKE packet to be prased.\r
+\r
+  return the type of the IKE packet.\r
+\r
+**/\r
+IKEV2_CREATE_CHILD_REQUEST_TYPE\r
+Ikev2ChildExchangeRequestType(\r
+  IN IKE_PACKET               *IkePacket\r
+  );\r
+\r
+/**\r
+  This function finds the SPI from Create Child Sa Exchange Packet.\r
\r
+  @param[in] IkePacket       Pointer to IKE_PACKET to be searched.\r
+\r
+  @retval SPI number.\r
+\r
+**/\r
+UINT32\r
+Ikev2ChildExchangeRekeySpi(\r
+  IN IKE_PACKET               *IkePacket\r
+  );\r
+\r
+\r
+/**\r
+  Associate a SPD selector to the Child SA Session.\r
+\r
+  This function is called when the Child SA is not the first child SA of its \r
+  IKE SA. It associate a SPD to this Child SA.\r
+\r
+  @param[in, out]  ChildSaSession     Pointer to the Child SA Session to be associated to \r
+                                      a SPD selector.\r
+\r
+  @retval EFI_SUCCESS        Associate one SPD selector to this Child SA Session successfully.\r
+  @retval EFI_NOT_FOUND      Can't find the related SPD selector.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2ChildSaAssociateSpdEntry (\r
+  IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession\r
+  );\r
+\r
+/**\r
+  Validate the IKE header of received IKE packet.\r
+\r
+  @param[in]   IkeSaSession  Pointer to IKEV2_SA_SESSION related to this IKE packet.\r
+  @param[in]   IkeHdr        Pointer to IKE header of received IKE packet.\r
+\r
+  @retval TRUE   If the IKE header is valid.\r
+  @retval FALSE  If the IKE header is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+Ikev2ValidateHeader (\r
+  IN IKEV2_SA_SESSION         *IkeSaSession,\r
+  IN IKE_HEADER               *IkeHdr\r
+  );\r
+\r
+/**\r
+  Create and intialize IKEV2_SA_DATA for speicifed IKEV2_SESSION_COMMON.\r
+\r
+  This function will be only called by the initiator. The responder's IKEV2_SA_DATA\r
+  will be generated during parsed the initiator packet.\r
+\r
+  @param[in]  SessionCommon  Pointer to IKEV2_SESSION_COMMON related to.\r
+\r
+  @retval a Pointer to a new IKEV2_SA_DATA or NULL.\r
+\r
+**/\r
+IKEV2_SA_DATA *\r
+Ikev2InitializeSaData (\r
+  IN IKEV2_SESSION_COMMON     *SessionCommon\r
+  );\r
+\r
+/**\r
+  Store the SA into SAD.\r
+\r
+  @param[in]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION.\r
+\r
+**/\r
+VOID\r
+Ikev2StoreSaData (\r
+  IN IKEV2_CHILD_SA_SESSION   *ChildSaSession\r
+  );\r
+\r
+/**\r
+  Routine process before the payload decoding.\r
+\r
+  @param[in] SessionCommon  Pointer to ChildSa SessionCommon.\r
+  @param[in] PayloadBuf     Pointer to the payload.\r
+  @param[in] PayloadSize    Size of PayloadBuf in byte.\r
+  @param[in] PayloadType    Type of Payload.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaBeforeDecodePayload (\r
+  IN UINT8 *SessionCommon,\r
+  IN UINT8 *PayloadBuf,\r
+  IN UINTN PayloadSize,\r
+  IN UINT8 PayloadType\r
+  );\r
+\r
+/**\r
+  Routine Process after the encode payload.\r
+\r
+  @param[in] SessionCommon  Pointer to ChildSa SessionCommon.\r
+  @param[in] PayloadBuf     Pointer to the payload.\r
+  @param[in] PayloadSize    Size of PayloadBuf in byte.\r
+  @param[in] PayloadType    Type of Payload.\r
+\r
+**/\r
+VOID\r
+Ikev2ChildSaAfterEncodePayload (\r
+  IN UINT8 *SessionCommon,\r
+  IN UINT8 *PayloadBuf,\r
+  IN UINTN PayloadSize,\r
+  IN UINT8 PayloadType\r
+  );\r
+\r
+/**\r
+  Generate Ikev2 SA payload according to SessionSaData\r
+\r
+  @param[in] SessionSaData   The data used in SA payload.\r
+  @param[in] NextPayload     The payload type presented in NextPayload field of \r
+                             SA Payload header.\r
+  @param[in] Type            The SA type. It MUST be neither (1) for IKE_SA or\r
+                             (2) for CHILD_SA or (3) for INFO.\r
+\r
+  @retval a Pointer to SA IKE payload.\r
+  \r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateSaPayload (\r
+  IN IKEV2_SA_DATA    *SessionSaData,\r
+  IN UINT8            NextPayload,\r
+  IN IKE_SESSION_TYPE Type\r
+  );\r
+\r
+/**\r
+  Generate a ID payload.\r
+\r
+  @param[in] CommonSession   Pointer to IKEV2_SESSION_COMMON related to ID payload.\r
+  @param[in] NextPayload     The payload type presented in the NextPayload field \r
+                             of ID Payload header.\r
+\r
+  @retval Pointer to ID IKE payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateIdPayload (\r
+  IN IKEV2_SESSION_COMMON *CommonSession,\r
+  IN UINT8                NextPayload\r
+  );\r
+\r
+/**\r
+  Generate a ID payload.\r
+\r
+  @param[in] CommonSession   Pointer to IKEV2_SESSION_COMMON related to ID payload.\r
+  @param[in] NextPayload     The payload type presented in the NextPayload field \r
+                             of ID Payload header.\r
+  @param[in] InCert          Pointer to the Certificate which distinguished name\r
+                             will be added into the Id payload.\r
+  @param[in] CertSize        Size of the Certificate.\r
+\r
+  @retval Pointer to ID IKE payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateCertIdPayload (\r
+  IN IKEV2_SESSION_COMMON *CommonSession,\r
+  IN UINT8                NextPayload, \r
+  IN UINT8                *InCert,\r
+  IN UINTN                CertSize\r
+  );\r
+\r
+/**\r
+  Generate a Nonce payload contenting the input parameter NonceBuf.\r
+\r
+  @param[in]  NonceBuf       The nonce buffer content the whole Nonce payload block \r
+                            except the payload header.\r
+  @param[in]  NonceSize      The buffer size of the NonceBuf\r
+  @param[in]  NextPayload   The payload type presented in the NextPayload field \r
+                            of Nonce Payload header.\r
+\r
+  @retval Pointer to Nonce IKE paload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateNoncePayload (\r
+  IN UINT8            *NonceBuf,\r
+  IN UINTN            NonceSize,\r
+  IN UINT8            NextPayload\r
+  );\r
+\r
+/**\r
+  Generate the Notify payload.\r
+\r
+  Since the structure of Notify payload which defined in RFC 4306 is simple, so\r
+  there is no internal data structure for Notify payload. This function generate \r
+  Notify payload defined in RFC 4306, but all the fields in this payload are still \r
+  in host order and need call Ikev2EncodePayload() to convert those fields from \r
+  the host order to network order beforing sending it.\r
+\r
+  @param[in]  ProtocolId        The protocol type ID. For IKE_SA it MUST be one (1).\r
+                                For IPsec SAs it MUST be neither (2) for AH or (3)\r
+                                for ESP.\r
+  @param[in]  NextPayload       The next paylaod type in NextPayload field of \r
+                                the Notify payload.\r
+  @param[in]  SpiSize           Size of the SPI in SPI size field of the Notify Payload.\r
+  @param[in]  MessageType       The message type in NotifyMessageType field of the \r
+                                Notify Payload.\r
+  @param[in]  SpiBuf            Pointer to buffer contains the SPI value.\r
+  @param[in]  NotifyData        Pointer to buffer contains the notification data.\r
+  @param[in]  NotifyDataSize    The size of NotifyData in bytes.\r
+  \r
+\r
+  @retval Pointer to IKE Notify Payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateNotifyPayload (\r
+  IN UINT8            ProtocolId,\r
+  IN UINT8            NextPayload,\r
+  IN UINT8            SpiSize,\r
+  IN UINT16           MessageType,\r
+  IN UINT8            *SpiBuf,\r
+  IN UINT8            *NotifyData,\r
+  IN UINTN            NotifyDataSize\r
+  );\r
+\r
+/**\r
+  Generate the Delete payload.\r
+\r
+  Since the structure of Delete payload which defined in RFC 4306 is simple, \r
+  there is no internal data structure for Delete payload. This function generate \r
+  Delete payload defined in RFC 4306, but all the fields in this payload are still \r
+  in host order and need call Ikev2EncodePayload() to convert those fields from \r
+  the host order to network order beforing sending it.\r
+\r
+  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used of Delete payload generation.\r
+  @param[in]  NextPayload       The next paylaod type in NextPayload field of \r
+                                the Delete payload.\r
+  @param[in]  SpiSize           Size of the SPI in SPI size field of the Delete Payload.\r
+  @param[in]  SpiNum            Number of SPI in NumofSPIs field of the Delete Payload.\r
+  @param[in]  SpiBuf            Pointer to buffer contains the SPI value.\r
+\r
+  @retval Pointer to IKE Delete Payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateDeletePayload (\r
+  IN IKEV2_SA_SESSION  *IkeSaSession,\r
+  IN UINT8             NextPayload,\r
+  IN UINT8             SpiSize,\r
+  IN UINT16            SpiNum,\r
+  IN UINT8             *SpiBuf  \r
+  );\r
+\r
+/**\r
+  Generate the Configuration payload.\r
+\r
+  This function generates a configuration payload defined in RFC 4306, but all the \r
+  fields in this payload are still in host order and need call Ikev2EncodePayload() \r
+  to convert those fields from the host order to network order beforing sending it.\r
+\r
+  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used for Delete payload\r
+                                generation.\r
+  @param[in]  NextPayload       The next paylaod type in NextPayload field of \r
+                                the Delete payload.\r
+  @param[in]  CfgType           The attribute type in the Configuration attribute.\r
+\r
+  @retval Pointer to IKE CP Payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateCpPayload (\r
+  IN IKEV2_SA_SESSION  *IkeSaSession,\r
+  IN UINT8             NextPayload,\r
+  IN UINT8             CfgType\r
+  );\r
+\r
+/**\r
+  Generate a Authentication Payload.\r
+\r
+  This function is used for both Authentication generation and verification. When the \r
+  IsVerify is TRUE, it create a Auth Data for verification. This function choose the \r
+  related IKE_SA_INIT Message for Auth data creation according to the IKE Session's type\r
+  and the value of IsVerify parameter.\r
+\r
+  @param[in]  IkeSaSession  Pointer to IKEV2_SA_SESSION related to.\r
+  @param[in]  IdPayload     Pointer to the ID payload to be used for Authentication \r
+                            payload generation.\r
+  @param[in]  NextPayload   The type filled into the Authentication Payload next \r
+                            payload field.\r
+  @param[in]  IsVerify      If it is TURE, the Authentication payload is used for\r
+                            verification.\r
+\r
+  @return pointer to IKE Authentication payload for pre-shard key method.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2PskGenerateAuthPayload (\r
+  IN IKEV2_SA_SESSION *IkeSaSession,\r
+  IN IKE_PAYLOAD      *IdPayload,\r
+  IN UINT8            NextPayload,\r
+  IN BOOLEAN          IsVerify\r
+  );\r
+\r
+/**\r
+  Generate a Authentication Payload for Certificate Auth method.  \r
+\r
+  This function has two functions. One is creating a local Authentication \r
+  Payload for sending and other is creating the remote Authentication data \r
+  for verification when the IsVerify is TURE.\r
+\r
+  @param[in]  IkeSaSession      Pointer to IKEV2_SA_SESSION related to.\r
+  @param[in]  IdPayload         Pointer to the ID payload to be used for Authentication \r
+                                payload generation.\r
+  @param[in]  NextPayload       The type filled into the Authentication Payload \r
+                                next payload field.\r
+  @param[in]  IsVerify          If it is TURE, the Authentication payload is used \r
+                                for verification.\r
+  @param[in]  UefiPrivateKey    Pointer to the UEFI private key. Ignore it when \r
+                                verify the authenticate payload.\r
+  @param[in]  UefiPrivateKeyLen The size of UefiPrivateKey in bytes. Ignore it \r
+                                when verify the authenticate payload.\r
+  @param[in]  UefiKeyPwd        Pointer to the password of UEFI private key. \r
+                                Ignore it when verify the authenticate payload.\r
+  @param[in]  UefiKeyPwdLen     The size of UefiKeyPwd in bytes.Ignore it when \r
+                                verify the authenticate payload.\r
+\r
+  @return pointer to IKE Authentication payload for certification method.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2CertGenerateAuthPayload (\r
+  IN IKEV2_SA_SESSION *IkeSaSession,\r
+  IN IKE_PAYLOAD      *IdPayload,\r
+  IN UINT8            NextPayload,\r
+  IN BOOLEAN          IsVerify,\r
+  IN UINT8            *UefiPrivateKey,\r
+  IN UINTN            UefiPrivateKeyLen,\r
+  IN UINT8            *UefiKeyPwd,\r
+  IN UINTN            UefiKeyPwdLen\r
+  );\r
+\r
+/**\r
+  Generate TS payload.\r
+\r
+  This function generates TSi or TSr payload according to type of next payload.\r
+  If the next payload is Responder TS, gereate TSi Payload. Otherwise, generate\r
+  TSr payload\r
+  \r
+  @param[in] ChildSa        Pointer to IKEV2_CHILD_SA_SESSION related to this TS payload.\r
+  @param[in] NextPayload    The payload type presented in the NextPayload field \r
+                            of ID Payload header.\r
+  @param[in] IsTunnel       It indicates that if the Ts Payload is after the CP payload.\r
+                            If yes, it means the Tsi and Tsr payload should be with\r
+                            Max port range and address range and protocol is marked\r
+                            as zero.\r
+\r
+  @retval Pointer to Ts IKE payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateTsPayload (\r
+  IN IKEV2_CHILD_SA_SESSION *ChildSa,\r
+  IN UINT8                  NextPayload,\r
+  IN BOOLEAN                IsTunnel\r
+  );\r
+\r
+/**\r
+  Parser the Notify Cookie payload.\r
+\r
+  This function parses the Notify Cookie payload.If the Notify ProtocolId is not\r
+  IPSEC_PROTO_ISAKMP or if the SpiSize is not zero or if the MessageType is not\r
+  the COOKIE, return EFI_INVALID_PARAMETER.\r
+\r
+  @param[in]      IkeNCookie    Pointer to the IKE_PAYLOAD which contians the \r
+                                Notify Cookie payload.\r
+                                the Notify payload.\r
+  @param[in, out] IkeSaSession  Pointer to the relevant IKE SA Session.\r
+\r
+  @retval EFI_SUCCESS           The Notify Cookie Payload is valid.\r
+  @retval EFI_INVALID_PARAMETER The Notify Cookie Payload is invalid.\r
+  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2ParserNotifyCookiePayload (\r
+  IN     IKE_PAYLOAD      *IkeNCookie,\r
+  IN OUT IKEV2_SA_SESSION *IkeSaSession\r
+  );\r
+\r
+/**\r
+  Generate the Certificate payload or Certificate Request Payload.\r
+\r
+  Since the Certificate Payload structure is same with Certificate Request Payload, \r
+  the only difference is that one contains the Certificate Data, other contains\r
+  the acceptable certificateion CA. This function generate Certificate payload \r
+  or Certificate Request Payload defined in RFC 4306, but all the fields \r
+  in the payload are still in host order and need call Ikev2EncodePayload() \r
+  to convert those fields from the host order to network order beforing sending it.\r
+\r
+  @param[in]  IkeSaSession      Pointer to IKE SA Session to be used of Delete payload \r
+                                generation.\r
+  @param[in]  NextPayload       The next paylaod type in NextPayload field of \r
+                                the Delete payload.\r
+  @param[in]  Certificate       Pointer of buffer contains the certification data.\r
+  @param[in]  CertificateLen    The length of Certificate in byte.\r
+  @param[in]  EncodeType        Specified the Certificate Encodeing which is defined\r
+                                in RFC 4306.\r
+  @param[in]  IsRequest         To indicate create Certificate Payload or Certificate\r
+                                Request Payload. If it is TURE, create Certificate\r
+                                Request Payload. Otherwise, create Certificate Payload.\r
+\r
+  @retval  a Pointer to IKE Payload whose payload buffer containing the Certificate\r
+           payload or Certificated Request payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateCertificatePayload (\r
+  IN IKEV2_SA_SESSION  *IkeSaSession,\r
+  IN UINT8             NextPayload,\r
+  IN UINT8             *Certificate,\r
+  IN UINTN             CertificateLen,\r
+  IN UINT8             EncodeType,\r
+  IN BOOLEAN           IsRequest\r
+  );\r
+  \r
+/**\r
+  General interface of payload encoding.\r
+\r
+  This function encode the internal data structure into payload which \r
+  is defined in RFC 4306. The IkePayload->PayloadBuf used to store both the input \r
+  payload and converted payload. Only the SA payload use the interal structure \r
+  to store the attribute. Other payload use structure which is same with the RFC \r
+  defined, for this kind payloads just do host order to network order change of \r
+  some fields.\r
+\r
+  @param[in]      SessionCommon       Pointer to IKE Session Common used to encode the payload.\r
+  @param[in, out] IkePayload          Pointer to IKE payload to be encode as input, and\r
+                                      store the encoded result as output.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Meet error when encode the SA payload.\r
+  @retval EFI_SUCCESS            Encode successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2EncodePayload (\r
+  IN     UINT8          *SessionCommon,\r
+  IN OUT IKE_PAYLOAD    *IkePayload\r
+  );\r
+\r
+/**\r
+  The general interface of decode Payload.\r
+\r
+  This function convert the received Payload into internal structure.\r
+\r
+  @param[in]      SessionCommon     Pointer to IKE Session Common to use for decoding.\r
+  @param[in, out] IkePayload        Pointer to IKE payload to be decode as input, and\r
+                                    store the decoded result as output. \r
+\r
+  @retval EFI_INVALID_PARAMETER  Meet error when decode the SA payload.\r
+  @retval EFI_SUCCESS            Decode successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2DecodePayload (\r
+  IN     UINT8       *SessionCommon,\r
+  IN OUT IKE_PAYLOAD *IkePayload\r
+  );\r
+\r
+/**\r
+  Decrypt IKE packet.\r
+\r
+  This function decrpt the Encrypted IKE packet and put the result into IkePacket->PayloadBuf.\r
+\r
+  @param[in]      SessionCommon       Pointer to IKEV2_SESSION_COMMON containing \r
+                                      some parameter used during decrypting.\r
+  @param[in, out] IkePacket           Point to IKE_PACKET to be decrypted as input, \r
+                                      and the decrypted reslult as output.\r
+  @param[in, out] IkeType             The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and\r
+                                      IKE_CHILD_TYPE are supportted.\r
+\r
+  @retval EFI_INVALID_PARAMETER      If the IKE packet length is zero or the \r
+                                     IKE packet length is not Algorithm Block Size\r
+                                     alignment.\r
+  @retval EFI_SUCCESS                Decrypt IKE packet successfully.\r
+  \r
+**/\r
+EFI_STATUS\r
+Ikev2DecryptPacket (\r
+  IN     IKEV2_SESSION_COMMON *SessionCommon,\r
+  IN OUT IKE_PACKET           *IkePacket,\r
+  IN OUT UINTN                IkeType\r
+  );\r
+\r
+/**\r
+  Encrypt IKE packet.\r
+\r
+  This function encrypt IKE packet before sending it. The Encrypted IKE packet\r
+  is put in to IKEV2 Encrypted Payload.\r
+  \r
+  @param[in]        SessionCommon     Pointer to IKEV2_SESSION_COMMON related to the IKE packet.\r
+  @param[in, out]   IkePacket         Pointer to IKE packet to be encrypted.\r
+\r
+  @retval      EFI_SUCCESS       Operation is successful.\r
+  @retval      Others            OPeration is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2EncryptPacket (\r
+  IN     IKEV2_SESSION_COMMON *SessionCommon,\r
+  IN OUT IKE_PACKET           *IkePacket\r
+  );\r
+\r
+/**\r
+  Encode the IKE packet.\r
+\r
+  This function put all Payloads into one payload then encrypt it if needed.\r
+\r
+  @param[in]      SessionCommon      Pointer to IKEV2_SESSION_COMMON containing \r
+                                     some parameter used during IKE packet encoding.\r
+  @param[in, out] IkePacket          Pointer to IKE_PACKET to be encoded as input, \r
+                                     and the encoded reslult as output.\r
+  @param[in]      IkeType            The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and\r
+                                     IKE_CHILD_TYPE are supportted.\r
+\r
+  @retval         EFI_SUCCESS        Encode IKE packet successfully.\r
+  @retval         Otherwise          Encode IKE packet failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2EncodePacket (\r
+  IN     IKEV2_SESSION_COMMON *SessionCommon,\r
+  IN OUT IKE_PACKET           *IkePacket,\r
+  IN     UINTN                IkeType\r
+  );\r
+\r
+/**\r
+  Decode the IKE packet.\r
+\r
+  This function first decrypts the IKE packet if needed , then separats the whole \r
+  IKE packet from the IkePacket->PayloadBuf into IkePacket payload list.\r
+  \r
+  @param[in]      SessionCommon          Pointer to IKEV1_SESSION_COMMON containing \r
+                                         some parameter used by IKE packet decoding.\r
+  @param[in, out] IkePacket              The IKE Packet to be decoded on input, and \r
+                                         the decoded result on return.\r
+  @param[in]      IkeType                The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and\r
+                                         IKE_CHILD_TYPE are supportted.\r
+\r
+  @retval         EFI_SUCCESS            The IKE packet is decoded successfull.\r
+  @retval         Otherwise              The IKE packet decoding is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2DecodePacket (\r
+  IN     IKEV2_SESSION_COMMON  *SessionCommon,\r
+  IN OUT IKE_PACKET            *IkePacket,\r
+  IN     UINTN                 IkeType\r
+  );\r
+\r
+/**\r
+  Save some useful payloads after accepting the Packet.\r
+\r
+  @param[in] SessionCommon   Pointer to IKEV2_SESSION_COMMON related to the operation.\r
+  @param[in] IkePacket       Pointer to received IkePacet.\r
+  @param[in] IkeType         The type used to indicate it is in IkeSa or ChildSa or Info\r
+                             exchange.\r
+\r
+**/\r
+VOID\r
+Ikev2OnPacketAccepted (\r
+  IN IKEV2_SESSION_COMMON *SessionCommon,\r
+  IN IKE_PACKET           *IkePacket,\r
+  IN UINT8                IkeType\r
+  );\r
+\r
+/**\r
+  Send out IKEV2 packet.\r
+\r
+  @param[in]  IkeUdpService     Pointer to IKE_UDP_SERVICE used to send the IKE packet.\r
+  @param[in]  SessionCommon     Pointer to IKEV1_SESSION_COMMON related to the IKE packet.\r
+  @param[in]  IkePacket         Pointer to IKE_PACKET to be sent out.\r
+  @param[in]  IkeType           The type of IKE to point what's kind of the IKE \r
+                                packet is to be sent out. IKE_SA_TYPE, IKE_INFO_TYPE \r
+                                and IKE_CHILD_TYPE are supportted.\r
+\r
+  @retval     EFI_SUCCESS       The operation complete successfully.\r
+  @retval     Otherwise         The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2SendIkePacket (\r
+  IN IKE_UDP_SERVICE    *IkeUdpService,\r
+  IN UINT8              *SessionCommon,\r
+  IN IKE_PACKET         *IkePacket,\r
+  IN UINTN              IkeType\r
+  );\r
+\r
+/**\r
+  Callback function for the IKE life time is over.\r
+\r
+  This function will mark the related IKE SA Session as deleting and trigger a \r
+  Information negotiation.\r
+\r
+  @param[in]    Event     The time out event.\r
+  @param[in]    Context   Pointer to data passed by caller.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+Ikev2LifetimeNotify (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  );\r
+\r
+/**\r
+  This function will be called if the TimeOut Event is signaled.\r
+\r
+  @param[in]  Event      The signaled Event.\r
+  @param[in]  Context    The data passed by caller.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ikev2ResendNotify (\r
+  IN EFI_EVENT                 Event,\r
+  IN VOID                      *Context\r
+  );\r
+\r
+/**\r
+  Generate a Key Exchange payload according to the DH group type and save the \r
+  public Key into IkeSaSession IkeKey field.\r
+\r
+  @param[in, out] IkeSaSession    Pointer of the IKE_SA_SESSION.\r
+  @param[in]      NextPayload     The payload type presented in the NextPayload field of Key \r
+                                  Exchange Payload header.\r
+\r
+  @retval Pointer to Key IKE payload.\r
+\r
+**/\r
+IKE_PAYLOAD *\r
+Ikev2GenerateKePayload (\r
+  IN OUT IKEV2_SA_SESSION *IkeSaSession, \r
+  IN     UINT8            NextPayload      \r
+  );\r
+\r
+/**\r
+  Check if the SPD is related to the input Child SA Session.\r
+\r
+  This function is the subfunction of Ikev1AssociateSpdEntry(). It is the call\r
+  back function of IpSecVisitConfigData(). \r
+  \r
+\r
+  @param[in]  Type               Type of the input Config Selector.\r
+  @param[in]  Selector           Pointer to the Configure Selector to be checked. \r
+  @param[in]  Data               Pointer to the Configure Selector's Data passed \r
+                                 from the caller.\r
+  @param[in]  SelectorSize       The buffer size of Selector.\r
+  @param[in]  DataSize           The buffer size of the Data.\r
+  @param[in]  Context            The data passed from the caller. It is a Child\r
+                                 SA Session in this context.\r
+\r
+  @retval EFI_SUCCESS        The SPD Selector is not related to the Child SA Session. \r
+  @retval EFI_ABORTED        The SPD Selector is related to the Child SA session and \r
+                             set the ChildSaSession->Spd to point to this SPD Selector.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2MatchSpdEntry (\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 VOID                           *Context\r
+  );\r
+\r
+/**\r
+  Check if the Algorithm ID is supported.\r
+\r
+  @param[in]  AlgorithmId The specified Algorithm ID.\r
+  @param[in]  Type        The type used to indicate the Algorithm is for Encrypt or\r
+                          Authentication.\r
+\r
+  @retval     TRUE        If the Algorithm ID is supported.\r
+  @retval     FALSE       If the Algorithm ID is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+Ikev2IsSupportAlg (\r
+  IN UINT16 AlgorithmId,\r
+  IN UINT8  Type\r
+  );\r
+\r
+/**\r
+  Generate a ChildSa Session and insert it into related IkeSaSession.\r
+\r
+  @param[in]  IkeSaSession    Pointer to related IKEV2_SA_SESSION.\r
+  @param[in]  UdpService      Pointer to related IKE_UDP_SERVICE.\r
+\r
+  @return pointer of IKEV2_CHILD_SA_SESSION.\r
+\r
+**/\r
+IKEV2_CHILD_SA_SESSION *\r
+Ikev2ChildSaSessionCreate (\r
+  IN IKEV2_SA_SESSION   *IkeSaSession,\r
+  IN IKE_UDP_SERVICE     *UdpService\r
+  ) ;\r
+\r
+/**\r
+  Parse the received Initial Exchange Packet.\r
+  \r
+  This function parse the SA Payload and Key Payload to find out the cryptographic \r
+  suite for the further IKE negotiation and fill it into the IKE SA Session's \r
+  CommonSession->SaParams.\r
+\r
+  @param[in, out]  IkeSaSession  Pointer to related IKEV2_SA_SESSION.\r
+  @param[in]       SaPayload     The received packet.\r
+  @param[in]       Type          The received packet IKE header flag. \r
+\r
+  @retval          TRUE          If the SA proposal in Packet is acceptable.\r
+  @retval          FALSE         If the SA proposal in Packet is not acceptable.\r
+\r
+**/\r
+BOOLEAN\r
+Ikev2SaParseSaPayload (\r
+  IN OUT IKEV2_SA_SESSION *IkeSaSession,\r
+  IN     IKE_PAYLOAD      *SaPayload,\r
+  IN     UINT8            Type\r
+  );\r
+\r
+/**\r
+  Parse the received Authentication Exchange Packet.\r
+  \r
+  This function parse the SA Payload and Key Payload to find out the cryptographic\r
+  suite for the ESP and fill it into the Child SA Session's CommonSession->SaParams.\r
+  \r
+  @param[in, out]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION related to \r
+                                   this Authentication Exchange.\r
+  @param[in]       SaPayload       The received packet.\r
+  @param[in]       Type            The IKE header's flag of received packet . \r
+  \r
+  @retval          TRUE            If the SA proposal in Packet is acceptable.\r
+  @retval          FALSE           If the SA proposal in Packet is not acceptable.\r
+\r
+**/\r
+BOOLEAN\r
+Ikev2ChildSaParseSaPayload (\r
+  IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession,\r
+  IN     IKE_PAYLOAD            *SaPayload,\r
+  IN     UINT8                  Type\r
+  );\r
+\r
+/**\r
+  Generate Key buffer from fragments.\r
+\r
+  If the digest length of specified HashAlgId is larger than or equal with the \r
+  required output key length, derive the key directly. Otherwise, Key Material \r
+  needs to be PRF-based concatenation according to 2.13 of RFC 4306: \r
+  prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01),\r
+  T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04)\r
+  then derive the key from this key material.\r
+  \r
+  @param[in]       HashAlgId        The Hash Algorithm ID used to generate key.\r
+  @param[in]       HashKey          Pointer to a key buffer which contains hash key.\r
+  @param[in]       HashKeyLength    The length of HashKey in bytes.\r
+  @param[in, out]  OutputKey        Pointer to buffer which is used to receive the \r
+                                    output key.\r
+  @param[in]       OutputKeyLength  The length of OutPutKey buffer.\r
+  @param[in]       Fragments        Pointer to the data to be used to generate key.\r
+  @param[in]       NumFragments     The numbers of the Fragement.\r
+\r
+  @retval EFI_SUCCESS            The operation complete successfully.\r
+  @retval EFI_INVALID_PARAMETER  If NumFragments is zero.\r
+  @retval EFI_OUT_OF_RESOURCES   If the required resource can't be allocated.\r
+  @retval Others                 The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+Ikev2SaGenerateKey (\r
+  IN     UINT8                 HashAlgId,\r
+  IN     UINT8                 *HashKey,\r
+  IN     UINTN                 HashKeyLength,\r
+  IN OUT UINT8                 *OutputKey,\r
+  IN     UINTN                 OutputKeyLength,\r
+  IN     PRF_DATA_FRAGMENT    *Fragments,\r
+  IN     UINTN                 NumFragments\r
+  );\r
+\r
+/**\r
+  Copy ChildSaSession->Spd->Selector to ChildSaSession->SpdSelector.\r
+\r
+  ChildSaSession->SpdSelector stores the real Spdselector for its SA. Sometime,\r
+  the SpdSelector in ChildSaSession is more accurated or the scope is smaller \r
+  than the one in ChildSaSession->Spd, especially for the tunnel mode.\r
+    \r
+  @param[in, out]  ChildSaSession  Pointer to IKEV2_CHILD_SA_SESSION related to.\r
+  \r
+**/\r
+VOID\r
+Ikev2ChildSaSessionSpdSelectorCreate (\r
+  IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession\r
+  );\r
+\r
+extern IKE_ALG_GUID_INFO mIPsecEncrAlgInfo[];\r
+#endif\r
+\r
index 0b52a49ae589721f5e4c2a770699d789e61ea858..87f85e7ca675d8b9ec33b8f0f48b853e8ef701a9 100644 (file)
@@ -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
@@ -97,7 +97,7 @@ EFI_IPSEC_CONFIG_PROTOCOL mIpSecConfigInstance = {
   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
+  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
@@ -121,7 +121,7 @@ IpSecConfigRestore (
 \r
   @retval  TRUE    The specified AddressInfo is in the AddressInfoList.\r
   @retval  FALSE   The specified AddressInfo is not in the AddressInfoList.\r
-\r
+  \r
 **/\r
 BOOLEAN\r
 IsInAddressInfoList(\r
@@ -130,27 +130,42 @@ 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
           &AddressInfoList[Index].Address,\r
           sizeof (EFI_IP_ADDRESS)\r
-          ) == 0 &&\r
+          ) == 0 && \r
           AddressInfo->PrefixLength == AddressInfoList[Index].PrefixLength\r
-          ) {\r
+          ) { \r
        return TRUE;\r
      }\r
   }\r
   return FALSE;\r
 }\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
+  NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the \r
   Local Addresses and remote Addresses.\r
 \r
   @param[in]   Selector1           Pointer of first SPD Selector.\r
@@ -158,7 +173,7 @@ IsInAddressInfoList(
 \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
 **/\r
 BOOLEAN\r
 CompareSpdSelector (\r
@@ -178,7 +193,7 @@ CompareSpdSelector (
   //\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
+  // two Spdselectors. Since the SPD supports two directions, it needs to \r
   // compare two directions.\r
   //\r
   if ((SpdSel1->LocalAddressCount != SpdSel2->LocalAddressCount &&\r
@@ -194,10 +209,10 @@ CompareSpdSelector (
     IsMatch = FALSE;\r
     return IsMatch;\r
   }\r
-\r
+  \r
   //\r
   // Compare the all LocalAddress fields in the two Spdselectors.\r
-  // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare\r
+  // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare \r
   // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return\r
   // TRUE.\r
   //\r
@@ -248,14 +263,14 @@ CompareSpdSelector (
     }\r
   }\r
   //\r
-  // Finish the one direction compare. If it is matched, return; otherwise,\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
+  // 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
@@ -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 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 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->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
@@ -317,7 +469,7 @@ CompareSpdSelector (
 \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
 **/\r
 BOOLEAN\r
 CompareSaId (\r
@@ -348,7 +500,7 @@ CompareSaId (
 \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
 **/\r
 BOOLEAN\r
 ComparePadId (\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
-\r
-  DestAddr  = &Selector->SaId.DestAddress;\r
+  BOOLEAN                   IsZero;\r
+  EFI_IPSEC_CONFIG_SELECTOR ZeroSelector;\r
+  \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
@@ -486,14 +636,14 @@ IsZeroPadId (
 \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
+  @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_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
@@ -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
@@ -552,13 +702,13 @@ DuplicateSpdSelector (
 \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
+  @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_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
@@ -594,9 +744,9 @@ DuplicateSaId (
 \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
+  @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
@@ -632,11 +782,11 @@ DuplicatePadId (
 }\r
 \r
 /**\r
-  Fix the value of some members of SPD Selector.\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 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
@@ -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
@@ -667,11 +817,11 @@ FixSpdEntry (
 }\r
 \r
 /**\r
-  Fix the value of some members of SA ID.\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 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
@@ -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
@@ -708,10 +858,10 @@ FixSadEntry (
 }\r
 \r
 /**\r
-  Fix the value of some members of PAD ID.\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
+  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
@@ -740,7 +890,7 @@ FixPadEntry (
 }\r
 \r
 /**\r
-  Recover the value of some members of SPD Selector.\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
@@ -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
@@ -768,11 +918,11 @@ UnfixSpdEntry (
       UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data);\r
     }\r
   }\r
-\r
+  \r
 }\r
 \r
 /**\r
-  Recover the value of some members of SA ID.\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
@@ -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
@@ -811,7 +961,7 @@ UnfixSadEntry (
 }\r
 \r
 /**\r
-  Recover the value of some members of PAD ID.\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
@@ -843,30 +993,30 @@ UnfixPadEntry (
 /**\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
+  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
+  @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
+  @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
+  @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
+                                   - 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
+                                   - 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
+                                   - 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
+                                   - 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
@@ -887,8 +1037,8 @@ 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
   IPSEC_SPD_ENTRY         *SpdEntry;\r
   IPSEC_SAD_ENTRY         *SadEntry;\r
   UINTN                   SpdEntrySize;\r
@@ -926,13 +1076,13 @@ 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
     SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
 \r
-    if (SpdSel == NULL ||\r
+    if (SpdSel == NULL || \r
         CompareSpdSelector ((EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel)\r
         ) {\r
       //\r
@@ -942,21 +1092,26 @@ 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
+      \r
+      //\r
+      // TODO: Deleted the related SAs.\r
+      //\r
       NET_LIST_FOR_EACH (Entry2, SpdSas) {\r
         SadEntry                  = IPSEC_SAD_ENTRY_FROM_SPD (Entry2);\r
         SadEntry->Data->SpdEntry  = NULL;\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
@@ -993,7 +1148,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
@@ -1017,7 +1172,7 @@ SetSpdEntry (
 \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 +1184,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
@@ -1046,11 +1201,16 @@ SetSpdEntry (
             )) {\r
         InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);\r
         SadEntry->Data->SpdEntry = SpdEntry;\r
+        DuplicateSpdSelector (\r
+          (EFI_IPSEC_CONFIG_SELECTOR *)SadEntry->Data->SpdSelector,\r
+          (EFI_IPSEC_CONFIG_SELECTOR *)SpdEntry->Selector,\r
+          NULL\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
@@ -1060,17 +1220,17 @@ SetSpdEntry (
 /**\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
+  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
+  @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
+  @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
+  @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
@@ -1092,13 +1252,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
+  \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,13 +1268,13 @@ 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
     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);\r
 \r
-    if (SaId == NULL ||\r
+    if (SaId == NULL || \r
         CompareSaId (\r
           (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,\r
           (EFI_IPSEC_CONFIG_SELECTOR *) SaId\r
@@ -1125,7 +1285,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 +1296,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 +1323,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
+  \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 + (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector);\r
+  }\r
   SadEntry      = AllocateZeroPool (SadEntrySize);\r
 \r
   if (SadEntry == NULL) {\r
@@ -1180,7 +1343,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
@@ -1219,7 +1382,7 @@ SetSadEntry (
 \r
     if (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {\r
       SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (\r
-                                                               ((UINT8 *) (SadEntry->Data + 1) +\r
+                                                               ((UINT8 *) (SadEntry->Data + 1) + \r
                                                                  SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength),\r
                                                                  sizeof (UINTN)\r
                                                                  );\r
@@ -1238,28 +1401,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
+                                                                (UINTN)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
@@ -1269,17 +1456,17 @@ SetSadEntry (
 /**\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
+  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
+  @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
+  @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
+  @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
@@ -1303,7 +1490,7 @@ SetPadEntry (
   EFI_IPSEC_PAD_ID    *InsertBefore;\r
   LIST_ENTRY          *EntryInsertBefore;\r
   UINTN               PadEntrySize;\r
-\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
@@ -1321,7 +1508,7 @@ SetPadEntry (
 \r
     PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);\r
 \r
-    if (PadId == NULL ||\r
+    if (PadId == NULL || \r
         ComparePadId ((EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) PadId)\r
         ) {\r
       //\r
@@ -1421,16 +1608,16 @@ SetPadEntry (
 }\r
 \r
 /**\r
-  This function lookup the data entry from IPsec SPD. Return the configuration\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
+  @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
+  @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
@@ -1462,7 +1649,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 +1669,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,7 +1683,7 @@ 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
@@ -1522,16 +1709,16 @@ GetSpdEntry (
 }\r
 \r
 /**\r
-  This function lookup the data entry from IPsec SAD. Return the configuration\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
+  @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
+  @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
@@ -1549,32 +1736,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
+      // |SpdSelector (Optional)     \r
+      // \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 +1770,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
+      \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 +1847,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
+       \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
@@ -1692,16 +1893,16 @@ GetSadEntry (
 }\r
 \r
 /**\r
-  This function lookup the data entry from IPsec PAD. Return the configuration\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
+  @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
+  @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
@@ -1864,7 +2065,7 @@ IpSecGetSizeOfEfiSpdData (
 \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
+  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
@@ -1900,25 +2101,25 @@ IpSecGetSizeOfSpdData (
   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
+  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
+  \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
+  @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
+  @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
+        \r
   @retval  EFI_ABORTED           If the Variable size which contained in the variable\r
-                                 structure doesn't match the variable size obtained\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
+                                 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
@@ -1951,7 +2152,7 @@ IpSecGetVariable (
   VariableNameISize   = (VariableNameLength + 5) * sizeof (CHAR16);\r
   VariableNameI       = AllocateZeroPool (VariableNameISize);\r
   ASSERT (VariableNameI != NULL);\r
-\r
+  \r
   //\r
   // Construct the varible name of ipsecconfig meta data.\r
   //\r
@@ -2084,14 +2285,14 @@ ON_EXIT:
   @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
+  @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
+  @retval  others           Storing the variables failed.      \r
 \r
 **/\r
 EFI_STATUS\r
@@ -2121,7 +2322,7 @@ IpSecSetVariable (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-\r
+  \r
   //\r
   // "VariableName + Info/0001/0002/... + NULL"\r
   //\r
@@ -2138,7 +2339,7 @@ IpSecSetVariable (
   //\r
   UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%s", VariableName, L"Info");\r
   MaximumVariableSize -= VariableNameSize;\r
-\r
+  \r
   IpSecVariableInfo.VariableCount       = (UINT32) ((DataSize + (UINTN) MaximumVariableSize - 1) / (UINTN) MaximumVariableSize);\r
   IpSecVariableInfo.VariableSize        = (UINT32) DataSize;\r
   IpSecVariableInfo.SingleVariableSize  = (UINT32) MaximumVariableSize;\r
@@ -2163,7 +2364,7 @@ IpSecSetVariable (
     // 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
+    // \r
     UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%04d", VariableName, VariableIndex + 1);\r
     Status = gRT->SetVariable (\r
                     VariableNameI,\r
@@ -2190,20 +2391,20 @@ ON_EXIT:
 }\r
 \r
 /**\r
-  Return the configuration value for the EFI IPsec driver.\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
+  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
+  @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
+  @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
@@ -2243,26 +2444,26 @@ EfiIpSecConfigGetData (
 \r
 /**\r
   Set the security association, security policy and peer authorization configuration\r
-  information for the EFI IPsec driver.\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
+  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
+  @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
+  @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
\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
@@ -2289,7 +2490,7 @@ EfiIpSecConfigSetData (
   if (DataType >= IPsecConfigDataTypeMaximum) {\r
     return EFI_UNSUPPORTED;\r
   }\r
-\r
+  \r
   Status = mSetPolicyEntry[DataType](Selector, Data, InsertBefore);\r
 \r
   if (!EFI_ERROR (Status) && !mSetBySelf) {\r
@@ -2303,30 +2504,30 @@ EfiIpSecConfigSetData (
 }\r
 \r
 /**\r
-  Enumerates the current selector for IPsec configuration data entry.\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
+  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
\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
+  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
+  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
+  @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
+                                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
@@ -2335,7 +2536,7 @@ EfiIpSecConfigSetData (
   @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
+                                has been updated with the size needed to complete the search \r
                                 request.\r
 \r
 **/\r
@@ -2384,14 +2585,14 @@ EfiIpSecConfigGetNextSelector (
 \r
 /**\r
   Register an event that is to be signaled whenever a configuration process on the\r
-  specified IPsec configuration information is done.\r
+  specified IPsec configuration information is done. \r
 \r
   The register function is not surpport now and always returns EFI_UNSUPPORTED.\r
-\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
\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
@@ -2412,16 +2613,16 @@ EfiIpSecConfigRegisterNotify (
 \r
 /**\r
   Remove the specified event that was previously registered on the specified IPsec\r
-  configuration data.\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
\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
+  @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
@@ -2443,10 +2644,10 @@ EfiIpSecConfigUnregisterNotify (
   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
+  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
+  \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
@@ -2474,12 +2675,12 @@ IpSecCopyPolicyEntry (
   IPSEC_VAR_ITEM_HEADER DataHeader;\r
   UINTN                 EntrySize;\r
   UINT8                 *TempPoint;\r
-\r
+  \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
@@ -2490,7 +2691,7 @@ IpSecCopyPolicyEntry (
   EntrySize  = ALIGN_VARIABLE (EntrySize + SelectorSize);\r
   EntrySize  = ALIGN_VARIABLE (EntrySize + sizeof (SelectorHeader));\r
   EntrySize  = ALIGN_VARIABLE (EntrySize + DataSize);\r
-\r
+  \r
   //EntrySize = SelectorSize + DataSize + 2 * sizeof (SelectorHeader);\r
   if (Buffer->Capacity - Buffer->Size < EntrySize) {\r
     //\r
@@ -2498,7 +2699,7 @@ IpSecCopyPolicyEntry (
     //\r
     Buffer->Capacity += EntrySize;\r
     TempPoint         = AllocatePool (Buffer->Capacity);\r
-\r
+    \r
     if (Buffer->Ptr == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
@@ -2507,8 +2708,8 @@ IpSecCopyPolicyEntry (
     //\r
     CopyMem (TempPoint, Buffer->Ptr, Buffer->Size);\r
     FreePool (Buffer->Ptr);\r
-\r
-    Buffer->Ptr       =  TempPoint;\r
+    \r
+    Buffer->Ptr       =  TempPoint;    \r
   }\r
 \r
   mFixPolicyEntry[Type](Selector, Data);\r
@@ -2525,7 +2726,7 @@ IpSecCopyPolicyEntry (
     sizeof (SelectorHeader)\r
     );\r
   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + sizeof (SelectorHeader));\r
-\r
+  \r
   //\r
   // Copy the selector into buffer.\r
   //\r
@@ -2557,7 +2758,7 @@ IpSecCopyPolicyEntry (
     DataSize\r
     );\r
   Buffer->Size  = ALIGN_VARIABLE (Buffer->Size + DataSize);\r
-\r
+  \r
   mUnfixPolicyEntry[Type](Selector, Data);\r
 \r
   return EFI_SUCCESS;\r
@@ -2768,7 +2969,7 @@ IpSecConfigSave (
   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
+  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
@@ -2846,10 +3047,10 @@ IpSecConfigRestore (
       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
+      \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
+                                              (UINT8 *) Selector + Header->Size, \r
                                               sizeof (UINTN)\r
                                               );\r
       ASSERT (Header->Type == Type);\r
index 54d43bd01cf361e889d7164555590c4e4083d340..036cd8d4e078917b13156ba2e9c3bfc8c0efa566 100644 (file)
@@ -342,21 +342,22 @@ IpSecDuplicateProcessPolicy (
   );\r
 \r
 /**\r
-  Compare two SPD Selectors.\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
+  NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the \r
   Local Addresses and remote Addresses.\r
 \r
-  @param[in]   Selector1           Pointer of the first SPD Selector.\r
-  @param[in]   Selector2           Pointer of the second SPD Selector.\r
-\r
-  @retval  TRUE    This two Selector have the same value in above fields.\r
-  @retval  FALSE   Not all of the above fields have the same value in these two Selectors.\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
-CompareSpdSelector (\r
+IsSubSpdSelector (\r
   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector1,\r
   IN EFI_IPSEC_CONFIG_SELECTOR        *Selector2\r
   );\r
@@ -537,7 +538,7 @@ 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
@@ -588,7 +589,7 @@ 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
@@ -949,4 +950,6 @@ EfiIpSecConfigUnregisterNotify (
   IN EFI_EVENT                        Event\r
   );\r
 \r
+extern LIST_ENTRY   mConfigData[IPsecConfigDataTypeMaximum];\r
+\r
 #endif\r
index 93b69a6682c753ca8950182d6418ae802553f1fb..027e078e7a8ca959f17f7ddb30cf2126494ae36c 100644 (file)
@@ -1,5 +1,5 @@
 /** @file\r
-  Common operation for Security.\r
+  Common interfaces to call Security library.\r
 \r
   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
 \r
 \r
 #include "IpSecCryptIo.h"\r
 //\r
-// Alogrithm's informations for the Encrypt/Decrpt Alogrithm.\r
+// The informations for the supported Encrypt/Decrpt Alogrithm.\r
 //\r
-ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {\r
+GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {\r
   {IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},\r
-  {(UINT8)-1,           0, 0, 0, NULL, NULL, NULL, NULL}\r
+  {IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL},  \r
+  {IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt},\r
+  {IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt}\r
 };\r
+\r
+//\r
+// The informations for the supported Authentication algorithm\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {\r
+  {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r
+  {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r
+  {IKE_AALG_SHA1HMAC, 20, 12, 64, HmacSha1GetContextSize, HmacSha1Init, HmacSha1Update, HmacSha1Final}\r
+};\r
+\r
 //\r
-// Alogrithm's informations for the Authentication algorithm\r
+// The information for the supported Hash aglorithm\r
 //\r
-AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {\r
+GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = {\r
   {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},\r
   {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},\r
-  {(UINT8)-1,           0, 0, 0, NULL, NULL, NULL, NULL}\r
+  {IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final}\r
 };\r
 \r
+BOOLEAN  mInitialRandomSeed = FALSE;\r
 \r
 /**\r
-  Get the block size of encrypt alogrithm. The block size is based on the algorithm used.\r
+  Get the block size of specified encryption alogrithm.\r
 \r
-  @param[in]  AlgorithmId          The encrypt algorithm ID.\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
 \r
   @return The value of block size.\r
 \r
@@ -48,9 +61,6 @@ IpSecGetEncryptBlockSize (
 \r
   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
-      //\r
-      // The BlockSize is same with IvSize.\r
-      //\r
       return mIpsecEncryptAlgorithmList[Index].BlockSize;\r
     }\r
   }\r
@@ -59,9 +69,33 @@ IpSecGetEncryptBlockSize (
 }\r
 \r
 /**\r
-  Get the IV size of encrypt alogrithm. The IV size is based on the algorithm used.\r
+  Get the key length of the specified encryption alogrithm.\r
+\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
+\r
+  @return The value of key length.\r
+\r
+**/\r
+UINTN\r
+IpSecGetEncryptKeyLength (\r
+  IN UINT8   AlgorithmId\r
+  )\r
+{\r
+  UINT8 Index;\r
+\r
+  for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
+    if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
+      return mIpsecEncryptAlgorithmList[Index].KeyLength;\r
+    }\r
+  }\r
+\r
+  return (UINTN) -1;\r
+}\r
+\r
+/**\r
+  Get the IV size of the specified encryption alogrithm.\r
 \r
-  @param[in]  AlgorithmId          The encrypt algorithm ID.\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
 \r
   @return The value of IV size.\r
 \r
@@ -75,9 +109,6 @@ IpSecGetEncryptIvLength (
 \r
   for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
     if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
-      //\r
-      // The BlockSize is same with IvSize.\r
-      //\r
       return mIpsecEncryptAlgorithmList[Index].IvLength;\r
     }\r
   }\r
@@ -86,24 +117,53 @@ IpSecGetEncryptIvLength (
 }\r
 \r
 /**\r
-  Get the ICV size of Authenticaion alogrithm. The ICV size is based on the algorithm used.\r
+  Get the HMAC digest length by the specified Algorithm ID.\r
+\r
+  @param[in]  AlgorithmId  The specified Alogrithm ID.\r
+\r
+  @return The digest length of the specified Authentication Algorithm ID.\r
+\r
+**/\r
+UINTN\r
+IpSecGetHmacDigestLength (\r
+  IN UINT8  AlgorithmId\r
+  )\r
+{\r
+  UINT8 Index;\r
+\r
+  for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
+    if (mIpsecAuthAlgorithmList[Index].AlgorithmId == AlgorithmId) {\r
+      //\r
+      // Return the Digest Length of the Algorithm.\r
+      //\r
+      return mIpsecAuthAlgorithmList[Index].DigestLength;\r
+    }\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+  Get the ICV size of the specified Authenticaion alogrithm.\r
 \r
-  @param[in]  AuthAlgorithmId          The Authentication algorithm ID.\r
+  @param[in]  AlgorithmId          The Authentication algorithm ID.\r
 \r
   @return The value of ICV size.\r
 \r
 **/\r
 UINTN\r
 IpSecGetIcvLength (\r
-  IN UINT8  AuthAlgorithmId\r
+  IN UINT8  AlgorithmId\r
   )\r
 {\r
   UINT8 Index;\r
+\r
   for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
-    if (AuthAlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
+    if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
       return mIpsecAuthAlgorithmList[Index].IcvLength;\r
     }\r
   }\r
+\r
   return (UINTN) -1;\r
 }\r
 \r
@@ -112,7 +172,7 @@ IpSecGetIcvLength (
   IV and return EFI_SUCCESS.\r
 \r
   @param[in]  IvBuffer  The pointer of the IV buffer.\r
-  @param[in]  IvSize    The IV size.\r
+  @param[in]  IvSize    The IV size in bytes.\r
 \r
   @retval     EFI_SUCCESS  Create a random data for IV.\r
 \r
@@ -124,10 +184,833 @@ IpSecGenerateIv (
   )\r
 {\r
   if (IvSize != 0) {\r
+    return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get index of the specified encryption alogrithm from the mIpsecEncryptAlgorithemList.\r
+\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
+\r
+  @return the index.\r
+  \r
+**/\r
+UINTN\r
+IpSecGetIndexFromEncList (\r
+  IN UINT8   AlgorithmId\r
+  )\r
+{\r
+  UINT8 Index;\r
+  \r
+  for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {\r
+    if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {\r
+      return Index;\r
+    }\r
+  }\r
+  \r
+  return (UINTN) -1;\r
+}\r
+\r
+/**\r
+  Get index of the specified encryption alogrithm from the mIpsecAuthAlgorithemList.\r
+\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
+\r
+  @return the index.\r
+  \r
+**/\r
+UINTN\r
+IpSecGetIndexFromAuthList (\r
+  IN UINT8   AlgorithmId\r
+  )\r
+{\r
+  UINT8 Index;\r
+  \r
+  for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {\r
+    if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {\r
+      //\r
+      // The BlockSize is same with IvSize.\r
+      //\r
+      return Index;\r
+    }\r
+  }\r
+  \r
+  return (UINTN) -1;\r
+}\r
+\r
+/**\r
+  Encrypt the buffer.\r
+\r
+  This function calls relevant encryption interface from CryptoLib according to\r
+  the input alogrithm ID. The InData should be multiple of block size. This function\r
+  doesn't perform the padding. If it has the Ivec data, the length of it should be\r
+  same with the block size. The block size is different from the different algorithm.\r
+\r
+  @param[in]       AlgorithmId    The Alogrithem identification defined in RFC.\r
+  @param[in]       Key            Pointer to the buffer containing encrypting key.\r
+  @param[in}       KeyBits        The length of the key in bits.\r
+  @param[in]       Ivec           Point to the buffer containning the Initializeion\r
+                                  Vector (IV) data.\r
+  @param[in]       InData         Point to the buffer containing the data to be\r
+                                  encrypted.\r
+  @param[in]       InDataLength   The length of InData in Bytes.\r
+  @param[out]      OutData        Point to the buffer that receives the encryption\r
+                                  output.\r
+\r
+  @retval EFI_UNSUPPORTED       The input Algorithm is not supported.\r
+  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoEncrypt (\r
+  IN CONST UINT8      AlgorithmId,\r
+  IN CONST UINT8      *Key,\r
+  IN CONST UINTN      KeyBits,\r
+  IN CONST UINT8      *Ivec, OPTIONAL\r
+  IN       UINT8      *InData,\r
+  IN       UINTN      InDataLength,\r
+     OUT   UINT8      *OutData\r
+  )\r
+{  \r
+  UINTN         Index;\r
+  UINTN         ContextSize;\r
+  UINT8         *Context;\r
+  EFI_STATUS    Status;\r
+  \r
+  Status = EFI_UNSUPPORTED;\r
+  \r
+  switch (AlgorithmId) {\r
+\r
+  case IKE_EALG_NULL:\r
+  case IKE_EALG_NONE:\r
+    CopyMem (OutData, InData, InDataLength);\r
+    return EFI_SUCCESS;\r
+\r
+  case IKE_EALG_3DESCBC:\r
+  case IKE_EALG_AESCBC:\r
+    Index = IpSecGetIndexFromEncList (AlgorithmId);\r
+    if (Index == -1) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Get Context Size\r
+    //\r
+    ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize ();\r
+    Context     = AllocateZeroPool (ContextSize);\r
+\r
+    if (Context == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
     //\r
-    //TODO: return CryptGenerateRandom (IvBuffer, IvSize);\r
+    // Initiate Context\r
     //\r
+    if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {\r
+      if (mIpsecEncryptAlgorithmList[Index].CipherEncrypt (Context, InData, InDataLength, Ivec, OutData)) {\r
+        Status = EFI_SUCCESS;\r
+      }\r
+    }\r
+    break;\r
+\r
+  default:\r
+    return Status;\r
+\r
+  }\r
+\r
+  if (Context != NULL) {\r
+    FreePool (Context);\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Decrypts the buffer.\r
+\r
+  This function calls relevant Decryption interface from CryptoLib according to\r
+  the input alogrithm ID. The InData should be multiple of block size. This function\r
+  doesn't perform the padding. If it has the Ivec data, the length of it should be\r
+  same with the block size. The block size is different from the different algorithm.\r
+\r
+  @param[in]       AlgorithmId    The Alogrithem identification defined in RFC.\r
+  @param[in]       Key            Pointer to the buffer containing encrypting key.\r
+  @param[in}       KeyBits        The length of the key in bits.\r
+  @param[in]       Ivec           Point to the buffer containning the Initializeion\r
+                                  Vector (IV) data.\r
+  @param[in]       InData         Point to the buffer containing the data to be\r
+                                  Decrypted.\r
+  @param[in]       InDataLength   The length of InData in Bytes.\r
+  @param[out]      OutData        Pointer to the buffer that receives the decryption\r
+                                  output.\r
+\r
+  @retval EFI_UNSUPPORTED       The input Algorithm is not supported.\r
+  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDecrypt (\r
+  IN CONST UINT8      AlgorithmId,\r
+  IN CONST UINT8      *Key,\r
+  IN CONST UINTN      KeyBits,\r
+  IN CONST UINT8      *Ivec, OPTIONAL\r
+  IN       UINT8      *InData,\r
+  IN       UINTN      InDataLength,\r
+     OUT   UINT8      *OutData\r
+  )\r
+{  \r
+  UINTN         Index;\r
+  UINTN         ContextSize;\r
+  UINT8         *Context;\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_UNSUPPORTED;\r
+\r
+  switch (AlgorithmId) {\r
+\r
+  case IKE_EALG_NULL:\r
+  case IKE_EALG_NONE:\r
+    CopyMem (OutData, InData, InDataLength);\r
     return EFI_SUCCESS;\r
+\r
+  case IKE_EALG_3DESCBC:\r
+  case IKE_EALG_AESCBC:\r
+    Index = IpSecGetIndexFromEncList(AlgorithmId);\r
+    if (Index == -1) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Get Context Size\r
+    //\r
+    ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize();\r
+    Context     = AllocateZeroPool (ContextSize);\r
+    if (Context == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // Initiate Context\r
+    //\r
+    if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {\r
+      if (mIpsecEncryptAlgorithmList[Index].CipherDecrypt (Context, InData, InDataLength, Ivec, OutData)) {\r
+        Status = EFI_SUCCESS;      \r
+      }\r
+    }\r
+    break;\r
+\r
+  default:\r
+    return Status;\r
+  }\r
+\r
+  if (Context != NULL) {\r
+    FreePool (Context);\r
   }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Digests the Payload with key and store the result into the OutData.\r
+\r
+  This function calls relevant Hmac interface from CryptoLib according to\r
+  the input alogrithm ID. It computes all datas from InDataFragment and output\r
+  the result into the OutData buffer. If the OutDataSize is larger than the related\r
+  HMAC alogrithm output size, return EFI_INVALID_PARAMETER.\r
+  \r
+  @param[in]      AlgorithmId     The authentication Identification.\r
+  @param[in]      Key             Pointer of the authentication key.\r
+  @param[in]      KeyLength       The length of the Key in bytes.\r
+  @param[in]      InDataFragment  The list contains all data to be authenticated.\r
+  @param[in]      FragmentCount   The size of the InDataFragment.\r
+  @param[out]     OutData         For in, the buffer to receive the output data.\r
+                                  For out, the buffer contains the authenticated data.\r
+  @param[in]      OutDataSize     The size of the buffer of OutData.\r
+\r
+  @retval EFI_UNSUPPORTED       If the AuthAlg is not in the support list.\r
+  @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.\r
+  @retval EFI_SUCCESS           Authenticate the payload successfully.\r
+  @retval otherwise             Authentication of the payload fails.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoHmac (\r
+  IN     CONST UINT8              AlgorithmId,\r
+  IN     CONST UINT8              *Key,\r
+  IN           UINTN              KeyLength,\r
+  IN           HASH_DATA_FRAGMENT *InDataFragment,\r
+  IN           UINTN              FragmentCount,\r
+     OUT       UINT8              *OutData,\r
+  IN           UINTN              OutDataSize\r
+  )\r
+{\r
+  UINTN        ContextSize;\r
+  UINTN        Index;\r
+  UINT8        FragmentIndex;\r
+  UINT8        *HashContext;\r
+  EFI_STATUS   Status;\r
+  UINT8        *OutHashData;\r
+  UINTN        OutHashSize;\r
+\r
+  Status      = EFI_UNSUPPORTED;\r
+  OutHashData = NULL;\r
+\r
+  OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r
+  //\r
+  // If the expected hash data size is larger than the related Hash algorithm\r
+  // output length, return EFI_INVALID_PARAMETER.\r
+  //\r
+  if (OutDataSize > OutHashSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  OutHashData = AllocatePool (OutHashSize);\r
+\r
+  if (OutHashData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  switch (AlgorithmId) {\r
+\r
+  case IKE_AALG_NONE :\r
+  case IKE_AALG_NULL :\r
+    return EFI_SUCCESS;\r
+\r
+  case IKE_AALG_SHA1HMAC:\r
+    Index = IpSecGetIndexFromAuthList (AlgorithmId);\r
+    if (Index == -1) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Get Context Size\r
+    //\r
+    ContextSize = mIpsecAuthAlgorithmList[Index].HmacGetContextSize();\r
+    HashContext = AllocateZeroPool (ContextSize);\r
+\r
+    if (HashContext == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Initiate HMAC context and hash the input data.\r
+    //\r
+    if (mIpsecAuthAlgorithmList[Index].HmacInitiate(HashContext, Key, KeyLength)) {\r
+      for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {\r
+        if (!mIpsecAuthAlgorithmList[Index].HmacUpdate (\r
+                HashContext,\r
+                InDataFragment[FragmentIndex].Data,\r
+                InDataFragment[FragmentIndex].DataSize\r
+                )\r
+          ) {\r
+          goto Exit;\r
+        }\r
+      }\r
+      if (mIpsecAuthAlgorithmList[Index].HmacFinal (HashContext, OutHashData)) {\r
+        //\r
+        // In some cases, like the Icv computing, the Icv size might be less than\r
+        // the key length size, so copy the part of hash data to the OutData.\r
+        //\r
+        CopyMem (OutData, OutHashData, OutDataSize);\r
+        Status = EFI_SUCCESS;\r
+      }\r
+\r
+      goto Exit;\r
+    }    \r
+      \r
+  default:\r
+    return Status;\r
+  }\r
+\r
+Exit:\r
+  if (HashContext != NULL) {\r
+    FreePool (HashContext);\r
+  }\r
+  if (OutHashData != NULL) {\r
+    FreePool (OutHashData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Digests the Payload and store the result into the OutData.\r
+\r
+  This function calls relevant Hash interface from CryptoLib according to\r
+  the input alogrithm ID. It computes all datas from InDataFragment and output\r
+  the result into the OutData buffer. If the OutDataSize is larger than the related\r
+  Hash alogrithm output size, return EFI_INVALID_PARAMETER.\r
+\r
+  @param[in]      AlgorithmId     The authentication Identification.\r
+  @param[in]      InDataFragment  A list contains all data to be authenticated.\r
+  @param[in]      FragmentCount   The size of the InDataFragment.\r
+  @param[out]     OutData         For in, the buffer to receive the output data.\r
+                                  For out, the buffer contains the authenticated data.\r
+  @param[in]      OutDataSize     The size of the buffer of OutData.\r
+\r
+  @retval EFI_UNSUPPORTED       If the AuthAlg is not in the support list.\r
+  @retval EFI_SUCCESS           Authenticated the payload successfully.\r
+  @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash\r
+                                algorithm could handle.\r
+  @retval otherwise             Authentication of the payload failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoHash (\r
+  IN     CONST UINT8              AlgorithmId,\r
+  IN           HASH_DATA_FRAGMENT *InDataFragment,\r
+  IN           UINTN              FragmentCount,\r
+     OUT       UINT8              *OutData,\r
+  IN           UINTN              OutDataSize\r
+  )\r
+{\r
+  UINTN        ContextSize;\r
+  UINTN        Index;\r
+  UINT8        FragmentIndex;\r
+  UINT8        *HashContext;\r
+  EFI_STATUS   Status;\r
+  UINT8        *OutHashData;\r
+  UINTN        OutHashSize;\r
+\r
+  Status      = EFI_UNSUPPORTED;\r
+  OutHashData = NULL;\r
+  \r
+  OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);\r
+  //\r
+  // If the expected hash data size is larger than the related Hash algorithm\r
+  // output length, return EFI_INVALID_PARAMETER.  \r
+  //\r
+  if (OutDataSize > OutHashSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  OutHashData = AllocatePool (OutHashSize);\r
+  if (OutHashData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  switch (AlgorithmId) {\r
+\r
+  case IKE_AALG_NONE:\r
+  case IKE_AALG_NULL:\r
+    return EFI_SUCCESS;\r
+\r
+  case IKE_AALG_SHA1HMAC:\r
+    Index = IpSecGetIndexFromAuthList (AlgorithmId);\r
+    if (Index == -1) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Get Context Size\r
+    //\r
+    ContextSize = mIpsecHashAlgorithmList[Index].HashGetContextSize();\r
+    HashContext = AllocateZeroPool (ContextSize);\r
+    if (HashContext == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Exit;\r
+    }\r
+    \r
+    //\r
+    // Initiate Hash context and hash the input data.\r
+    //\r
+    if (mIpsecHashAlgorithmList[Index].HashInitiate(HashContext)) {\r
+      for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {\r
+        if (!mIpsecHashAlgorithmList[Index].HashUpdate (\r
+                HashContext,\r
+                InDataFragment[FragmentIndex].Data,\r
+                InDataFragment[FragmentIndex].DataSize\r
+                )\r
+          ) {\r
+          goto Exit;\r
+        }\r
+      }\r
+      if (mIpsecHashAlgorithmList[Index].HashFinal (HashContext, OutHashData)) {\r
+        //\r
+        // In some cases, like the Icv computing, the Icv size might be less than\r
+        // the key length size, so copy the part of hash data to the OutData.\r
+        //\r
+        CopyMem (OutData, OutHashData, OutDataSize);            \r
+        Status = EFI_SUCCESS;\r
+      }\r
+      \r
+      goto Exit;        \r
+    }    \r
+    \r
+  default:\r
+    return Status;\r
+  }\r
+\r
+Exit:\r
+  if (HashContext != NULL) {\r
+    FreePool (HashContext);\r
+  }\r
+  if (OutHashData != NULL) {\r
+    FreePool (OutHashData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Generates the Diffie-Hellman public key.\r
+\r
+  This function first initiate a DHContext, then call the DhSetParameter() to set\r
+  the prime and primelenght, at end call the DhGenerateKey() to generates random\r
+  secret exponent, and computes the public key. The output returned via parameter\r
+  PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey\r
+  buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned\r
+  and PublicKeySize is set to the required buffer size to obtain the public key.\r
+\r
+  @param[in, out] DhContext       Pointer to the DH context.\r
+  @param[in]      Generator       Vlaue of generator.\r
+  @param[in]      PrimeLength     Length in bits of prime to be generated.\r
+  @param[in]      Prime           Pointer to the buffer to receive the generated\r
+                                  prime number.\r
+  @param[out]     PublicKey       Pointer to the buffer to receive generated public key.\r
+  @param[in, out] PublicKeySize   For in, the size of PublicKey buffer in bytes.\r
+                                  For out, the size of data returned in PublicKey\r
+                                  buffer in bytes.\r
+\r
+  @retval EFI_SUCCESS             The operation perfoms successfully.\r
+  @retval Otherwise               The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDhGetPublicKey (\r
+  IN OUT   UINT8  **DhContext,\r
+  IN       UINTN  Generator,\r
+  IN       UINTN  PrimeLength,\r
+  IN CONST UINT8  *Prime,\r
+     OUT   UINT8  *PublicKey,\r
+  IN OUT   UINTN  *PublicKeySize\r
+  ) \r
+{\r
+  EFI_STATUS   Status;\r
+  \r
+  *DhContext = DhNew ();\r
+  ASSERT (*DhContext != NULL);\r
+  if (!DhSetParameter (*DhContext, Generator, PrimeLength, Prime)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Exit;\r
+  }\r
+\r
+  if (!DhGenerateKey (*DhContext, PublicKey, PublicKeySize)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Exit;\r
+  }\r
+  return EFI_SUCCESS;\r
+\r
+Exit:\r
+  if (*DhContext != NULL) {\r
+    DhFree (*DhContext);\r
+    DhContext = NULL;\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Generates exchanged common key.\r
+\r
+  Given peer's public key, this function computes the exchanged common key, based\r
+  on its own context including value of prime modulus and random secret exponent.\r
+\r
+  @param[in, out] DhContext         Pointer to the DH context.\r
+  @param[in]      PeerPublicKey     Pointer to the peer's Public Key.\r
+  @param[in]      PeerPublicKeySize Size of peer's public key in bytes.\r
+  @param[out]     Key               Pointer to the buffer to receive generated key.\r
+  @param[in, out] KeySize           For in, the size of Key buffer in bytes.\r
+                                    For out, the size of data returned in Key\r
+                                    buffer in bytes.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval Otherwise                The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDhComputeKey (\r
+  IN   OUT   UINT8  *DhContext,     \r
+  IN   CONST UINT8  *PeerPublicKey,\r
+  IN         UINTN  PeerPublicKeySize,\r
+       OUT   UINT8  *Key,\r
+  IN   OUT   UINTN  *KeySize\r
+  )\r
+{\r
+  if (!DhComputeKey (DhContext, PeerPublicKey, PeerPublicKeySize, Key, KeySize)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.\r
+\r
+  @param[in, out]     DhContext         Pointer to the DH context to be freed.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval EFI_INVALID_PARAMETER    The DhContext is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoFreeDh (\r
+  IN   OUT   UINT8  **DhContext\r
+  )\r
+{ \r
+  if (*DhContext == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  DhFree (*DhContext);\r
   return EFI_SUCCESS;\r
 }\r
+\r
+/**\r
+  Generates random numbers of specified size.\r
+\r
+  If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.\r
+\r
+  @param[out]  OutBuffer        Pointer to buffer to receive random value.\r
+  @param[in]   Bytes            Size of randome bytes to generate.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval Otherwise                The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGenerateRandomBytes (\r
+  OUT UINT8*    OutBuffer,\r
+  IN  UINTN     Bytes\r
+  )\r
+{\r
+  if (!mInitialRandomSeed) {\r
+    RandomSeed (NULL, 0);\r
+    mInitialRandomSeed = TRUE;\r
+  }\r
+  if (RandomBytes (OutBuffer, Bytes)) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+}\r
+\r
+/**\r
+  Authenticate data with the certificate.\r
+\r
+  @param[in]      InData          Pointer to the Data to be signed.\r
+  @param[in]      InDataSize      InData size in bytes.\r
+  @param[in]      PrivateKey      Pointer to the  private key.\r
+  @param[in]      PrivateKeySize  The size of Private Key in bytes.\r
+  @param[in]      KeyPassWord     Pointer to the password for retrieving private key.\r
+  @param[in]      KeyPwdSize      The size of Key Password in bytes.\r
+  @param[out]     OutData         The pointer to the signed data.\r
+  @param[in, out] OutDataSize     Pointer to contain the size of out data.\r
\r
+**/\r
+VOID\r
+IpSecCryptoIoAuthDataWithCertificate (\r
+  IN     UINT8   *InData,\r
+  IN     UINTN   InDataSize,\r
+  IN     UINT8   *PrivateKey,\r
+  IN     UINTN   PrivateKeySize,\r
+  IN     UINT8   *KeyPassWord,\r
+  IN     UINTN   KeyPwdSize,\r
+     OUT UINT8   **OutData,\r
+  IN OUT UINTN   *OutDataSize\r
+  )\r
+{\r
+  UINT8         *RsaContext;\r
+  UINT8         *Signature;\r
+  UINTN         SigSize;\r
+   \r
+  SigSize   = 0;\r
+  //\r
+  // Retrieve RSA Private Key from password-protected PEM data\r
+  //\r
+  RsaGetPrivateKeyFromPem (\r
+    (CONST UINT8 *)PrivateKey,\r
+    PrivateKeySize,\r
+    (CONST CHAR8 *)KeyPassWord,\r
+    (VOID **) &RsaContext\r
+    );\r
+  if (RsaContext == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Sign data\r
+  //\r
+  Signature = NULL;  \r
+  if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) {\r
+    Signature = AllocateZeroPool (SigSize);\r
+  } else {\r
+    return;\r
+  } \r
+\r
+  RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize);\r
+\r
+  *OutData     = Signature;\r
+  *OutDataSize = SigSize;\r
+\r
+  if (RsaContext != NULL) {\r
+    RsaFree (RsaContext);\r
+  }\r
+}\r
+\r
+/**\r
+  Verify the singed data with the public key which is contained in a certificate.\r
+\r
+  @param[in]     InCert          Pointer to the Certificate which contains the\r
+                                 public key.\r
+  @param[in]     InCertLen       The size of Certificate in bytes.\r
+  @param[in]     InCa            Pointer to the CA certificate\r
+  @param[in]     CaLen           The size of CA certificate in bytes.\r
+  @param[in]     InData          Pointer to octect message hash to be checked.\r
+  @param[in]     InDataSize      Size of the message hash in bytes.\r
+  @param[in]     Singnature      The pointer to the RSA PKCS1-V1_5 signature to be verifed.\r
+  @param[in]     SigSize         Size of signature in bytes.\r
+\r
+  @retval  TRUE   Valid signature encoded in PKCS1-v1_5.\r
+  @retval  FALSE  Invalid signature or invalid RSA context.\r
\r
+**/\r
+BOOLEAN\r
+IpSecCryptoIoVerifySignDataByCertificate (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertLen,\r
+  IN     UINT8   *InCa,\r
+  IN     UINTN   CaLen,\r
+  IN     UINT8   *InData,\r
+  IN     UINTN   InDataSize,\r
+  IN     UINT8   *Singnature,\r
+  IN     UINTN   SigSize\r
+  )\r
+{\r
+  UINT8         *RsaContext;\r
+  BOOLEAN       Status;\r
+\r
+  //\r
+  // Create the RSA Context\r
+  //\r
+  RsaContext = RsaNew ();\r
+  if (RsaContext == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Verify the validity of X509 Certificate\r
+  //\r
+  if (!X509VerifyCert (InCert, CertLen, InCa, CaLen)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Retrieve the RSA public Key from Certificate\r
+  //\r
+  RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **)&RsaContext);\r
\r
+  //\r
+  // Verify data\r
+  //\r
+  Status = RsaPkcs1Verify (RsaContext, InData, InDataSize, Singnature, SigSize);\r
+\r
+  if (RsaContext != NULL) {\r
+    RsaFree (RsaContext);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the RSA Public Key from one X509 certificate (DER format only).\r
+\r
+  @param[in]     InCert            Pointer to the certificate.\r
+  @param[in]     CertLen           The size of the certificate in bytes.\r
+  @param[out]    PublicKey         Pointer to the retrieved public key.\r
+  @param[out]    PublicKeyLen      Size of Public Key in bytes.\r
+\r
+  @retval  EFI_SUCCESS            Successfully get the public Key.\r
+  @retval  EFI_INVALID_PARAMETER  The certificate is malformed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGetPublicKeyFromCert (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertLen,\r
+  OUT    UINT8   **PublicKey,\r
+  OUT    UINTN   *PublicKeyLen\r
+  )\r
+{\r
+  UINT8         *RsaContext;\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Create the RSA Context\r
+  //\r
+  RsaContext = RsaNew ();\r
+\r
+  //\r
+  // Retrieve the RSA public key from CA Certificate\r
+  //\r
+  if (!RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **) &RsaContext)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto EXIT;\r
+  }\r
+\r
+  *PublicKeyLen = 0;\r
\r
+  RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen);\r
\r
+  *PublicKey = AllocateZeroPool (*PublicKeyLen);\r
+  ASSERT (*PublicKey != NULL);\r
+\r
+  if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+EXIT:\r
+  if (RsaContext != NULL) {\r
+    RsaFree (RsaContext);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieves the subject name from one X509 certificate (DER format only).\r
+\r
+  @param[in]     InCert            Pointer to the X509 certificate.\r
+  @param[in]     CertSize          The size of the X509 certificate in bytes.\r
+  @param[out]    CertSubject       Pointer to the retrieved certificate subject.\r
+  @param[out]    SubjectSize       The size of Certificate Subject in bytes.\r
+  \r
+  @retval  EFI_SUCCESS            Retrieved the certificate subject successfully.\r
+  @retval  EFI_INVALID_PARAMETER  The certificate is malformed.\r
\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGetSubjectFromCert (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertSize,\r
+  OUT    UINT8   **CertSubject,\r
+  OUT    UINTN   *SubjectSize\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  *SubjectSize = 0;\r
+  X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize);\r
+\r
+  *CertSubject = AllocateZeroPool (*SubjectSize);\r
+  if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return Status;\r
+}\r
index ddceb12bb6ad3b2d27114a1e58b9c2b88f748a8e..87e5a494c587a42eb59e78b0d3a1ed0119d23038 100644 (file)
@@ -1,5 +1,5 @@
 /** @file\r
-  Definition related to the Security operation.\r
+  Definitions related to the Cryptographic Operations in IPsec.\r
 \r
   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
 \r
   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
 **/\r
-\r
 #ifndef _EFI_IPSEC_CRYPTIO_H_\r
 #define _EFI_IPSEC_CRYPTIO_H_\r
 \r
 #include <Protocol/IpSecConfig.h>\r
 #include <Library/DebugLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include "IpSecImpl.h"\r
+#include "IkeCommon.h"\r
 \r
-#define IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE 2\r
+#define IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE 4\r
 #define IPSEC_AUTH_ALGORITHM_LIST_SIZE    3\r
+#define IPSEC_HASH_ALGORITHM_LIST_SIZE    3\r
 \r
 ///\r
 /// Authentication Algorithm Definition\r
 #define IKE_EALG_AESCBC              0x0C\r
 \r
 /**\r
-  Prototype of Hash GetContextSize.\r
-\r
+  Prototype of HMAC GetContextSize.\r
+  \r
   Retrieves the size, in bytes, of the context buffer required.\r
-\r
+  \r
   @return  The size, in bytes, of the context buffer required.\r
 \r
 **/\r
 typedef\r
 UINTN\r
-(EFIAPI *CPL_HASH_GETCONTEXTSIZE) (\r
+(EFIAPI *CRYPTO_HMAC_GETCONTEXTSIZE) (\r
   VOID\r
   );\r
 \r
 /**\r
-  Prototype of Hash Operation Initiating.\r
-\r
+  Prototype of HMAC Operation Initiating.\r
+  \r
   Initialization with a new context.\r
 \r
-\r
-  @param[in,out]  Context  Input Context.\r
-\r
+  @param[out]     Context  Input Context.\r
+  @param[in]      Key      Pointer to the key for HMAC.\r
+  @param[in]      KeySize  The length of the Key in bytes.\r
\r
   @retval TRUE  Initialization Successfully.\r
 \r
 **/\r
 typedef\r
-EFI_STATUS\r
-(EFIAPI *CPL_HASH_INIT) (\r
-  IN OUT  VOID     *Context\r
+BOOLEAN\r
+(EFIAPI *CRYPTO_HMAC_INIT) (\r
+  OUT           VOID     *Context,\r
+  IN     CONST  UINT8    *Key,\r
+  IN            UINTN    KeySize\r
   );\r
 \r
 /**\r
-  Prototype of HASH update.\r
-  Hash update operation. Continue an Hash message digest operation, processing\r
-  another message block, and updating the Hash context.\r
+  Prototype of HMAC update.\r
+  HMAC update operation. Continue an HMAC message digest operation, processing\r
+  another message block, and updating the HMAC context.\r
 \r
   If Context is NULL, then ASSERT().\r
   If Data is NULL, then ASSERT().\r
 \r
   @param[in,out]  Context     The Specified Context.\r
-  @param[in,out]  Data        The Input Data to hash.\r
+  @param[in,out]  Data        The Input Data to be digested.\r
   @param[in]      DataLength  The length, in bytes, of Data.\r
 \r
   @retval TRUE   Update data successfully.\r
@@ -88,34 +97,34 @@ EFI_STATUS
 **/\r
 typedef\r
 BOOLEAN\r
-(EFIAPI *CPL_HASH_UPDATE) (\r
+(EFIAPI *CRYPTO_HMAC_UPDATE) (\r
   IN OUT       VOID  *Context,\r
   IN     CONST VOID  *Data,\r
   IN           UINTN DataLength\r
   );\r
 \r
 /**\r
-  Prototype of Hash finallization.\r
-  Terminate a Hash message digest operation and output the message digest.\r
+  Prototype of HMAC finallization.\r
+  Terminate a HMAC message digest operation and output the message digest.\r
 \r
   If Context is NULL, then ASSERT().\r
   If HashValue is NULL, then ASSERT().\r
 \r
   @param[in,out]  Context     The specified Context.\r
-  @param[out]     HashValue   Pointer to a 16-byte message digest output buffer.\r
+  @param[out]     HmacValue   Pointer to a 16-byte message digest output buffer.\r
 \r
   @retval TRUE  Finalized successfully.\r
 \r
 **/\r
 typedef\r
 BOOLEAN\r
-(EFIAPI *CPL_HASH_FINAL) (\r
+(EFIAPI *CRYPTO_HMAC_FINAL) (\r
   IN OUT  VOID   *Context,\r
-     OUT  UINT8  *HashValue\r
+     OUT  UINT8  *HmacValue\r
   );\r
 \r
 /**\r
-  Prototype of Cipher GetContextSize.\r
+  Prototype of Block Cipher GetContextSize.\r
 \r
   Retrieves the size, in bytes, of the context buffer required.\r
 \r
@@ -124,12 +133,12 @@ BOOLEAN
 **/\r
 typedef\r
 UINTN\r
-(EFIAPI *CPL_CIPHER_GETCONTEXTSIZE) (\r
+(EFIAPI *CRYPTO_CIPHER_GETCONTEXTSIZE) (\r
   VOID\r
   );\r
 \r
 /**\r
-  Prototype of Cipher initiation.\r
+  Prototype of Block Cipher initiation.\r
   Intializes the user-supplied key as the specifed context (key materials) for both\r
   encryption and decryption operations.\r
 \r
@@ -137,21 +146,20 @@ UINTN
   If Key is NULL, then generate random key for usage.\r
 \r
   @param[in,out]  Context      The specified Context.\r
-  @param[in]      Key          User-supplied TDES key (64/128/192 bits).\r
+  @param[in]      Key          User-supplied cipher key.\r
   @param[in]      KeyBits      Key length in bits.\r
 \r
-  @retval TRUE  TDES Initialization was successful.\r
+  @retval TRUE  Block Cipher Initialization was successful.\r
 \r
 **/\r
 typedef\r
 BOOLEAN\r
-(EFIAPI *CPL_CIPHER_INIT) (\r
+(EFIAPI *CRYPTO_CIPHER_INIT) (\r
   IN OUT        VOID   *Context,\r
   IN      CONST UINT8  *Key,\r
-  IN      CONST UINTN  KeyBits\r
+  IN            UINTN  KeyBits\r
   );\r
 \r
-\r
 /**\r
   Prototype of Cipher encryption.\r
   Encrypts plaintext message with the specified cipher.\r
@@ -163,22 +171,23 @@ BOOLEAN
 \r
   @param[in]      Context      The specified Context.\r
   @param[in]      InData       The input plaintext data to be encrypted.\r
+  @param[in]      InputSize    The size of input data.\r
+  @param[in]      Ivec         Pointer to Initial Vector data for encryption.\r
   @param[out]     OutData      The resultant encrypted ciphertext.\r
-  @param[in]      DataLength   Length of input data in bytes.\r
 \r
   @retval TRUE  Encryption successful.\r
 \r
 **/\r
 typedef\r
 BOOLEAN\r
-(EFIAPI *CPL_CIPHER_ENCRYPT) (\r
+(EFIAPI *CRYPTO_CIPHER_ENCRYPT) (\r
   IN            VOID   *Context,\r
   IN      CONST UINT8  *InData,\r
-      OUT       UINT8  *OutData,\r
-  IN      CONST UINTN  DataLength\r
+  IN            UINTN  InputSize,\r
+  IN      CONST UINT8  *Ivec,\r
+      OUT       UINT8  *OutData\r
   );\r
 \r
-\r
 /**\r
   Prototype of Cipher decryption.\r
   Decrypts cipher message with specified cipher.\r
@@ -189,61 +198,154 @@ BOOLEAN
 \r
   @param[in]      Context      The specified Context.\r
   @param[in]      InData       The input ciphertext data to be decrypted.\r
+  @param[in]      InputSize    The InData size.\r
+  @param[in]      Ivec         Pointer to the Initial Vector data for decryption.\r
   @param[out]     OutData      The resultant decrypted plaintext.\r
-  @param[in]      DataLength   Length of input data in bytes.\r
 \r
   @retval TRUE  Decryption successful.\r
 \r
 **/\r
 typedef\r
 BOOLEAN\r
-(EFIAPI *CPL_CIPHER_DECRYPT) (\r
-  IN     CONST VOID   *Context,\r
+(EFIAPI *CRYPTO_CIPHER_DECRYPT) (\r
+  IN           VOID   *Context,\r
   IN     CONST UINT8  *InData,\r
-     OUT       UINT8  *OutData,\r
-  IN     CONST UINTN  DataLength\r
+  IN           UINTN  InputSize,\r
+  IN     CONST UINT8  *Ivec,\r
+     OUT       UINT8  *OutData\r
+  );\r
+\r
+/**\r
+  Prototype of Hash ContextSize.\r
+\r
+  Retrieves the size, in bytes, of the context buffer required for specified hash operations.\r
+\r
+  @return  The size, in bytes, of the context buffer required for certain hash operations.\r
+\r
+**/\r
+typedef\r
+UINTN\r
+(EFIAPI *CRYPTO_HASH_GETCONTEXTSIZE) (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Prototype of Hash Initiate.\r
+\r
+  Initializes user-supplied memory pointed by Context as specified hash context for\r
+  subsequent use.\r
+\r
+  If Context is NULL, then ASSERT().\r
+\r
+  @param[out]  Context  Pointer to specified context being initialized.\r
+\r
+  @retval TRUE   context initialization succeeded.\r
+  @retval FALSE  context initialization failed.\r
+\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *CRYPTO_HASH_INIT) (\r
+  OUT  VOID  *Context\r
+  );\r
+\r
+/**\r
+  Prototype of Hash Update\r
+  \r
+  Digests the input data and updates hash context.\r
+\r
+  This function performs digest on a data buffer of the specified size.\r
+  It can be called multiple times to compute the digest of long or discontinuous data streams.\r
+  Context should be already correctly intialized by HashInit(), and should not be finalized\r
+  by HashFinal(). Behavior with invalid context is undefined.\r
+\r
+  If Context is NULL, then ASSERT().\r
+\r
+  @param[in, out]  Context      Pointer to the specified context.\r
+  @param[in]       Data         Pointer to the buffer containing the data to be hashed.\r
+  @param[in]       DataSize     Size of Data buffer in bytes.\r
+\r
+  @retval TRUE   data digest succeeded.\r
+  @retval FALSE  data digest failed.\r
+\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *CRYPTO_HASH_UPDATE) (\r
+  IN OUT  VOID        *Context,\r
+  IN      CONST VOID  *Data,\r
+  IN      UINTN       DataSize\r
+  );\r
+\r
+/**\r
+  Prototype of Hash Finalization.\r
+\r
+  Completes computation of the digest value.\r
+\r
+  This function completes hash computation and retrieves the digest value into\r
+  the specified memory. After this function has been called, the context cannot\r
+  be used again.\r
+  context should be already correctly intialized by HashInit(), and should not be\r
+  finalized by HashFinal(). Behavior with invalid context is undefined.\r
+\r
+  If Context is NULL, then ASSERT().\r
+  If HashValue is NULL, then ASSERT().\r
+\r
+  @param[in, out]  Context      Pointer to the specified context.\r
+  @param[out]      HashValue    Pointer to a buffer that receives the digest\r
+                                value.\r
+\r
+  @retval TRUE   digest computation succeeded.\r
+  @retval FALSE  digest computation failed.\r
+\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *CRYPTO_HASH_FINAL) (\r
+  IN OUT  VOID   *Context,\r
+  OUT     UINT8  *HashValue\r
   );\r
 \r
 //\r
-// The struct used to store the informatino and operation of  Cipher algorithm.\r
+// The struct used to store the information and operation of Block Cipher algorithm.\r
 //\r
 typedef struct _ENCRYPT_ALGORITHM {\r
-//\r
-// The ID of the Algorithm\r
-//\r
-UINT8                     AlgorithmId;\r
-//\r
-// The Key length of the Algorithm\r
-//\r
-UINTN                     KeyLength;\r
-//\r
-// Iv Size of the Algorithm\r
-//\r
-UINTN                     IvLength;\r
-//\r
-// The Block Size of the Algorithm\r
-//\r
-UINTN                     BlockSize;\r
-//\r
-// The Function pointer of GetContextSize.\r
-//\r
-CPL_CIPHER_GETCONTEXTSIZE CipherGetContextSize;\r
-//\r
-// The Function pointer of Cipher intitiaion.\r
-//\r
-CPL_CIPHER_INIT           CipherInitiate;\r
-//\r
-// The Function pointer of Cipher Encryption.\r
-//\r
-CPL_CIPHER_ENCRYPT        CipherEncrypt;\r
-//\r
-// The Function pointer of Cipher Decrption.\r
-//\r
-CPL_CIPHER_DECRYPT        CipherDecrypt;\r
+  //\r
+  // The ID of the Algorithm\r
+  //\r
+  UINT8                     AlgorithmId;\r
+  //\r
+  // The Key length of the Algorithm\r
+  //\r
+  UINTN                     KeyLength;\r
+  //\r
+  // Iv Size of the Algorithm\r
+  //\r
+  UINTN                     IvLength;\r
+  //\r
+  // The Block Size of the Algorithm\r
+  //\r
+  UINTN                     BlockSize;\r
+  //\r
+  // The Function pointer of GetContextSize.\r
+  //\r
+  CRYPTO_CIPHER_GETCONTEXTSIZE CipherGetContextSize;\r
+  //\r
+  // The Function pointer of Cipher initiation.\r
+  //\r
+  CRYPTO_CIPHER_INIT           CipherInitiate;\r
+  //\r
+  // The Function pointer of Cipher Encryption.\r
+  //\r
+  CRYPTO_CIPHER_ENCRYPT        CipherEncrypt;\r
+  //\r
+  // The Function pointer of Cipher Decrption.\r
+  //\r
+  CRYPTO_CIPHER_DECRYPT        CipherDecrypt;\r
 } ENCRYPT_ALGORITHM;\r
 \r
 //\r
-// The struct used to store the informatino and operation of  Autahentication algorithm.\r
+// The struct used to store the information and operation of Autahentication algorithm.\r
 //\r
 typedef struct _AUTH_ALGORITHM {\r
   //\r
@@ -252,8 +354,8 @@ typedef struct _AUTH_ALGORITHM {
   UINT8                    AlgorithmId;\r
   //\r
   // The Key length of the Algorithm\r
-  //\r
-  UINTN                    KeyLength;\r
+  // \r
+  UINTN                    DigestLength;\r
   //\r
   // The ICV length of the Algorithm\r
   //\r
@@ -265,25 +367,63 @@ typedef struct _AUTH_ALGORITHM {
   //\r
   // The function pointer of GetContextSize.\r
   //\r
-  CPL_HASH_GETCONTEXTSIZE  HashGetContextSize;\r
+  CRYPTO_HMAC_GETCONTEXTSIZE  HmacGetContextSize;\r
   //\r
-  // The function pointer of Initiatoion\r
+  // The function pointer of Initiation\r
   //\r
-  CPL_HASH_INIT            HashInitiate;\r
+  CRYPTO_HMAC_INIT            HmacInitiate;\r
   //\r
-  // The function pointer of Hash Update.\r
+  // The function pointer of HMAC Update.\r
   //\r
-  CPL_HASH_UPDATE          HashUpdate;\r
+  CRYPTO_HMAC_UPDATE          HmacUpdate;\r
   //\r
-  // The fucntion pointer of Hash Final\r
+  // The fucntion pointer of HMAC Final\r
   //\r
-  CPL_HASH_FINAL           HashFinal;\r
+  CRYPTO_HMAC_FINAL           HmacFinal;\r
 } AUTH_ALGORITHM;\r
 \r
+//\r
+// The struct used to store the informatino and operation of Hash algorithm.\r
+//\r
+typedef struct _HASH_ALGORITHM {\r
+  //\r
+  // ID of the Algorithm\r
+  //\r
+  UINT8                    AlgorithmId;\r
+  //\r
+  // The Key length of the Algorithm\r
+  //\r
+  UINTN                    DigestLength;\r
+  //\r
+  // The ICV length of the Algorithm\r
+  //\r
+  UINTN                    IcvLength;\r
+  //\r
+  // The block size of the Algorithm\r
+  //\r
+  UINTN                    BlockSize;\r
+  //\r
+  // The function pointer of GetContextSize\r
+  //\r
+  CRYPTO_HASH_GETCONTEXTSIZE  HashGetContextSize;\r
+  //\r
+  // The function pointer of Initiation\r
+  //\r
+  CRYPTO_HASH_INIT            HashInitiate;\r
+  //\r
+  // The function pointer of Hash Update\r
+  //\r
+  CRYPTO_HASH_UPDATE          HashUpdate;\r
+  //\r
+  // The fucntion pointer of Hash Final\r
+  //\r
+  CRYPTO_HASH_FINAL           HashFinal;\r
+} HASH_ALGORITHM;\r
+\r
 /**\r
-  Get the IV size of encrypt alogrithm. IV size is different from different algorithm.\r
+  Get the IV size of specified encryption alogrithm.\r
 \r
-  @param[in]  AlgorithmId          The encrypt algorithm ID.\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
 \r
   @return The value of IV size.\r
 \r
@@ -294,9 +434,9 @@ IpSecGetEncryptIvLength (
   );\r
 \r
 /**\r
-  Get the block size of encrypt alogrithm. Block size is different from different algorithm.\r
+  Get the block size of specified encryption alogrithm.\r
 \r
-  @param[in]  AlgorithmId          The encrypt algorithm ID.\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
 \r
   @return The value of block size.\r
 \r
@@ -307,16 +447,42 @@ IpSecGetEncryptBlockSize (
   );\r
 \r
 /**\r
-  Get the ICV size of Authenticaion alogrithm. ICV size is different from different algorithm.\r
+  Get the required key length of the specified encryption alogrithm.\r
 \r
-  @param[in]  AuthAlgorithmId          The Authentication algorithm ID.\r
+  @param[in]  AlgorithmId          The encryption algorithm ID.\r
+\r
+  @return The value of key length.\r
+\r
+**/\r
+UINTN\r
+IpSecGetEncryptKeyLength (\r
+  IN UINT8   AlgorithmId\r
+  );\r
+\r
+/**\r
+  Get the ICV size of the specified Authenticaion alogrithm.\r
+\r
+  @param[in]  AlgorithmId          The Authentication algorithm ID.\r
 \r
   @return The value of ICV size.\r
 \r
 **/\r
 UINTN\r
 IpSecGetIcvLength (\r
-  IN UINT8  AuthAlgorithmId\r
+  IN UINT8  AlgorithmId\r
+  );\r
+\r
+/**\r
+  Get the HMAC digest length by the specified Algorithm ID.\r
+\r
+  @param[in]  AlgorithmId  The specified Alogrithm ID.\r
+\r
+  @return The digest length of the specified Authentication Algorithm ID.\r
+\r
+**/\r
+UINTN\r
+IpSecGetHmacDigestLength (\r
+  IN UINT8  AlgorithmId\r
   );\r
 \r
 /**\r
@@ -324,7 +490,7 @@ IpSecGetIcvLength (
   IV and return EFI_SUCCESS.\r
 \r
   @param[in]  IvBuffer  The pointer of the IV buffer.\r
-  @param[in]  IvSize    The IV size.\r
+  @param[in]  IvSize    The IV size in bytes.\r
 \r
   @retval     EFI_SUCCESS  Create random data for IV.\r
 \r
@@ -335,5 +501,327 @@ IpSecGenerateIv (
   IN UINTN                           IvSize\r
   );\r
 \r
+/**\r
+  Encrypt the buffer.\r
+\r
+  This function calls relevant encryption interface from CryptoLib according to\r
+  the input alogrithm ID. The InData should be multiple of block size. This function\r
+  doesn't perform the padding. If it has the Ivec data, the length of it should be\r
+  same with the block size. The block size is different from the different algorithm.\r
+\r
+  @param[in]       AlgorithmId    The Alogrithem identification defined in RFC.\r
+  @param[in]       Key            Pointer to the buffer containing encrypting key.\r
+  @param[in}       KeyBits        The length of the key in bits.\r
+  @param[in]       Ivec           Point to the buffer containning the Initializeion\r
+                                  Vector (IV) data.\r
+  @param[in]       InData         Point to the buffer containing the data to be\r
+                                  encrypted.\r
+  @param[in]       InDataLength   The length of InData in Bytes.\r
+  @param[out]      OutData        Point to the buffer that receives the encryption\r
+                                  output.\r
+\r
+  @retval EFI_UNSUPPORTED       The input Algorithm is not supported.\r
+  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoEncrypt (\r
+  IN CONST UINT8      AlgorithmId,\r
+  IN CONST UINT8      *Key,\r
+  IN CONST UINTN      KeyBits,\r
+  IN CONST UINT8      *Ivec, OPTIONAL\r
+  IN       UINT8      *InData,\r
+  IN       UINTN      InDataLength,\r
+     OUT   UINT8      *OutData\r
+  );\r
+\r
+/**\r
+  Decrypts the buffer.\r
+\r
+  This function calls relevant Decryption interface from CryptoLib according to\r
+  the input alogrithm ID. The InData should be multiple of block size. This function\r
+  doesn't perform the padding. If it has the Ivec data, the length of it should be\r
+  same with the block size. The block size is different from the different algorithm.\r
+\r
+  @param[in]       AlgorithmId    The Alogrithem identification defined in RFC.\r
+  @param[in]       Key            Pointer to the buffer containing encrypting key.\r
+  @param[in}       KeyBits        The length of the key in bits.\r
+  @param[in]       Ivec           Point to the buffer containning the Initializeion\r
+                                  Vector (IV) data.\r
+  @param[in]       InData         Point to the buffer containing the data to be\r
+                                  Decrypted.\r
+  @param[in]       InDataLength   The length of InData in Bytes.\r
+  @param[out]      OutData        Pointer to the buffer that receives the decryption\r
+                                  output.\r
+\r
+  @retval EFI_UNSUPPORTED       The input Algorithm is not supported.\r
+  @retval EFI_OUT_OF_RESOURCE   The required resource can't be allocated.\r
+  @retval EFI_SUCCESS           The operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDecrypt (\r
+  IN CONST UINT8      AlgorithmId,\r
+  IN CONST UINT8      *Key,\r
+  IN CONST UINTN      KeyBits,\r
+  IN CONST UINT8      *Ivec, OPTIONAL\r
+  IN       UINT8      *InData,\r
+  IN       UINTN      InDataLength,\r
+     OUT   UINT8      *OutData\r
+  );\r
+\r
+/**\r
+  Digests the Payload with key and store the result into the OutData.\r
+\r
+  This function calls relevant Hmac interface from CryptoLib according to\r
+  the input alogrithm ID. It computes all datas from InDataFragment and output\r
+  the result into the OutData buffer. If the OutDataSize is larger than the related\r
+  HMAC alogrithm output size, return EFI_INVALID_PARAMETER.\r
+  \r
+  @param[in]      AlgorithmId     The authentication Identification.\r
+  @param[in]      Key             Pointer of the authentication key.\r
+  @param[in]      KeyLength       The length of the Key in bytes.\r
+  @param[in]      InDataFragment  The list contains all data to be authenticated.\r
+  @param[in]      FragmentCount   The size of the InDataFragment.\r
+  @param[out]     OutData         For in, the buffer to receive the output data.\r
+                                  For out, the buffer contains the authenticated data.\r
+  @param[in]      OutDataSize     The size of the buffer of OutData.\r
+\r
+  @retval EFI_UNSUPPORTED       If the AuthAlg is not in the support list.\r
+  @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.\r
+  @retval EFI_SUCCESS           Authenticate the payload successfully.\r
+  @retval otherwise             Authentication of the payload fails.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoHmac (\r
+  IN     CONST UINT8              AlgorithmId,\r
+  IN     CONST UINT8              *Key,\r
+  IN           UINTN              KeyLength,\r
+  IN           HASH_DATA_FRAGMENT *InDataFragment,\r
+  IN           UINTN              FragmentCount,\r
+     OUT       UINT8              *OutData,\r
+  IN           UINTN              OutDataSize\r
+  );\r
+\r
+/**\r
+  Digests the Payload and store the result into the OutData.\r
+\r
+  This function calls relevant Hash interface from CryptoLib according to\r
+  the input alogrithm ID. It computes all datas from InDataFragment and output\r
+  the result into the OutData buffer. If the OutDataSize is larger than the related\r
+  Hash alogrithm output size, return EFI_INVALID_PARAMETER.\r
+\r
+  @param[in]      AlgorithmId     The authentication Identification.\r
+  @param[in]      InDataFragment  A list contains all data to be authenticated.\r
+  @param[in]      FragmentCount   The size of the InDataFragment.\r
+  @param[out]     OutData         For in, the buffer to receive the output data.\r
+                                  For out, the buffer contains the authenticated data.\r
+  @param[in]      OutDataSize     The size of the buffer of OutData.\r
+\r
+  @retval EFI_UNSUPPORTED       If the AuthAlg is not in the support list.\r
+  @retval EFI_SUCCESS           Authenticated the payload successfully.\r
+  @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash\r
+                                algorithm could handle.\r
+  @retval otherwise             Authentication of the payload failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoHash (\r
+  IN     CONST UINT8              AlgorithmId,\r
+  IN           HASH_DATA_FRAGMENT *InDataFragment,\r
+  IN           UINTN              FragmentCount,\r
+     OUT       UINT8              *OutData,\r
+  IN           UINTN              OutDataSize\r
+  );\r
+\r
+/**\r
+  Generates the Diffie-Hellman public key.\r
+\r
+  This function first initiate a DHContext, then call the DhSetParameter() to set\r
+  the prime and primelenght, at end call the DhGenerateKey() to generates random\r
+  secret exponent, and computes the public key. The output returned via parameter\r
+  PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey\r
+  buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned\r
+  and PublicKeySize is set to the required buffer size to obtain the public key.\r
+\r
+  @param[in, out] DhContext       Pointer to the DH context.\r
+  @param[in]      Generator       Vlaue of generator.\r
+  @param[in]      PrimeLength     Length in bits of prime to be generated.\r
+  @param[in]      Prime           Pointer to the buffer to receive the generated\r
+                                  prime number.\r
+  @param[out]     PublicKey       Pointer to the buffer to receive generated public key.\r
+  @param[in, out] PublicKeySize   For in, the size of PublicKey buffer in bytes.\r
+                                  For out, the size of data returned in PublicKey\r
+                                  buffer in bytes.\r
+\r
+  @retval EFI_SUCCESS             The operation perfoms successfully.\r
+  @retval Otherwise               The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDhGetPublicKey (\r
+  IN OUT   UINT8  **DhContext,\r
+  IN       UINTN  Generator,\r
+  IN       UINTN  PrimeLength,\r
+  IN CONST UINT8  *Prime,\r
+     OUT   UINT8  *PublicKey,\r
+  IN OUT   UINTN  *PublicKeySize\r
+  );\r
+\r
+/**\r
+  Generates exchanged common key.\r
+\r
+  Given peer's public key, this function computes the exchanged common key, based\r
+  on its own context including value of prime modulus and random secret exponent.\r
+\r
+  @param[in, out] DhContext         Pointer to the DH context.\r
+  @param[in]      PeerPublicKey     Pointer to the peer's Public Key.\r
+  @param[in]      PeerPublicKeySize Size of peer's public key in bytes.\r
+  @param[out]     Key               Pointer to the buffer to receive generated key.\r
+  @param[in, out] KeySize           For in, the size of Key buffer in bytes.\r
+                                    For out, the size of data returned in Key\r
+                                    buffer in bytes.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval Otherwise                The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoDhComputeKey (\r
+  IN   OUT   UINT8  *DhContext,\r
+  IN   CONST UINT8  *PeerPublicKey,\r
+  IN         UINTN  PeerPublicKeySize,\r
+       OUT   UINT8  *Key,\r
+  IN   OUT   UINTN  *KeySize\r
+  );\r
+\r
+/**\r
+  Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.\r
+\r
+  @param[in, out]     DhContext         Pointer to the DH context to be freed.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval EFI_INVALID_PARAMETER    The DhContext is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoFreeDh (\r
+  IN   OUT   UINT8  **DhContext\r
+  );\r
+\r
+/**\r
+  Generates random numbers of specified size.\r
+\r
+  If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.\r
+\r
+  @param[out]  OutBuffer        Pointer to buffer to receive random value.\r
+  @param[in]   Bytes            Size of randome bytes to generate.\r
+\r
+  @retval EFI_SUCCESS              The operation perfoms successfully.\r
+  @retval Otherwise                The operation is failed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGenerateRandomBytes (\r
+  OUT UINT8*    OutBuffer,\r
+  IN  UINTN     Bytes\r
+  );\r
+\r
+/**\r
+  Authenticate data with the certificate.\r
+\r
+  @param[in]      InData          Pointer to the Data to be signed.\r
+  @param[in]      InDataSize      InData size in bytes.\r
+  @param[in]      PrivateKey      Pointer to the  private key.\r
+  @param[in]      PrivateKeySize  The size of Private Key in bytes.\r
+  @param[in]      KeyPassWord     Pointer to the password for retrieving private key.\r
+  @param[in]      KeyPwdSize      The size of Key Password in bytes.\r
+  @param[out]     OutData         The pointer to the signed data.\r
+  @param[in, out] OutDataSize     Pointer to contain the size of out data.\r
\r
+**/\r
+VOID\r
+IpSecCryptoIoAuthDataWithCertificate (\r
+  IN     UINT8   *InData,\r
+  IN     UINTN   InDataSize,\r
+  IN     UINT8   *PrivateKey,\r
+  IN     UINTN   PrivateKeySize,\r
+  IN     UINT8   *KeyPassWord,\r
+  IN     UINTN   KeyPwdSize,\r
+     OUT UINT8   **OutData,\r
+  IN OUT UINTN   *OutDataSize\r
+  );\r
+\r
+/**\r
+  Verify the singed data with the public key which is contained in a certificate.\r
+\r
+  @param[in]     InCert          Pointer to the Certificate which contains the\r
+                                 public key.\r
+  @param[in]     InCertLen       The size of Certificate in bytes.\r
+  @param[in]     InCa            Pointer to the CA certificate\r
+  @param[in]     CaLen           The size of CA certificate in bytes.\r
+  @param[in]     InData          Pointer to octect message hash to be checked.\r
+  @param[in]     InDataSize      Size of the message hash in bytes.\r
+  @param[in]     Singnature      The pointer to the RSA PKCS1-V1_5 signature to be verifed.\r
+  @param[in]     SigSize         Size of signature in bytes.\r
+\r
+  @retval  TRUE   Valid signature encoded in PKCS1-v1_5.\r
+  @retval  FALSE  Invalid signature or invalid RSA context.\r
\r
+**/\r
+BOOLEAN\r
+IpSecCryptoIoVerifySignDataByCertificate (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertLen,\r
+  IN     UINT8   *InCa,\r
+  IN     UINTN   CaLen,\r
+  IN     UINT8   *InData,\r
+  IN     UINTN   InDataSize,\r
+  IN     UINT8   *Singnature,\r
+  IN     UINTN   SigSize\r
+  );\r
+\r
+/**\r
+  Retrieves the RSA Public Key from one X509 certificate (DER format only).\r
+\r
+  @param[in]     InCert            Pointer to the certificate.\r
+  @param[in]     CertLen           The size of the certificate in bytes.\r
+  @param[out]    PublicKey         Pointer to the retrieved public key.\r
+  @param[out]    PublicKeyLen      Size of Public Key in bytes.\r
+\r
+  @retval  EFI_SUCCESS            Successfully get the public Key.\r
+  @retval  EFI_INVALID_PARAMETER  The CA certificate is malformed.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGetPublicKeyFromCert (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertLen,\r
+  OUT    UINT8   **PublicKey,\r
+  OUT    UINTN   *PublicKeyLen\r
+  );\r
+\r
+/**\r
+  Retrieves the subject name from one X509 certificate (DER format only).\r
+\r
+  @param[in]     InCert            Pointer to the X509 certificate.\r
+  @param[in]     CertSize          The size of the X509 certificate in bytes.\r
+  @param[out]    CertSubject       Pointer to the retrieved certificate subject.\r
+  @param[out]    SubjectSize       The size of Certificate Subject in bytes.\r
+  \r
+  @retval  EFI_SUCCESS            Retrieved the certificate subject successfully.\r
+  @retval  EFI_INVALID_PARAMETER  The certificate is malformed.\r
\r
+**/\r
+EFI_STATUS\r
+IpSecCryptoIoGetSubjectFromCert (\r
+  IN     UINT8   *InCert,\r
+  IN     UINTN   CertSize,\r
+  OUT    UINT8   **CertSubject,\r
+  OUT    UINTN   *SubjectSize\r
+  );\r
+\r
 #endif\r
 \r
index 8a5811b960f6c2ece3d1d24c1431dee681d6ec63..56b35a1a146ef8a7fd8cba06d24d508634c8383e 100644 (file)
@@ -1,5 +1,5 @@
 /** @file\r
-  Interface of IPsec printing debug information.\r
+  The Interfaces of IPsec debug information printing.\r
 \r
   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
 \r
@@ -19,7 +19,7 @@
 //\r
 // The print title for IKEv1 variety phase.\r
 //\r
-CHAR8 *mStateStr[] = {\r
+CHAR8 *mIkev1StateStr[] = {\r
   "IKEv1_MAIN_1",\r
   "IKEv1_MAIN_2",\r
   "IKEv1_MAIN_3",\r
@@ -28,6 +28,20 @@ CHAR8 *mStateStr[] = {
   "IKEv1_QUICK_2",\r
   "IKEv1_QUICK_ESTABLISHED"\r
 };\r
+\r
+//\r
+// The print title for IKEv2 variety phase.\r
+//\r
+CHAR8 *mIkev2StateStr[] = {\r
+  "IKEv2_STATE_INIT",\r
+  "IKEv2_STATE_AUTH",\r
+  "IKEv2_STATE_SA_ESTABLISH",\r
+  "IKEv2_STATE_CREATE_CHILD",\r
+  "IKEv2_STATE_SA_REKEYING",\r
+  "IKEv2_STATE_CHILD_SA_ESTABLISHED",\r
+  "IKEv2_STATE_SA_DELETING"\r
+};\r
+\r
 //\r
 // The print title for IKEv1 variety Exchagne.\r
 //\r
@@ -35,13 +49,17 @@ CHAR8 *mExchangeStr[] = {
   "IKEv1 Main Exchange",\r
   "IKEv1 Info Exchange",\r
   "IKEv1 Quick Exchange",\r
-  "IKEv1 Unknown Exchange"\r
+  "IKEv2 Initial Exchange",\r
+  "IKEv2 Auth Exchange",\r
+  "IKEv2 Create Child Exchange",\r
+  "IKEv2 Info Exchange",\r
+  "IKE   Unknow Exchange"\r
 };\r
 \r
 //\r
 // The print title for IKEv1 variety Payload.\r
 //\r
-CHAR8 *mPayloadStr[] = {\r
+CHAR8 *mIkev1PayloadStr[] = {\r
   "IKEv1 None Payload",\r
   "IKEv1 SA Payload",\r
   "IKEv1 Proposal Payload",\r
@@ -58,6 +76,28 @@ CHAR8 *mPayloadStr[] = {
   "IKEv1 Vendor Payload"\r
 };\r
 \r
+//\r
+// The print title for IKEv2 variety Payload.\r
+//\r
+CHAR8* mIkev2PayloadStr[] = {\r
+  "IKEv2 SA Payload",\r
+  "IKEv2 Key Payload",\r
+  "IKEv2 Identity Initial Payload",\r
+  "IKEv2 Identity Respond Payload",\r
+  "IKEv2 Certificate Payload",\r
+  "IKEv2 Certificate Request Payload",\r
+  "IKEv2 Auth Payload",\r
+  "IKEv2 Nonce Payload",\r
+  "IKEv2 Notify Payload",\r
+  "IKEv2 Delet Payload",\r
+  "IKEv2 Vendor Payload",\r
+  "IKEv2 Traffic Selector Initiator Payload",\r
+  "IKEv2 Traffic Selector Respond Payload",\r
+  "IKEv2 Encrypt Payload",\r
+  "IKEv2 Configuration Payload",\r
+  "IKEv2 Extensible Authentication Payload"\r
+};\r
+\r
 /**\r
   Print the IP address.\r
 \r
@@ -112,24 +152,146 @@ IpSecDumpAddress (
 }\r
 \r
 /**\r
-  Print IKEv1 Current states.\r
+  Print IKE Current states.\r
 \r
-  @param[in]  Previous    The Previous state of IKEv1.\r
-  @param[in]  Current     The current state of IKEv1.\r
+  @param[in]  Previous    The Previous state of IKE.\r
+  @param[in]  Current     The current state of IKE.\r
+  @param[in]  IkeVersion  The version of IKE.\r
 \r
 **/\r
 VOID\r
-IpSecDumpState (\r
+IkeDumpState (\r
   IN UINT32              Previous,\r
-  IN UINT32              Current\r
+  IN UINT32              Current,\r
+  IN UINT8               IkeVersion\r
   )\r
 {\r
+  \r
   if (Previous == Current) {\r
-    DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mStateStr[Previous]));\r
+    if (IkeVersion == 1) {\r
+      DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mIkev1StateStr[Previous]));\r
+    } else if (IkeVersion == 2) {\r
+      DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mIkev2StateStr[Previous]));\r
+    }\r
+    \r
+  } else {\r
+    if (IkeVersion == 1) {\r
+      DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mIkev1StateStr[Previous], mIkev1StateStr[Current]));\r
+    } else {\r
+      DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mIkev2StateStr[Previous], mIkev2StateStr[Current]));\r
+    }\r
+    \r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Print the IKE Packet.\r
+\r
+  @param[in]  Packet      Point to IKE packet to be printed.\r
+  @param[in]  Direction   Point to the IKE packet is inbound or outbound.\r
+  @param[in]  IpVersion   Specified IP Version.\r
+\r
+**/\r
+VOID\r
+IpSecDumpPacket (\r
+  IN IKE_PACKET            *Packet,\r
+  IN EFI_IPSEC_TRAFFIC_DIR Direction,\r
+  IN UINT8                 IpVersion\r
+  )\r
+{\r
+  CHAR8                     *TypeStr;\r
+  UINTN                     PacketSize;\r
+  UINT64                    InitCookie;\r
+  UINT64                    RespCookie;\r
+\r
+  ASSERT (Packet != NULL);\r
+\r
+  PacketSize = Packet->PayloadTotalSize + sizeof (IKE_HEADER);\r
+  InitCookie = (Direction == EfiIPsecOutBound) ? HTONLL (Packet->Header->InitiatorCookie) : Packet->Header->InitiatorCookie;\r
+  RespCookie = (Direction == EfiIPsecOutBound) ? HTONLL (Packet->Header->ResponderCookie) : Packet->Header->ResponderCookie;\r
+\r
+  switch (Packet->Header->ExchangeType) {\r
+  case IKE_XCG_TYPE_IDENTITY_PROTECT:\r
+    TypeStr = mExchangeStr[0];\r
+    break;\r
+\r
+  case IKE_XCG_TYPE_INFO:\r
+    TypeStr = mExchangeStr[1];\r
+    break;\r
+\r
+  case IKE_XCG_TYPE_QM:\r
+    TypeStr = mExchangeStr[2];\r
+    break;\r
+    \r
+  case IKE_XCG_TYPE_SA_INIT:\r
+    TypeStr = mExchangeStr[3];\r
+    break;\r
+\r
+  case IKE_XCG_TYPE_AUTH:\r
+    TypeStr = mExchangeStr[4];\r
+    break;\r
+\r
+  case IKE_XCG_TYPE_CREATE_CHILD_SA:\r
+    TypeStr = mExchangeStr[5];\r
+    break;\r
+\r
+  case IKE_XCG_TYPE_INFO2:\r
+    TypeStr = mExchangeStr[6];\r
+    break;\r
+    \r
+  default:\r
+    TypeStr = mExchangeStr[7];\r
+    break;\r
+  }\r
+\r
+  if (Direction == EfiIPsecOutBound) {\r
+    DEBUG ((DEBUG_INFO, "\n>>>Sending %d bytes %a to ", PacketSize, TypeStr));\r
   } else {\r
-    DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mStateStr[Previous], mStateStr[Current]));\r
+    DEBUG ((DEBUG_INFO, "\n>>>Receiving %d bytes %a from ", PacketSize, TypeStr));\r
   }\r
 \r
+  IpSecDumpAddress (DEBUG_INFO, &Packet->RemotePeerIp, IpVersion);\r
+\r
+  DEBUG ((DEBUG_INFO, "   InitiatorCookie:0x%lx ResponderCookie:0x%lx\n", InitCookie, RespCookie));\r
+  DEBUG (\r
+    (DEBUG_INFO,\r
+    "   Version: 0x%x Flags:0x%x ExchangeType:0x%x\n",\r
+    Packet->Header->Version,\r
+    Packet->Header->Flags,\r
+    Packet->Header->ExchangeType)\r
+    );\r
+  DEBUG (\r
+    (DEBUG_INFO,\r
+    "   MessageId:0x%x NextPayload:0x%x\n",\r
+    Packet->Header->MessageId,\r
+    Packet->Header->NextPayload)\r
+    );\r
+\r
+}\r
+\r
+/**\r
+  Print the IKE Paylolad.\r
+\r
+  @param[in]  IkePayload  Point to payload to be printed.\r
+  @param[in]  IkeVersion  The specified version of IKE.\r
\r
+**/\r
+VOID\r
+IpSecDumpPayload (\r
+  IN IKE_PAYLOAD           *IkePayload,\r
+  IN UINT8                 IkeVersion\r
+  )\r
+{\r
+  if (IkeVersion == 1) {\r
+    DEBUG ((DEBUG_INFO, "+%a\n", mIkev1PayloadStr[IkePayload->PayloadType]));\r
+  }  else {\r
+    //\r
+    // For IKEV2 the first Payload type is started from 33.\r
+    //\r
+    DEBUG ((DEBUG_INFO, "+%a\n", mIkev2PayloadStr[IkePayload->PayloadType - 33]));\r
+  }\r
+  IpSecDumpBuf ("Payload data", IkePayload->PayloadBuf, IkePayload->PayloadSize);\r
 }\r
 \r
 /**\r
index 0e6e6811c50e10607ed40973b234e17281372f19..d44677f300327d1671c541e087fed104eab5dca8 100644 (file)
@@ -1,5 +1,5 @@
 /** @file\r
-  The definition of functions and MACROs used for IPsec debug information print.\r
+  The definition of functions and MACROs used for IPsec debug information printting.\r
 \r
   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
 \r
   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
 **/\r
-\r
 #ifndef _EFI_IPSEC_DEBUG_H_\r
 #define _EFI_IPSEC_DEBUG_H_\r
 \r
-#include <Library/DebugLib.h>\r
+#include "IkeCommon.h"\r
+#include "IkePacket.h"\r
 \r
 #define IPSEC_DUMP_ADDRESS(Level, Ip, Version)           IpSecDumpAddress (Level, Ip, Version)\r
-#define IPSEC_DUMP_STATE(Previous, Current)              IpSecDumpState (Previous, Current)\r
+#define IKEV1_DUMP_STATE(Previous, Current)              IkeDumpState (Previous, Current, 1)\r
+#define IKEV2_DUMP_STATE(Previous, Current)              IkeDumpState (Previous, Current, 2)\r
 #define IPSEC_DUMP_PACKET(Packet, Direction, IpVersion)  IpSecDumpPacket (Packet, Direction, IpVersion)\r
-#define IPSEC_DUMP_PAYLOAD(IkePayload)                   IpSecDumpPayload (IkePayload)\r
+#define IPSEC_DUMP_PAYLOAD(IkePayload)                   IpSecDumpPayload (IkePayload, 1)\r
+#define IKEV2_DUMP_PAYLOAD(IkePayload)                   IpSecDumpPayload (IkePayload, 2)\r
 #define IPSEC_DUMP_BUF(Title, Data, DataSize)            IpSecDumpBuf (Title, Data, DataSize)\r
 \r
 #define IPSEC_DEBUG_BYTE_PER_LINE                       8\r
@@ -43,52 +45,53 @@ IpSecDumpAddress (
   );\r
 \r
 /**\r
-  Print IKEv1 Current states.\r
+  Print IKE Current states.\r
 \r
-  @param[in]  Previous    The Previous state of IKEv1.\r
-  @param[in]  Current     The current state of IKEv1.\r
+  @param[in]  Previous    The Previous state of IKE.\r
+  @param[in]  Current     The current state of IKE.\r
+  @param[in]  IkeVersion  The version of IKE.\r
 \r
 **/\r
 VOID\r
-IpSecDumpState (\r
+IkeDumpState (\r
   IN UINT32              Previous,\r
-  IN UINT32              Current\r
+  IN UINT32              Current, \r
+  IN UINT8               IkeVersion\r
   );\r
 \r
 /**\r
-  Print the Ike Packet.\r
+  Print the IKE Packet.\r
 \r
   @param[in]  Packet      Point to IKE packet to be printed.\r
   @param[in]  Direction   Point to the IKE packet is inbound or outbound.\r
   @param[in]  IpVersion   Specified IP Version.\r
 \r
 **/\r
-/*\r
 VOID\r
 IpSecDumpPacket (\r
   IN IKE_PACKET            *Packet,\r
   IN EFI_IPSEC_TRAFFIC_DIR Direction,\r
   IN UINT8                 IpVersion\r
   );\r
-*/\r
 \r
 /**\r
   Print the IKE Paylolad.\r
 \r
-  @param[in]  IkePayload  Points to the payload to be printed.\r
-\r
+  @param[in]  IkePayload  Point to payload to be printed.\r
+  @param[in]  IkeVersion  The specified version of IKE.\r
\r
 **/\r
-/*\r
 VOID\r
 IpSecDumpPayload (\r
-  IN IKE_PAYLOAD           *IkePayload\r
+  IN IKE_PAYLOAD           *IkePayload,\r
+  IN UINT8                 IkeVersion\r
   );\r
-*/\r
+\r
 /**\r
   Print the buffer in form of Hex.\r
 \r
   @param[in]  Title       The strings to be printed before the data of the buffer.\r
-  @param[in]  Data        Points to the buffer to be printed.\r
+  @param[in]  Data        Point to buffer to be printed.\r
   @param[in]  DataSize    The size of the buffer to be printed.\r
 \r
 **/\r
index 00fb26f7610853a2e0ac943a371faa0eafaa3a7a..7e0d1fa4ed5e9ffd1b24c1fbbddadc26a0b5f947 100644 (file)
 \r
 **/\r
 \r
-#include <Library/UdpIoLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+\r
 #include "IpSecConfigImpl.h"\r
+#include "IkeService.h"\r
 #include "IpSecDebug.h"\r
 \r
 /**\r
@@ -38,9 +40,34 @@ IpSecDriverBindingSupported (
   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL\r
   )\r
 {\r
+  EFI_STATUS  Udp4Status;\r
+  EFI_STATUS  Udp6Status;\r
+\r
+  Udp4Status = gBS->OpenProtocol (\r
+                      ControllerHandle,\r
+                      &gEfiUdp4ServiceBindingProtocolGuid,\r
+                      NULL,\r
+                      This->DriverBindingHandle,\r
+                      ControllerHandle,\r
+                      EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                      );\r
+\r
+  Udp6Status = gBS->OpenProtocol (\r
+                      ControllerHandle,\r
+                      &gEfiUdp6ServiceBindingProtocolGuid,\r
+                      NULL,\r
+                      This->DriverBindingHandle,\r
+                      ControllerHandle,\r
+                      EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                      );\r
+\r
   //\r
-  //TODO: Add Udp4Protocol and Udp6Protocol testing.\r
+  // The controller with either Udp4Sb or Udp6Sb is supported.\r
   //\r
+  if (!EFI_ERROR (Udp4Status) || !EFI_ERROR (Udp6Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   return EFI_UNSUPPORTED;\r
 }\r
 \r
@@ -54,7 +81,7 @@ IpSecDriverBindingSupported (
 \r
   @retval EFI_SUCCES           This driver is added to ControllerHandle\r
   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle\r
-  @retval EFI_DEVICE_ERROR     The device could not be started due to a device error.\r
+  @retval EFI_DEVICE_ERROR     The device could not be started due to a device error.  \r
                                Currently not implemented.\r
   @retval other                This driver does not support this device\r
 \r
@@ -67,10 +94,59 @@ IpSecDriverBindingStart (
   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
   )\r
 {\r
+  EFI_IPSEC_PROTOCOL  *IpSec;\r
+  EFI_STATUS          Status;\r
+  EFI_STATUS          Udp4Status;\r
+  EFI_STATUS          Udp6Status;\r
+  IPSEC_PRIVATE_DATA  *Private;\r
+\r
   //\r
-  //TODO: Add Udp4Io and Udp6Io creation for the IKE.\r
+  // Ipsec protocol should be installed when load image.\r
   //\r
-  return EFI_SUCCESS;\r
+  Status = gBS->LocateProtocol (&gEfiIpSecProtocolGuid, NULL, (VOID **) &IpSec);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (IpSec);\r
+\r
+  //\r
+  // If udp4 sb is on the controller, try to open a udp4 io for input.\r
+  //\r
+  Udp4Status = gBS->OpenProtocol (\r
+                      ControllerHandle,\r
+                      &gEfiUdp4ServiceBindingProtocolGuid,\r
+                      NULL,\r
+                      This->DriverBindingHandle,\r
+                      ControllerHandle,\r
+                      EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                      );\r
+\r
+  if (!EFI_ERROR (Udp4Status)) {\r
+    Udp4Status = IkeOpenInputUdp4 (Private, ControllerHandle);\r
+  }\r
+  //\r
+  // If udp6 sb is on the controller, try to open a udp6 io for input.\r
+  //\r
+  Udp6Status = gBS->OpenProtocol (\r
+                      ControllerHandle,\r
+                      &gEfiUdp6ServiceBindingProtocolGuid,\r
+                      NULL,\r
+                      This->DriverBindingHandle,\r
+                      ControllerHandle,\r
+                      EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                      );\r
+\r
+  if (!EFI_ERROR (Udp6Status)) {\r
+    Udp6Status = IkeOpenInputUdp6 (Private, ControllerHandle);\r
+  }\r
+\r
+  if (!EFI_ERROR (Udp4Status) || !EFI_ERROR (Udp6Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_DEVICE_ERROR;\r
 }\r
 \r
 /**\r
@@ -95,10 +171,78 @@ IpSecDriverBindingStop (
   IN EFI_HANDLE                   *ChildHandleBuffer\r
   )\r
 {\r
+  EFI_IPSEC_PROTOCOL  *IpSec;\r
+  EFI_STATUS          Status;\r
+  IPSEC_PRIVATE_DATA  *Private;\r
+  IKE_UDP_SERVICE     *UdpSrv;\r
+  LIST_ENTRY          *Entry;\r
+  LIST_ENTRY          *Next;\r
+\r
   //\r
-  //TODO: Add UdpIo4 and UdpIo6 destruction when the Udp driver unload or stop.\r
+  // Locate ipsec protocol to get private data.\r
   //\r
-  return EFI_UNSUPPORTED;\r
+  Status = gBS->LocateProtocol (&gEfiIpSecProtocolGuid, NULL, (VOID **) &IpSec);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (IpSec);\r
+\r
+  //\r
+  // If has udp4 io opened on the controller, close and free it.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Udp4List) {\r
+\r
+    UdpSrv = IPSEC_UDP_SERVICE_FROM_LIST (Entry);\r
+    //\r
+    // Find the right udp service which installed on the appointed nic handle.\r
+    //\r
+    if (UdpSrv->Input != NULL && ControllerHandle == UdpSrv->Input->UdpHandle) {\r
+      UdpIoFreeIo (UdpSrv->Input);\r
+      UdpSrv->Input = NULL;\r
+    }\r
+\r
+    if (UdpSrv->Output != NULL && ControllerHandle == UdpSrv->Output->UdpHandle) {\r
+      UdpIoFreeIo (UdpSrv->Output);\r
+      UdpSrv->Output = NULL;\r
+    }\r
+\r
+    if (UdpSrv->Input == NULL && UdpSrv->Output == NULL) {\r
+      RemoveEntryList (&UdpSrv->List);\r
+      FreePool (UdpSrv);\r
+      ASSERT (Private->Udp4Num > 0);\r
+      Private->Udp4Num--;\r
+    }\r
+  }\r
+  //\r
+  // If has udp6 io opened on the controller, close and free it.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Udp6List) {\r
+\r
+    UdpSrv = IPSEC_UDP_SERVICE_FROM_LIST (Entry);\r
+    //\r
+    // Find the right udp service which installed on the appointed nic handle.\r
+    //\r
+    if (UdpSrv->Input != NULL && ControllerHandle == UdpSrv->Input->UdpHandle) {\r
+      UdpIoFreeIo (UdpSrv->Input);\r
+      UdpSrv->Input = NULL;\r
+    }\r
+\r
+    if (UdpSrv->Output != NULL && ControllerHandle == UdpSrv->Output->UdpHandle) {\r
+      UdpIoFreeIo (UdpSrv->Output);\r
+      UdpSrv->Output = NULL;\r
+    }\r
+\r
+    if (UdpSrv->Input == NULL && UdpSrv->Output == NULL) {\r
+      RemoveEntryList (&UdpSrv->List);\r
+      FreePool (UdpSrv);\r
+      ASSERT (Private->Udp6Num > 0);\r
+      Private->Udp6Num--;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 EFI_DRIVER_BINDING_PROTOCOL gIpSecDriverBinding = {\r
@@ -112,9 +256,9 @@ EFI_DRIVER_BINDING_PROTOCOL gIpSecDriverBinding = {
 \r
 /**\r
   This is a callback function when the mIpSecInstance.DisabledEvent is signaled.\r
-\r
+    \r
   @param[in]  Event        Event whose notification function is being invoked.\r
-  @param[in]  Context      Pointer to the notification function's context.\r
+  @param[in]  Context      Pointer to the notification function's context. \r
 \r
 **/\r
 VOID\r
@@ -125,34 +269,17 @@ IpSecCleanupAllSa (
   )\r
 {\r
   IPSEC_PRIVATE_DATA  *Private;\r
-  UINT8               Value;\r
-  EFI_STATUS          Status;\r
-\r
-  Private = (IPSEC_PRIVATE_DATA *) Context;\r
-\r
-  //\r
-  // Set the Status Variable\r
-  //\r
-  Value  = IPSEC_STATUS_DISABLED;\r
-  Status = gRT->SetVariable (\r
-                  IPSECCONFIG_STATUS_NAME,\r
-                  &gEfiIpSecConfigProtocolGuid,\r
-                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
-                  sizeof (Value),\r
-                  &Value\r
-                  );\r
-  if (!EFI_ERROR (Status)) {\r
-    Private->IpSec.DisabledFlag = TRUE;\r
-  }\r
-\r
+  Private                   = (IPSEC_PRIVATE_DATA *) Context;\r
+  Private->IsIPsecDisabling = TRUE;\r
+  IkeDeleteAllSas (Private);\r
 }\r
 \r
 /**\r
   This is the declaration of an EFI image entry point. This entry point is\r
   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including\r
   both device drivers and bus drivers.\r
-\r
-  The entry point for IPsec driver which installs the driver binding,\r
+  \r
+  The entry point for IPsec driver which installs the driver binding, \r
   component name protocol, IPsec Config protcolon, and IPsec protocol in\r
   its ImageHandle.\r
 \r
@@ -162,7 +289,7 @@ IpSecCleanupAllSa (
   @retval EFI_SUCCESS           The operation completed successfully.\r
   @retval EFI_ALREADY_STARTED   The IPsec driver has been already loaded.\r
   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
-  @retval Others                The operation is failed.\r
+  @retval Others                The operation is failed. \r
 \r
 **/\r
 EFI_STATUS\r
@@ -174,7 +301,7 @@ IpSecDriverEntryPoint (
 {\r
   EFI_STATUS          Status;\r
   IPSEC_PRIVATE_DATA  *Private;\r
-  EFI_IPSEC2_PROTOCOL *IpSec;\r
+  EFI_IPSEC_PROTOCOL  *IpSec;\r
 \r
   //\r
   // Check whether ipsec protocol has already been installed.\r
@@ -202,7 +329,7 @@ IpSecDriverEntryPoint (
     goto ON_EXIT;\r
   }\r
   //\r
-  // Create disable event to cleanup all sa when ipsec disabled by user.\r
+  // Create disable event to cleanup all SA when ipsec disabled by user.\r
   //\r
   Status = gBS->CreateEvent (\r
                   EVT_NOTIFY_SIGNAL,\r
@@ -218,8 +345,8 @@ IpSecDriverEntryPoint (
 \r
   Private->Signature    = IPSEC_PRIVATE_DATA_SIGNATURE;\r
   Private->ImageHandle  = ImageHandle;\r
-  CopyMem (&Private->IpSec, &mIpSecInstance, sizeof (EFI_IPSEC2_PROTOCOL));\r
-\r
+  CopyMem (&Private->IpSec, &mIpSecInstance, sizeof (EFI_IPSEC_PROTOCOL));\r
+  \r
   //\r
   // Initilize Private's members. Thess members is used for IKE.\r
   //\r
@@ -229,7 +356,8 @@ IpSecDriverEntryPoint (
   InitializeListHead (&Private->Ikev1EstablishedList);\r
   InitializeListHead (&Private->Ikev2SessionList);\r
   InitializeListHead (&Private->Ikev2EstablishedList);\r
-\r
+  \r
+  RandomSeed (NULL, 0);\r
   //\r
   // Initialize the ipsec config data and restore it from variable.\r
   //\r
@@ -260,11 +388,17 @@ IpSecDriverEntryPoint (
              &gIpSecComponentName2\r
              );\r
   if (EFI_ERROR (Status)) {\r
-    goto ON_UNINSTALL_CONFIG;\r
+    goto ON_UNINSTALL_IPSEC;\r
   }\r
-\r
+  \r
   return Status;\r
 \r
+ON_UNINSTALL_IPSEC:\r
+  gBS->UninstallProtocolInterface (\r
+         Private->Handle,\r
+         &gEfiIpSecProtocolGuid,\r
+         &Private->IpSec\r
+         );\r
 ON_UNINSTALL_CONFIG:\r
   gBS->UninstallProtocolInterface (\r
         Private->Handle,\r
index 250ef1cdca6729bcb6aa892a3c3033550a90b71c..9b4c7a5462b4f1412daf07b7d0c0617186d307d5 100644 (file)
@@ -19,6 +19,7 @@
   FILE_GUID                      = EE8367C0-A1D6-4565-8F89-EF628547B722\r
   MODULE_TYPE                    = UEFI_DRIVER\r
   VERSION_STRING                 = 1.0\r
+\r
   ENTRY_POINT                    = IpSecDriverEntryPoint\r
 \r
 #\r
   IpSecCryptIo.c\r
   IpSecDebug.h\r
   ComponentName.c\r
+  IkeCommon.h\r
   IpSecImpl.c\r
+  IkeService.c\r
+  Ike.h\r
+  IkePacket.h\r
+  IkePacket.c\r
   IpSecDebug.c\r
-  IpSecSaEngine.c\r
+  IpSecMain.c\r
   IpSecDriver.c\r
+  IkeCommon.c\r
+  IetfConstants.c\r
   IpSecImpl.h\r
+  IkeService.h\r
+  Ikev2/Ikev2.h\r
+  Ikev2/Payload.h\r
+  Ikev2/Utility.h\r
+  Ikev2/Utility.c\r
+  Ikev2/Sa.c\r
+  Ikev2/ChildSa.c\r
+  Ikev2/Info.c\r
+  Ikev2/Payload.c\r
+  Ikev2/Exchange.c\r
+  \r
+\r
 \r
 [Packages]\r
   MdePkg/MdePkg.dec\r
   MdeModulePkg/MdeModulePkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+  LocalNetworkPkg/LocalNetworkPkg.dec\r
 \r
 [LibraryClasses]\r
   MemoryAllocationLib\r
   BaseMemoryLib\r
   DebugLib\r
   PrintLib\r
+  #CryptLib\r
+  BaseCryptLib\r
   DpcLib\r
-  NetLib\r
-\r
+  UdpIoLib\r
+  NetLib  \r
+  PcdLib\r
+  \r
 [Protocols]\r
   gEfiIp4ConfigProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUdp4ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED  \r
+  gEfiUdp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUdp6ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED  \r
+  gEfiUdp6ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
   gEfiIpSecConfigProtocolGuid                   # PROTOCOL ALWAYS_PRODUCED\r
   gEfiIpSecProtocolGuid                         # PROTOCOL ALWAYS_PRODUCED\r
+  \r
+[Pcd]\r
+  gEfiNetworkPkgTokenSpaceGuid.PcdIpsecCertiifcateEnabled\r
+  gEfiMdeModulePkgTokenSpaceGuid.UefiCaFile\r
+  gEfiMdeModulePkgTokenSpaceGuid.UefiCaFileSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.UefiCertificate\r
+  gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateKey\r
+  gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateKeySize\r
+  \r
+[BuildOptions.common]\r
+#DEBUG_MYTOOLS_IA32_CC_FLAGS            = /Od /GL
\ No newline at end of file
index b693eb94d1cc44391bd78d4301f9958acf152788..7ccbfa25eea5f8bdc71c2601588e7e6df87506ac 100644 (file)
@@ -1,5 +1,5 @@
 /** @file\r
-  The implementation of IPsec Protocol\r
+  The implementation of IPsec.\r
 \r
   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
 \r
 \r
 **/\r
 \r
+#include "IpSecImpl.h"\r
+#include "IkeService.h"\r
+#include "IpSecDebug.h"\r
+#include "IpSecCryptIo.h"\r
 #include "IpSecConfigImpl.h"\r
 \r
-EFI_IPSEC2_PROTOCOL  mIpSecInstance = { IpSecProcess, NULL, TRUE };\r
-\r
-extern LIST_ENTRY   mConfigData[IPsecConfigDataTypeMaximum];\r
-\r
 /**\r
   Check if the specified Address is the Valid Address Range.\r
 \r
   This function checks if the bytes after prefixed length are all Zero in this\r
-  Address. This Address is supposed to point to a range address,  meaning it only\r
-  gives the correct prefixed address.\r
+  Address. This Address is supposed to point to a range address. That means it \r
+  should gives the correct prefixed address and the bytes outside the prefixed are\r
+  zero.\r
 \r
   @param[in]  IpVersion         The IP version.\r
   @param[in]  Address           Points to EFI_IP_ADDRESS to be checked.\r
@@ -208,7 +209,6 @@ IpSecMatchIpAddress (
       break;\r
     }\r
   }\r
-\r
   return IsMatch;\r
 }\r
 \r
@@ -315,6 +315,7 @@ IpSecMatchNextLayerProtocol (
 \r
   @param[in]  SadList           SAD list related to a specified SPD entry.\r
   @param[in]  DestAddress       The destination address used to find the SAD entry.\r
+  @param[in]  IpVersion         The IP version. Ip4 or Ip6.\r
 \r
   @return  The pointer to a certain SAD entry.\r
 \r
@@ -322,23 +323,25 @@ IpSecMatchNextLayerProtocol (
 IPSEC_SAD_ENTRY *\r
 IpSecLookupSadBySpd (\r
   IN LIST_ENTRY                 *SadList,\r
-  IN EFI_IP_ADDRESS             *DestAddress\r
+  IN EFI_IP_ADDRESS             *DestAddress,\r
+  IN UINT8                      IpVersion\r
   )\r
 {\r
   LIST_ENTRY      *Entry;\r
   IPSEC_SAD_ENTRY *SadEntry;\r
-\r
-  for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) {\r
+  \r
+  NET_LIST_FOR_EACH (Entry, SadList) {\r
 \r
     SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);\r
     //\r
-    // Find the right sad entry which contains the appointed dest address.\r
+    // Find the right SAD entry which contains the appointed dest address.\r
     //\r
-    if (CompareMem (\r
-          &SadEntry->Id->DestAddress,\r
+    if (IpSecMatchIpAddress (\r
+          IpVersion,\r
           DestAddress,\r
-          sizeof (EFI_IP_ADDRESS)\r
-          ) == 0) {\r
+          SadEntry->Data->SpdSelector->RemoteAddress,\r
+          SadEntry->Data->SpdSelector->RemoteAddressCount\r
+          )){    \r
       return SadEntry;\r
     }\r
   }\r
@@ -351,6 +354,7 @@ IpSecLookupSadBySpd (
 \r
   @param[in]  Spi               The SPI used to search the SAD entry.\r
   @param[in]  DestAddress       The destination used to search the SAD entry.\r
+  @param[in]  IpVersion         The IP version. Ip4 or Ip6.\r
 \r
   @return  the pointer to a certain SAD entry.\r
 \r
@@ -358,7 +362,8 @@ IpSecLookupSadBySpd (
 IPSEC_SAD_ENTRY *\r
 IpSecLookupSadBySpi (\r
   IN UINT32                   Spi,\r
-  IN EFI_IP_ADDRESS           *DestAddress\r
+  IN EFI_IP_ADDRESS           *DestAddress,\r
+  IN UINT8                    IpVersion\r
   )\r
 {\r
   LIST_ENTRY      *Entry;\r
@@ -367,22 +372,36 @@ IpSecLookupSadBySpi (
 \r
   SadList = &mConfigData[IPsecConfigDataTypeSad];\r
 \r
-  for (Entry = SadList->ForwardLink; Entry != SadList; Entry = Entry->ForwardLink) {\r
+  NET_LIST_FOR_EACH (Entry, SadList) {\r
 \r
     SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);\r
+\r
     //\r
-    // Find the right sad entry which contain the appointed spi and dest addr.\r
+    // Find the right SAD entry which contain the appointed spi and dest addr.\r
     //\r
-    if (SadEntry->Id->Spi == Spi && CompareMem (\r
-                                      &SadEntry->Id->DestAddress,\r
-                                      DestAddress,\r
-                                      sizeof (EFI_IP_ADDRESS)\r
-                                      ) == 0) {\r
-\r
-      return SadEntry;\r
+    if (SadEntry->Id->Spi == Spi) {\r
+      if (SadEntry->Data->Mode == EfiIPsecTunnel) {\r
+        if (CompareMem (\r
+              &DestAddress, \r
+              &SadEntry->Data->TunnelDestAddress,\r
+              sizeof (EFI_IP_ADDRESS)\r
+              )) {\r
+          return SadEntry;\r
+        }\r
+      } else {\r
+        if (SadEntry->Data->SpdSelector != NULL &&\r
+            IpSecMatchIpAddress (\r
+              IpVersion, \r
+              DestAddress, \r
+              SadEntry->Data->SpdSelector->RemoteAddress,\r
+              SadEntry->Data->SpdSelector->RemoteAddressCount\r
+              )\r
+            ) {\r
+          return SadEntry;\r
+        }       \r
+      }\r
     }\r
   }\r
-\r
   return NULL;\r
 }\r
 \r
@@ -407,7 +426,6 @@ IpSecLookupSadBySpi (
                             - If don't find related UDP service.\r
                             - Sequence Number is used up.\r
                             - Extension Sequence Number is used up.\r
-  @retval EFI_DEVICE_ERROR  GC_TODO: Add description for return value.\r
   @retval EFI_NOT_READY     No existing SAD entry could be used.\r
   @retval EFI_SUCCESS       Find the related SAD entry.\r
 \r
@@ -424,12 +442,18 @@ IpSecLookupSadEntry (
   OUT IPSEC_SAD_ENTRY        **SadEntry\r
   )\r
 {\r
+  IKE_UDP_SERVICE *UdpService;\r
   IPSEC_SAD_ENTRY *Entry;\r
   IPSEC_SAD_DATA  *Data;\r
   EFI_IP_ADDRESS  DestIp;\r
   UINT32          SeqNum32;\r
 \r
   *SadEntry   = NULL;\r
+  UdpService  = IkeLookupUdp (Private, NicHandle, IpVersion);\r
+\r
+  if (UdpService == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
   //\r
   // Parse the destination address from ip header.\r
   //\r
@@ -447,10 +471,11 @@ IpSecLookupSadEntry (
       sizeof (EFI_IP_ADDRESS)\r
       );\r
   }\r
+  \r
   //\r
-  // Find the sad entry in the spd.sas list according to the dest address.\r
+  // Find the SAD entry in the spd.sas list according to the dest address.\r
   //\r
-  Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp);\r
+  Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp, IpVersion);\r
 \r
   if (Entry == NULL) {\r
 \r
@@ -458,9 +483,22 @@ IpSecLookupSadEntry (
         (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST)\r
         ) {\r
       //\r
-      // TODO: Start ike negotiation process except the request packet of ping.\r
+      // Start ike negotiation process except the request packet of ping.\r
       //\r
-      //IkeNegotiate (UdpService, SpdEntry, &DestIp);\r
+      if (SpdEntry->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {\r
+        IkeNegotiate (\r
+          UdpService,\r
+          SpdEntry,\r
+          &SpdEntry->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress\r
+          );\r
+      } else {\r
+        IkeNegotiate (\r
+          UdpService,\r
+          SpdEntry,\r
+          &DestIp\r
+        );\r
+      }\r
+      \r
     }\r
 \r
     return EFI_NOT_READY;\r
@@ -473,7 +511,7 @@ IpSecLookupSadEntry (
       //\r
       // Validate the 64bit sn number if 64bit sn enabled.\r
       //\r
-      if (Data->SequenceNumber + 1 < Data->SequenceNumber) {\r
+      if ((UINT64) (Data->SequenceNumber + 1) == 0) {\r
         //\r
         // TODO: Re-negotiate SA\r
         //\r
@@ -484,7 +522,7 @@ IpSecLookupSadEntry (
       // Validate the 32bit sn number if 64bit sn disabled.\r
       //\r
       SeqNum32 = (UINT32) Data->SequenceNumber;\r
-      if (SeqNum32 + 1 < SeqNum32) {\r
+      if ((UINT32) (SeqNum32 + 1) == 0) {\r
         //\r
         // TODO: Re-negotiate SA\r
         //\r
@@ -544,19 +582,21 @@ IpSecLookupPadEntry (
   @param[in]  IpPayload         Point to IP payload.\r
   @param[in]  Protocol          The Last protocol of IP packet.\r
   @param[in]  IsOutbound        Traffic direction.\r
+  @param[out] Action            The support action of SPD entry.\r
 \r
-  @retval EFI_IPSEC_ACTION  The support action of SPD entry.\r
-  @retval -1                If the input packet header doesn't match the SpdEntry.\r
+  @retval EFI_SUCCESS       Find the related SPD.\r
+  @retval EFI_NOT_FOUND     Not find the related SPD entry;\r
 \r
 **/\r
-EFI_IPSEC_ACTION\r
+EFI_STATUS\r
 IpSecLookupSpdEntry (\r
-  IN IPSEC_SPD_ENTRY         *SpdEntry,\r
-  IN UINT8                   IpVersion,\r
-  IN VOID                    *IpHead,\r
-  IN UINT8                   *IpPayload,\r
-  IN UINT8                   Protocol,\r
-  IN BOOLEAN                 IsOutbound\r
+  IN     IPSEC_SPD_ENTRY         *SpdEntry,\r
+  IN     UINT8                   IpVersion,\r
+  IN     VOID                    *IpHead,\r
+  IN     UINT8                   *IpPayload,\r
+  IN     UINT8                   Protocol,\r
+  IN     BOOLEAN                 IsOutbound, \r
+     OUT EFI_IPSEC_ACTION        *Action\r
   )\r
 {\r
   EFI_IPSEC_SPD_SELECTOR  *SpdSel;\r
@@ -637,220 +677,1478 @@ IpSecLookupSpdEntry (
 \r
   if (SpdMatch) {\r
     //\r
-    // Find the right spd entry if match the 5 key elements.\r
+    // Find the right SPD entry if match the 5 key elements.\r
     //\r
-    return SpdEntry->Data->Action;\r
+    *Action = SpdEntry->Data->Action;\r
+    return EFI_SUCCESS;\r
   }\r
 \r
-  return (EFI_IPSEC_ACTION) - 1;\r
+  return EFI_NOT_FOUND;\r
 }\r
 \r
 /**\r
-  Handles IPsec packet processing for inbound and outbound IP packets.\r
-\r
-  The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.\r
-  The behavior is that it can perform one of the following actions:\r
-  bypass the packet, discard the packet, or protect the packet.\r
-\r
-  @param[in]      This             Pointer to the EFI_IPSEC_PROTOCOL instance.\r
-  @param[in]      NicHandle        Instance of the network interface.\r
-  @param[in]      IpVersion        IPV4 or IPV6.\r
-  @param[in, out] IpHead           Pointer to the IP Header.\r
-  @param[in, out] LastHead         The protocol of the next layer to be processed by IPsec.\r
-  @param[in, out] OptionsBuffer    Pointer to the options buffer.\r
-  @param[in, out] OptionsLength    Length of the options buffer.\r
-  @param[in, out] FragmentTable    Pointer to a list of fragments.\r
-  @param[in, out] FragmentCount    Number of fragments.\r
-  @param[in]      TrafficDirection Traffic direction.\r
-  @param[out]     RecycleSignal    Event for recycling of resources.\r
-\r
-  @retval EFI_SUCCESS              The packet was bypassed and all buffers remain the same.\r
-  @retval EFI_SUCCESS              The packet was protected.\r
-  @retval EFI_ACCESS_DENIED        The packet was discarded.\r
+  The call back function of NetbufFromExt.\r
+\r
+  @param[in]  Arg            The argument passed from the caller.\r
 \r
 **/\r
-EFI_STATUS\r
+VOID\r
 EFIAPI\r
-IpSecProcess (\r
-  IN     EFI_IPSEC2_PROTOCOL              *This,\r
-  IN     EFI_HANDLE                      NicHandle,\r
-  IN     UINT8                           IpVersion,\r
-  IN OUT VOID                            *IpHead,\r
-  IN OUT UINT8                           *LastHead,\r
-  IN OUT VOID                            **OptionsBuffer,\r
-  IN OUT UINT32                          *OptionsLength,\r
-  IN OUT EFI_IPSEC_FRAGMENT_DATA         **FragmentTable,\r
-  IN OUT UINT32                          *FragmentCount,\r
-  IN     EFI_IPSEC_TRAFFIC_DIR           TrafficDirection,\r
-     OUT EFI_EVENT                       *RecycleSignal\r
+IpSecOnRecyclePacket (\r
+  IN VOID                            *Arg\r
   )\r
 {\r
-  IPSEC_PRIVATE_DATA  *Private;\r
-  IPSEC_SPD_ENTRY     *SpdEntry;\r
-  IPSEC_SAD_ENTRY     *SadEntry;\r
-  LIST_ENTRY          *SpdList;\r
-  LIST_ENTRY          *Entry;\r
-  EFI_IPSEC_ACTION    Action;\r
-  EFI_STATUS          Status;\r
-  UINT8               *IpPayload;\r
-  UINT8               OldLastHead;\r
-  BOOLEAN             IsOutbound;\r
-\r
-  Private         = IPSEC_PRIVATE_DATA_FROM_IPSEC (This);\r
-  IpPayload       = (*FragmentTable)[0].FragmentBuffer;\r
-  IsOutbound      = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE);\r
-  OldLastHead     = *LastHead;\r
-  *RecycleSignal  = NULL;\r
-\r
-  if (!IsOutbound) {\r
-    //\r
-    // For inbound traffic, process the ipsec header of the packet.\r
-    //\r
-    Status = IpSecProtectInboundPacket (\r
-              IpVersion,\r
-              IpHead,\r
-              LastHead,\r
-              OptionsBuffer,\r
-              OptionsLength,\r
-              FragmentTable,\r
-              FragmentCount,\r
-              &SpdEntry,\r
-              RecycleSignal\r
-              );\r
+}\r
+\r
+/**\r
+  This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP\r
+  is released.\r
+\r
+  @param[in]  Event              The related event.\r
+  @param[in]  Context            The data passed by the caller.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IpSecRecycleCallback (\r
+  IN EFI_EVENT                       Event,\r
+  IN VOID                            *Context\r
+  )\r
+{\r
+  IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
+\r
+  RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context;\r
+\r
+  if (RecycleContext->FragmentTable != NULL) {\r
+    FreePool (RecycleContext->FragmentTable);\r
+  }\r
+\r
+  if (RecycleContext->PayloadBuffer != NULL) {\r
+    FreePool (RecycleContext->PayloadBuffer);\r
+  }\r
+\r
+  FreePool (RecycleContext);\r
+  gBS->CloseEvent (Event);\r
+\r
+}\r
+\r
+/**\r
+  Calculate the extension hader of IP. The return length only doesn't contain \r
+  the fixed IP header length.\r
+\r
+  @param[in]  IpHead             Points to an IP head to be calculated.\r
+  @param[in]  LastHead           Points to the last header of the IP header.\r
+\r
+  @return The length of the extension header.\r
+\r
+**/\r
+UINT16\r
+IpSecGetPlainExtHeadSize (\r
+  IN VOID                             *IpHead,\r
+  IN UINT8                            *LastHead\r
+  )\r
+{\r
+  UINT16  Size;\r
+\r
+  Size = (UINT16) (LastHead - (UINT8 *) IpHead);\r
+\r
+  if (Size > sizeof (EFI_IP6_HEADER)) {\r
+    //\r
+    // * (LastHead+1) point the last header's length but not include the first\r
+    // 8 octers, so this formluation add 8 at the end.\r
+    //\r
+    Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);\r
+  } else {\r
+    Size = 0;\r
+  }\r
+\r
+  return Size;\r
+}\r
+\r
+/**\r
+  Verify if the Authentication payload is correct.\r
+\r
+  @param[in]  EspBuffer          Points to the ESP wrapped buffer.\r
+  @param[in]  EspSize            The size of the ESP wrapped buffer.\r
+  @param[in]  SadEntry           The related SAD entry to store the authentication\r
+                                 algorithm key.\r
+  @param[in]  IcvSize            The length of ICV.\r
+\r
+  @retval EFI_SUCCESS        The authentication data is correct.\r
+  @retval EFI_ACCESS_DENIED  The authentication data is not correct.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecEspAuthVerifyPayload (\r
+  IN UINT8                           *EspBuffer,\r
+  IN UINTN                           EspSize,\r
+  IN IPSEC_SAD_ENTRY                 *SadEntry,\r
+  IN UINTN                           *IcvSize\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+  UINTN                AuthSize;\r
+  UINT8                IcvBuffer[12];\r
+  HASH_DATA_FRAGMENT   HashFragment[1];\r
+\r
+  //\r
+  // Calculate the size of authentication payload.\r
+  //\r
+  *IcvSize  = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);\r
+  AuthSize  = EspSize - *IcvSize;\r
+\r
+  //\r
+  // Calculate the icv buffer and size of the payload.\r
+  //\r
+  HashFragment[0].Data     = EspBuffer;\r
+  HashFragment[0].DataSize = AuthSize;\r
+  \r
+  Status = IpSecCryptoIoHmac (\r
+             SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,\r
+             SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r
+             SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,\r
+             HashFragment,\r
+             1,\r
+             IcvBuffer,\r
+             *IcvSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Compare the calculated icv and the appended original icv.\r
+  //\r
+  if (CompareMem (EspBuffer + AuthSize, IcvBuffer, *IcvSize) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));\r
+  return EFI_ACCESS_DENIED;\r
+}\r
+\r
+/**\r
+  Search the related SAD entry by the input .\r
+\r
+  @param[in]  IpHead       The pointer to IP header.\r
+  @param[in]  IpVersion    The version of IP (IP4 or IP6).\r
+  @param[in]  Spi          The SPI used to search the related SAD entry.\r
+  \r
+\r
+  @retval     NULL             Not find the related SAD entry.\r
+  @retval     IPSEC_SAD_ENTRY  Return the related SAD entry. \r
+\r
+**/\r
+IPSEC_SAD_ENTRY *\r
+IpSecFoundSadFromInboundPacket (\r
+   UINT8   *IpHead,\r
+   UINT8   IpVersion,\r
+   UINT32  Spi\r
+   ) \r
+{\r
+  EFI_IP_ADDRESS   DestIp;\r
+   \r
+  //\r
+  // Parse destination address from ip header.\r
+  //\r
+  ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));\r
+  if (IpVersion == IP_VERSION_4) {\r
+    CopyMem (\r
+      &DestIp,\r
+      &((IP4_HEAD *) IpHead)->Dst,\r
+      sizeof (IP4_ADDR)\r
+      );\r
+  } else {\r
+    CopyMem (\r
+      &DestIp,\r
+      &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,\r
+      sizeof (EFI_IPv6_ADDRESS)\r
+      );\r
+  }\r
+  \r
+  //\r
+  // Lookup SAD entry according to the spi and dest address.\r
+  //  \r
+  return IpSecLookupSadBySpi (Spi, &DestIp, IpVersion);\r
+}\r
+\r
+/**\r
+  Validate the IP6 extension header format for both the packets we received\r
+  and that we will transmit.\r
+\r
+  @param[in]  NextHeader    The next header field in IPv6 basic header.\r
+  @param[in]  ExtHdrs       The first bye of the option.\r
+  @param[in]  ExtHdrsLen    The length of the whole option.\r
+  @param[out] LastHeader    The pointer of NextHeader of the last extension\r
+                            header processed by IP6.\r
+  @param[out] RealExtsLen   The length of extension headers processed by IP6 layer.\r
+                            This is an optional parameter that may be NULL.\r
+\r
+  @retval     TRUE          The option is properly formated.\r
+  @retval     FALSE         The option is malformated.\r
+\r
+**/\r
+BOOLEAN\r
+IpSecIsIp6ExtsValid (\r
+  IN UINT8                  *NextHeader,\r
+  IN UINT8                  *ExtHdrs,\r
+  IN UINT32                 ExtHdrsLen,\r
+  OUT UINT8                 **LastHeader,\r
+  OUT UINT32                *RealExtsLen    OPTIONAL\r
+  )\r
+{\r
+  UINT32                     Pointer;\r
+  UINT8                      *Option;\r
+  UINT8                      OptionLen;\r
+  BOOLEAN                    Flag;\r
+  UINT8                      CountD;\r
+  UINT8                      CountF;\r
+  UINT8                      CountA;\r
+\r
+  if (RealExtsLen != NULL) {\r
+    *RealExtsLen = 0;\r
+  }\r
+\r
+  *LastHeader = NextHeader;\r
 \r
-    if (Status == EFI_ACCESS_DENIED) {\r
+  if (ExtHdrs == NULL && ExtHdrsLen == 0) {\r
+    return TRUE;\r
+  }\r
+\r
+  if ((ExtHdrs == NULL && ExtHdrsLen != 0) || (ExtHdrs != NULL && ExtHdrsLen == 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Pointer = 0;\r
+  Flag    = FALSE;\r
+  CountD  = 0;\r
+  CountF  = 0;\r
+  CountA  = 0;\r
+\r
+  while (Pointer <= ExtHdrsLen) {\r
+\r
+    switch (*NextHeader) {\r
+    case IP6_HOP_BY_HOP:\r
+      if (Pointer != 0) {\r
+        return FALSE;\r
+      }\r
+\r
+      Flag = TRUE;\r
+\r
+    //\r
+    // Fall through\r
+    //\r
+    case IP6_DESTINATION:\r
+      if (*NextHeader == IP6_DESTINATION) {\r
+        CountD++;\r
+      }\r
+\r
+      if (CountD > 2) {\r
+        return FALSE;\r
+      }\r
+\r
+      NextHeader = ExtHdrs + Pointer;\r
+\r
+      Pointer++;\r
+      Option     = ExtHdrs + Pointer;\r
+      OptionLen  = (UINT8) ((*Option + 1) * 8 - 2);\r
+      Option++;\r
+      Pointer++;\r
+\r
+      Pointer = Pointer + OptionLen;\r
+      break;\r
+\r
+    case IP6_FRAGMENT:\r
+      if (++CountF > 1) {\r
+        return FALSE;\r
+      }\r
       //\r
-      // The packet is denied to access.\r
+      // RFC2402, AH header should after fragment header.\r
       //\r
-      goto ON_EXIT;\r
-    }\r
+      if (CountA > 1) {\r
+        return FALSE;\r
+      }\r
+\r
+      NextHeader = ExtHdrs + Pointer;\r
+      Pointer    = Pointer + 8;\r
+      break;\r
 \r
-    if (Status == EFI_SUCCESS) {\r
+    case IP6_AH:\r
+      if (++CountA > 1) {\r
+        return FALSE;\r
+      }\r
+\r
+      Option     = ExtHdrs + Pointer;\r
+      NextHeader = Option;\r
+      Option++;\r
       //\r
-      // Check the spd entry if the packet is accessible.\r
+      // RFC2402, Payload length is specified in 32-bit words, minus "2".\r
       //\r
-      if (SpdEntry == NULL) {\r
-        Status = EFI_ACCESS_DENIED;\r
-        goto ON_EXIT;\r
+      OptionLen  = (UINT8) ((*Option + 2) * 4);\r
+      Pointer    = Pointer + OptionLen;\r
+      break;\r
+\r
+    default:\r
+      *LastHeader = NextHeader;\r
+       if (RealExtsLen != NULL) {\r
+         *RealExtsLen = Pointer;\r
+       }\r
+\r
+       return TRUE;\r
+    }   \r
+  }\r
+\r
+  *LastHeader = NextHeader;\r
+\r
+  if (RealExtsLen != NULL) {\r
+    *RealExtsLen = Pointer;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  The actual entry to process the tunnel header and inner header for tunnel mode \r
+  outbound traffic.\r
+\r
+  This function is the subfunction of IpSecEspInboundPacket(). It change the destination \r
+  Ip address to the station address and recalculate the uplayyer's checksum.\r
+  \r
+\r
+  @param[in, out] IpHead             Points to the IP header containing the ESP header \r
+                                     to be trimed on input, and without ESP header\r
+                                     on return.\r
+  @param[in]      IpPayload          The decrypted Ip payload. It start from the inner\r
+                                     header.\r
+  @param[in]      IpVersion          The version of IP.\r
+  @param[in]      SadData            Pointer of the relevant SAD.\r
+  @param[in, out] LastHead           The Last Header in IP header on return.\r
+\r
+**/\r
+VOID\r
+IpSecTunnelInboundPacket (\r
+  IN OUT UINT8           *IpHead,\r
+  IN     UINT8           *IpPayload,\r
+  IN     UINT8           IpVersion,\r
+  IN     IPSEC_SAD_DATA  *SadData,\r
+  IN OUT UINT8           *LastHead\r
+  )\r
+{\r
+  EFI_UDP_HEADER   *UdpHeader;\r
+  TCP_HEAD         *TcpHeader;\r
+  UINT16            *Checksum;\r
+  UINT16           PseudoChecksum;\r
+  UINT16           PacketChecksum;\r
+  UINT32           OptionLen;\r
+  IP6_ICMP_HEAD    *Icmp6Head;\r
+\r
+  Checksum = NULL;\r
+  \r
+  if (IpVersion == IP_VERSION_4) {\r
+    //\r
+    // Zero OutIP header use this to indicate the input packet is under \r
+    // IPsec Tunnel protected.\r
+    //\r
+    ZeroMem (\r
+      (IP4_HEAD *)IpHead,\r
+      sizeof (IP4_HEAD)\r
+      );\r
+    CopyMem (\r
+      &((IP4_HEAD *)IpPayload)->Dst,\r
+      &SadData->TunnelDestAddress.v4,\r
+      sizeof (EFI_IPv4_ADDRESS)\r
+      );\r
+      \r
+    //\r
+    // Recalculate IpHeader Checksum\r
+    //\r
+    if (((IP4_HEAD *)(IpPayload))->Checksum != 0 ) {\r
+      ((IP4_HEAD *)(IpPayload))->Checksum = 0;\r
+      ((IP4_HEAD *)(IpPayload))->Checksum = (UINT16) (~NetblockChecksum (\r
+                                                        (UINT8 *)IpPayload, \r
+                                                        ((IP4_HEAD *)IpPayload)->HeadLen << 2\r
+                                                        ));\r
+\r
+\r
+    }\r
+    \r
+    //\r
+    // Recalcualte PseudoChecksum\r
+    //\r
+    switch (((IP4_HEAD *)IpPayload)->Protocol) {\r
+    case EFI_IP_PROTO_UDP :\r
+      UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));\r
+      Checksum  = & UdpHeader->Checksum;\r
+      *Checksum = 0;\r
+      break;\r
+\r
+    case EFI_IP_PROTO_TCP:\r
+      TcpHeader = (TCP_HEAD *) ((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));\r
+      Checksum  = &TcpHeader->Checksum;\r
+      *Checksum = 0;\r
+      break;\r
+\r
+    default:\r
+      break;\r
       }\r
-      Action = IpSecLookupSpdEntry (\r
-                SpdEntry,\r
-                IpVersion,\r
-                IpHead,\r
-                IpPayload,\r
-                *LastHead,\r
-                IsOutbound\r
-                );\r
-\r
-      if (Action != EfiIPsecActionProtect) {\r
-        //\r
-        // Discard the packet if the spd entry is not protect.\r
-        //\r
-        gBS->SignalEvent (*RecycleSignal);\r
-        *RecycleSignal  = NULL;\r
-        Status          = EFI_ACCESS_DENIED;\r
+    PacketChecksum = NetblockChecksum (\r
+                       (UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2), \r
+                       NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)\r
+                       );\r
+    PseudoChecksum = NetPseudoHeadChecksum (\r
+                       ((IP4_HEAD *)IpPayload)->Src,\r
+                       ((IP4_HEAD *)IpPayload)->Dst,\r
+                       ((IP4_HEAD *)IpPayload)->Protocol,\r
+                       0\r
+                       );\r
+      \r
+      if (Checksum != NULL) {\r
+        *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);\r
+        *Checksum = (UINT16) ~(NetAddChecksum (*Checksum, HTONS((UINT16)(NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)))));\r
       }\r
+    }else {\r
+      //\r
+      //  Zero OutIP header use this to indicate the input packet is under \r
+      //  IPsec Tunnel protected.\r
+      //\r
+      ZeroMem (\r
+        IpHead,\r
+        sizeof (EFI_IP6_HEADER)\r
+        );\r
+      CopyMem (\r
+        &((EFI_IP6_HEADER*)IpPayload)->DestinationAddress,\r
+        &SadData->TunnelDestAddress.v6,\r
+        sizeof (EFI_IPv6_ADDRESS)\r
+        );\r
+      \r
+      //\r
+      // Get the Extension Header and Header length.\r
+      //\r
+      IpSecIsIp6ExtsValid (\r
+        &((EFI_IP6_HEADER *)IpPayload)->NextHeader,\r
+        IpPayload + sizeof (EFI_IP6_HEADER),\r
+        ((EFI_IP6_HEADER *)IpPayload)->PayloadLength,\r
+        &LastHead,\r
+        &OptionLen\r
+        );\r
+      \r
+      //\r
+      // Recalcualte PseudoChecksum\r
+      //\r
+      switch (*LastHead) {\r
+      case EFI_IP_PROTO_UDP:\r
+        UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);\r
+        Checksum  = &UdpHeader->Checksum;\r
+        *Checksum = 0;\r
+        break;\r
 \r
-      goto ON_EXIT;\r
+      case EFI_IP_PROTO_TCP:\r
+        TcpHeader = (TCP_HEAD *)(IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);\r
+        Checksum  = &TcpHeader->Checksum;\r
+        *Checksum = 0;\r
+        break;\r
+\r
+      case IP6_ICMP:\r
+        Icmp6Head  = (IP6_ICMP_HEAD *) (IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);\r
+        Checksum   = &Icmp6Head->Checksum;\r
+        *Checksum  = 0;\r
+        break;\r
+      }\r
+      PacketChecksum = NetblockChecksum (\r
+                         IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen, \r
+                         NTOHS(((EFI_IP6_HEADER *)IpPayload)->PayloadLength) - OptionLen\r
+                         );\r
+      PseudoChecksum = NetIp6PseudoHeadChecksum (\r
+                         &((EFI_IP6_HEADER *)IpPayload)->SourceAddress,\r
+                         &((EFI_IP6_HEADER *)IpPayload)->DestinationAddress,\r
+                         *LastHead,\r
+                         0\r
+                         );\r
+    \r
+    if (Checksum != NULL) {\r
+      *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);\r
+      *Checksum = (UINT16) ~(NetAddChecksum (\r
+                               *Checksum,\r
+                               HTONS ((UINT16)((NTOHS (((EFI_IP6_HEADER *)(IpPayload))->PayloadLength)) - OptionLen))\r
+                               ));\r
     }\r
+  }    \r
+}\r
+\r
+/**\r
+  The actual entry to create inner header for tunnel mode inbound traffic.\r
+\r
+  This function is the subfunction of IpSecEspOutboundPacket(). It create \r
+  the sending packet by encrypting its payload and inserting ESP header in the orginal \r
+  IP header, then return the IpHeader and IPsec protected Fragmentable.\r
+  \r
+  @param[in, out] IpHead             Points to IP header containing the orginal IP header \r
+                                     to be processed on input, and inserted ESP header\r
+                                     on return.\r
+  @param[in]      IpVersion          The version of IP.\r
+  @param[in]      SadData            The related SAD data.\r
+  @param[in, out] LastHead           The Last Header in IP header.  \r
+  @param[in]      OptionsBuffer      Pointer to the options buffer. It is optional.\r
+  @param[in]      OptionsLength      Length of the options buffer. It is optional.\r
+  @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by\r
+                                     IPsec on input, and with IPsec protected\r
+                                     on return.\r
+  @param[in]      FragmentCount      The number of fragments.\r
+\r
+  @retval EFI_SUCCESS              The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES     The required system resources can't be allocated.\r
+\r
+**/\r
+UINT8 *\r
+IpSecTunnelOutboundPacket (\r
+  IN OUT UINT8                   *IpHead,\r
+  IN     UINT8                   IpVersion,\r
+  IN     IPSEC_SAD_DATA          *SadData,\r
+  IN OUT UINT8                   *LastHead,\r
+  IN     VOID                    **OptionsBuffer,\r
+  IN     UINT32                  *OptionsLength,\r
+  IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,\r
+  IN     UINT32                  *FragmentCount\r
+  )\r
+{\r
+  UINT8         *InnerHead;\r
+  NET_BUF       *Packet;\r
+  UINT16        PacketChecksum;\r
+  UINT16        *Checksum;\r
+  UINT16        PseudoChecksum;\r
+  IP6_ICMP_HEAD *IcmpHead;\r
+\r
+  Checksum = NULL;\r
+  if (OptionsLength == NULL) {\r
+    return NULL;\r
   }\r
+  \r
+  if (IpVersion == IP_VERSION_4) {\r
+    InnerHead = AllocateZeroPool (sizeof (IP4_HEAD) + *OptionsLength);\r
+    ASSERT (InnerHead != NULL);\r
+    CopyMem (\r
+      InnerHead,\r
+      IpHead,\r
+      sizeof (IP4_HEAD)\r
+      );\r
+    CopyMem (\r
+      InnerHead + sizeof (IP4_HEAD),\r
+      *OptionsBuffer,\r
+      *OptionsLength\r
+      );\r
+  } else {\r
+    InnerHead = AllocateZeroPool (sizeof (EFI_IP6_HEADER) + *OptionsLength);\r
+    CopyMem (\r
+      InnerHead,\r
+      IpHead,\r
+      sizeof (EFI_IP6_HEADER)\r
+      );\r
+    CopyMem (\r
+      InnerHead + sizeof (EFI_IP6_HEADER),\r
+      *OptionsBuffer,\r
+      *OptionsLength\r
+      );\r
+  }\r
+  if (OptionsBuffer != NULL) {\r
+    if (*OptionsLength != 0) {\r
 \r
-  Status  = EFI_ACCESS_DENIED;\r
-  SpdList = &mConfigData[IPsecConfigDataTypeSpd];\r
+      *OptionsBuffer = NULL;\r
+      *OptionsLength = 0;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // 2. Reassamlbe Fragment into Packet\r
+  //\r
+  Packet = NetbufFromExt (\r
+             (NET_FRAGMENT *)(*FragmentTable),\r
+             *FragmentCount,\r
+             0,\r
+             0,\r
+             IpSecOnRecyclePacket,\r
+             NULL\r
+             );\r
+  ASSERT (Packet != NULL);\r
+  //\r
+  // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo\r
+  //    CheckSum.\r
+  //\r
+  switch (*LastHead) {\r
+  case EFI_IP_PROTO_UDP:\r
+    Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, 0);\r
+    ASSERT (Packet->Udp != NULL);\r
+    Checksum = &Packet->Udp->Checksum;\r
+    *Checksum = 0;\r
+    break;\r
+\r
+  case EFI_IP_PROTO_TCP:\r
+    Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, 0);\r
+    ASSERT (Packet->Tcp != NULL);\r
+    Checksum = &Packet->Tcp->Checksum;\r
+    *Checksum = 0;\r
+    break;\r
+\r
+  case IP6_ICMP:\r
+    IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);\r
+    ASSERT (IcmpHead != NULL);\r
+    Checksum = &IcmpHead->Checksum;\r
+    *Checksum = 0;\r
+    break;\r
+  \r
+  default: \r
+    break;\r
+  }\r
 \r
-  for (Entry = SpdList->ForwardLink; Entry != SpdList; Entry = Entry->ForwardLink) {\r
+  PacketChecksum = NetbufChecksum (Packet);\r
+    \r
+  if (IpVersion == IP_VERSION_4) {\r
     //\r
-    // For outbound and non-ipsec Inbound traffic: check the spd entry.\r
+    // Replace the source address of Inner Header.\r
     //\r
-    SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
-    Action = IpSecLookupSpdEntry (\r
-              SpdEntry,\r
-              IpVersion,\r
-              IpHead,\r
-              IpPayload,\r
-              OldLastHead,\r
-              IsOutbound\r
+    CopyMem (\r
+      &((IP4_HEAD *)InnerHead)->Src,\r
+      &SadData->SpdSelector->LocalAddress[0].Address.v4,\r
+      sizeof (EFI_IPv4_ADDRESS)\r
+      );\r
+\r
+    PacketChecksum = NetbufChecksum (Packet);\r
+    PseudoChecksum = NetPseudoHeadChecksum (\r
+                       ((IP4_HEAD *)InnerHead)->Src,\r
+                       ((IP4_HEAD *)InnerHead)->Dst,\r
+                       *LastHead,\r
+                       0\r
+                       );\r
+    \r
+   } else {\r
+     //\r
+     // Replace the source address of Inner Header.\r
+     //\r
+     CopyMem (\r
+       &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,\r
+       &(SadData->SpdSelector->LocalAddress[0].Address.v6),\r
+       sizeof (EFI_IPv6_ADDRESS)\r
+       );\r
+     PacketChecksum = NetbufChecksum (Packet);\r
+     PseudoChecksum = NetIp6PseudoHeadChecksum (\r
+                      &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,\r
+                      &((EFI_IP6_HEADER *)InnerHead)->DestinationAddress,\r
+                      *LastHead,\r
+                      0\r
+                      );\r
+   \r
+   }\r
+   if (Checksum != NULL) {\r
+     *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);\r
+     *Checksum = (UINT16) ~(NetAddChecksum ((UINT16)*Checksum, HTONS ((UINT16) Packet->TotalSize)));\r
+   }\r
+\r
+  if (Packet != NULL) {\r
+    NetbufFree (Packet);\r
+  }\r
+  return InnerHead;\r
+}\r
+\r
+/**\r
+  The actual entry to relative function processes the inbound traffic of ESP header.\r
+\r
+  This function is the subfunction of IpSecProtectInboundPacket(). It checks the \r
+  received packet security property and trim the ESP header and then returns without\r
+  an IPsec protected IP Header and FramgmentTable.\r
+  \r
+  @param[in]      IpVersion          The version of IP.\r
+  @param[in, out] IpHead             Points to the IP header containing the ESP header \r
+                                     to be trimed on input, and without ESP header\r
+                                     on return.\r
+  @param[out]     LastHead           The Last Header in IP header on return.\r
+  @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
+  @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
+  @param[in, out] FragmentTable      Pointer to a list of fragments in the form of IPsec\r
+                                     protected on input, and without IPsec protected\r
+                                     on return.\r
+  @param[in, out] FragmentCount      The number of fragments.\r
+  @param[out]     SpdSelector        Pointer to contain the address of SPD selector on return.\r
+  @param[out]     RecycleEvent       The event for recycling of resources.\r
+\r
+  @retval EFI_SUCCESS              The operation was successful.\r
+  @retval EFI_ACCESS_DENIED        One or more following conditions is TRUE:\r
+                                   - ESP header was not found.\r
+                                   - The related SAD entry was not found.\r
+                                   - The related SAD entry does not support the ESP protocol.\r
+  @retval EFI_OUT_OF_RESOURCES     The required system resource can't be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecEspInboundPacket (\r
+  IN     UINT8                       IpVersion,\r
+  IN OUT VOID                        *IpHead,\r
+     OUT UINT8                       *LastHead,\r
+  IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
+  IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
+  IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
+  IN OUT UINT32                      *FragmentCount,\r
+     OUT EFI_IPSEC_SPD_SELECTOR      **SpdSelector,\r
+     OUT EFI_EVENT                   *RecycleEvent\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  NET_BUF               *Payload;\r
+  UINTN                 EspSize;\r
+  UINTN                 IvSize;\r
+  UINTN                 PlainPayloadSize;\r
+  UINTN                 PaddingSize;\r
+  UINTN                 IcvSize;\r
+  UINT8                 *ProcessBuffer;\r
+  EFI_ESP_HEADER        *EspHeader;\r
+  EFI_ESP_TAIL          *EspTail;\r
+  EFI_IPSEC_SA_ID       *SaId;\r
+  IPSEC_SAD_DATA        *SadData;\r
+  IPSEC_SAD_ENTRY       *SadEntry;\r
+  IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
+  UINT8                 NextHeader;\r
+  UINT16                IpSecHeadSize;\r
+  UINT8                 *InnerHead;\r
+\r
+  Status            = EFI_SUCCESS;\r
+  Payload           = NULL;\r
+  ProcessBuffer     = NULL;\r
+  RecycleContext    = NULL;\r
+  *RecycleEvent     = NULL;\r
+  PlainPayloadSize  = 0;\r
+  NextHeader        = 0;\r
+  \r
+  //\r
+  // Build netbuf from fragment table first.\r
+  //\r
+  Payload = NetbufFromExt (\r
+              (NET_FRAGMENT *) *FragmentTable,\r
+              *FragmentCount,\r
+              0,\r
+              sizeof (EFI_ESP_HEADER),\r
+              IpSecOnRecyclePacket,\r
+              NULL\r
               );\r
+  if (Payload == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // Get the esp size and esp header from netbuf.\r
+  //\r
+  EspSize   = Payload->TotalSize;\r
+  EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);\r
+  \r
+  if (EspHeader == NULL) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // Parse destination address from ip header and found the related SAD Entry.\r
+  //\r
+  SadEntry = IpSecFoundSadFromInboundPacket (\r
+               IpHead, \r
+               IpVersion,\r
+               NTOHL (EspHeader->Spi)\r
+               );\r
+  \r
+  if (SadEntry == NULL) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_EXIT;\r
+  }\r
 \r
-    switch (Action) {\r
+  SaId    = SadEntry->Id;\r
+  SadData = SadEntry->Data;\r
 \r
-    case EfiIPsecActionProtect:\r
+  //\r
+  // Only support esp protocol currently.\r
+  //\r
+  if (SaId->Proto != EfiIPsecESP) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto ON_EXIT;\r
+  }\r
 \r
-      if (IsOutbound) {\r
-        //\r
-        // For outbound traffic, lookup the sad entry.\r
-        //\r
-        Status = IpSecLookupSadEntry (\r
-                  Private,\r
-                  NicHandle,\r
-                  IpVersion,\r
+  if (!SadData->ManualSet) {\r
+    //\r
+    // TODO: Check SA lifetime and sequence number\r
+    //\r
+  }\r
+    \r
+  //\r
+  // Allocate buffer for decryption and authentication.\r
+  //\r
+  ProcessBuffer = AllocateZeroPool (EspSize);\r
+  if (ProcessBuffer == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);\r
+\r
+  //\r
+  // Authenticate the esp wrapped buffer by the auth keys which is from SAD entry.\r
+  //\r
+  IcvSize = 0;\r
+  if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
+    Status = IpSecEspAuthVerifyPayload (\r
+               ProcessBuffer,\r
+               EspSize,\r
+               SadEntry,\r
+               &IcvSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+  //\r
+  // Decrypt the payload by the SAD entry if it has decrypt key.\r
+  //\r
+  IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
+  if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
+    Status = IpSecCryptoIoDecrypt (\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,\r
+               ProcessBuffer + sizeof (EFI_ESP_HEADER),\r
+               ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize,\r
+               EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize,\r
+               ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Parse EspTail and compute the plain payload size.\r
+  //\r
+  EspTail           = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));\r
+  PaddingSize       = EspTail->PaddingLength;\r
+  NextHeader        = EspTail->NextHeader;\r
+  PlainPayloadSize  = EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize - sizeof (EFI_ESP_TAIL) - PaddingSize;\r
+  \r
+  //\r
+  // TODO: handle anti-replay window\r
+  //\r
+  //\r
+  // Decryption and authentication with esp has been done, so it's time to\r
+  // reload the new packet, create recycle event and fixup ip header.\r
+  //\r
+  RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));\r
+  if (RecycleContext == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  IpSecRecycleCallback,\r
+                  RecycleContext,\r
+                  RecycleEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  \r
+  //\r
+  // The caller will take responsible to handle the original fragment table\r
+  //\r
+  *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));\r
+  if (*FragmentTable == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  RecycleContext->PayloadBuffer       = ProcessBuffer;\r
+  RecycleContext->FragmentTable       = *FragmentTable;\r
+  \r
+  //\r
+  // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out\r
+  //\r
+  if (SadData->Mode == EfiIPsecTunnel) {\r
+    InnerHead = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;\r
+    IpSecTunnelInboundPacket (\r
+      IpHead,\r
+      InnerHead,\r
+      IpVersion,\r
+      SadData,\r
+      LastHead\r
+      );\r
+    \r
+    if (IpVersion == IP_VERSION_4) {\r
+      (*FragmentTable)[0].FragmentBuffer  = InnerHead ;\r
+      (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;\r
+      \r
+    }else {      \r
+      (*FragmentTable)[0].FragmentBuffer  = InnerHead;\r
+      (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;\r
+    }    \r
+  } else {\r
+    (*FragmentTable)[0].FragmentBuffer  = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;\r
+    (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;\r
+  }\r
+  \r
+  *FragmentCount                      = 1;\r
+\r
+  //\r
+  // Update the total length field in ip header since processed by esp.\r
+  //\r
+  if (!SadData->Mode == EfiIPsecTunnel) {\r
+    if (IpVersion == IP_VERSION_4) {\r
+      ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + PlainPayloadSize));\r
+    } else {\r
+      IpSecHeadSize                              = IpSecGetPlainExtHeadSize (IpHead, LastHead);\r
+      ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));\r
+    }\r
+    //\r
+    // Update the next layer field in ip header since esp header inserted.\r
+    //\r
+    *LastHead = NextHeader;\r
+  }\r
+  \r
+\r
+  //\r
+  // Update the SPD association of the SAD entry.\r
+  //\r
+  *SpdSelector = SadData->SpdSelector;\r
+\r
+ON_EXIT:\r
+  if (Payload != NULL) {\r
+    NetbufFree (Payload);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (ProcessBuffer != NULL) {\r
+      FreePool (ProcessBuffer);\r
+    }\r
+\r
+    if (RecycleContext != NULL) {\r
+      FreePool (RecycleContext);\r
+    }\r
+\r
+    if (*RecycleEvent != NULL) {\r
+      gBS->CloseEvent (*RecycleEvent);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The actual entry to the relative function processes the output traffic using the ESP protocol.\r
+\r
+  This function is the subfunction of IpSecProtectOutboundPacket(). It protected\r
+  the sending packet by encrypting its payload and inserting ESP header in the orginal\r
+  IP header, then return the IpHeader and IPsec protected Fragmentable.\r
+\r
+  @param[in]      IpVersion          The version of IP.\r
+  @param[in, out] IpHead             Points to IP header containing the orginal IP header\r
+                                     to be processed on input, and inserted ESP header\r
+                                     on return.\r
+  @param[in, out] LastHead           The Last Header in IP header.\r
+  @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
+  @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
+  @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by\r
+                                     IPsec on input, and with IPsec protected\r
+                                     on return.\r
+  @param[in, out] FragmentCount      The number of fragments.\r
+  @param[in]      SadEntry           The related SAD entry.\r
+  @param[out]     RecycleEvent       The event for recycling of resources.\r
+\r
+  @retval EFI_SUCCESS              The operation was successful.\r
+  @retval EFI_OUT_OF_RESOURCES     The required system resources can't be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecEspOutboundPacket (\r
+  IN UINT8                           IpVersion,\r
+  IN OUT VOID                        *IpHead,\r
+  IN OUT UINT8                       *LastHead,\r
+  IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
+  IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
+  IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
+  IN OUT UINT32                      *FragmentCount,\r
+  IN     IPSEC_SAD_ENTRY             *SadEntry,\r
+     OUT EFI_EVENT                   *RecycleEvent\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 Index;\r
+  EFI_IPSEC_SA_ID       *SaId;\r
+  IPSEC_SAD_DATA        *SadData;\r
+  IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
+  UINT8                 *ProcessBuffer;\r
+  UINTN                 BytesCopied;\r
+  INTN                  EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4\r
+  UINTN                 EspSize;         // Total size of esp wrapped ip payload\r
+  UINTN                 IvSize;          // Size of IV, optional, might be 0\r
+  UINTN                 PlainPayloadSize;// Original IP payload size\r
+  UINTN                 PaddingSize;     // Size of padding\r
+  UINTN                 EncryptSize;     // Size of data to be encrypted, start after IV and\r
+                                         // stop before ICV\r
+  UINTN                 IcvSize;         // Size of ICV, optional, might be 0\r
+  UINT8                 *RestOfPayload;  // Start of Payload after IV\r
+  UINT8                 *Padding;        // Start address of padding\r
+  EFI_ESP_HEADER        *EspHeader;      // Start address of ESP frame\r
+  EFI_ESP_TAIL          *EspTail;        // Address behind padding\r
+  UINT8                 *InnerHead;\r
+  HASH_DATA_FRAGMENT    HashFragment[1];\r
+  \r
+  Status          = EFI_ACCESS_DENIED;\r
+  SaId            = SadEntry->Id;\r
+  SadData         = SadEntry->Data;\r
+  ProcessBuffer   = NULL;\r
+  RecycleContext  = NULL;\r
+  *RecycleEvent   = NULL;\r
+  InnerHead       = NULL;\r
+\r
+  if (!SadData->ManualSet &&\r
+      SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&\r
+      SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL\r
+      ) {\r
+    //\r
+    // Invalid manual SAD entry configuration.\r
+    //\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Create OutHeader according to Inner Header\r
+  //\r
+  if (SadData->Mode == EfiIPsecTunnel) {\r
+    InnerHead = IpSecTunnelOutboundPacket (\r
                   IpHead,\r
-                  IpPayload,\r
-                  OldLastHead,\r
-                  SpdEntry,\r
-                  &SadEntry\r
+                  IpVersion,\r
+                  SadData,\r
+                  LastHead,\r
+                  OptionsBuffer,\r
+                  OptionsLength,\r
+                  FragmentTable,\r
+                  FragmentCount\r
                   );\r
+    \r
+    if (InnerHead == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
 \r
-        if (SadEntry != NULL) {\r
-          //\r
-          // Process the packet by the found sad entry.\r
-          //\r
-          Status = IpSecProtectOutboundPacket (\r
-                    IpVersion,\r
-                    IpHead,\r
-                    LastHead,\r
-                    OptionsBuffer,\r
-                    OptionsLength,\r
-                    FragmentTable,\r
-                    FragmentCount,\r
-                    SadEntry,\r
-                    RecycleSignal\r
-                    );\r
-\r
-        } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {\r
-          //\r
-          // TODO: if no need return not ready to upper layer, change here.\r
-          //\r
-          Status = EFI_SUCCESS;\r
-        }\r
-      } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {\r
-        //\r
-        // For inbound icmpv6 traffic except ping request, accept the packet\r
-        // although no sad entry associated with protect spd entry.\r
-        //\r
-        IpSecLookupSadEntry (\r
-          Private,\r
-          NicHandle,\r
-          IpVersion,\r
-          IpHead,\r
-          IpPayload,\r
-          OldLastHead,\r
-          SpdEntry,\r
-          &SadEntry\r
-          );\r
-        if (SadEntry == NULL) {\r
-          Status = EFI_SUCCESS;\r
-        }\r
-      }\r
+  }\r
 \r
-      goto ON_EXIT;\r
+  //\r
+  // Calculate enctrypt block size, need iv by default and 4 bytes alignment.\r
+  //\r
+  EncryptBlockSize  = 4;\r
+\r
+  if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
+    EncryptBlockSize  = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
 \r
-    case EfiIPsecActionBypass:\r
-      Status = EFI_SUCCESS;\r
+    if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {\r
       goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Calculate the plain payload size accroding to the fragment table.\r
+  //\r
+  PlainPayloadSize = 0;\r
+  for (Index = 0; Index < *FragmentCount; Index++) {\r
+    PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;\r
+  }\r
+\r
+  //\r
+  // Add IPHeader size for Tunnel Mode\r
+  //\r
+  if (SadData->Mode == EfiIPsecTunnel) {\r
+    if (IpVersion == IP_VERSION_4) {\r
+      PlainPayloadSize += sizeof (IP4_HEAD);\r
+    } else {\r
+      PlainPayloadSize += sizeof (EFI_IP6_HEADER);\r
+    }\r
+    //\r
+    // OPtions should be encryption into it\r
+    //\r
+    PlainPayloadSize += *OptionsLength;    \r
+  }\r
+\r
 \r
-    case EfiIPsecActionDiscard:\r
+  //\r
+  // Calculate icv size, optional by default and 4 bytes alignment.\r
+  //\r
+  IcvSize = 0;\r
+  if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
+    IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);\r
+    if (IcvSize % 4 != 0) {\r
       goto ON_EXIT;\r
+    }\r
+  }\r
 \r
-    default:\r
+  //\r
+  // Calcuate the total size of esp wrapped ip payload.\r
+  //\r
+  IvSize        = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
+  EncryptSize   = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;\r
+  PaddingSize   = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);\r
+  EspSize       = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;\r
+\r
+  ProcessBuffer = AllocateZeroPool (EspSize);\r
+  if (ProcessBuffer == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Calculate esp header and esp tail including header, payload and padding.\r
+  //\r
+  EspHeader     = (EFI_ESP_HEADER *) ProcessBuffer;\r
+  RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;\r
+  Padding       = RestOfPayload + PlainPayloadSize;\r
+  EspTail       = (EFI_ESP_TAIL *) (Padding + PaddingSize);\r
+\r
+  //\r
+  // Fill the sn and spi fields in esp header.\r
+  //\r
+  EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);\r
+  //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber);\r
+  EspHeader->Spi            = HTONL (SaId->Spi);\r
+\r
+  //\r
+  // Copy the rest of payload (after iv) from the original fragment buffer.\r
+  //\r
+  BytesCopied = 0;\r
+\r
+  //\r
+  // For Tunnel Mode\r
+  //\r
+  if (SadData->Mode == EfiIPsecTunnel) {\r
+    if (IpVersion == IP_VERSION_4) {\r
       //\r
-      // Discard the packet if no spd entry match.\r
+      // HeadLen, Total Length\r
       //\r
-      break;\r
+      ((IP4_HEAD *)InnerHead)->HeadLen  = (UINT8) ((sizeof (IP4_HEAD) + *OptionsLength) >> 2);\r
+      ((IP4_HEAD *)InnerHead)->TotalLen = HTONS ((UINT16) PlainPayloadSize);  \r
+      ((IP4_HEAD *)InnerHead)->Checksum = 0;\r
+      ((IP4_HEAD *)InnerHead)->Checksum = (UINT16) (~NetblockChecksum (\r
+                                                  (UINT8 *)InnerHead,\r
+                                                  sizeof(IP4_HEAD)\r
+                                                  ));\r
+      CopyMem (\r
+        RestOfPayload + BytesCopied,\r
+        InnerHead,\r
+        sizeof (IP4_HEAD) + *OptionsLength\r
+        );\r
+      BytesCopied += sizeof (IP4_HEAD) + *OptionsLength;\r
+\r
+    } else {\r
+    ((EFI_IP6_HEADER *)InnerHead)->PayloadLength = HTONS ((UINT16) (PlainPayloadSize - sizeof (EFI_IP6_HEADER)));\r
+      CopyMem (\r
+        RestOfPayload + BytesCopied,\r
+        InnerHead,\r
+        sizeof (EFI_IP6_HEADER) + *OptionsLength\r
+        );\r
+      BytesCopied += sizeof (EFI_IP6_HEADER) + *OptionsLength;\r
     }\r
   }\r
 \r
+  for (Index = 0; Index < *FragmentCount; Index++) {\r
+    CopyMem (\r
+      (RestOfPayload + BytesCopied),\r
+      (*FragmentTable)[Index].FragmentBuffer,\r
+      (*FragmentTable)[Index].FragmentLength\r
+      );\r
+    BytesCopied += (*FragmentTable)[Index].FragmentLength;\r
+  }\r
+  //\r
+  // Fill the padding buffer by natural number sequence.\r
+  //\r
+  for (Index = 0; Index < PaddingSize; Index++) {\r
+    Padding[Index] = (UINT8) (Index + 1);\r
+  }\r
+  //\r
+  // Fill the padding length and next header fields in esp tail.\r
+  //\r
+  EspTail->PaddingLength  = (UINT8) PaddingSize;\r
+  EspTail->NextHeader     = *LastHead;\r
+\r
+  //\r
+  // Fill the next header for Tunnel mode.\r
+  //\r
+  if (SadData->Mode == EfiIPsecTunnel) {\r
+    if (IpVersion == IP_VERSION_4) {\r
+      EspTail->NextHeader = 4;\r
+    } else {\r
+      EspTail->NextHeader = 41;\r
+    }    \r
+  }\r
+\r
+  //\r
+  // Generate iv at random by crypt library.\r
+  //\r
+  Status = IpSecGenerateIv (\r
+             (UINT8 *) (EspHeader + 1),\r
+             IvSize\r
+             );\r
+  \r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Encryption the payload (after iv) by the SAD entry if has encrypt key.\r
+  //\r
+  if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
+    Status = IpSecCryptoIoEncrypt (\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,\r
+               (UINT8 *)(EspHeader + 1),\r
+               RestOfPayload,\r
+               EncryptSize,\r
+               RestOfPayload\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Authenticate the esp wrapped buffer by the SAD entry if it has auth key.\r
+  //\r
+  if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
+\r
+    HashFragment[0].Data     = ProcessBuffer;\r
+    HashFragment[0].DataSize = EspSize - IcvSize;\r
+    Status = IpSecCryptoIoHmac (\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r
+               SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,\r
+               HashFragment,\r
+               1,\r
+               ProcessBuffer + EspSize - IcvSize,\r
+               IcvSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Encryption and authentication with esp has been done, so it's time to\r
+  // reload the new packet, create recycle event and fixup ip header.\r
+  //\r
+  RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));\r
+  if (RecycleContext == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  IpSecRecycleCallback,\r
+                  RecycleContext,\r
+                  RecycleEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Caller take responsible to handle the original fragment table.\r
+  //\r
+  *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));\r
+  if (*FragmentTable == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  RecycleContext->FragmentTable       = *FragmentTable;\r
+  RecycleContext->PayloadBuffer       = ProcessBuffer;\r
+  (*FragmentTable)[0].FragmentBuffer  = ProcessBuffer;\r
+  (*FragmentTable)[0].FragmentLength  = (UINT32) EspSize;\r
+  *FragmentCount                      = 1;\r
+\r
+  //\r
+  // Update the total length field in ip header since processed by esp.\r
+  //\r
+  if (IpVersion == IP_VERSION_4) {\r
+    ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + EspSize));\r
+  } else {\r
+    ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);\r
+  }\r
+\r
+  //\r
+  // If tunnel mode, it should change the outer Ip header with tunnel source address\r
+  // and destination tunnel address.\r
+  //\r
+  if (SadData->Mode == EfiIPsecTunnel) {\r
+    if (IpVersion == IP_VERSION_4) {\r
+      CopyMem (\r
+        &((IP4_HEAD *) IpHead)->Src, \r
+        &SadData->TunnelSourceAddress.v4,\r
+        sizeof (EFI_IPv4_ADDRESS)\r
+        );  \r
+      CopyMem (\r
+        &((IP4_HEAD *) IpHead)->Dst,\r
+        &SadData->TunnelDestAddress.v4,\r
+        sizeof (EFI_IPv4_ADDRESS)\r
+        );\r
+    } else {\r
+      CopyMem (\r
+        &((EFI_IP6_HEADER *) IpHead)->SourceAddress,\r
+        &SadData->TunnelSourceAddress.v6,\r
+        sizeof (EFI_IPv6_ADDRESS)\r
+        );\r
+      CopyMem (\r
+        &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,\r
+        &SadData->TunnelDestAddress.v6,\r
+        sizeof (EFI_IPv6_ADDRESS)\r
+        );\r
+    }\r
+  }\r
+\r
+  //\r
+  // Update the next layer field in ip header since esp header inserted.\r
+  //\r
+  *LastHead = IPSEC_ESP_PROTOCOL;\r
+\r
+  //\r
+  // Increase the sn number in SAD entry according to rfc4303.\r
+  //\r
+  SadData->SequenceNumber++;\r
+\r
 ON_EXIT:\r
+  if (EFI_ERROR (Status)) {\r
+    if (ProcessBuffer != NULL) {\r
+      FreePool (ProcessBuffer);\r
+    }\r
+\r
+    if (RecycleContext != NULL) {\r
+      FreePool (RecycleContext);\r
+    }\r
+\r
+    if (*RecycleEvent != NULL) {\r
+      gBS->CloseEvent (*RecycleEvent);\r
+    }\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
+/**\r
+  This function processes the inbound traffic with IPsec.\r
+\r
+  It checks the received packet security property, trims the ESP/AH header, and then \r
+  returns without an IPsec protected IP Header and FragmentTable.\r
+  \r
+  @param[in]      IpVersion          The version of IP.\r
+  @param[in, out] IpHead             Points to IP header containing the ESP/AH header \r
+                                     to be trimed on input, and without ESP/AH header\r
+                                     on return.\r
+  @param[in, out] LastHead           The Last Header in IP header on return.\r
+  @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
+  @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
+  @param[in, out] FragmentTable      Pointer to a list of fragments in form of IPsec\r
+                                     protected on input, and without IPsec protected\r
+                                     on return.\r
+  @param[in, out] FragmentCount      The number of fragments.\r
+  @param[out]     SpdEntry           Pointer to contain the address of SPD entry on return.\r
+  @param[out]     RecycleEvent       The event for recycling of resources.\r
+\r
+  @retval EFI_SUCCESS              The operation was successful.\r
+  @retval EFI_UNSUPPORTED          The IPSEC protocol is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecProtectInboundPacket (\r
+  IN     UINT8                       IpVersion,\r
+  IN OUT VOID                        *IpHead,\r
+  IN OUT UINT8                       *LastHead,\r
+  IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
+  IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
+  IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
+  IN OUT UINT32                      *FragmentCount,\r
+     OUT EFI_IPSEC_SPD_SELECTOR      **SpdEntry,\r
+     OUT EFI_EVENT                   *RecycleEvent\r
+  )\r
+{\r
+  if (*LastHead == IPSEC_ESP_PROTOCOL) {\r
+    //\r
+    // Process the esp ipsec header of the inbound traffic.\r
+    //\r
+    return IpSecEspInboundPacket (\r
+             IpVersion,\r
+             IpHead,\r
+             LastHead,\r
+             OptionsBuffer,\r
+             OptionsLength,\r
+             FragmentTable,\r
+             FragmentCount,\r
+             SpdEntry,\r
+             RecycleEvent\r
+             );\r
+  }\r
+  //\r
+  // The other protocols are not supported.\r
+  //\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  This fucntion processes the output traffic with IPsec.\r
+\r
+  It protected the sending packet by encrypting it payload and inserting ESP/AH header\r
+  in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.\r
+\r
+  @param[in]      IpVersion          The version of IP.\r
+  @param[in, out] IpHead             Point to IP header containing the orginal IP header\r
+                                     to be processed on input, and inserted ESP/AH header\r
+                                     on return.\r
+  @param[in, out] LastHead           The Last Header in IP header.\r
+  @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
+  @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
+  @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by\r
+                                     IPsec on input, and with IPsec protected\r
+                                     on return.\r
+  @param[in, out] FragmentCount      Number of fragments.\r
+  @param[in]      SadEntry           Related SAD entry.\r
+  @param[out]     RecycleEvent       Event for recycling of resources.\r
+\r
+  @retval EFI_SUCCESS              The operation is successful.\r
+  @retval EFI_UNSUPPORTED          If the IPSEC protocol is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecProtectOutboundPacket (\r
+  IN     UINT8                       IpVersion,\r
+  IN OUT VOID                        *IpHead,\r
+  IN OUT UINT8                       *LastHead,\r
+  IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
+  IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
+  IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
+  IN OUT UINT32                      *FragmentCount,\r
+  IN     IPSEC_SAD_ENTRY             *SadEntry,\r
+     OUT EFI_EVENT                   *RecycleEvent\r
+  )\r
+{\r
+  if (SadEntry->Id->Proto == EfiIPsecESP) {\r
+    //\r
+    // Process the esp ipsec header of the outbound traffic.\r
+    //\r
+    return IpSecEspOutboundPacket (\r
+             IpVersion,\r
+             IpHead,\r
+             LastHead,\r
+             OptionsBuffer,\r
+             OptionsLength,\r
+             FragmentTable,\r
+             FragmentCount,\r
+             SadEntry,\r
+             RecycleEvent\r
+             );\r
+  }\r
+  //\r
+  // The other protocols are not supported.\r
+  //\r
+  return EFI_UNSUPPORTED;\r
+}\r
index 84494460c4c95506b349261f5038c30ec2227dc6..47805f3b9f8ad538e31e6ae7714b04a36251b48c 100644 (file)
@@ -121,6 +121,14 @@ typedef struct _IPSEC_RECYCLE_CONTEXT {
   UINT8                   *PayloadBuffer;\r
 } IPSEC_RECYCLE_CONTEXT;\r
 \r
+//\r
+// Struct used to store the Hash and its data.\r
+//\r
+typedef struct {
+  UINTN DataSize;
+  UINT8 *Data;
+} HASH_DATA_FRAGMENT;\r
+\r
 struct _IPSEC_PRIVATE_DATA {\r
   UINT32                    Signature;\r
   EFI_HANDLE                Handle;           // Virtual handle to install private prtocol\r
@@ -142,37 +150,37 @@ struct _IPSEC_PRIVATE_DATA {
 /**\r
   This function processes the inbound traffic with IPsec.\r
 \r
-  It checks the received packet security property, trims the ESP/AH header, and then\r
+  It checks the received packet security property, trims the ESP/AH header, and then \r
   returns without an IPsec protected IP Header and FragmentTable.\r
-\r
+  \r
   @param[in]      IpVersion          The version of IP.\r
-  @param[in, out] IpHead             Points to IP header containing the ESP/AH header\r
+  @param[in, out] IpHead             Points to IP header containing the ESP/AH header \r
                                      to be trimed on input, and without ESP/AH header\r
                                      on return.\r
-  @param[out]     LastHead           The Last Header in IP header on return.\r
+  @param[in, out] LastHead           The Last Header in IP header on return.\r
   @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
   @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
-  @param[in, out] FragmentTable      Pointer to a list of fragments in the form of IPsec\r
+  @param[in, out] FragmentTable      Pointer to a list of fragments in form of IPsec\r
                                      protected on input, and without IPsec protected\r
                                      on return.\r
-  @param[in, out] FragmentCount      Number of fragments.\r
+  @param[in, out] FragmentCount      The number of fragments.\r
   @param[out]     SpdEntry           Pointer to contain the address of SPD entry on return.\r
-  @param[out]     RecycleEvent       Event for recycling of resources.\r
+  @param[out]     RecycleEvent       The event for recycling of resources.\r
 \r
-  @retval EFI_SUCCESS              The operation is successful.\r
-  @retval EFI_UNSUPPORTED          If the IPSEC protocol is not supported.\r
+  @retval EFI_SUCCESS              The operation was successful.\r
+  @retval EFI_UNSUPPORTED          The IPSEC protocol is not supported.\r
 \r
 **/\r
 EFI_STATUS\r
 IpSecProtectInboundPacket (\r
   IN     UINT8                       IpVersion,\r
   IN OUT VOID                        *IpHead,\r
-     OUT UINT8                       *LastHead,\r
+  IN OUT UINT8                       *LastHead,\r
   IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
   IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
   IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
   IN OUT UINT32                      *FragmentCount,\r
-     OUT IPSEC_SPD_ENTRY             **SpdEntry,\r
+     OUT EFI_IPSEC_SPD_SELECTOR      **SpdEntry,\r
      OUT EFI_EVENT                   *RecycleEvent\r
   );\r
 \r
@@ -250,11 +258,75 @@ IpSecLookupPadEntry (
   IN EFI_IP_ADDRESS                         *IpAddr\r
   );\r
 \r
+/**\r
+  Check if the specified IP packet can be serviced by this SPD entry.\r
+\r
+  @param[in]  SpdEntry          Point to SPD entry.\r
+  @param[in]  IpVersion         Version of IP.\r
+  @param[in]  IpHead            Point to IP header.\r
+  @param[in]  IpPayload         Point to IP payload.\r
+  @param[in]  Protocol          The Last protocol of IP packet.\r
+  @param[in]  IsOutbound        Traffic direction.\r
+  @param[out] Action            The support action of SPD entry.\r
+\r
+  @retval EFI_SUCCESS       Find the related SPD.\r
+  @retval EFI_NOT_FOUND     Not find the related SPD entry;\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecLookupSpdEntry (\r
+  IN     IPSEC_SPD_ENTRY         *SpdEntry,\r
+  IN     UINT8                   IpVersion,\r
+  IN     VOID                    *IpHead,\r
+  IN     UINT8                   *IpPayload,\r
+  IN     UINT8                   Protocol,\r
+  IN     BOOLEAN                 IsOutbound, \r
+     OUT EFI_IPSEC_ACTION        *Action\r
+  );\r
+\r
+/**\r
+  Look up if there is existing SAD entry for specified IP packet sending.\r
+\r
+  This function is called by the IPsecProcess when there is some IP packet needed to\r
+  send out. This function checks if there is an existing SAD entry that can be serviced\r
+  to this IP packet sending. If no existing SAD entry could be used, this\r
+  function will invoke an IPsec Key Exchange Negotiation.\r
+\r
+  @param[in]  Private           Points to private data.\r
+  @param[in]  NicHandle         Points to a NIC handle.\r
+  @param[in]  IpVersion         The version of IP.\r
+  @param[in]  IpHead            The IP Header of packet to be sent out.\r
+  @param[in]  IpPayload         The IP Payload to be sent out.\r
+  @param[in]  OldLastHead       The Last protocol of the IP packet.\r
+  @param[in]  SpdEntry          Points to a related SPD entry.\r
+  @param[out] SadEntry          Contains the Point of a related SAD entry.\r
+\r
+  @retval EFI_DEVICE_ERROR  One of following conditions is TRUE:\r
+                            - If don't find related UDP service.\r
+                            - Sequence Number is used up.\r
+                            - Extension Sequence Number is used up.\r
+  @retval EFI_NOT_READY     No existing SAD entry could be used.\r
+  @retval EFI_SUCCESS       Find the related SAD entry.\r
+\r
+**/\r
+EFI_STATUS\r
+IpSecLookupSadEntry (\r
+  IN IPSEC_PRIVATE_DATA      *Private,\r
+  IN EFI_HANDLE              NicHandle,\r
+  IN UINT8                   IpVersion,\r
+  IN VOID                    *IpHead,\r
+  IN UINT8                   *IpPayload,\r
+  IN UINT8                   OldLastHead,\r
+  IN IPSEC_SPD_ENTRY         *SpdEntry,\r
+  OUT IPSEC_SAD_ENTRY        **SadEntry\r
+  );\r
+\r
 /**\r
   Find the SAD through whole SAD list.\r
 \r
   @param[in]  Spi               The SPI used to search the SAD entry.\r
   @param[in]  DestAddress       The destination used to search the SAD entry.\r
+  @param[in]  IpVersion         The IP version. Ip4 or Ip6.\r
 \r
   @return  The pointer to a certain SAD entry.\r
 \r
@@ -262,7 +334,8 @@ IpSecLookupPadEntry (
 IPSEC_SAD_ENTRY *\r
 IpSecLookupSadBySpi (\r
   IN UINT32                                 Spi,\r
-  IN EFI_IP_ADDRESS                         *DestAddress\r
+  IN EFI_IP_ADDRESS                         *DestAddress,\r
+  IN UINT8                                  IpVersion\r
   )\r
 ;\r
 \r
diff --git a/NetworkPkg/IpSecDxe/IpSecMain.c b/NetworkPkg/IpSecDxe/IpSecMain.c
new file mode 100644 (file)
index 0000000..247dab3
--- /dev/null
@@ -0,0 +1,235 @@
+/** @file\r
+  The mian interface of IPsec 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 "IpSecImpl.h"\r
+\r
+EFI_IPSEC2_PROTOCOL  mIpSecInstance = { IpSecProcess, NULL, TRUE };\r
+\r
+/**\r
+  Handles IPsec packet processing for inbound and outbound IP packets.\r
+\r
+  The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.\r
+  The behavior is that it can perform one of the following actions:\r
+  bypass the packet, discard the packet, or protect the packet.\r
+\r
+  @param[in]      This             Pointer to the EFI_IPSEC_PROTOCOL instance.\r
+  @param[in]      NicHandle        Instance of the network interface.\r
+  @param[in]      IpVersion        IPV4 or IPV6.\r
+  @param[in, out] IpHead           Pointer to the IP Header.\r
+  @param[in, out] LastHead         The protocol of the next layer to be processed by IPsec.\r
+  @param[in, out] OptionsBuffer    Pointer to the options buffer.\r
+  @param[in, out] OptionsLength    Length of the options buffer.\r
+  @param[in, out] FragmentTable    Pointer to a list of fragments.\r
+  @param[in, out] FragmentCount    Number of fragments.\r
+  @param[in]      TrafficDirection Traffic direction.\r
+  @param[out]     RecycleSignal    Event for recycling of resources.\r
+\r
+  @retval EFI_SUCCESS              The packet was bypassed and all buffers remain the same.\r
+  @retval EFI_SUCCESS              The packet was protected.\r
+  @retval EFI_ACCESS_DENIED        The packet was discarded.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IpSecProcess (\r
+  IN     EFI_IPSEC2_PROTOCOL             *This,\r
+  IN     EFI_HANDLE                      NicHandle,\r
+  IN     UINT8                           IpVersion,\r
+  IN OUT VOID                            *IpHead,\r
+  IN OUT UINT8                           *LastHead,\r
+  IN OUT VOID                            **OptionsBuffer,\r
+  IN OUT UINT32                          *OptionsLength,\r
+  IN OUT EFI_IPSEC_FRAGMENT_DATA         **FragmentTable,\r
+  IN OUT UINT32                          *FragmentCount,\r
+  IN     EFI_IPSEC_TRAFFIC_DIR           TrafficDirection,\r
+     OUT EFI_EVENT                       *RecycleSignal\r
+  )\r
+{\r
+  IPSEC_PRIVATE_DATA     *Private;\r
+  IPSEC_SPD_ENTRY        *SpdEntry;\r
+  EFI_IPSEC_SPD_SELECTOR *SpdSelector;\r
+  IPSEC_SAD_ENTRY        *SadEntry;\r
+  LIST_ENTRY             *SpdList;\r
+  LIST_ENTRY             *Entry;\r
+  EFI_IPSEC_ACTION       Action;\r
+  EFI_STATUS             Status;\r
+  UINT8                  *IpPayload;\r
+  UINT8                  OldLastHead;\r
+  BOOLEAN                IsOutbound;\r
+\r
+  Private         = IPSEC_PRIVATE_DATA_FROM_IPSEC (This);\r
+  IpPayload       = (*FragmentTable)[0].FragmentBuffer;\r
+  IsOutbound      = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE);\r
+  OldLastHead     = *LastHead;\r
+  *RecycleSignal  = NULL;\r
+  SpdList         = &mConfigData[IPsecConfigDataTypeSpd];\r
+  \r
+  if (!IsOutbound) {\r
+    //\r
+    // For inbound traffic, process the ipsec header of the packet.\r
+    //\r
+    Status = IpSecProtectInboundPacket (\r
+              IpVersion,\r
+              IpHead,\r
+              LastHead,\r
+              OptionsBuffer,\r
+              OptionsLength,\r
+              FragmentTable,\r
+              FragmentCount,\r
+              &SpdSelector,\r
+              RecycleSignal\r
+              );\r
+\r
+    if (Status == EFI_ACCESS_DENIED || Status == EFI_OUT_OF_RESOURCES) {\r
+      //\r
+      // The packet is denied to access.\r
+      //\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    if (Status == EFI_SUCCESS) {\r
+      \r
+      //\r
+      // Check the spd entry if the packet is accessible.\r
+      //\r
+      if (SpdSelector == NULL) {\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Status =  EFI_ACCESS_DENIED;\r
+      NET_LIST_FOR_EACH (Entry, SpdList) {\r
+        SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
+        if (IsSubSpdSelector (               \r
+              (EFI_IPSEC_CONFIG_SELECTOR *) SpdSelector,\r
+              (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector\r
+              )) {\r
+          Status = EFI_SUCCESS;\r
+        }\r
+      }      \r
+      goto ON_EXIT;\r
+    }       \r
+  }\r
+\r
+  Status  = EFI_ACCESS_DENIED;  \r
+\r
+  NET_LIST_FOR_EACH (Entry, SpdList) {\r
+    //\r
+    // For outbound and non-ipsec Inbound traffic: check the spd entry.\r
+    //\r
+    SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);\r
+\r
+    if (EFI_ERROR (IpSecLookupSpdEntry (\r
+                     SpdEntry,\r
+                     IpVersion,\r
+                     IpHead,\r
+                     IpPayload,\r
+                     OldLastHead,\r
+                     IsOutbound, \r
+                     &Action\r
+                     ))) {\r
+      //\r
+      // If the related SPD not find\r
+      //\r
+      continue;\r
+    }\r
+\r
+    switch (Action) {\r
+\r
+    case EfiIPsecActionProtect:\r
+\r
+      if (IsOutbound) {\r
+        //\r
+        // For outbound traffic, lookup the sad entry.\r
+        //\r
+        Status = IpSecLookupSadEntry (\r
+                   Private,\r
+                   NicHandle,\r
+                   IpVersion,\r
+                   IpHead,\r
+                   IpPayload,\r
+                   OldLastHead,\r
+                   SpdEntry,\r
+                   &SadEntry\r
+                   );\r
+\r
+        if (SadEntry != NULL) {\r
+          //\r
+          // Process the packet by the found sad entry.\r
+          //\r
+          Status = IpSecProtectOutboundPacket (\r
+                    IpVersion,\r
+                    IpHead,\r
+                    LastHead,\r
+                    OptionsBuffer,\r
+                    OptionsLength,\r
+                    FragmentTable,\r
+                    FragmentCount,\r
+                    SadEntry,\r
+                    RecycleSignal\r
+                    );\r
+\r
+        } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {\r
+          //\r
+          // TODO: if no need return not ready to upper layer, change here.\r
+          //\r
+          Status = EFI_SUCCESS;\r
+        }\r
+      } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {\r
+        //\r
+        // For inbound icmpv6 traffic except ping request, accept the packet\r
+        // although no sad entry associated with protect spd entry.\r
+        //\r
+        Status = IpSecLookupSadEntry (\r
+                   Private,\r
+                   NicHandle,\r
+                   IpVersion,\r
+                   IpHead,\r
+                   IpPayload,\r
+                   OldLastHead,\r
+                   SpdEntry,\r
+                   &SadEntry\r
+                   );\r
+        if (SadEntry == NULL) {\r
+          Status = EFI_SUCCESS;\r
+        }\r
+      }\r
+\r
+      goto ON_EXIT;\r
+\r
+    case EfiIPsecActionBypass:\r
+      Status = EFI_SUCCESS;\r
+      goto ON_EXIT;\r
+\r
+    case EfiIPsecActionDiscard:\r
+      goto ON_EXIT;   \r
+    }\r
+  }\r
+   \r
+  //\r
+  // If don't find the related SPD entry, return the EFI_ACCESS_DENIED and discard it.\r
+  // But it the packet is NS/NA, it should be by passed even not find the related SPD entry.\r
+  //\r
+  if (OldLastHead == IP6_ICMP && \r
+      (*IpPayload == ICMP_V6_NEIGHBOR_SOLICIT || *IpPayload == ICMP_V6_NEIGHBOR_ADVERTISE)\r
+      ){\r
+    Status = EFI_SUCCESS;\r
+  }\r
+  \r
+ON_EXIT:\r
+  return Status;\r
+}\r
+\r
diff --git a/NetworkPkg/IpSecDxe/IpSecSaEngine.c b/NetworkPkg/IpSecDxe/IpSecSaEngine.c
deleted file mode 100644 (file)
index b556b24..0000000
+++ /dev/null
@@ -1,934 +0,0 @@
-/** @file\r
-  IPsec inbound and outbound traffic processing.\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 "IpSecImpl.h"\r
-#include "IpSecDebug.h"\r
-#include "IpSecCryptIo.h"\r
-\r
-extern LIST_ENTRY     mConfigData[IPsecConfigDataTypeMaximum];\r
-\r
-/**\r
-  The call back function of NetbufFromExt.\r
-\r
-  @param[in]  Arg            The argument passed from the caller.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-IpSecOnRecyclePacket (\r
-  IN VOID                            *Arg\r
-  )\r
-{\r
-}\r
-\r
-/**\r
-  This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP\r
-  is released.\r
-\r
-  @param[in]  Event              The related event.\r
-  @param[in]  Context            The data passed by the caller.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-IpSecRecycleCallback (\r
-  IN EFI_EVENT                       Event,\r
-  IN VOID                            *Context\r
-  )\r
-{\r
-  IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
-\r
-  RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context;\r
-\r
-  if (RecycleContext->FragmentTable != NULL) {\r
-    FreePool (RecycleContext->FragmentTable);\r
-  }\r
-\r
-  if (RecycleContext->PayloadBuffer != NULL) {\r
-    FreePool (RecycleContext->PayloadBuffer);\r
-  }\r
-\r
-  FreePool (RecycleContext);\r
-  gBS->CloseEvent (Event);\r
-\r
-}\r
-\r
-/**\r
-  Calculate the extension header of IP. The return length only doesn't contain\r
-  the fixed IP header length.\r
-\r
-  @param[in]  IpHead             Points to an IP head to be calculated.\r
-  @param[in]  LastHead           Points to the last header of the IP header.\r
-\r
-  @return The length of the extension header.\r
-\r
-**/\r
-UINT16\r
-IpSecGetPlainExtHeadSize (\r
-  IN VOID                             *IpHead,\r
-  IN UINT8                            *LastHead\r
-  )\r
-{\r
-  UINT16  Size;\r
-\r
-  Size = (UINT16) (LastHead - (UINT8 *) IpHead);\r
-\r
-  if (Size > sizeof (EFI_IP6_HEADER)) {\r
-    //\r
-    // * (LastHead+1) point the last header's length but not include the first\r
-    // 8 octers, so this formluation add 8 at the end.\r
-    //\r
-    Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);\r
-  } else {\r
-    Size = 0;\r
-  }\r
-\r
-  return Size;\r
-}\r
-\r
-/**\r
-  Authenticate the IpSec Payload and store the result in the IcvBuffer.\r
-\r
-  @param[in]      BufferToAuth    The buffer to be Authenticated.\r
-  @param[in]      AuthSize        The size of the buffer to be Authenticated.\r
-  @param[in, out] IcvBuffer       The buffer to store the ICV.\r
-  @param[in]      IcvSize         The size of ICV.\r
-  @param[in]      Key             The Key passed to the CryptLib to generate a\r
-                                  CRYPT_HANDLE.\r
-  @param[in]      AuthAlgId       The Authentication Algorithm ID.\r
-\r
-  @retval EFI_UNSUPPORTED     If the AuthAlg is not in the support list.\r
-  @retval EFI_SUCCESS         Authenticated the payload successfully.\r
-  @retval otherwise           Authentication of the payload failed.\r
-**/\r
-EFI_STATUS\r
-IpSecAuthPayload (\r
-  IN     UINT8                           *BufferToAuth,\r
-  IN     UINTN                           AuthSize,\r
-  IN OUT UINT8                           *IcvBuffer,\r
-  IN     UINTN                           IcvSize,\r
-  IN     VOID                            *Key,\r
-  IN     UINT8                           AuthAlgId\r
-  )\r
-{\r
-  switch (AuthAlgId) {\r
-    case IKE_AALG_NONE :\r
-    case IKE_AALG_NULL :\r
-        return EFI_SUCCESS;\r
-\r
-    default:\r
-        return EFI_UNSUPPORTED;\r
-  }\r
-}\r
-\r
-/**\r
-  Verify if the Authentication payload is correct.\r
-\r
-  @param[in]  EspBuffer          Points to the ESP wrapped buffer.\r
-  @param[in]  EspSize            The size of the ESP wrapped buffer.\r
-  @param[in]  SadEntry           The related SAD entry to store the authentication\r
-                                 algorithm key.\r
-  @param[in]  IcvSize            The length of ICV.\r
-\r
-  @retval EFI_SUCCESS        The authentication data is correct.\r
-  @retval EFI_ACCESS_DENIED  The authentication data is not correct.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecEspAuthVerifyPayload (\r
-  IN UINT8                           *EspBuffer,\r
-  IN UINTN                           EspSize,\r
-  IN IPSEC_SAD_ENTRY                 *SadEntry,\r
-  IN UINTN                           *IcvSize\r
-  )\r
-{\r
-  EFI_STATUS  Status;\r
-  UINTN       AuthSize;\r
-  UINT8       IcvBuffer[12];\r
-\r
-  //\r
-  // Calculate the size of authentication payload.\r
-  //\r
-  *IcvSize  = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);\r
-  AuthSize  = EspSize - *IcvSize;\r
-\r
-  //\r
-  // Calculate the icv buffer and size of the payload.\r
-  //\r
-  Status = IpSecAuthPayload (\r
-             EspBuffer,\r
-             AuthSize,\r
-             IcvBuffer,\r
-             *IcvSize,\r
-             SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r
-             SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-  //\r
-  // Compare the calculated icv and the appended original icv.\r
-  //\r
-  if (CompareMem (EspBuffer + AuthSize, IcvBuffer, *IcvSize) == 0) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));\r
-  return EFI_ACCESS_DENIED;\r
-}\r
-\r
-/**\r
-  ESP Decrypt the payload.\r
-\r
-  @param[in, out] PayloadBuffer      Pointer to the buffer containing the ESP wrapped;\r
-                                     to be decrypted on input, and plaintext on return. The\r
-                                     number of bytes of data to be decrypted is\r
-                                     specified by EncryptSize.\r
-  @param[in]      EncryptSize        The size of the PayloadBuffer as input.\r
-  @param[in]      SadEntry           The related SAD entry.\r
-  @param[in]      IvSize             The size of IV.\r
-  @param[out]     PlainPayloadSize   Contains the return value of decrypted size.\r
-  @param[out]     PaddingSize        Contains the return value of Padding size.\r
-  @param[out]     NextHeader         Contains the return value of the last protocol header\r
-                                     of the IP packet.\r
-\r
-  @retval EFI_UNSUPPORTED    The Algorithm pointed to by the SAD entry is not supported.\r
-  @retval EFI_SUCCESS        The operation completed successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecEspDecryptPayload (\r
-  IN OUT UINT8                       *PayloadBuffer,\r
-  IN     UINTN                       EncryptSize,\r
-  IN     IPSEC_SAD_ENTRY             *SadEntry,\r
-  IN     UINTN                       *IvSize,\r
-     OUT UINTN                       *PlainPayloadSize,\r
-     OUT UINTN                       *PaddingSize,\r
-     OUT UINT8                       *NextHeader\r
-  )\r
-{\r
-  EFI_ESP_TAIL *EspTail;\r
-\r
-  switch (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId) {\r
-    case IKE_EALG_NULL:\r
-      EspTail            = (EFI_ESP_TAIL *) (PayloadBuffer + EncryptSize - sizeof (EFI_ESP_TAIL));\r
-      *PaddingSize       = EspTail->PaddingLength;\r
-      *NextHeader        = EspTail->NextHeader;\r
-      *PlainPayloadSize  = EncryptSize - EspTail->PaddingLength - sizeof (EFI_ESP_TAIL);\r
-      break;\r
-\r
-    case IKE_EALG_3DESCBC:\r
-    case IKE_EALG_AESCBC:\r
-      //\r
-      // TODO: support these algorithm\r
-      //\r
-      return EFI_UNSUPPORTED;\r
-    default :\r
-      return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
-  ESP Encrypt the payload.\r
-\r
-  @param[in, out] BufferToEncrypt Pointer to the buffer containing plaintext to be\r
-                                  encrypted on input, and ciphertext on return. The\r
-                                  number of bytes of data to be encrypted is\r
-                                  specified by EncryptSize.\r
-  @param[in, out] EncryptSize     The size of the plaintext on input, and the size of the\r
-                                  ciphertext on return.\r
-  @param[in]      IvBuffer        Points to IV data.\r
-  @param[in]      IvSize          Size of IV.\r
-  @param[in]      SadEntry        Related SAD entry.\r
-\r
-  @retval EFI_UNSUPPORTED    The Algorithm pointed by SAD entry is not supported.\r
-  @retval EFI_SUCCESS        The operation completed successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecEspEncryptPayload (\r
-  IN OUT UINT8                       *BufferToEncrypt,\r
-  IN OUT UINTN                       EncryptSize,\r
-  IN     UINT8                       *IvBuffer,\r
-  IN     UINTN                       IvSize,\r
-  IN     IPSEC_SAD_ENTRY             *SadEntry\r
-  )\r
-{\r
-  switch (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId) {\r
-    case IKE_EALG_NULL:\r
-      return EFI_SUCCESS;\r
-\r
-    case IKE_EALG_3DESCBC:\r
-    case IKE_EALG_AESCBC:\r
-      //\r
-      // TODO: support these algorithms\r
-      //\r
-      return EFI_UNSUPPORTED;\r
-    default :\r
-      return EFI_UNSUPPORTED;\r
-\r
-  }\r
-}\r
-\r
-/**\r
-  The actual entry to relative function processes the inbound traffic of ESP header.\r
-\r
-  This function is the subfunction of IpSecProtectInboundPacket(). It checks the\r
-  received packet security property and trim the ESP header and then returns without\r
-  an IPsec protected IP Header and FramgmentTable.\r
-\r
-  @param[in]      IpVersion          The version of IP.\r
-  @param[in, out] IpHead             Points to the IP header containing the ESP header\r
-                                     to be trimed on input, and without ESP header\r
-                                     on return.\r
-  @param[out]     LastHead           The Last Header in IP header on return.\r
-  @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
-  @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
-  @param[in, out] FragmentTable      Pointer to a list of fragments in the form of IPsec\r
-                                     protected on input, and without IPsec protected\r
-                                     on return.\r
-  @param[in, out] FragmentCount      The number of fragments.\r
-  @param[out]     SpdEntry           Pointer to contain the address of SPD entry on return.\r
-  @param[out]     RecycleEvent       The event for recycling of resources.\r
-\r
-  @retval EFI_SUCCESS              The operation was successful.\r
-  @retval EFI_ACCESS_DENIED        One or more following conditions is TRUE:\r
-                                   - ESP header was not found.\r
-                                   - The related SAD entry was not found.\r
-                                   - The related SAD entry does not support the ESP protocol.\r
-  @retval EFI_OUT_OF_RESOURCES     The required system resource can't be allocated.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecEspInboundPacket (\r
-  IN     UINT8                       IpVersion,\r
-  IN OUT VOID                        *IpHead,\r
-     OUT UINT8                       *LastHead,\r
-  IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
-  IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
-  IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
-  IN OUT UINT32                      *FragmentCount,\r
-     OUT IPSEC_SPD_ENTRY             **SpdEntry,\r
-     OUT EFI_EVENT                   *RecycleEvent\r
-  )\r
-{\r
-  EFI_STATUS            Status;\r
-  NET_BUF               *Payload;\r
-  UINTN                 EspSize;\r
-  UINTN                 IvSize;\r
-  UINTN                 PlainPayloadSize;\r
-  UINTN                 PaddingSize;\r
-  UINTN                 IcvSize;\r
-  UINT8                 *ProcessBuffer;\r
-  EFI_IP_ADDRESS        DestIp;\r
-  EFI_ESP_HEADER        *EspHeader;\r
-  EFI_ESP_TAIL          *EspTail;\r
-  EFI_IPSEC_SA_ID       *SaId;\r
-  IPSEC_SAD_DATA        *SadData;\r
-  IPSEC_SAD_ENTRY       *SadEntry;\r
-  IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
-  UINT32                Spi;\r
-  UINT8                 NextHeader;\r
-  UINT16                IpSecHeadSize;\r
-\r
-  Status            = EFI_SUCCESS;\r
-  Payload           = NULL;\r
-  ProcessBuffer     = NULL;\r
-  RecycleContext    = NULL;\r
-  *RecycleEvent     = NULL;\r
-  PlainPayloadSize  = 0;\r
-  NextHeader        = 0;\r
-  //\r
-  // Build netbuf from fragment table first.\r
-  //\r
-  Payload = NetbufFromExt (\r
-              (NET_FRAGMENT *) *FragmentTable,\r
-              *FragmentCount,\r
-              0,\r
-              sizeof (EFI_ESP_HEADER),\r
-              IpSecOnRecyclePacket,\r
-              NULL\r
-              );\r
-  if (Payload == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-  //\r
-  // Get the esp size and eso header from netbuf.\r
-  //\r
-  EspSize   = Payload->TotalSize;\r
-  EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);\r
-  if (EspHeader == NULL) {\r
-    Status = EFI_ACCESS_DENIED;\r
-    goto ON_EXIT;\r
-  }\r
-  //\r
-  // Parse destination address from ip header.\r
-  //\r
-  ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));\r
-  if (IpVersion == IP_VERSION_4) {\r
-    CopyMem (\r
-      &DestIp,\r
-      &((IP4_HEAD *) IpHead)->Dst,\r
-      sizeof (IP4_ADDR)\r
-      );\r
-  } else {\r
-    CopyMem (\r
-      &DestIp,\r
-      &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,\r
-      sizeof (EFI_IPv6_ADDRESS)\r
-      );\r
-  }\r
-  //\r
-  // Lookup sad entry according to the spi and dest address.\r
-  //\r
-  Spi       = NTOHL (EspHeader->Spi);\r
-  SadEntry  = IpSecLookupSadBySpi (Spi, &DestIp);\r
-  if (SadEntry == NULL) {\r
-    Status = EFI_ACCESS_DENIED;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  SaId    = SadEntry->Id;\r
-  SadData = SadEntry->Data;\r
-\r
-  //\r
-  // Only support esp protocol currently.\r
-  //\r
-  if (SaId->Proto != EfiIPsecESP) {\r
-    Status = EFI_ACCESS_DENIED;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  if (!SadData->ManualSet) {\r
-    //\r
-    // TODO: Check sa lifetime and sequence number\r
-    //\r
-  }\r
-  //\r
-  // Allocate buffer for decryption and authentication by esp.\r
-  //\r
-  ProcessBuffer = AllocateZeroPool (EspSize);\r
-  if (ProcessBuffer == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);\r
-\r
-  //\r
-  // Authenticate the esp wrapped buffer by the sad entry if has auth key.\r
-  //\r
-  IcvSize = 0;\r
-  if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
-    Status = IpSecEspAuthVerifyPayload (\r
-               ProcessBuffer,\r
-               EspSize,\r
-               SadEntry,\r
-               &IcvSize\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\r
-    }\r
-  }\r
-  //\r
-  // Decrypt the payload by the sad entry if has decrypt key.\r
-  //\r
-  IvSize = 0;\r
-  if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
-    Status = IpSecEspDecryptPayload (\r
-               ProcessBuffer + sizeof (EFI_ESP_HEADER),\r
-               EspSize - sizeof (EFI_ESP_HEADER) - IcvSize,\r
-               SadEntry,\r
-               &IvSize,\r
-               &PlainPayloadSize,\r
-               &PaddingSize,\r
-               &NextHeader\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\r
-    }\r
-  } else {\r
-    EspTail           = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));\r
-    PaddingSize       = EspTail->PaddingLength;\r
-    NextHeader        = EspTail->NextHeader;\r
-    PlainPayloadSize  = EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize - sizeof (EFI_ESP_TAIL) - PaddingSize;\r
-  }\r
-  //\r
-  // TODO: handle anti-replay window\r
-  //\r
-  //\r
-  // Decryption and authentication with esp has been done, so it's time to\r
-  // reload the new packet, create recycle event and fixup ip header.\r
-  //\r
-  RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));\r
-  if (RecycleContext == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  IpSecRecycleCallback,\r
-                  RecycleContext,\r
-                  RecycleEvent\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_EXIT;\r
-  }\r
-  //\r
-  // TODO: Who take responsible to handle the original fragment table?\r
-  //\r
-  *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));\r
-  if (*FragmentTable == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  RecycleContext->PayloadBuffer       = ProcessBuffer;\r
-  RecycleContext->FragmentTable       = *FragmentTable;\r
-  (*FragmentTable)[0].FragmentBuffer  = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;\r
-  (*FragmentTable)[0].FragmentLength  = (UINT32) PlainPayloadSize;\r
-  *FragmentCount                      = 1;\r
-\r
-  //\r
-  // Update the total length field in ip header since processed by esp.\r
-  //\r
-  if (IpVersion == IP_VERSION_4) {\r
-    ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + PlainPayloadSize));\r
-  } else {\r
-    IpSecHeadSize                              = IpSecGetPlainExtHeadSize (IpHead, LastHead);\r
-    ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));\r
-  }\r
-  //\r
-  // Update the next layer field in ip header since esp header inserted.\r
-  //\r
-  *LastHead = NextHeader;\r
-\r
-  //\r
-  // Update the spd association of the sad entry.\r
-  //\r
-  *SpdEntry = SadData->SpdEntry;\r
-\r
-ON_EXIT:\r
-  if (Payload != NULL) {\r
-    NetbufFree (Payload);\r
-  }\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    if (ProcessBuffer != NULL) {\r
-      FreePool (ProcessBuffer);\r
-    }\r
-\r
-    if (RecycleContext != NULL) {\r
-      FreePool (RecycleContext);\r
-    }\r
-\r
-    if (*RecycleEvent != NULL) {\r
-      gBS->CloseEvent (*RecycleEvent);\r
-    }\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
-/**\r
-  The actual entry to the relative function processes the output traffic using the ESP protocol.\r
-\r
-  This function is the subfunction of IpSecProtectOutboundPacket(). It protected\r
-  the sending packet by encrypting its payload and inserting ESP header in the orginal\r
-  IP header, then return the IpHeader and IPsec protected Fragmentable.\r
-\r
-  @param[in]      IpVersion          The version of IP.\r
-  @param[in, out] IpHead             Points to IP header containing the orginal IP header\r
-                                     to be processed on input, and inserted ESP header\r
-                                     on return.\r
-  @param[in, out] LastHead           The Last Header in IP header.\r
-  @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
-  @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
-  @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by\r
-                                     IPsec on input, and with IPsec protected\r
-                                     on return.\r
-  @param[in, out] FragmentCount      The number of fragments.\r
-  @param[in]      SadEntry           The related SAD entry.\r
-  @param[out]     RecycleEvent       The event for recycling of resources.\r
-\r
-  @retval EFI_SUCCESS              The operation was successful.\r
-  @retval EFI_OUT_OF_RESOURCES     The required system resources can't be allocated.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecEspOutboundPacket (\r
-  IN UINT8                           IpVersion,\r
-  IN OUT VOID                        *IpHead,\r
-  IN OUT UINT8                       *LastHead,\r
-  IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
-  IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
-  IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
-  IN OUT UINT32                      *FragmentCount,\r
-  IN     IPSEC_SAD_ENTRY             *SadEntry,\r
-     OUT EFI_EVENT                   *RecycleEvent\r
-  )\r
-{\r
-  EFI_STATUS            Status;\r
-  UINTN                 Index;\r
-  EFI_IPSEC_SA_ID       *SaId;\r
-  IPSEC_SAD_DATA        *SadData;\r
-  IPSEC_RECYCLE_CONTEXT *RecycleContext;\r
-  UINT8                 *ProcessBuffer;\r
-  UINTN                 BytesCopied;\r
-  INTN                  EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4\r
-  UINTN                 EspSize;         // Total size of esp wrapped ip payload\r
-  UINTN                 IvSize;          // Size of IV, optional, might be 0\r
-  UINTN                 PlainPayloadSize;// Original IP payload size\r
-  UINTN                 PaddingSize;     // Size of padding\r
-  UINTN                 EncryptSize;     // Size of data to be encrypted, start after IV and\r
-                                         // stop before ICV\r
-  UINTN                 IcvSize;         // Size of ICV, optional, might be 0\r
-  UINT8                 *RestOfPayload;  // Start of Payload after IV\r
-  UINT8                 *Padding;        // Start address of padding\r
-  EFI_ESP_HEADER        *EspHeader;      // Start address of ESP frame\r
-  EFI_ESP_TAIL          *EspTail;        // Address behind padding\r
-\r
-  Status          = EFI_ACCESS_DENIED;\r
-  SaId            = SadEntry->Id;\r
-  SadData         = SadEntry->Data;\r
-  ProcessBuffer   = NULL;\r
-  RecycleContext  = NULL;\r
-  *RecycleEvent   = NULL;\r
-\r
-  if (!SadData->ManualSet &&\r
-      SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&\r
-      SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL\r
-      ) {\r
-    //\r
-    // Invalid manual sad entry configuration.\r
-    //\r
-    goto ON_EXIT;\r
-  }\r
-  //\r
-  // Calculate enctrypt block size, need iv by default and 4 bytes alignment.\r
-  //\r
-  EncryptBlockSize  = 4;\r
-\r
-  if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
-    EncryptBlockSize  = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
-\r
-    if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {\r
-      goto ON_EXIT;\r
-    }\r
-  }\r
-  //\r
-  // Calculate the plain payload size accroding to the fragment table.\r
-  //\r
-  PlainPayloadSize = 0;\r
-  for (Index = 0; Index < *FragmentCount; Index++) {\r
-    PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;\r
-  }\r
-  //\r
-  // Calculate icv size, optional by default and 4 bytes alignment.\r
-  //\r
-  IcvSize = 0;\r
-  if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
-    IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);\r
-    if (IcvSize % 4 != 0) {\r
-      goto ON_EXIT;\r
-    }\r
-  }\r
-  //\r
-  // Calcuate the total size of esp wrapped ip payload.\r
-  //\r
-  IvSize        = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);\r
-  EncryptSize   = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;\r
-  PaddingSize   = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);\r
-  EspSize       = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;\r
-\r
-  ProcessBuffer = AllocateZeroPool (EspSize);\r
-  if (ProcessBuffer == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-  //\r
-  // Calculate esp header and esp tail including header, payload and padding.\r
-  //\r
-  EspHeader     = (EFI_ESP_HEADER *) ProcessBuffer;\r
-  RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;\r
-  Padding       = RestOfPayload + PlainPayloadSize;\r
-  EspTail       = (EFI_ESP_TAIL *) (Padding + PaddingSize);\r
-\r
-  //\r
-  // Fill the sn and spi fields in esp header.\r
-  //\r
-  EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);\r
-  EspHeader->Spi            = HTONL (SaId->Spi);\r
-\r
-  //\r
-  // Copy the rest of payload (after iv) from the original fragment buffer.\r
-  //\r
-  BytesCopied = 0;\r
-  for (Index = 0; Index < *FragmentCount; Index++) {\r
-    CopyMem (\r
-      (RestOfPayload + BytesCopied),\r
-      (*FragmentTable)[Index].FragmentBuffer,\r
-      (*FragmentTable)[Index].FragmentLength\r
-      );\r
-    BytesCopied += (*FragmentTable)[Index].FragmentLength;\r
-  }\r
-  //\r
-  // Fill the padding buffer by natural number sequence.\r
-  //\r
-  for (Index = 0; Index < PaddingSize; Index++) {\r
-    Padding[Index] = (UINT8) (Index + 1);\r
-  }\r
-  //\r
-  // Fill the padding length and next header fields in esp tail.\r
-  //\r
-  EspTail->PaddingLength  = (UINT8) PaddingSize;\r
-  EspTail->NextHeader     = *LastHead;\r
-\r
-  //\r
-  // Generate iv at random by crypt library.\r
-  //\r
-  Status = IpSecGenerateIv (\r
-             (UINT8 *) (EspHeader + 1),\r
-             IvSize\r
-             );\r
-\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_EXIT;\r
-  }\r
-  //\r
-  // Encrypt the payload (after iv) by the sad entry if has encrypt key.\r
-  //\r
-  if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {\r
-    Status = IpSecEspEncryptPayload (\r
-               RestOfPayload,\r
-               EncryptSize,\r
-               (UINT8 *) (EspHeader + 1),\r
-               IvSize,\r
-               SadEntry\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\r
-    }\r
-  }\r
-  //\r
-  // Authenticate the esp wrapped buffer by the sad entry if has auth key.\r
-  //\r
-  if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {\r
-    Status = IpSecAuthPayload (\r
-               ProcessBuffer,\r
-               EspSize - IcvSize,\r
-               ProcessBuffer + EspSize - IcvSize,\r
-               IcvSize,\r
-               SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,\r
-               SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\r
-    }\r
-  }\r
-  //\r
-  // Encryption and authentication with esp has been done, so it's time to\r
-  // reload the new packet, create recycle event and fixup ip header.\r
-  //\r
-  RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));\r
-  if (RecycleContext == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  Status = gBS->CreateEvent (\r
-                  EVT_NOTIFY_SIGNAL,\r
-                  TPL_NOTIFY,\r
-                  IpSecRecycleCallback,\r
-                  RecycleContext,\r
-                  RecycleEvent\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    goto ON_EXIT;\r
-  }\r
-  //\r
-  // TODO: Who take responsible to handle the original fragment table?\r
-  //\r
-  *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));\r
-  if (*FragmentTable == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  RecycleContext->FragmentTable       = *FragmentTable;\r
-  RecycleContext->PayloadBuffer       = ProcessBuffer;\r
-  (*FragmentTable)[0].FragmentBuffer  = ProcessBuffer;\r
-  (*FragmentTable)[0].FragmentLength  = (UINT32) EspSize;\r
-  *FragmentCount                      = 1;\r
-\r
-  //\r
-  // Update the total length field in ip header since processed by esp.\r
-  //\r
-  if (IpVersion == IP_VERSION_4) {\r
-    ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) (((IP4_HEAD *) IpHead)->HeadLen + EspSize));\r
-  } else {\r
-    ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);\r
-  }\r
-  //\r
-  // Update the next layer field in ip header since esp header inserted.\r
-  //\r
-  *LastHead = IPSEC_ESP_PROTOCOL;\r
-\r
-  //\r
-  // Increase the sn number in sad entry according to rfc4303.\r
-  //\r
-  SadData->SequenceNumber++;\r
-\r
-ON_EXIT:\r
-  if (EFI_ERROR (Status)) {\r
-    if (ProcessBuffer != NULL) {\r
-      FreePool (ProcessBuffer);\r
-    }\r
-\r
-    if (RecycleContext != NULL) {\r
-      FreePool (RecycleContext);\r
-    }\r
-\r
-    if (*RecycleEvent != NULL) {\r
-      gBS->CloseEvent (*RecycleEvent);\r
-    }\r
-  }\r
-\r
-  return Status;\r
-}\r
-\r
-/**\r
-  This function processes the inbound traffic with IPsec.\r
-\r
-  It checks the received packet security property, trims the ESP/AH header, and then\r
-  returns without an IPsec protected IP Header and FragmentTable.\r
-\r
-  @param[in]      IpVersion          The version of IP.\r
-  @param[in, out] IpHead             Points to IP header containing the ESP/AH header\r
-                                     to be trimed on input, and without ESP/AH header\r
-                                     on return.\r
-  @param[out]     LastHead           The Last Header in IP header on return.\r
-  @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
-  @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
-  @param[in, out] FragmentTable      Pointer to a list of fragments in the form of IPsec\r
-                                     protected on input, and without IPsec protected\r
-                                     on return.\r
-  @param[in, out] FragmentCount      Number of fragments.\r
-  @param[out]     SpdEntry           Pointer to contain the address of SPD entry on return.\r
-  @param[out]     RecycleEvent       Event for recycling of resources.\r
-\r
-  @retval EFI_SUCCESS              The operation is successful.\r
-  @retval EFI_UNSUPPORTED          If the IPSEC protocol is not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecProtectInboundPacket (\r
-  IN     UINT8                       IpVersion,\r
-  IN OUT VOID                        *IpHead,\r
-     OUT UINT8                       *LastHead,\r
-  IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
-  IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
-  IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
-  IN OUT UINT32                      *FragmentCount,\r
-     OUT IPSEC_SPD_ENTRY             **SpdEntry,\r
-     OUT EFI_EVENT                   *RecycleEvent\r
-  )\r
-{\r
-  if (*LastHead == IPSEC_ESP_PROTOCOL) {\r
-    //\r
-    // Process the esp ipsec header of the inbound traffic.\r
-    //\r
-    return IpSecEspInboundPacket (\r
-             IpVersion,\r
-             IpHead,\r
-             LastHead,\r
-             OptionsBuffer,\r
-             OptionsLength,\r
-             FragmentTable,\r
-             FragmentCount,\r
-             SpdEntry,\r
-             RecycleEvent\r
-             );\r
-  }\r
-  //\r
-  // The other protocols are not supported.\r
-  //\r
-  return EFI_UNSUPPORTED;\r
-}\r
-\r
-/**\r
-  This fucntion processes the output traffic with IPsec.\r
-\r
-  It protected the sending packet by encrypting it payload and inserting ESP/AH header\r
-  in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.\r
-\r
-  @param[in]      IpVersion          The version of IP.\r
-  @param[in, out] IpHead             Point to IP header containing the orginal IP header\r
-                                     to be processed on input, and inserted ESP/AH header\r
-                                     on return.\r
-  @param[in, out] LastHead           The Last Header in IP header.\r
-  @param[in, out] OptionsBuffer      Pointer to the options buffer. It is optional.\r
-  @param[in, out] OptionsLength      Length of the options buffer. It is optional.\r
-  @param[in, out] FragmentTable      Pointer to a list of fragments to be protected by\r
-                                     IPsec on input, and with IPsec protected\r
-                                     on return.\r
-  @param[in, out] FragmentCount      Number of fragments.\r
-  @param[in]      SadEntry           Related SAD entry.\r
-  @param[out]     RecycleEvent       Event for recycling of resources.\r
-\r
-  @retval EFI_SUCCESS              The operation is successful.\r
-  @retval EFI_UNSUPPORTED          If the IPSEC protocol is not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-IpSecProtectOutboundPacket (\r
-  IN     UINT8                       IpVersion,\r
-  IN OUT VOID                        *IpHead,\r
-  IN OUT UINT8                       *LastHead,\r
-  IN OUT VOID                        **OptionsBuffer, OPTIONAL\r
-  IN OUT UINT32                      *OptionsLength,  OPTIONAL\r
-  IN OUT EFI_IPSEC_FRAGMENT_DATA     **FragmentTable,\r
-  IN OUT UINT32                      *FragmentCount,\r
-  IN     IPSEC_SAD_ENTRY             *SadEntry,\r
-     OUT EFI_EVENT                   *RecycleEvent\r
-  )\r
-{\r
-  if (SadEntry->Id->Proto == EfiIPsecESP) {\r
-    //\r
-    // Process the esp ipsec header of the outbound traffic.\r
-    //\r
-    return IpSecEspOutboundPacket (\r
-             IpVersion,\r
-             IpHead,\r
-             LastHead,\r
-             OptionsBuffer,\r
-             OptionsLength,\r
-             FragmentTable,\r
-             FragmentCount,\r
-             SadEntry,\r
-             RecycleEvent\r
-             );\r
-  }\r
-  //\r
-  // The other protocols are not supported.\r
-  //\r
-  return EFI_UNSUPPORTED;\r
-}\r
index 0c8df4eed8ef453754ba970f21869724dc473d58..5ac0b0ee2afaaf4b2c4a86c30a9972056f91cdfb 100644 (file)
   PACKAGE_NAME                   = NetworkPkg\r
   PACKAGE_GUID                   = 947988BE-8D5C-471a-893D-AD181C46BEBB\r
   PACKAGE_VERSION                = 0.92\r
+[Guids]\r
+  ## LocalNetwork package token space guid\r
+  # Include/Guid/NetworkPkgTokenSpace.h\r
+  gEfiNetworkPkgTokenSpaceGuid  = { 0x40e064b2, 0x0ae0, 0x48b1, { 0xa0, 0x7d, 0xf8, 0xcf, 0x1e, 0x1a, 0x23, 0x10}}\r
+  \r
+[PcdsFeatureFlag]\r
+  gEfiNetworkPkgTokenSpaceGuid.PcdIpsecCertiifcateEnabled|TRUE|BOOLEAN|0x00000001\r
+\r
+[PcdsFixedAtBuild]\r
+gEfiMdeModulePkgTokenSpaceGuid.UefiCaFile|{0x30, 0x82, 0x02, 0x76, 0x30, 0x82, 0x01, 0xDF, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x80, 0x1D, 0xB9, 0x63, 0x93, 0x7C, 0x9D, 0xE0, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0A, 0x4D, 0x79, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x48, 0x5A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4E, 0x31, 0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0D, 0x74, 0x65, 0x73, 0x74, 0x40, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1C, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,  0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x35, 0x33, 0x33, 0x37, 0x5A, 0x17, 0x0D, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x35, 0x33, 0x33, 0x37, 0x5A, 0x30, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0A, 0x4D, 0x79, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x48, 0x5A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4E, 0x31, 0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0D, 0x74, 0x65, 0x73, 0x74, 0x40, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x25, 0x30, 0x23,  0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1C, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8D, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xFC, 0x80, 0x5D, 0x32, 0x55, 0xC7, 0x4C, 0xC6, 0xA8, 0x2F, 0xF7, 0xEC, 0x1F, 0x75, 0x48, 0x02, 0x79, 0xEB, 0xDF, 0x17, 0x1B, 0x08, 0xBA, 0x21, 0xDD, 0xE5, 0x43, 0x06, 0xE8, 0x81, 0xC5, 0x50,  0x3C, 0x18, 0xDD, 0x53, 0xF4, 0xC9, 0xC9, 0xE1, 0x7A, 0xD3, 0xB3, 0x99, 0xA7, 0xC6, 0x43, 0x2A, 0x51, 0x65, 0x10, 0x93, 0xBA, 0x5F, 0x48, 0xAC, 0x54, 0x12, 0x70, 0x9E, 0xF2, 0x9E, 0x7D, 0xF7,  0x22, 0xAA, 0xB7, 0x19, 0xDE, 0xA9, 0x4D, 0x55, 0xAA, 0x41, 0x8F, 0x08, 0xBD, 0x74, 0xFA, 0xE5,  0x57, 0x13, 0xB4, 0x30, 0x9A, 0xBA, 0x56, 0x01, 0x55, 0x8A, 0x9B, 0x5B, 0x50, 0x29, 0x82, 0xF9,  0x00, 0x69, 0x7E, 0x7B, 0x91, 0xA7, 0x2D, 0x48, 0x1A, 0x93, 0x7C, 0xA2, 0xF9, 0x06, 0x64, 0x4B, 0x80, 0xF8, 0x47, 0x58, 0x45, 0x90, 0x09, 0xEA, 0xD6, 0x7B, 0x85, 0x49, 0x2A, 0x4E, 0xB6, 0x71, 0x02, 0x03, 0x01, 0x00, 0x01, 0xA3, 0x10, 0x30, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xEF, 0x38, 0x6A, 0x43, 0x1C, 0x1D, 0x37, 0xBD, 0xF7, 0xCF, 0x15, 0x6A, 0x99, 0x44, 0xE1, 0xFC, 0x68, 0x6E, 0x91, 0x31, 0x9C, 0x1E,  0x8C, 0x1F, 0x72, 0x4B, 0x93, 0x16, 0x1F, 0x06, 0xFE, 0x94, 0xA9, 0x41, 0x64, 0x81, 0xFD, 0xFF,  0xE7, 0x27, 0x4D, 0xE7, 0x59, 0x55, 0xE1, 0x20, 0x14, 0x07, 0x3C, 0x26, 0x78, 0xB0, 0x72, 0x48, 0x76, 0x0C, 0x8B, 0x3F, 0x08, 0xD0, 0x75, 0x7D, 0x76, 0xA4, 0xB5, 0x56, 0xA6, 0xC9, 0x88, 0x17, 0x27, 0x95, 0x85, 0xEE, 0x42, 0x1E, 0x15, 0x0B, 0x05, 0xDC, 0x2F, 0x97, 0x7B, 0x26, 0x82, 0x62, 0x23, 0xDF, 0xBF, 0x55, 0x09, 0xBF, 0x5E, 0x28, 0x1A, 0xCA, 0x1B, 0xEC, 0xA4, 0x81, 0xB7, 0x9D, 0x91, 0xC9, 0x60, 0x5B, 0x29, 0x2B, 0x4C, 0x6F, 0x8B, 0xCC, 0x17, 0xA8, 0xD6, 0x5D, 0x6B, 0xBC, 0x0D, 0x03, 0x31, 0xB0, 0x57, 0xC9, 0xF8, 0x59, 0x88, 0x3D}|VOID*|0x00000001\r
+gEfiMdeModulePkgTokenSpaceGuid.UefiCaFileSize|0x0000027A|UINT32|0x00000002\r
+gEfiMdeModulePkgTokenSpaceGuid.UefiCertificate|{0x30, 0x82, 0x02, 0x4D, 0x30, 0x82, 0x01, 0xB6, 0x02, 0x01, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x74, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0A, 0x4D, 0x79, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x48, 0x5A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4E, 0x31, 0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x0D, 0x74, 0x65, 0x73, 0x74, 0x40, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1C, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x32, 0x30, 0x34, 0x35, 0x39, 0x5A, 0x17, 0x0D, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x30, 0x32, 0x30, 0x34, 0x35, 0x39, 0x5A, 0x30, 0x6A, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x04, 0x55, 0x45, 0x46, 0x49, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x53, 0x48, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4E, 0x31, 0x23, 0x30, 0x21, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01, 0x16, 0x14, 0x75, 0x65, 0x66, 0x69, 0x2E, 0x74, 0x69, 0x61, 0x6E, 0x6F, 0x40, 0x69, 0x6E, 0x74, 0x65, 0x6C, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x03, 0x53, 0x53, 0x47, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x03, 0x53, 0x53, 0x47, 0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8D, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xE9, 0x90, 0x47, 0x0D, 0x79, 0x93, 0xED, 0xF5, 0xBD, 0xC9, 0x56, 0x03, 0xDF, 0xE2, 0x71, 0xA9, 0x42, 0x3B, 0x20, 0x1E, 0xAF, 0x88, 0x9D, 0x3F, 0xE1, 0xDE, 0x61, 0xEE, 0x83, 0xC4, 0x2E, 0x48, 0x7A, 0x1F, 0x86, 0x54, 0xD2, 0xD5, 0x61, 0x94, 0xE1, 0x15, 0x79, 0x65, 0xCB, 0x39, 0xEE, 0x78, 0x68, 0x3D, 0x2C, 0xEB, 0xE4, 0x7A, 0x8D, 0x98, 0x14, 0x28, 0x7E, 0x6B, 0xFD, 0xC5, 0xF5, 0x1B, 0x62, 0xB9, 0x86, 0x7C, 0xA1, 0x7C, 0xE9, 0x8F, 0xC8, 0xF4, 0xF3, 0x95, 0x5A, 0xAF, 0x0C, 0x21, 0x39, 0xEA, 0x47, 0x5A, 0x1E, 0xBD, 0xBE, 0x7F, 0x1B, 0x0F, 0x31, 0xFB, 0xBD, 0x57, 0xAE, 0xD7, 0xCB, 0x46, 0x83, 0x8B, 0x16, 0x19, 0x74, 0xD9, 0x9E, 0x2D, 0x18, 0xE6, 0xA4, 0x5F, 0x90, 0x90, 0x54, 0xE1, 0x4B, 0x7B, 0x57, 0x76, 0xBD, 0xF4, 0xC0, 0x4D, 0x79, 0x5F, 0x64, 0x6C, 0x0D, 0x2D, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x5A, 0x80, 0x5F, 0xD3, 0x3C, 0x93, 0x81, 0xB9, 0x1B, 0xAA, 0x08, 0x1F, 0x47, 0x9C, 0x88,  0xF3, 0x1E, 0xE6, 0x6B, 0xBB, 0x99, 0xE6, 0x23, 0x1A, 0xCB, 0x25, 0x81, 0x54, 0x51, 0x88, 0xDF,  0x9B, 0xC6, 0xBF, 0x60, 0xDB, 0x6C, 0x5D, 0x69, 0xB1, 0x3A, 0xDE, 0x94, 0xEE, 0xD7, 0x6C, 0xF2, 0x2D, 0x63, 0xD3, 0xB3, 0xAB, 0xE6, 0xB5, 0x0A, 0xBF, 0xCE, 0x61, 0xC0, 0xD3, 0x73, 0x9E, 0x80,  0xB5, 0x0C, 0xC0, 0x03, 0x57, 0xA9, 0x56, 0x59, 0x1B, 0xA2, 0x99, 0x03, 0xA6, 0xA3, 0xC4, 0x59, 0xB3, 0xD9, 0x14, 0xA1, 0x34, 0x18, 0xF3, 0x73, 0xB8, 0x54, 0xAA, 0xED, 0x7D, 0x31, 0x3E, 0x23, 0xAD, 0xF1, 0x86, 0xF7, 0xE6, 0xD9, 0x01, 0x0D, 0x68, 0xC6, 0xC5, 0x95, 0x18, 0xD2, 0x89, 0xB7, 0x06, 0x96, 0xC9, 0x11, 0xB9, 0xF0, 0xDA, 0xD9, 0x02, 0x25, 0xC4, 0xB9, 0x72, 0xF8, 0x6D, 0xC5, 0x5B}|VOID*|0x00000003\r
+gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateSize|0x251|UINT32|0x00000004\r
+gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateKey|{0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50,  0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x50, 0x72, 0x6F, 0x63, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, 0x20, 0x34, 0x2C, 0x45, 0x4E, 0x43,  0x52, 0x59, 0x50, 0x54, 0x45, 0x44, 0x0A, 0x44, 0x45, 0x4B, 0x2D, 0x49, 0x6E, 0x66, 0x6F, 0x3A,  0x20, 0x44, 0x45, 0x53, 0x2D, 0x45, 0x44, 0x45, 0x33, 0x2D, 0x43, 0x42, 0x43, 0x2C, 0x32, 0x42,  0x31, 0x46, 0x42, 0x41, 0x43, 0x41, 0x38, 0x36, 0x32, 0x36, 0x33, 0x34, 0x41, 0x37, 0x0A, 0x0A,  0x61, 0x52, 0x78, 0x49, 0x58, 0x33, 0x59, 0x4D, 0x68, 0x49, 0x50, 0x41, 0x73, 0x59, 0x79, 0x6F,  0x6A, 0x49, 0x76, 0x46, 0x7A, 0x42, 0x75, 0x6B, 0x74, 0x6B, 0x4A, 0x47, 0x5A, 0x38, 0x4D, 0x64,  0x33, 0x5A, 0x53, 0x73, 0x39, 0x41, 0x2B, 0x52, 0x2B, 0x57, 0x45, 0x59, 0x41, 0x70, 0x34, 0x63,  0x4F, 0x55, 0x43, 0x4A, 0x78, 0x51, 0x2F, 0x66, 0x4A, 0x38, 0x58, 0x4F, 0x45, 0x64, 0x58, 0x38,  0x0A, 0x31, 0x63, 0x4E, 0x66, 0x4B, 0x2B, 0x49, 0x62, 0x76, 0x4B, 0x4D, 0x68, 0x55, 0x67, 0x30,  0x4B, 0x4E, 0x35, 0x38, 0x37, 0x71, 0x66, 0x2F, 0x4C, 0x31, 0x76, 0x57, 0x58, 0x6F, 0x31, 0x74,  0x5A, 0x6B, 0x59, 0x2B, 0x5A, 0x53, 0x4E, 0x63, 0x46, 0x45, 0x41, 0x76, 0x37, 0x43, 0x43, 0x50,  0x51, 0x6B, 0x64, 0x4A, 0x42, 0x48, 0x35, 0x65, 0x6B, 0x35, 0x44, 0x51, 0x2F, 0x37, 0x6D, 0x71,  0x55, 0x0A, 0x6B, 0x76, 0x78, 0x48, 0x53, 0x50, 0x70, 0x34, 0x66, 0x41, 0x71, 0x47, 0x61, 0x68,  0x54, 0x31, 0x75, 0x37, 0x37, 0x56, 0x66, 0x4E, 0x66, 0x31, 0x53, 0x74, 0x61, 0x73, 0x31, 0x6E,  0x4F, 0x67, 0x6A, 0x50, 0x31, 0x41, 0x6C, 0x7A, 0x6E, 0x6B, 0x6A, 0x57, 0x61, 0x72, 0x6A, 0x51,  0x4F, 0x73, 0x48, 0x46, 0x33, 0x41, 0x46, 0x31, 0x62, 0x61, 0x51, 0x4A, 0x50, 0x5A, 0x31, 0x6A,  0x71, 0x4C, 0x0A, 0x61, 0x30, 0x49, 0x45, 0x6E, 0x30, 0x6C, 0x59, 0x6C, 0x78, 0x35, 0x79, 0x4D,  0x6D, 0x78, 0x54, 0x47, 0x57, 0x79, 0x52, 0x35, 0x70, 0x57, 0x51, 0x35, 0x71, 0x66, 0x78, 0x2B,  0x62, 0x37, 0x64, 0x37, 0x75, 0x71, 0x67, 0x47, 0x69, 0x66, 0x36, 0x6A, 0x44, 0x47, 0x4D, 0x37,  0x68, 0x38, 0x43, 0x78, 0x2F, 0x74, 0x67, 0x2B, 0x61, 0x62, 0x45, 0x31, 0x34, 0x30, 0x2F, 0x50,  0x66, 0x6C, 0x33, 0x0A, 0x33, 0x6A, 0x50, 0x6C, 0x52, 0x75, 0x73, 0x57, 0x6F, 0x6F, 0x63, 0x49,  0x41, 0x76, 0x49, 0x74, 0x79, 0x51, 0x6D, 0x39, 0x39, 0x71, 0x74, 0x34, 0x64, 0x6E, 0x74, 0x6E,  0x74, 0x6F, 0x4A, 0x43, 0x6D, 0x4F, 0x53, 0x79, 0x71, 0x67, 0x4D, 0x6E, 0x76, 0x2F, 0x76, 0x2B,  0x51, 0x48, 0x74, 0x79, 0x4D, 0x73, 0x42, 0x64, 0x38, 0x34, 0x78, 0x45, 0x57, 0x46, 0x36, 0x72,  0x58, 0x4D, 0x52, 0x63, 0x0A, 0x53, 0x2B, 0x66, 0x68, 0x54, 0x71, 0x58, 0x74, 0x54, 0x38, 0x44,  0x50, 0x65, 0x70, 0x2F, 0x56, 0x44, 0x66, 0x65, 0x78, 0x6B, 0x41, 0x63, 0x6D, 0x63, 0x75, 0x41,  0x69, 0x6F, 0x2B, 0x79, 0x64, 0x51, 0x75, 0x49, 0x31, 0x32, 0x7A, 0x50, 0x70, 0x45, 0x68, 0x50,  0x45, 0x68, 0x31, 0x44, 0x50, 0x58, 0x73, 0x64, 0x58, 0x67, 0x64, 0x77, 0x39, 0x75, 0x46, 0x47,  0x6D, 0x63, 0x35, 0x68, 0x52, 0x0A, 0x35, 0x31, 0x57, 0x41, 0x31, 0x65, 0x63, 0x44, 0x48, 0x6A,  0x31, 0x58, 0x32, 0x45, 0x72, 0x36, 0x39, 0x59, 0x70, 0x31, 0x50, 0x69, 0x43, 0x37, 0x49, 0x47,  0x79, 0x6F, 0x71, 0x57, 0x43, 0x37, 0x69, 0x2F, 0x71, 0x6D, 0x6D, 0x72, 0x49, 0x66, 0x6F, 0x41,  0x54, 0x74, 0x39, 0x58, 0x34, 0x30, 0x54, 0x56, 0x63, 0x37, 0x42, 0x63, 0x6A, 0x34, 0x63, 0x54,  0x31, 0x78, 0x37, 0x6B, 0x70, 0x4F, 0x0A, 0x4C, 0x71, 0x67, 0x33, 0x6C, 0x50, 0x78, 0x33, 0x2B,  0x4A, 0x63, 0x33, 0x43, 0x67, 0x34, 0x79, 0x5A, 0x54, 0x66, 0x6E, 0x4A, 0x5A, 0x37, 0x48, 0x76,  0x36, 0x64, 0x68, 0x67, 0x45, 0x6D, 0x70, 0x4D, 0x73, 0x74, 0x46, 0x65, 0x35, 0x34, 0x49, 0x53,  0x76, 0x74, 0x38, 0x37, 0x59, 0x4E, 0x77, 0x74, 0x4C, 0x65, 0x6C, 0x34, 0x67, 0x50, 0x4A, 0x79,  0x53, 0x42, 0x30, 0x4B, 0x76, 0x37, 0x69, 0x0A, 0x33, 0x32, 0x74, 0x37, 0x67, 0x4F, 0x30, 0x79,  0x6D, 0x73, 0x62, 0x71, 0x4A, 0x55, 0x75, 0x79, 0x41, 0x68, 0x47, 0x64, 0x33, 0x63, 0x2B, 0x78,  0x4C, 0x46, 0x2F, 0x63, 0x63, 0x4F, 0x57, 0x44, 0x52, 0x34, 0x79, 0x72, 0x30, 0x6A, 0x79, 0x64,  0x74, 0x70, 0x79, 0x69, 0x64, 0x52, 0x45, 0x66, 0x56, 0x46, 0x66, 0x5\r
+3, 0x6C, 0x39, 0x54, 0x30,  0x6D, 0x53, 0x72, 0x4E, 0x76, 0x43, 0x71, 0x45, 0x0A, 0x52, 0x52, 0x5A, 0x6E, 0x42, 0x56, 0x76,  0x37, 0x50, 0x66, 0x6C, 0x75, 0x72, 0x31, 0x59, 0x35, 0x70, 0x2F, 0x65, 0x78, 0x54, 0x63, 0x56,  0x34, 0x72, 0x4B, 0x52, 0x69, 0x6C, 0x35, 0x58, 0x6A, 0x2F, 0x39, 0x59, 0x56, 0x31, 0x4E, 0x6E,  0x6D, 0x4E, 0x2B, 0x2F, 0x31, 0x31, 0x74, 0x36, 0x58, 0x74, 0x6A, 0x72, 0x75, 0x52, 0x62, 0x33,  0x79, 0x70, 0x38, 0x76, 0x64, 0x6C, 0x61, 0x65, 0x5A, 0x0A, 0x6C, 0x67, 0x45, 0x69, 0x73, 0x30,  0x42, 0x7A, 0x4B, 0x59, 0x39, 0x59, 0x64, 0x58, 0x48, 0x64, 0x46, 0x58, 0x57, 0x59, 0x4F, 0x41,  0x71, 0x50, 0x48, 0x45, 0x65, 0x4B, 0x57, 0x79, 0x61, 0x59, 0x5A, 0x56, 0x79, 0x43, 0x70, 0x51,  0x65, 0x43, 0x53, 0x71, 0x4F, 0x71, 0x48, 0x38, 0x67, 0x42, 0x6B, 0x4F, 0x62, 0x43, 0x69, 0x72,  0x41, 0x6A, 0x65, 0x56, 0x70, 0x35, 0x7A, 0x37, 0x6B, 0x31, 0x0A, 0x64, 0x4F, 0x2F, 0x6D, 0x56,  0x74, 0x49, 0x2B, 0x57, 0x47, 0x30, 0x48, 0x72, 0x37, 0x5A, 0x4C, 0x53, 0x52, 0x78, 0x6F, 0x61,  0x44, 0x47, 0x42, 0x33, 0x4E, 0x35, 0x38, 0x4B, 0x56, 0x45, 0x4F, 0x34, 0x65, 0x46, 0x56, 0x75,  0x6E, 0x59, 0x77, 0x51, 0x42, 0x54, 0x7A, 0x4F, 0x65, 0x57, 0x39, 0x6C, 0x4B, 0x79, 0x49, 0x38,  0x67, 0x4D, 0x45, 0x57, 0x6C, 0x62, 0x4B, 0x72, 0x41, 0x45, 0x49, 0x0A, 0x46, 0x4B, 0x38, 0x7A,  0x58, 0x6F, 0x44, 0x74, 0x39, 0x6A, 0x7A, 0x54, 0x37, 0x67, 0x68, 0x6A, 0x79, 0x45, 0x54, 0x67,  0x44, 0x6C, 0x69, 0x50, 0x53, 0x49, 0x46, 0x6A, 0x79, 0x31, 0x64, 0x6B, 0x6A, 0x6D, 0x68, 0x53,  0x78, 0x79, 0x6A, 0x67, 0x62, 0x71, 0x45, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E,  0x44, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4B, 0x45,  0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A}|VOID*|0x00000005\r
+gEfiMdeModulePkgTokenSpaceGuid.UefiCertificateKeySize|0x3d5|UINT32|0x00000006\r
index b12d5fd04ae5d980e86962ffd7a2bf1575eeaf48..6de9a11415a4f22dbe3de9b576dab2b8817f2b06 100644 (file)
@@ -42,6 +42,9 @@
   NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf\r
   IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf\r
   UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
+  BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
+  OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf\r
+  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\r
 \r
 [LibraryClasses.common.UEFI_DRIVER]\r
   DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf\r