+**/\r
+EFI_STATUS\r
+Ip4IpSecProcessPacket (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN OUT IP4_HEAD **Head,\r
+ IN OUT NET_BUF **Netbuf,\r
+ IN OUT UINT8 **Options,\r
+ IN OUT UINT32 *OptionsLen,\r
+ IN EFI_IPSEC_TRAFFIC_DIR Direction,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ NET_FRAGMENT *FragmentTable;\r
+ NET_FRAGMENT *OriginalFragmentTable;\r
+ UINT32 FragmentCount;\r
+ UINT32 OriginalFragmentCount;\r
+ EFI_EVENT RecycleEvent;\r
+ NET_BUF *Packet;\r
+ IP4_TXTOKEN_WRAP *TxWrap;\r
+ IP4_IPSEC_WRAP *IpSecWrap;\r
+ EFI_STATUS Status;\r
+ IP4_HEAD ZeroHead;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (!mIpSec2Installed) {\r
+ goto ON_EXIT;\r
+ }\r
+ ASSERT (mIpSec != NULL);\r
+\r
+ Packet = *Netbuf;\r
+ RecycleEvent = NULL;\r
+ IpSecWrap = NULL;\r
+ FragmentTable = NULL;\r
+ TxWrap = (IP4_TXTOKEN_WRAP *) Context;\r
+ FragmentCount = Packet->BlockOpNum;\r
+\r
+ ZeroMem (&ZeroHead, sizeof (IP4_HEAD));\r
+\r
+ //\r
+ // Check whether the IPsec enable variable is set.\r
+ //\r
+ if (mIpSec->DisabledFlag) {\r
+ //\r
+ // If IPsec is disabled, restore the original MTU\r
+ //\r
+ IpSb->MaxPacketSize = IpSb->OldMaxPacketSize;\r
+ goto ON_EXIT;\r
+ } else {\r
+ //\r
+ // If IPsec is enabled, use the MTU which reduce the IPsec header length.\r
+ //\r
+ IpSb->MaxPacketSize = IpSb->OldMaxPacketSize - IP4_MAX_IPSEC_HEADLEN;\r
+ }\r
+\r
+ //\r
+ // Rebuild fragment table from netbuf to ease IPsec process.\r
+ //\r
+ FragmentTable = AllocateZeroPool (FragmentCount * sizeof (NET_FRAGMENT));\r
+\r
+ if (FragmentTable == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = NetbufBuildExt (Packet, FragmentTable, &FragmentCount);\r
+\r
+ //\r
+ // Record the original FragmentTable and count.\r
+ //\r
+ OriginalFragmentTable = FragmentTable;\r
+ OriginalFragmentCount = FragmentCount;\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (FragmentTable);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Convert host byte order to network byte order\r
+ //\r
+ Ip4NtohHead (*Head);\r
+\r
+ Status = mIpSec->ProcessExt (\r
+ mIpSec,\r
+ IpSb->Controller,\r
+ IP_VERSION_4,\r
+ (VOID *) (*Head),\r
+ &(*Head)->Protocol,\r
+ (VOID **) Options,\r
+ OptionsLen,\r
+ (EFI_IPSEC_FRAGMENT_DATA **) (&FragmentTable),\r
+ &FragmentCount,\r
+ Direction,\r
+ &RecycleEvent\r
+ );\r
+ //\r
+ // Convert back to host byte order\r
+ //\r
+ Ip4NtohHead (*Head);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (OriginalFragmentTable);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (OriginalFragmentTable == FragmentTable && OriginalFragmentCount == FragmentCount) {\r
+ //\r
+ // For ByPass Packet\r
+ //\r
+ FreePool (FragmentTable);\r
+ goto ON_EXIT;\r
+ } else {\r
+ //\r
+ // Free the FragmentTable which allocated before calling the IPsec.\r
+ //\r
+ FreePool (OriginalFragmentTable);\r
+ }\r
+\r
+ if (Direction == EfiIPsecOutBound && TxWrap != NULL) {\r
+\r
+ TxWrap->IpSecRecycleSignal = RecycleEvent;\r
+ TxWrap->Packet = NetbufFromExt (\r
+ FragmentTable,\r
+ FragmentCount,\r
+ IP4_MAX_HEADLEN,\r
+ 0,\r
+ Ip4FreeTxToken,\r
+ TxWrap\r
+ );\r
+ if (TxWrap->Packet == NULL) {\r
+ //\r
+ // Recover the TxWrap->Packet, if meet a error, and the caller will free\r
+ // the TxWrap.\r
+ //\r
+ TxWrap->Packet = *Netbuf;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Free orginal Netbuf.\r
+ //\r
+ NetIpSecNetbufFree (*Netbuf);\r
+ *Netbuf = TxWrap->Packet;\r
+\r
+ } else {\r
+\r
+ IpSecWrap = AllocateZeroPool (sizeof (IP4_IPSEC_WRAP));\r
+\r
+ if (IpSecWrap == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ gBS->SignalEvent (RecycleEvent);\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ IpSecWrap->IpSecRecycleSignal = RecycleEvent;\r
+ IpSecWrap->Packet = Packet;\r
+ Packet = NetbufFromExt (\r
+ FragmentTable,\r
+ FragmentCount,\r
+ IP4_MAX_HEADLEN,\r
+ 0,\r
+ Ip4IpSecFree,\r
+ IpSecWrap\r
+ );\r
+\r
+ if (Packet == NULL) {\r
+ Packet = IpSecWrap->Packet;\r
+ gBS->SignalEvent (RecycleEvent);\r
+ FreePool (IpSecWrap);\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ if (Direction == EfiIPsecInBound && 0 != CompareMem (*Head, &ZeroHead, sizeof (IP4_HEAD))) {\r
+ Ip4PrependHead (Packet, *Head, *Options, *OptionsLen);\r
+ Ip4NtohHead (Packet->Ip.Ip4);\r
+ NetbufTrim (Packet, ((*Head)->HeadLen << 2), TRUE);\r