]> git.proxmox.com Git - mirror_edk2.git/commitdiff
add iSCSI protocol
authoreric_tian <eric_tian@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 24 Dec 2007 02:20:21 +0000 (02:20 +0000)
committereric_tian <eric_tian@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 24 Dec 2007 02:20:21 +0000 (02:20 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4423 6f19259b-4bc3-4df7-8a09-765794883524

30 files changed:
MdeModulePkg/Include/Library/NetLib.h
MdeModulePkg/MdeModulePkg.dsc
MdeModulePkg/Universal/iScsi/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsi.inf [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiCHAP.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiCHAP.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiCommon.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiConfig.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiConfig.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiConfigDxe.vfr [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiConfigDxeStrings.uni [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiConfigNVDataStruc.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiDhcp.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiDhcp.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiDriver.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiDriver.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiExtScsiPassThru.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiExtScsiPassThru.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiIbft.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiIbft.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiImpl.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiInitiatorName.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiMisc.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiMisc.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiProto.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiProto.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiTcp4Io.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/IScsiTcp4Io.h [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/Md5.c [new file with mode: 0644]
MdeModulePkg/Universal/iScsi/Md5.h [new file with mode: 0644]

index 4a621e111eb4573848e54c33c1f697df5ec98ffe..e621c24c8db85c31ac713299adf0db3ebafbeae8 100644 (file)
@@ -24,6 +24,8 @@ Abstract:
 #define _NET_LIB_H_
 
 #include <PiDxe.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
 #include <Protocol/DriverBinding.h>
 #include <Protocol/ComponentName.h>
 #include <Protocol/DriverConfiguration.h>
@@ -214,6 +216,8 @@ extern EFI_IPv4_ADDRESS  mZeroIp4Addr;
 
 #define NET_IS_DIGIT(Ch)            (('0' <= (Ch)) && ((Ch) <= '9'))
 #define NET_ROUNDUP(size, unit)     (((size) + (unit) - 1) & (~((unit) - 1)))
+#define NET_IS_LOWER_CASE_CHAR(Ch)  (('a' <= (Ch)) && ((Ch) <= 'z'))
+#define NET_IS_UPPER_CASE_CHAR(Ch)  (('A' <= (Ch)) && ((Ch) <= 'Z'))
 
 //
 // Wrap functions to ease the impact of EFI library changes.
index bda1f8bfa0f8ca9c0ee8c1ab4ff7feb17ac3f949..5c57569da6862705d1f729c50c14afbfece9adc2 100644 (file)
@@ -35,6 +35,7 @@
   PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf\r
   PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf\r
   PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf\r
+  FrameworkIfrSupportLib|IntelFrameworkPkg/Library/FrameworkIfrSupportLib/IfrSupportLib.inf\r
 \r
   PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf\r
   PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf\r
   MdeModulePkg/Library/PeiS3LibNull/PeiS3LibNull.inf\r
   MdeModulePkg/Library/PeiRecoveryLibNull/PeiRecoveryLibNull.inf\r
 \r
+  MdeModulePkg/Universal/iScsi/IScsi.inf\r
+\r
   MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf\r
   MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf\r
   MdeModulePkg/Universal/Network/Ip4ConfigDxe/Ip4ConfigDxe.inf\r
diff --git a/MdeModulePkg/Universal/iScsi/ComponentName.c b/MdeModulePkg/Universal/iScsi/ComponentName.c
new file mode 100644 (file)
index 0000000..146dd3c
--- /dev/null
@@ -0,0 +1,146 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+  ComponentName protocol for iSCSI.\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL     gIScsiComponentName = {\r
+  IScsiComponentNameGetDriverName,\r
+  IScsiComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL    gIScsiComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IScsiComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IScsiComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIScsiDriverNameTable[] = {\r
+       {"eng;en", L"iSCSI Driver"}, \r
+       {NULL, NULL}\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL   *This,\r
+  IN  CHAR8                         *Language,\r
+  OUT CHAR16                        **DriverName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+  Arguments:\r
+    This       - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    Language   - A pointer to a three character ISO 639-2 language identifier.\r
+                 This is the language of the driver name that that the caller \r
+                 is requesting, and it must match one of the languages specified\r
+                 in SupportedLanguages.  The number of languages supported by a \r
+                 driver is up to the driver writer.\r
+    DriverName - A pointer to the Unicode string to return.  This Unicode string\r
+                 is the name of the driver specified by This in the language \r
+                 specified by Language.\r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the Driver specified by This\r
+                            and the language specified by Language was returned \r
+                            in DriverName.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - DriverName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the \r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return LookupUnicodeString2 (\r
+          Language,\r
+          This->SupportedLanguages,\r
+          mIScsiDriverNameTable,\r
+          DriverName,\r
+          (BOOLEAN)(This == &gIScsiComponentName)\r
+          );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL   *This,\r
+  IN  EFI_HANDLE                    ControllerHandle,\r
+  IN  EFI_HANDLE                    ChildHandle        OPTIONAL,\r
+  IN  CHAR8                         *Language,\r
+  OUT CHAR16                        **ControllerName\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Retrieves a Unicode string that is the user readable name of the controller\r
+    that is being managed by an EFI Driver.\r
+\r
+  Arguments:\r
+    This             - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+    ControllerHandle - The handle of a controller that the driver specified by \r
+                       This is managing.  This handle specifies the controller \r
+                       whose name is to be returned.\r
+    ChildHandle      - The handle of the child controller to retrieve the name \r
+                       of.  This is an optional parameter that may be NULL.  It \r
+                       will be NULL for device drivers.  It will also be NULL \r
+                       for a bus drivers that wish to retrieve the name of the \r
+                       bus controller.  It will not be NULL for a bus driver \r
+                       that wishes to retrieve the name of a child controller.\r
+    Language         - A pointer to a three character ISO 639-2 language \r
+                       identifier.  This is the language of the controller name \r
+                       that that the caller is requesting, and it must match one\r
+                       of the languages specified in SupportedLanguages.  The \r
+                       number of languages supported by a driver is up to the \r
+                       driver writer.\r
+    ControllerName   - A pointer to the Unicode string to return.  This Unicode\r
+                       string is the name of the controller specified by \r
+                       ControllerHandle and ChildHandle in the language \r
+                       specified by Language from the point of view of the \r
+                       driver specified by This. \r
+\r
+  Returns:\r
+    EFI_SUCCESS           - The Unicode string for the user readable name in the \r
+                            language specified by Language for the driver \r
+                            specified by This was returned in DriverName.\r
+    EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid \r
+                            EFI_HANDLE.\r
+    EFI_INVALID_PARAMETER - Language is NULL.\r
+    EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+    EFI_UNSUPPORTED       - The driver specified by This is not currently \r
+                            managing the controller specified by \r
+                            ControllerHandle and ChildHandle.\r
+    EFI_UNSUPPORTED       - The driver specified by This does not support the \r
+                            language specified by Language.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsi.inf b/MdeModulePkg/Universal/iScsi/IScsi.inf
new file mode 100644 (file)
index 0000000..faa570d
--- /dev/null
@@ -0,0 +1,96 @@
+#/** @file\r
+#  Component description file for iSCSI module.\r
+#\r
+#  Copyright (c) 2006 - 2007, Intel Corporation\r
+#  All rights reserved. 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
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = iSCSI\r
+  FILE_GUID                      = 4579B72D-7EC4-4dd4-8486-083C86B182A7\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  EDK_RELEASE_VERSION            = 0x00020000\r
+  EFI_SPECIFICATION_VERSION      = 0x00020000\r
+\r
+  ENTRY_POINT                    = IScsiDriverEntryPoint\r
+  UNLOAD_IMAGE                   = EfiIScsiUnload\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gIScsiDriverBinding\r
+#  COMPONENT_NAME                =  gIScsiComponentName\r
+#\r
+\r
+[Sources.common]\r
+  IScsiTcp4Io.h\r
+  IScsiProto.h\r
+  IScsiMisc.h\r
+  IScsiIbft.h\r
+  IScsiExtScsiPassThru.h\r
+  IScsiDriver.h\r
+  IScsiDhcp.h\r
+  IScsiCommon.h\r
+  IScsiCHAP.h\r
+  IScsiTcp4Io.c\r
+  IScsiProto.c\r
+  IScsiMisc.c\r
+  IScsiInitiatorName.c\r
+  IScsiIbft.c\r
+  IScsiExtScsiPassThru.c\r
+  IScsiDriver.c\r
+  IScsiDhcp.c\r
+  IScsiCHAP.c\r
+  ComponentName.c\r
+  Md5.c\r
+  IScsiConfigDxeStrings.uni\r
+  IScsiConfigDxe.vfr\r
+  IScsiConfig.c\r
+  IScsiConfig.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  UefiLib\r
+  BaseLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+  DevicePathLib\r
+  DebugLib\r
+  PrintLib\r
+  FrameworkHiiLib\r
+  FrameworkIfrSupportLib\r
+  NetLib\r
+\r
+[Protocols]\r
+  gEfiIScsiInitiatorNameProtocolGuid\r
+  gEfiBlockIoProtocolGuid\r
+  gEfiTcp4ProtocolGuid\r
+  gEfiExtScsiPassThruProtocolGuid\r
+  gEfiDevicePathProtocolGuid\r
+  gEfiTcp4ServiceBindingProtocolGuid\r
+  gEfiFormCallbackProtocolGuid\r
+  gEfiFormBrowserProtocolGuid\r
+  gEfiPciIoProtocolGuid\r
+  gEfiAcpiSupportProtocolGuid\r
+  gEfiDhcp4ProtocolGuid\r
+  gEfiDhcp4ServiceBindingProtocolGuid
\ No newline at end of file
diff --git a/MdeModulePkg/Universal/iScsi/IScsiCHAP.c b/MdeModulePkg/Universal/iScsi/IScsiCHAP.c
new file mode 100644 (file)
index 0000000..e6ea8b5
--- /dev/null
@@ -0,0 +1,429 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiCHAP.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+#include "Md5.h"\r
+\r
+EFI_GUID  mIScsiCHAPAuthInfoGuid = ISCSI_CHAP_AUTH_INFO_GUID;\r
+\r
+EFI_STATUS\r
+IScsiCHAPCalculateResponse (\r
+  IN  UINT32  ChapIdentifier,\r
+  IN  CHAR8   *ChapSecret,\r
+  IN  UINT32  SecretLength,\r
+  IN  UINT8   *ChapChallenge,\r
+  IN  UINT32  ChallengeLength,\r
+  OUT UINT8   *ChapResponse\r
+  )\r
+{\r
+  MD5_CTX     Md5Ctx;\r
+  CHAR8       IdByte[1];\r
+  EFI_STATUS  Status;\r
+\r
+  Status = MD5Init (&Md5Ctx);\r
+\r
+  //\r
+  // Hash Identifier - Only calculate 1 byte data (RFC1994)\r
+  //\r
+  IdByte[0] = (CHAR8) ChapIdentifier;\r
+  MD5Update (&Md5Ctx, IdByte, 1);\r
+\r
+  //\r
+  // Hash Secret\r
+  //\r
+  if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN - 1) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  MD5Update (&Md5Ctx, ChapSecret, SecretLength);\r
+\r
+  //\r
+  // Hash Challenge received from Target\r
+  //\r
+  MD5Update (&Md5Ctx, ChapChallenge, ChallengeLength);\r
+\r
+  Status = MD5Final (&Md5Ctx, ChapResponse);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiCHAPAuthTarget (\r
+  IN  ISCSI_CHAP_AUTH_DATA  *AuthData,\r
+  IN  UINT8                 *TargetResponse\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      SecretSize;\r
+  UINT8       VerifyRsp[ISCSI_CHAP_RSP_LEN];\r
+\r
+  Status      = EFI_SUCCESS;\r
+\r
+  SecretSize  = (UINT32) AsciiStrLen (AuthData->AuthConfig.ReverseCHAPSecret);\r
+  Status = IScsiCHAPCalculateResponse (\r
+            AuthData->OutIdentifier,\r
+            AuthData->AuthConfig.ReverseCHAPSecret,\r
+            SecretSize,\r
+            AuthData->OutChallenge,\r
+            AuthData->OutChallengeLength,\r
+            VerifyRsp\r
+            );\r
+\r
+  if (NetCompareMem (VerifyRsp, TargetResponse, ISCSI_CHAP_RSP_LEN)) {\r
+    Status = EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiCHAPOnRspReceived (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN BOOLEAN           Transit\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function checks the received iSCSI Login Response during the security\r
+  negotiation stage.\r
+  \r
+Arguments:\r
+\r
+  Conn    - The iSCSI connection.\r
+  Transit - The transit flag of the latest iSCSI Login Response.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The Login Response passed the CHAP validation.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+  EFI_PROTOCOL_ERROR   - Some kind of protocol error happend.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  ISCSI_SESSION             *Session;\r
+  ISCSI_SESSION_CONFIG_DATA *ConfigData;\r
+  ISCSI_CHAP_AUTH_DATA      *AuthData;\r
+  CHAR8                     *Value;\r
+  UINT8                     *Data;\r
+  UINT32                    Len;\r
+  NET_LIST_ENTRY            *KeyValueList;\r
+  UINTN                     Algorithm;\r
+  CHAR8                     *Identifier;\r
+  CHAR8                     *Challenge;\r
+  CHAR8                     *Name;\r
+  CHAR8                     *Response;\r
+  UINT8                     TargetRsp[ISCSI_CHAP_RSP_LEN];\r
+  UINT32                    RspLen;\r
+\r
+  ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
+  ASSERT (Conn->RspQue.BufNum != 0);\r
+\r
+  Session     = Conn->Session;\r
+  ConfigData  = &Session->ConfigData;\r
+  AuthData    = &Session->AuthData;\r
+\r
+  Len         = Conn->RspQue.BufSize;\r
+  Data        = NetAllocatePool (Len);\r
+  if (Data == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Copy the data in case the data spans over multiple PDUs.\r
+  //\r
+  NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
+\r
+  //\r
+  // Build the key-value list from the data segment of the Login Response.\r
+  //\r
+  KeyValueList = IScsiBuildKeyValueList (Data, Len);\r
+  if (KeyValueList == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = EFI_PROTOCOL_ERROR;\r
+\r
+  switch (Conn->CHAPStep) {\r
+  case ISCSI_CHAP_INITIAL:\r
+    //\r
+    // The first Login Response.\r
+    //\r
+    Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
+    if (Value == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Session->TargetPortalGroupTag = (UINT16) AsciiStrDecimalToUintn (Value);\r
+\r
+    Value                         = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_AUTH_METHOD);\r
+    if (Value == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+    //\r
+    // Initiator mandates CHAP authentication but target replies without "CHAP" or\r
+    // initiator suggets "None" but target replies with some kind of auth method.\r
+    //\r
+    if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) == 0) {\r
+      if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {\r
+        goto ON_EXIT;\r
+      }\r
+    } else {\r
+      if (AuthData->AuthConfig.CHAPType != ISCSI_CHAP_NONE) {\r
+        goto ON_EXIT;\r
+      }\r
+    }\r
+    //\r
+    // Transit to CHAP step one.\r
+    //\r
+    Conn->CHAPStep  = ISCSI_CHAP_STEP_ONE;\r
+    Status          = EFI_SUCCESS;\r
+    break;\r
+\r
+  case ISCSI_CHAP_STEP_TWO:\r
+    //\r
+    // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
+    //\r
+    Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_ALGORITHM);\r
+    if (Value == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Algorithm = AsciiStrDecimalToUintn (Value);\r
+    if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {\r
+      //\r
+      // Unsupported algorithm is chosen by target.\r
+      //\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Identifier = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_IDENTIFIER);\r
+    if (Identifier == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Challenge = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_CHALLENGE);\r
+    if (Challenge == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+    //\r
+    // Process the CHAP identifier and CHAP Challenge from Target\r
+    // Calculate Response value\r
+    //\r
+    AuthData->InIdentifier      = (UINT32) AsciiStrDecimalToUintn (Identifier);\r
+    AuthData->InChallengeLength = ISCSI_CHAP_AUTH_MAX_LEN;\r
+    IScsiHexToBin ((UINT8 *) AuthData->InChallenge, &AuthData->InChallengeLength, Challenge);\r
+    Status = IScsiCHAPCalculateResponse (\r
+              AuthData->InIdentifier,\r
+              AuthData->AuthConfig.CHAPSecret,\r
+              (UINT32) AsciiStrLen (AuthData->AuthConfig.CHAPSecret),\r
+              AuthData->InChallenge,\r
+              AuthData->InChallengeLength,\r
+              AuthData->CHAPResponse\r
+              );\r
+\r
+    //\r
+    // Transit to next step.\r
+    //\r
+    Conn->CHAPStep = ISCSI_CHAP_STEP_THREE;\r
+    break;\r
+\r
+  case ISCSI_CHAP_STEP_THREE:\r
+    //\r
+    // one way CHAP authentication and the target would like to\r
+    // authenticate us.\r
+    //\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  case ISCSI_CHAP_STEP_FOUR:\r
+    ASSERT (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_MUTUAL);\r
+    //\r
+    // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
+    //\r
+    Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
+    if (Name == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Response = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_RESPONSE);\r
+    if (Response == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    RspLen = ISCSI_CHAP_RSP_LEN;\r
+    IScsiHexToBin (TargetRsp, &RspLen, Response);\r
+\r
+    //\r
+    // Check the CHAP Name and Response replied by Target.\r
+    //\r
+    Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  IScsiFreeKeyValueList (KeyValueList);\r
+\r
+  NetFreePool (Data);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiCHAPToSendReq (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN NET_BUF           *Pdu\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function fills the CHAP authentication information into the login PDU\r
+  during the security negotiation stage in the iSCSI connection login.\r
+  \r
+Arguments:\r
+\r
+  Conn - The iSCSI connection.\r
+  Pdu  - The PDU to send out.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - All check passed and the phase-related CHAP authentication\r
+                         info is filled into the iSCSI PDU.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+  EFI_PROTOCOL_ERROR   - Some kind of protocol error happend.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  ISCSI_SESSION             *Session;\r
+  ISCSI_LOGIN_REQUEST       *LoginReq;\r
+  ISCSI_SESSION_CONFIG_DATA *ConfigData;\r
+  ISCSI_CHAP_AUTH_DATA      *AuthData;\r
+  CHAR8                     *Value;\r
+  CHAR8                     ValueStr[256];\r
+  CHAR8                     *Response;\r
+  UINT32                    RspLen;\r
+  CHAR8                     *Challenge;\r
+  UINT32                    ChallengeLen;\r
+\r
+  ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
+\r
+  Session     = Conn->Session;\r
+  ConfigData  = &Session->ConfigData;\r
+  AuthData    = &Session->AuthData;\r
+  LoginReq    = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);\r
+  Status      = EFI_SUCCESS;\r
+\r
+  RspLen      = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
+  Response    = NetAllocatePool (RspLen);\r
+  if (Response == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ChallengeLen  = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
+  Challenge     = NetAllocatePool (ChallengeLen);\r
+  if (Challenge == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  switch (Conn->CHAPStep) {\r
+  case ISCSI_CHAP_INITIAL:\r
+    //\r
+    // It's the initial Login Request. Fill in the key=value pairs mandatory\r
+    // for the initial Login Request.\r
+    //\r
+    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_INITIATOR_NAME, Session->InitiatorName);\r
+    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
+    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_TARGET_NAME, Session->ConfigData.NvData.TargetName);\r
+\r
+    if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {\r
+      Value = ISCSI_KEY_VALUE_NONE;\r
+      ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+    } else {\r
+      Value = ISCSI_AUTH_METHOD_CHAP;\r
+    }\r
+\r
+    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
+\r
+    break;\r
+\r
+  case ISCSI_CHAP_STEP_ONE:\r
+    //\r
+    // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.\r
+    //\r
+    AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);\r
+    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);\r
+\r
+    Conn->CHAPStep = ISCSI_CHAP_STEP_TWO;\r
+    break;\r
+\r
+  case ISCSI_CHAP_STEP_THREE:\r
+    //\r
+    // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
+    // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target ahtentication is\r
+    // required too.\r
+    //\r
+    // CHAP_N=<N>\r
+    //\r
+    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (UINT8 *) &AuthData->AuthConfig.CHAPName);\r
+    //\r
+    // CHAP_R=<R>\r
+    //\r
+    IScsiBinToHex ((UINT8 *) AuthData->CHAPResponse, ISCSI_CHAP_RSP_LEN, Response, &RspLen);\r
+    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
+\r
+    if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_MUTUAL) {\r
+      //\r
+      // CHAP_I=<I>\r
+      //\r
+      IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);\r
+      AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
+      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
+      //\r
+      // CHAP_C=<C>\r
+      //\r
+      IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN);\r
+      AuthData->OutChallengeLength = ISCSI_CHAP_RSP_LEN;\r
+      IScsiBinToHex ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN, Challenge, &ChallengeLen);\r
+      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
+\r
+      Conn->CHAPStep = ISCSI_CHAP_STEP_FOUR;\r
+    }\r
+    //\r
+    // set the stage transition flag.\r
+    //\r
+    ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_PROTOCOL_ERROR;\r
+    break;\r
+  }\r
+\r
+  NetFreePool (Response);\r
+  NetFreePool (Challenge);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiCHAP.h b/MdeModulePkg/Universal/iScsi/IScsiCHAP.h
new file mode 100644 (file)
index 0000000..4a15291
--- /dev/null
@@ -0,0 +1,95 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiCHAP.h\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_CHAP_H_\r
+#define _ISCSI_CHAP_H_\r
+\r
+#define ISCSI_CHAP_AUTH_INFO_GUID \\r
+  { \\r
+    0x786ec0ac, 0x65ae, 0x4d1b, 0xb1, 0x37, 0xd, 0x11, 0xa, 0x48, 0x37, 0x97 \\r
+  }\r
+\r
+extern EFI_GUID mIScsiCHAPAuthInfoGuid;\r
+\r
+#define ISCSI_AUTH_METHOD_CHAP    "CHAP"\r
+\r
+#define ISCSI_KEY_CHAP_ALGORITHM  "CHAP_A"\r
+#define ISCSI_KEY_CHAP_IDENTIFIER "CHAP_I"\r
+#define ISCSI_KEY_CHAP_CHALLENGE  "CHAP_C"\r
+#define ISCSI_KEY_CHAP_NAME       "CHAP_N"\r
+#define ISCSI_KEY_CHAP_RESPONSE   "CHAP_R"\r
+\r
+#define ISCSI_CHAP_ALGORITHM_MD5  5\r
+\r
+#define ISCSI_CHAP_AUTH_MAX_LEN   1024\r
+#define ISCSI_CHAP_RSP_LEN        16  // == MD5_HASHSIZE\r
+typedef enum {\r
+  ISCSI_CHAP_INITIAL,\r
+  ISCSI_CHAP_STEP_ONE,\r
+  ISCSI_CHAP_STEP_TWO,\r
+  ISCSI_CHAP_STEP_THREE,\r
+  ISCSI_CHAP_STEP_FOUR\r
+} ISCSI_CHAP_STEP;\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct _ISCSI_CHAP_AUTH_CONFIG_NVDATA {\r
+  UINT8 CHAPType;\r
+  CHAR8 CHAPName[ISCSI_CHAP_NAME_MAX_LEN];\r
+  CHAR8 CHAPSecret[ISCSI_CHAP_SECRET_MAX_LEN];\r
+  CHAR8 ReverseCHAPName[ISCSI_CHAP_NAME_MAX_LEN];\r
+  CHAR8 ReverseCHAPSecret[ISCSI_CHAP_SECRET_MAX_LEN];\r
+} ISCSI_CHAP_AUTH_CONFIG_NVDATA;\r
+\r
+#pragma pack()\r
+\r
+//\r
+// ISCSI CHAP Authentication Data\r
+//\r
+typedef struct _ISCSI_CHAP_AUTH_DATA {\r
+  ISCSI_CHAP_AUTH_CONFIG_NVDATA AuthConfig;\r
+  UINT32                        InIdentifier;\r
+  UINT8                         InChallenge[ISCSI_CHAP_AUTH_MAX_LEN];\r
+  UINT32                        InChallengeLength;\r
+  //\r
+  // Calculated CHAP Response (CHAP_R) value\r
+  //\r
+  UINT8                         CHAPResponse[ISCSI_CHAP_RSP_LEN];\r
+\r
+  //\r
+  // Auth-data to be sent out for mutual authentication\r
+  //\r
+  UINT32                        OutIdentifier;\r
+  UINT8                         OutChallenge[ISCSI_CHAP_AUTH_MAX_LEN];\r
+  UINT32                        OutChallengeLength;\r
+} ISCSI_CHAP_AUTH_DATA;\r
+\r
+EFI_STATUS\r
+IScsiCHAPOnRspReceived (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN BOOLEAN           Transit\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiCHAPToSendReq (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN NET_BUF           *Pdu\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiCommon.h b/MdeModulePkg/Universal/iScsi/IScsiCommon.h
new file mode 100644 (file)
index 0000000..2d0991c
--- /dev/null
@@ -0,0 +1,28 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiCommon.h\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_COMMON_H_\r
+#define _ISCSI_COMMON_H_\r
+\r
+typedef struct _ISCSI_SESSION             ISCSI_SESSION;\r
+typedef struct _ISCSI_CONNECTION          ISCSI_CONNECTION;\r
+typedef struct _ISCSI_DRIVER_DATA         ISCSI_DRIVER_DATA;\r
+typedef struct _ISCSI_SESSION_CONFIG_DATA ISCSI_SESSION_CONFIG_DATA;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfig.c b/MdeModulePkg/Universal/iScsi/IScsiConfig.c
new file mode 100644 (file)
index 0000000..a8ef2c7
--- /dev/null
@@ -0,0 +1,1074 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiConfig.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_GUID        mVendorGuid             = ISCSI_CONFIG_GUID;\r
+BOOLEAN         mIScsiDeviceListUpdated = FALSE;\r
+UINTN           mNumberOfIScsiDevices   = 0;\r
+\r
+NET_LIST_ENTRY  mIScsiConfigFormList = {\r
+  &mIScsiConfigFormList,\r
+  &mIScsiConfigFormList\r
+};\r
+\r
+STATIC\r
+VOID\r
+IScsiIpToStr (\r
+  IN  EFI_IPv4_ADDRESS  *Ip,\r
+  OUT CHAR16            *Str\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the IPv4 address into a dotted string.\r
+\r
+Arguments:\r
+\r
+  Ip  - The IPv4 address.\r
+  Str - The dotted IP string.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  UnicodeSPrint ( Str, 2 * IP4_STR_MAX_SIZE, L"%d.%d.%d.%d", Ip->Addr[0], Ip->Addr[1], Ip->Addr[2], Ip->Addr[3]);\r
+}\r
+\r
+VOID\r
+PopUpInvalidNotify (\r
+  IN CHAR16 *Warning\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Pop up an invalid notify which displays the message in Warning.\r
+\r
+Arguments:\r
+\r
+  Warning - The warning message.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_FORM_BROWSER_PROTOCOL *FormBrowser;\r
+  EFI_STATUS                Status;\r
+  EFI_INPUT_KEY             Key;\r
+  CHAR16                    Buffer[10];\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiFormBrowserProtocolGuid,\r
+                  NULL,\r
+                  (VOID **)&FormBrowser\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  FormBrowser->CreatePopUp (1, TRUE, 10, Buffer, &Key, Warning);\r
+}\r
+\r
+EFI_STATUS\r
+IScsiUpdateDeviceList (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Update the list of iSCSI devices the iSCSI driver is controlling.\r
+\r
+Arguments:\r
+\r
+  None.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  ISCSI_DEVICE_LIST           *DeviceList;\r
+  UINTN                       DataSize;\r
+  UINTN                       NumHandles;\r
+  EFI_HANDLE                  *Handles;\r
+  UINTN                       HandleIndex;\r
+  UINTN                       Index;\r
+  UINTN                       LastDeviceIndex;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  EFI_SIMPLE_NETWORK_MODE     *Mode;\r
+  ISCSI_MAC_INFO              *CurMacInfo;\r
+  ISCSI_MAC_INFO              TempMacInfo;\r
+  CHAR16                      MacString[65];\r
+  UINTN                       DeviceListSize;\r
+\r
+  //\r
+  // Dump all the handles the Simple Network Protocol is installed on.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  NULL,\r
+                  &NumHandles,\r
+                  &Handles\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DataSize = 0;\r
+  Status = gRT->GetVariable (\r
+                  L"iSCSIDeviceList",\r
+                  &mVendorGuid,\r
+                  NULL,\r
+                  &DataSize,\r
+                  NULL\r
+                  );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    DeviceList = (ISCSI_DEVICE_LIST *) NetAllocatePool (DataSize);\r
+\r
+    gRT->GetVariable (\r
+          L"iSCSIDeviceList",\r
+          &mVendorGuid,\r
+          NULL,\r
+          &DataSize,\r
+          DeviceList\r
+          );\r
+\r
+    LastDeviceIndex = 0;\r
+\r
+    for (HandleIndex = 0; HandleIndex < NumHandles; HandleIndex++) {\r
+      gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);\r
+\r
+      Mode = Snp->Mode;\r
+\r
+      for (Index = LastDeviceIndex; Index < DeviceList->NumDevice; Index++) {\r
+        CurMacInfo = &DeviceList->MacInfo[Index];\r
+        if ((CurMacInfo->Len == Mode->HwAddressSize) &&\r
+            (NET_MAC_EQUAL (&CurMacInfo->Mac, &Mode->PermanentAddress, Mode->HwAddressSize))\r
+            ) {\r
+          //\r
+          // The previous configured NIC is still here.\r
+          //\r
+          if (Index != LastDeviceIndex) {\r
+            //\r
+            // Swap the current MAC address entry with the one indexed by\r
+            // LastDeviceIndex.\r
+            //\r
+            NetCopyMem (&TempMacInfo, CurMacInfo, sizeof (ISCSI_MAC_INFO));\r
+            NetCopyMem (CurMacInfo, &DeviceList->MacInfo[LastDeviceIndex], sizeof (ISCSI_MAC_INFO));\r
+            NetCopyMem (&DeviceList->MacInfo[LastDeviceIndex], &TempMacInfo, sizeof (ISCSI_MAC_INFO));\r
+          }\r
+\r
+          LastDeviceIndex++;\r
+        }\r
+      }\r
+\r
+      if (LastDeviceIndex == DeviceList->NumDevice) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    for (Index = LastDeviceIndex; Index < DeviceList->NumDevice; Index++) {\r
+      //\r
+      // delete the variables\r
+      //\r
+      CurMacInfo = &DeviceList->MacInfo[Index];\r
+      IScsiMacAddrToStr (&CurMacInfo->Mac, CurMacInfo->Len, MacString);\r
+      gRT->SetVariable (MacString, &gEfiIScsiInitiatorNameProtocolGuid, 0, 0, NULL);\r
+      gRT->SetVariable (MacString, &mIScsiCHAPAuthInfoGuid, 0, 0, NULL);\r
+    }\r
+\r
+    NetFreePool (DeviceList);\r
+  } else if (Status != EFI_NOT_FOUND) {\r
+    NetFreePool (Handles);\r
+    return Status;\r
+  }\r
+  //\r
+  // Construct the new iSCSI device list.\r
+  //\r
+  DeviceListSize        = sizeof (ISCSI_DEVICE_LIST) + (NumHandles - 1) * sizeof (ISCSI_MAC_INFO);\r
+  DeviceList            = (ISCSI_DEVICE_LIST *) NetAllocatePool (DeviceListSize);\r
+  DeviceList->NumDevice = (UINT8) NumHandles;\r
+\r
+  for (Index = 0; Index < NumHandles; Index++) {\r
+    gBS->HandleProtocol (Handles[Index], &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);\r
+    Mode        = Snp->Mode;\r
+\r
+    CurMacInfo  = &DeviceList->MacInfo[Index];\r
+    NetCopyMem (&CurMacInfo->Mac, &Mode->PermanentAddress, Mode->HwAddressSize);\r
+    CurMacInfo->Len = (UINT8) Mode->HwAddressSize;\r
+  }\r
+\r
+  gRT->SetVariable (\r
+        L"iSCSIDeviceList",\r
+        &mVendorGuid,\r
+        ISCSI_CONFIG_VAR_ATTR,\r
+        DeviceListSize,\r
+        DeviceList\r
+        );\r
+\r
+  NetFreePool (DeviceList);\r
+\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+ISCSI_CONFIG_FORM_ENTRY *\r
+IScsiGetConfigFormEntryByIndex (\r
+  IN UINT32 Index\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the iSCSI configuration form entry by the index of the goto opcode actived.\r
+\r
+Arguments:\r
+\r
+  Index - The 0-based index of the goto opcode actived.\r
+\r
+Returns:\r
+\r
+  The iSCSI configuration form entry found.\r
+\r
+--*/\r
+{\r
+  UINT32                  CurrentIndex;\r
+  NET_LIST_ENTRY          *Entry;\r
+  ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;\r
+\r
+  CurrentIndex    = 0;\r
+  ConfigFormEntry = NULL;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {\r
+    if (CurrentIndex == Index) {\r
+      ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);\r
+      break;\r
+    }\r
+\r
+    CurrentIndex++;\r
+  }\r
+\r
+  return ConfigFormEntry;\r
+}\r
+\r
+STATIC\r
+VOID\r
+IScsiConvertDeviceConfigDataToIfrNvData (\r
+  IN ISCSI_CONFIG_FORM_ENTRY  *ConfigFormEntry,\r
+  IN ISCSI_CONFIG_IFR_NVDATA  *IfrNvData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the iSCSI configuration data into the IFR data.\r
+\r
+Arguments:\r
+\r
+  ConfigFormEntry - The iSCSI configuration form entry.\r
+  IfrNvData       - The IFR nv data.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  ISCSI_SESSION_CONFIG_NVDATA   *SessionConfigData;\r
+  ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData;\r
+\r
+  //\r
+  // Normal session configuration parameters.\r
+  //\r
+  SessionConfigData                 = &ConfigFormEntry->SessionConfigData;\r
+  IfrNvData->Enabled                = SessionConfigData->Enabled;\r
+\r
+  IfrNvData->InitiatorInfoFromDhcp  = SessionConfigData->InitiatorInfoFromDhcp;\r
+  IfrNvData->TargetInfoFromDhcp     = SessionConfigData->TargetInfoFromDhcp;\r
+  IfrNvData->TargetPort             = SessionConfigData->TargetPort;\r
+\r
+  IScsiIpToStr (&SessionConfigData->LocalIp, IfrNvData->LocalIp);\r
+  IScsiIpToStr (&SessionConfigData->SubnetMask, IfrNvData->SubnetMask);\r
+  IScsiIpToStr (&SessionConfigData->Gateway, IfrNvData->Gateway);\r
+  IScsiIpToStr (&SessionConfigData->TargetIp, IfrNvData->TargetIp);\r
+\r
+  IScsiAsciiStrToUnicodeStr (SessionConfigData->TargetName, IfrNvData->TargetName);\r
+\r
+  IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->BootLun);\r
+\r
+  //\r
+  // CHAP authentication parameters.\r
+  //\r
+  AuthConfigData      = &ConfigFormEntry->AuthConfigData;\r
+\r
+  IfrNvData->CHAPType = AuthConfigData->CHAPType;\r
+\r
+  IScsiAsciiStrToUnicodeStr (AuthConfigData->CHAPName, IfrNvData->CHAPName);\r
+  IScsiAsciiStrToUnicodeStr (AuthConfigData->CHAPSecret, IfrNvData->CHAPSecret);\r
+  IScsiAsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPName, IfrNvData->ReverseCHAPName);\r
+  IScsiAsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPSecret, IfrNvData->ReverseCHAPSecret);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiFormNvRead (\r
+  IN     EFI_FORM_CALLBACK_PROTOCOL    * This,\r
+  IN     CHAR16                        *VariableName,\r
+  IN     EFI_GUID                      * VendorGuid,\r
+  OUT    UINT32                        *Attributes OPTIONAL,\r
+  IN OUT UINTN                         *DataSize,\r
+  OUT    VOID                          *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  NV read function for the iSCSI form callback protocol.\r
+\r
+Arguments:\r
+\r
+  This         - The EFI form callback protocol instance.\r
+  VariableName - Name of the variable to read.\r
+  VendorGuid   - Guid of the variable to read.\r
+  Attributes   - The storage to get the attributes of the variable.\r
+  DataSize     - The size of the buffer to store the variable.\r
+  Buffer       - The buffer to store the variable to read.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The variable is read.\r
+  EFI_BUFFER_TOO_SMALL - The buffer provided is too small to hold the variable.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS              Status;\r
+  CHAR8                   InitiatorName[ISCSI_NAME_IFR_MAX_SIZE];\r
+  UINTN                   BufferSize;\r
+  ISCSI_CONFIG_IFR_NVDATA *IfrNvData;\r
+\r
+  if (!mIScsiDeviceListUpdated) {\r
+    //\r
+    // Update the device list.\r
+    //\r
+    IScsiUpdateDeviceList ();\r
+    mIScsiDeviceListUpdated = TRUE;\r
+  }\r
+\r
+  IfrNvData   = (ISCSI_CONFIG_IFR_NVDATA *) Buffer;\r
+  BufferSize  = ISCSI_NAME_IFR_MAX_SIZE;\r
+\r
+  Status      = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);\r
+  if (EFI_ERROR (Status)) {\r
+    IfrNvData->InitiatorName[0] = L'\0';\r
+  } else {\r
+    IScsiAsciiStrToUnicodeStr (InitiatorName, IfrNvData->InitiatorName);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiFormCallback (\r
+  IN EFI_FORM_CALLBACK_PROTOCOL       *This,\r
+  IN UINT16                           KeyValue,\r
+  IN EFI_IFR_DATA_ARRAY               *Data,\r
+  OUT EFI_HII_CALLBACK_PACKET         **Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The form callback function for iSCSI form callback protocol, it processes\r
+  the events tiggered in the UI and take some operations to update the form,\r
+  store the data, etc.\r
+\r
+Arguments:\r
+\r
+  This     - The EFI form callback protocol instance.\r
+  KeyValue - A unique value which is sent to the original exporting driver so that it\r
+             can identify the type of data to expect.  The format of the data tends to\r
+             vary based on the op-code that geerated the callback.\r
+  Data     - A pointer to the data being sent to the original exporting driver.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The data is valid and the correspondance operation is done.\r
+  EFI_INVALID_PARAMETER - The data is invalid.\r
+\r
+--*/\r
+{\r
+  ISCSI_FORM_CALLBACK_INFO  *Private;\r
+  UINTN                     BufferSize;\r
+  CHAR8                     IScsiName[ISCSI_NAME_IFR_MAX_SIZE];\r
+  CHAR16                    PortString[128];\r
+  CHAR8                     Ip4String[IP4_STR_MAX_SIZE];\r
+  CHAR8                     LunString[ISCSI_LUN_STR_MAX_LEN];\r
+  UINT64                    Lun;\r
+  STRING_REF                DeviceFormTitleToken;\r
+  ISCSI_CONFIG_IFR_NVDATA   *IfrNvData;\r
+  ISCSI_CONFIG_FORM_ENTRY   *ConfigFormEntry;\r
+  EFI_IP_ADDRESS            HostIp;\r
+  EFI_IP_ADDRESS            SubnetMask;\r
+  EFI_IP_ADDRESS            Gateway;\r
+  EFI_STATUS                Status;\r
+\r
+  Private   = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);\r
+  IfrNvData = (ISCSI_CONFIG_IFR_NVDATA *) Data->NvRamMap;\r
+  Status    = EFI_SUCCESS;\r
+\r
+  switch (KeyValue) {\r
+  case KEY_INITIATOR_NAME:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->InitiatorName, IScsiName);\r
+    BufferSize  = AsciiStrLen (IScsiName) + 1;\r
+\r
+    Status      = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, IScsiName);\r
+    if (EFI_ERROR (Status)) {\r
+      PopUpInvalidNotify (L"Invalid iSCSI Name!");\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_LOCAL_IP:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->LocalIp, Ip4String);\r
+    Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);\r
+    if (EFI_ERROR (Status) || !Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
+      PopUpInvalidNotify (L"Invalid IP address!");\r
+      Status = EFI_INVALID_PARAMETER;\r
+    } else {\r
+      NetCopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_SUBNET_MASK:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->SubnetMask, Ip4String);\r
+    Status = IScsiAsciiStrToIp (Ip4String, &SubnetMask.v4);\r
+    if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {\r
+      PopUpInvalidNotify (L"Invalid Subnet Mask!");\r
+      Status = EFI_INVALID_PARAMETER;\r
+    } else {\r
+      NetCopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_GATE_WAY:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->Gateway, Ip4String);\r
+    Status = IScsiAsciiStrToIp (Ip4String, &Gateway.v4);\r
+    if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !Ip4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {\r
+      PopUpInvalidNotify (L"Invalid Gateway!");\r
+      Status = EFI_INVALID_PARAMETER;\r
+    } else {\r
+      NetCopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_TARGET_IP:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->TargetIp, Ip4String);\r
+    Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);\r
+    if (EFI_ERROR (Status) || !Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
+      PopUpInvalidNotify (L"Invalid IP address!");\r
+      Status = EFI_INVALID_PARAMETER;\r
+    } else {\r
+      NetCopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp.v4, sizeof (HostIp.v4));\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_TARGET_NAME:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->TargetName, IScsiName);\r
+    Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));\r
+    if (EFI_ERROR (Status)) {\r
+      PopUpInvalidNotify (L"Invalid iSCSI Name!");\r
+    } else {\r
+      AsciiStrCpy (Private->Current->SessionConfigData.TargetName, IScsiName);\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_DHCP_ENABLE:\r
+    if (IfrNvData->InitiatorInfoFromDhcp == 0) {\r
+      IfrNvData->TargetInfoFromDhcp = 0;\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_BOOT_LUN:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->BootLun, LunString);\r
+    Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);\r
+    if (EFI_ERROR (Status)) {\r
+      PopUpInvalidNotify (L"Invalid LUN string!");\r
+    } else {\r
+      NetCopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun));\r
+    }\r
+\r
+    break;\r
+\r
+  case KEY_CHAP_NAME:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPName, Private->Current->AuthConfigData.CHAPName);\r
+    break;\r
+\r
+  case KEY_CHAP_SECRET:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPSecret, Private->Current->AuthConfigData.CHAPSecret);\r
+    break;\r
+\r
+  case KEY_REVERSE_CHAP_NAME:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPName, Private->Current->AuthConfigData.ReverseCHAPName);\r
+    break;\r
+\r
+  case KEY_REVERSE_CHAP_SECRET:\r
+    IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPSecret, Private->Current->AuthConfigData.ReverseCHAPSecret);\r
+    break;\r
+\r
+  case KEY_SAVE_CHANGES:\r
+    //\r
+    // First, update those fields which don't have INTERACTIVE set.\r
+    //\r
+    Private->Current->SessionConfigData.Enabled               = IfrNvData->Enabled;\r
+    Private->Current->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp;\r
+    Private->Current->SessionConfigData.TargetPort            = IfrNvData->TargetPort;\r
+    if (Private->Current->SessionConfigData.TargetPort == 0) {\r
+      Private->Current->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+    }\r
+\r
+    Private->Current->SessionConfigData.TargetInfoFromDhcp  = IfrNvData->TargetInfoFromDhcp;\r
+    Private->Current->AuthConfigData.CHAPType               = IfrNvData->CHAPType;\r
+\r
+    //\r
+    // Only do full parameter validation if iSCSI is enabled on this device.\r
+    //\r
+    if (Private->Current->SessionConfigData.Enabled) {\r
+      //\r
+      // Validate the address configuration of the Initiator if DHCP isn't\r
+      // deployed.\r
+      //\r
+      if (!Private->Current->SessionConfigData.InitiatorInfoFromDhcp) {\r
+        NetCopyMem (&HostIp.v4, &Private->Current->SessionConfigData.LocalIp, sizeof (HostIp.v4));\r
+        NetCopyMem (&SubnetMask.v4, &Private->Current->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));\r
+        NetCopyMem (&Gateway.v4, &Private->Current->SessionConfigData.Gateway, sizeof (Gateway.v4));\r
+\r
+        if ((Gateway.Addr[0] != 0)) {\r
+          if (SubnetMask.Addr[0] == 0) {\r
+            PopUpInvalidNotify (L"Gateway address is set but subnet mask is zero.");\r
+            Status = EFI_INVALID_PARAMETER;\r
+            break;\r
+          } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {\r
+            PopUpInvalidNotify (L"Local IP and Gateway are not in the same subnet.");\r
+            Status = EFI_INVALID_PARAMETER;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+      //\r
+      // Validate target configuration if DHCP isn't deployed.\r
+      //\r
+      if (!Private->Current->SessionConfigData.TargetInfoFromDhcp) {\r
+        NetCopyMem (&HostIp.v4, &Private->Current->SessionConfigData.TargetIp, sizeof (HostIp.v4));\r
+        if (!Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {\r
+          PopUpInvalidNotify (L"Target IP is invalid!");\r
+          Status = EFI_INVALID_PARAMETER;\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (IfrNvData->CHAPType != ISCSI_CHAP_NONE) {\r
+        if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {\r
+          PopUpInvalidNotify (L"CHAP Name or CHAP Secret is invalid!");\r
+          Status = EFI_INVALID_PARAMETER;\r
+          break;\r
+        }\r
+\r
+        if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&\r
+            ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))\r
+            ) {\r
+          PopUpInvalidNotify (L"Reverse CHAP Name or Reverse CHAP Secret is invalid!");\r
+          Status = EFI_INVALID_PARAMETER;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+    BufferSize = sizeof (Private->Current->SessionConfigData);\r
+    gRT->SetVariable (\r
+          Private->Current->MacString,\r
+          &gEfiIScsiInitiatorNameProtocolGuid,\r
+          ISCSI_CONFIG_VAR_ATTR,\r
+          BufferSize,\r
+          &Private->Current->SessionConfigData\r
+          );\r
+\r
+    BufferSize = sizeof (Private->Current->AuthConfigData);\r
+    gRT->SetVariable (\r
+          Private->Current->MacString,\r
+          &mIScsiCHAPAuthInfoGuid,\r
+          ISCSI_CONFIG_VAR_ATTR,\r
+          BufferSize,\r
+          &Private->Current->AuthConfigData\r
+          );\r
+\r
+    break;\r
+\r
+  default:\r
+    if ((KeyValue >= KEY_DEVICE_ENTRY_BASE) && (KeyValue < (mNumberOfIScsiDevices + KEY_DEVICE_ENTRY_BASE))) {\r
+      //\r
+      // In case goto the device configuration form, update the device form title.\r
+      //\r
+      ConfigFormEntry = IScsiGetConfigFormEntryByIndex ((UINT32) (KeyValue - KEY_DEVICE_ENTRY_BASE));\r
+      ASSERT (ConfigFormEntry != NULL);\r
+\r
+      UnicodeSPrint (PortString, 128, L"Port %s", ConfigFormEntry->MacString);\r
+      DeviceFormTitleToken = (STRING_REF) STR_ISCSI_DEVICE_FORM_TITLE;\r
+\r
+      Private->Hii->NewString (\r
+                      Private->Hii,\r
+                      NULL,\r
+                      Private->RegisteredHandle,\r
+                      &DeviceFormTitleToken,\r
+                      PortString\r
+                      );\r
+\r
+      IScsiConvertDeviceConfigDataToIfrNvData (ConfigFormEntry, IfrNvData);\r
+\r
+      Private->Current = ConfigFormEntry;\r
+    }\r
+\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiConfigUpdateForm (\r
+  IN EFI_HANDLE  DriverBindingHandle,\r
+  IN EFI_HANDLE  Controller,\r
+  IN BOOLEAN     AddForm\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Updates the iSCSI configuration form to add/delete an entry for the iSCSI\r
+  device specified by the Controller.\r
+\r
+Arguments:\r
+\r
+  DriverBindingHandle - The driverbinding handle.\r
+  Controller          - The controller handle of the iSCSI device.\r
+  AddForm             - Whether to add or delete a form entry.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The iSCSI configuration form is updated.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY              *Entry;\r
+  ISCSI_CONFIG_FORM_ENTRY     *ConfigFormEntry;\r
+  BOOLEAN                     EntryExisted;\r
+  EFI_HII_UPDATE_DATA         *UpdateData;\r
+  EFI_STATUS                  Status;\r
+  EFI_FORM_CALLBACK_PROTOCOL  *Callback;\r
+  ISCSI_FORM_CALLBACK_INFO    *CallbackInfo;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  CHAR16                      PortString[128];\r
+  UINT16                      FormIndex;\r
+  UINTN                       BufferSize;\r
+\r
+  //\r
+  // Get the EFI_FORM_CALLBACK_PROTOCOL.\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  DriverBindingHandle,\r
+                  &gEfiFormCallbackProtocolGuid,\r
+                  (VOID **)&Callback\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CallbackInfo    = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (Callback);\r
+\r
+  ConfigFormEntry = NULL;\r
+  EntryExisted    = FALSE;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {\r
+    ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);\r
+\r
+    if (ConfigFormEntry->Controller == Controller) {\r
+      EntryExisted = TRUE;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (AddForm) {\r
+    if (EntryExisted) {\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      //\r
+      // Add a new form.\r
+      //\r
+      ConfigFormEntry = (ISCSI_CONFIG_FORM_ENTRY *) NetAllocateZeroPool (sizeof (ISCSI_CONFIG_FORM_ENTRY));\r
+      if (ConfigFormEntry == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      NetListInit (&ConfigFormEntry->Link);\r
+      ConfigFormEntry->Controller = Controller;\r
+\r
+      //\r
+      // Get the simple network protocol and convert the MAC address into\r
+      // the formatted string.\r
+      //\r
+      Status = gBS->HandleProtocol (\r
+                      Controller,\r
+                      &gEfiSimpleNetworkProtocolGuid,\r
+                      (VOID **)&Snp\r
+                      );\r
+      ASSERT (Status == EFI_SUCCESS);\r
+\r
+      IScsiMacAddrToStr (&Snp->Mode->PermanentAddress, Snp->Mode->HwAddressSize, ConfigFormEntry->MacString);\r
+\r
+      //\r
+      // Get the normal session configuration data.\r
+      //\r
+      BufferSize = sizeof (ConfigFormEntry->SessionConfigData);\r
+      Status = gRT->GetVariable (\r
+                      ConfigFormEntry->MacString,\r
+                      &gEfiIScsiInitiatorNameProtocolGuid,\r
+                      NULL,\r
+                      &BufferSize,\r
+                      &ConfigFormEntry->SessionConfigData\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        NetZeroMem (&ConfigFormEntry->SessionConfigData, sizeof (ConfigFormEntry->SessionConfigData));\r
+      }\r
+      //\r
+      // Get the CHAP authentication configuration data.\r
+      //\r
+      BufferSize = sizeof (ConfigFormEntry->AuthConfigData);\r
+      Status = gRT->GetVariable (\r
+                      ConfigFormEntry->MacString,\r
+                      &mIScsiCHAPAuthInfoGuid,\r
+                      NULL,\r
+                      &BufferSize,\r
+                      &ConfigFormEntry->AuthConfigData\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        NetZeroMem (&ConfigFormEntry->AuthConfigData, sizeof (ConfigFormEntry->AuthConfigData));\r
+      }\r
+      //\r
+      // Compose the Port string and create a new STRING_REF.\r
+      //\r
+      UnicodeSPrint (PortString, 128, L"Port %s", ConfigFormEntry->MacString);\r
+      CallbackInfo->Hii->NewString (\r
+                          CallbackInfo->Hii,\r
+                          NULL,\r
+                          CallbackInfo->RegisteredHandle,\r
+                          &ConfigFormEntry->PortTitleToken,\r
+                          PortString\r
+                          );\r
+\r
+      //\r
+      // Compose the help string of this port and create a new STRING_REF.\r
+      //\r
+      UnicodeSPrint (PortString, 128, L"Set the iSCSI parameters on port %s", ConfigFormEntry->MacString);\r
+      CallbackInfo->Hii->NewString (\r
+                          CallbackInfo->Hii,\r
+                          NULL,\r
+                          CallbackInfo->RegisteredHandle,\r
+                          &ConfigFormEntry->PortTitleHelpToken,\r
+                          PortString\r
+                          );\r
+\r
+      NetListInsertTail (&mIScsiConfigFormList, &ConfigFormEntry->Link);\r
+      mNumberOfIScsiDevices++;\r
+    }\r
+  } else {\r
+    ASSERT (EntryExisted);\r
+\r
+    mNumberOfIScsiDevices--;\r
+    NetListRemoveEntry (&ConfigFormEntry->Link);\r
+    NetFreePool (ConfigFormEntry);\r
+  }\r
+  //\r
+  // Allocate space for creation of Buffer\r
+  //\r
+  UpdateData = (EFI_HII_UPDATE_DATA *) NetAllocatePool (0x1000);\r
+  NetZeroMem (UpdateData, 0x1000);\r
+\r
+  //\r
+  // Flag update pending in FormSet\r
+  //\r
+  UpdateData->FormSetUpdate = TRUE;\r
+\r
+  //\r
+  // Register CallbackHandle data for FormSet\r
+  //\r
+  UpdateData->FormCallbackHandle  = (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackInfo->CallbackHandle;\r
+  UpdateData->FormUpdate          = FALSE;\r
+  UpdateData->FormTitle           = 0;\r
+\r
+  //\r
+  // first of all, remove all the forms.\r
+  //\r
+  UpdateData->DataCount = 0xFF;\r
+\r
+  CallbackInfo->Hii->UpdateForm (\r
+                      CallbackInfo->Hii,\r
+                      CallbackInfo->RegisteredHandle,\r
+                      (EFI_FORM_LABEL) DEVICE_ENTRY_LABEL,\r
+                      FALSE,\r
+                      UpdateData\r
+                      );\r
+\r
+  UpdateData->DataCount = 1;\r
+  FormIndex             = 0;\r
+\r
+  NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {\r
+    ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);\r
+\r
+    CreateGotoOpCode (\r
+      FORMID_DEVICE_FORM,\r
+      ConfigFormEntry->PortTitleToken,\r
+      ConfigFormEntry->PortTitleHelpToken,\r
+      EFI_IFR_FLAG_INTERACTIVE,\r
+      (UINT16) (KEY_DEVICE_ENTRY_BASE + FormIndex),\r
+      &UpdateData->Data\r
+      );\r
+\r
+    CallbackInfo->Hii->UpdateForm (\r
+                        CallbackInfo->Hii,\r
+                        CallbackInfo->RegisteredHandle,\r
+                        (EFI_FORM_LABEL) DEVICE_ENTRY_LABEL,\r
+                        TRUE,\r
+                        UpdateData\r
+                        );\r
+\r
+    FormIndex++;\r
+  }\r
+\r
+  NetFreePool (UpdateData);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiConfigFormInit (\r
+  IN EFI_HANDLE  DriverBindingHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize the iSCSI configuration form.\r
+\r
+Arguments:\r
+\r
+  DriverBindingHandle - The iSCSI driverbinding handle.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The iSCSI configuration form is initialized.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_HII_PROTOCOL          *Hii;\r
+  EFI_HII_PACKAGES          *PackageList;\r
+  EFI_HII_HANDLE            HiiHandle;\r
+  EFI_HII_UPDATE_DATA       *UpdateData;\r
+  ISCSI_FORM_CALLBACK_INFO  *CallbackInfo;\r
+  EFI_GUID                  StringPackGuid = ISCSI_CONFIG_GUID;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, (VOID **)&Hii);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;;\r
+  }\r
+\r
+  CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) NetAllocatePool (sizeof (ISCSI_FORM_CALLBACK_INFO));\r
+  if (CallbackInfo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CallbackInfo->Signature             = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;\r
+  CallbackInfo->Hii                   = Hii;\r
+  CallbackInfo->Current               = NULL;\r
+\r
+  CallbackInfo->FormCallback.NvRead   = IScsiFormNvRead;\r
+  CallbackInfo->FormCallback.NvWrite  = NULL;\r
+  CallbackInfo->FormCallback.Callback = IScsiFormCallback;\r
+\r
+  //\r
+  // Install protocol interface\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &DriverBindingHandle,\r
+                  &gEfiFormCallbackProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &CallbackInfo->FormCallback\r
+                  );\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  CallbackInfo->CallbackHandle  = DriverBindingHandle;\r
+  PackageList                   = PreparePackages (2, &StringPackGuid, iSCSIStrings, IScsiConfigDxeBin);\r
+  Status                        = Hii->NewPack (Hii, PackageList, &HiiHandle);\r
+  NetFreePool (PackageList);\r
+\r
+  CallbackInfo->RegisteredHandle = HiiHandle;\r
+\r
+  //\r
+  // Allocate space for creation of Buffer\r
+  //\r
+  UpdateData = (EFI_HII_UPDATE_DATA *) NetAllocatePool (0x1000);\r
+  ASSERT (UpdateData != NULL);\r
+  if (UpdateData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NetZeroMem (UpdateData, 0x1000);\r
+\r
+  //\r
+  // Flag update pending in FormSet\r
+  //\r
+  UpdateData->FormSetUpdate = TRUE;\r
+\r
+  //\r
+  // Register CallbackHandle data for FormSet\r
+  //\r
+  UpdateData->FormCallbackHandle  = (EFI_PHYSICAL_ADDRESS) (UINTN) CallbackInfo->CallbackHandle;\r
+  UpdateData->FormUpdate          = FALSE;\r
+  UpdateData->FormTitle           = 0;\r
+  UpdateData->DataCount           = 0x1;\r
+\r
+  Hii->UpdateForm (Hii, HiiHandle, (EFI_FORM_LABEL) 0x1000, TRUE, UpdateData);\r
+\r
+  NetFreePool (UpdateData);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiConfigFormUnload (\r
+  IN EFI_HANDLE  DriverBindingHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Unload the iSCSI configuration form, this includes: delete all the iSCSI\r
+  device configuration entries, uninstall the form callback protocol and\r
+  free the resources used.\r
+\r
+Arguments:\r
+\r
+  DriverBindingHandle - The iSCSI driverbinding handle.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The iSCSI configuration form is unloaded.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+\r
+--*/\r
+{\r
+  ISCSI_CONFIG_FORM_ENTRY     *ConfigFormEntry;\r
+  EFI_STATUS                  Status;\r
+  EFI_HII_PROTOCOL            *Hii;\r
+  EFI_HII_UPDATE_DATA         *UpdateData;\r
+  EFI_FORM_CALLBACK_PROTOCOL  *FormCallback;\r
+  ISCSI_FORM_CALLBACK_INFO    *CallbackInfo;\r
+\r
+  while (!NetListIsEmpty (&mIScsiConfigFormList)) {\r
+    //\r
+    // Uninstall the device forms as the iSCSI driver instance may fail to\r
+    // control the controller but still install the device configuration form.\r
+    // In such case, upon driver unloading, the driver instance's driverbinding.\r
+    // stop () won't be called, so we have to take this chance here to uninstall\r
+    // the device form.\r
+    //\r
+    ConfigFormEntry = NET_LIST_USER_STRUCT (mIScsiConfigFormList.ForwardLink, ISCSI_CONFIG_FORM_ENTRY, Link);\r
+    IScsiConfigUpdateForm (DriverBindingHandle, ConfigFormEntry->Controller, FALSE);\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (&gEfiHiiProtocolGuid, NULL, (VOID **)&Hii);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (DriverBindingHandle, &gEfiFormCallbackProtocolGuid, (VOID **)&FormCallback);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CallbackInfo = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (FormCallback);\r
+\r
+  //\r
+  // remove the form.\r
+  //\r
+  UpdateData = (EFI_HII_UPDATE_DATA *) NetAllocatePool (0x1000);\r
+  ASSERT (UpdateData != NULL);\r
+  if (UpdateData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NetZeroMem (UpdateData, 0x1000);\r
+\r
+  UpdateData->FormSetUpdate       = FALSE;\r
+  UpdateData->FormCallbackHandle  = 0;\r
+  UpdateData->FormUpdate          = FALSE;\r
+  UpdateData->FormTitle           = 0;\r
+  UpdateData->DataCount           = 0xFF;\r
+\r
+  Hii->UpdateForm (Hii, CallbackInfo->RegisteredHandle, (EFI_FORM_LABEL) 0x1000, FALSE, UpdateData);\r
+\r
+  NetFreePool (UpdateData);\r
+\r
+  //\r
+  // Uninstall the EFI_FORM_CALLBACK_PROTOCOL.\r
+  //\r
+  gBS->UninstallProtocolInterface (\r
+        DriverBindingHandle,\r
+        &gEfiFormCallbackProtocolGuid,\r
+        FormCallback\r
+        );\r
+\r
+  //\r
+  // Remove the package.\r
+  //\r
+  Hii->RemovePack (Hii, CallbackInfo->RegisteredHandle);\r
+\r
+  NetFreePool (CallbackInfo);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfig.h b/MdeModulePkg/Universal/iScsi/IScsiConfig.h
new file mode 100644 (file)
index 0000000..e5c528e
--- /dev/null
@@ -0,0 +1,111 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiConfig.h\r
+\r
+Abstract:\r
+\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_CONFIG_H_\r
+#define _ISCSI_CONFIG_H_\r
+\r
+//#include "Tiano.h"\r
+//#include "EfiDriverLib.h"\r
+//#include "Base.h"\r
+#include <Library/FrameworkHiiLib.h>\r
+#include <Protocol/FrameworkFormBrowser.h>\r
+#include <Protocol/FrameworkFormCallback.h>\r
+#include <Library/FrameworkIfrSupportLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+//#include "EfiPrintLib.h"\r
+//#include EFI_PROTOCOL_DEFINITION (Hii)\r
+//#include EFI_PROTOCOL_DEFINITION (FormBrowser)\r
+//#include EFI_PROTOCOL_DEFINITION (FormCallback)\r
+\r
+#include <Library/NetLib.h>\r
+#include "IScsiConfigNVDataStruc.h"\r
+\r
+extern UINT8  IScsiConfigDxeBin[];\r
+extern UINT8  iSCSIStrings[];\r
+\r
+#define ISCSI_INITATOR_NAME_VAR_NAME        L"I_NAME"\r
+\r
+#define ISCSI_CONFIG_VAR_ATTR               (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE)\r
+\r
+#define ISCSI_FORM_CALLBACK_INFO_SIGNATURE  EFI_SIGNATURE_32 ('I', 'f', 'c', 'i')\r
+\r
+#define ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK(Callback) \\r
+  CR ( \\r
+  Callback, \\r
+  ISCSI_FORM_CALLBACK_INFO, \\r
+  FormCallback, \\r
+  ISCSI_FORM_CALLBACK_INFO_SIGNATURE \\r
+  )\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct _ISCSI_MAC_INFO {\r
+  EFI_MAC_ADDRESS Mac;\r
+  UINT8           Len;\r
+} ISCSI_MAC_INFO;\r
+\r
+typedef struct _ISCSI_DEVICE_LIST {\r
+  UINT8           NumDevice;\r
+  ISCSI_MAC_INFO  MacInfo[1];\r
+} ISCSI_DEVICE_LIST;\r
+\r
+#pragma pack()\r
+\r
+typedef struct _ISCSI_CONFIG_FORM_ENTRY {\r
+  NET_LIST_ENTRY                Link;\r
+  EFI_HANDLE                    Controller;\r
+  CHAR16                        MacString[95];\r
+  STRING_REF                    PortTitleToken;\r
+  STRING_REF                    PortTitleHelpToken;\r
+\r
+  ISCSI_SESSION_CONFIG_NVDATA   SessionConfigData;\r
+  ISCSI_CHAP_AUTH_CONFIG_NVDATA AuthConfigData;\r
+} ISCSI_CONFIG_FORM_ENTRY;\r
+\r
+typedef struct _ISCSI_FORM_CALLBACK_INFO {\r
+  UINTN                       Signature;\r
+  EFI_HANDLE                  CallbackHandle;\r
+  EFI_FORM_CALLBACK_PROTOCOL  FormCallback;\r
+  UINT16                      *KeyList;\r
+  VOID                        *FormBuffer;\r
+  EFI_HII_HANDLE              RegisteredHandle;\r
+  EFI_HII_PROTOCOL            *Hii;\r
+  ISCSI_CONFIG_FORM_ENTRY     *Current;\r
+} ISCSI_FORM_CALLBACK_INFO;\r
+\r
+EFI_STATUS\r
+IScsiConfigUpdateForm (\r
+  IN EFI_HANDLE  DriverBindingHandle,\r
+  IN EFI_HANDLE  Controller,\r
+  IN BOOLEAN     AddForm\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiConfigFormInit (\r
+  IN EFI_HANDLE  DriverBindingHandle\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiConfigFormUnload (\r
+  IN EFI_HANDLE  DriverBindingHandle\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfigDxe.vfr b/MdeModulePkg/Universal/iScsi/IScsiConfigDxe.vfr
new file mode 100644 (file)
index 0000000..3df9b18
--- /dev/null
@@ -0,0 +1,212 @@
+// *++\r
+//\r
+//Copyright (c)  2007 Intel Corporation. All rights reserved\r
+//This software and associated documentation (if any) is furnished\r
+//under a license and may only be used or copied in accordance\r
+//with the terms of the license. Except as permitted by such\r
+//license, no part of this software or documentation may be\r
+//reproduced, stored in a retrieval system, or transmitted in any\r
+//form or by any means without the express written consent of\r
+//Intel Corporation.\r
+//\r
+// Module Name:\r
+//\r
+//   IScsiConfigVfr.vfr \r
+// \r
+// Abstract:\r
+// \r
+// Revision History: \r
+// \r
+// --*/\r
+\r
+#include "IScsiConfigNVDataStruc.h"\r
+#define EFI_NETWORK_DEVICE_CLASS  0x04\r
+\r
+formset \r
+  guid     = ISCSI_CONFIG_GUID,\r
+  title    = STRING_TOKEN(STR_ISCSI_CONFIG_FORM_TITLE),\r
+  help     = STRING_TOKEN(STR_ISCSI_CONFIG_FORM_HELP),\r
+  class    = EFI_NETWORK_DEVICE_CLASS,\r
+  subclass = 0x03,\r
+\r
+  form formid = FORMID_MAIN_FORM,\r
+    title  = STRING_TOKEN(STR_ISCSI_MAIN_FORM_TITLE);  // note formid is a variable (for readability) (UINT16) - also added Form to the line to signify the Op-Code\r
+\r
+    string  varid   = ISCSI_CONFIG_IFR_NVDATA.InitiatorName, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_CONFIG_INIT_NAME),\r
+            help    = STRING_TOKEN(STR_ISCSI_CONFIG_INIT_NAME_HELP),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_INITIATOR_NAME,\r
+            minsize = 8,\r
+            maxsize = ISCSI_NAME_IFR_MAX_SIZE,\r
+    endstring;\r
+\r
+    label DEVICE_ENTRY_LABEL;\r
+\r
+  endform;\r
+\r
+  form formid = FORMID_DEVICE_FORM,\r
+    title  = STRING_TOKEN(STR_ISCSI_DEVICE_FORM_TITLE);\r
+\r
+    checkbox varid = ISCSI_CONFIG_IFR_NVDATA.Enabled,\r
+            prompt = STRING_TOKEN(STR_ISCSI_DEVICE_ENABLE),\r
+            help   = STRING_TOKEN(STR_NULL),\r
+            flags  = 0,\r
+    endcheckbox;\r
+\r
+    checkbox varid = ISCSI_CONFIG_IFR_NVDATA.InitiatorInfoFromDhcp,\r
+            prompt = STRING_TOKEN(STR_ISCSI_ENABLE_DHCP),\r
+            help   = STRING_TOKEN(STR_ISCSI_ENABLE_DHCP),\r
+            flags  = INTERACTIVE,\r
+            key    = KEY_DHCP_ENABLE,\r
+    endcheckbox;\r
+\r
+    suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.InitiatorInfoFromDhcp == 0x01; \r
+    string  varid   = ISCSI_CONFIG_IFR_NVDATA.LocalIp, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_LOCAL_IP_ADDRESS),\r
+            help    = STRING_TOKEN(STR_ISCSI_IP_ADDRESS_HELP),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_LOCAL_IP,\r
+            minsize = IP_MIN_SIZE,\r
+            maxsize = IP_MAX_SIZE,\r
+    endstring;\r
+\r
+    string  varid   = ISCSI_CONFIG_IFR_NVDATA.SubnetMask, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_LOCAL_MASK),\r
+            help    = STRING_TOKEN(STR_ISCSI_IP_ADDRESS_HELP),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_SUBNET_MASK,\r
+            minsize = IP_MIN_SIZE,\r
+            maxsize = IP_MAX_SIZE,\r
+    endstring;\r
+\r
+    string  varid   = ISCSI_CONFIG_IFR_NVDATA.Gateway, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_LOCAL_GATEWAY),\r
+            help    = STRING_TOKEN(STR_ISCSI_IP_ADDRESS_HELP),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_GATE_WAY,\r
+            minsize = IP_MIN_SIZE,\r
+            maxsize = IP_MAX_SIZE,\r
+    endstring;\r
+    endif;\r
+\r
+    subtitle text = STRING_TOKEN(STR_NULL); \r
+\r
+    suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.InitiatorInfoFromDhcp == 0x00; \r
+    checkbox varid  = ISCSI_CONFIG_IFR_NVDATA.TargetInfoFromDhcp,\r
+             prompt = STRING_TOKEN(STR_ISCSI_ENABLE_DHCP_ON_TARGET),\r
+             help   = STRING_TOKEN(STR_ISCSI_ENABLE_DHCP_ON_TARGET),\r
+             flags  = 0,\r
+    endcheckbox;\r
+    endif;\r
+      \r
+    suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.TargetInfoFromDhcp == 0x01; \r
+\r
+    string  varid   = ISCSI_CONFIG_IFR_NVDATA.TargetName, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_TARGET_NAME),\r
+            help    = STRING_TOKEN(STR_ISCSI_TARGET_NAME),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_TARGET_NAME,\r
+            minsize = 8,\r
+            maxsize = ISCSI_NAME_IFR_MAX_SIZE,\r
+    endstring;\r
+\r
+    string  varid   = ISCSI_CONFIG_IFR_NVDATA.TargetIp, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_TARGET_IP_ADDRESS),\r
+            help    = STRING_TOKEN(STR_ISCSI_IP_ADDRESS_HELP),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_TARGET_IP,\r
+            minsize = IP_MIN_SIZE,\r
+            maxsize = IP_MAX_SIZE,\r
+    endstring;\r
+    \r
+    numeric varid   = ISCSI_CONFIG_IFR_NVDATA.TargetPort, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_TARGET_PORT),\r
+            help    = STRING_TOKEN(STR_ISCSI_TARGET_PORT),\r
+            flags   = 0,\r
+            minimum = TARGET_PORT_MIN_NUM,\r
+            maximum = TARGET_PORT_MAX_NUM,     \r
+            step    = 0,\r
+    endnumeric;\r
+    \r
+    string varid    = ISCSI_CONFIG_IFR_NVDATA.BootLun, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_BOOT_LUN),\r
+            help    = STRING_TOKEN(STR_ISCSI_BOOT_LUN_HELP),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_BOOT_LUN,\r
+            minsize = LUN_MIN_SIZE,\r
+            maxsize = LUN_MAX_SIZE,\r
+    endstring;\r
+    endif;\r
+\r
+    subtitle text = STRING_TOKEN(STR_NULL); \r
+\r
+    oneof varid  = ISCSI_CONFIG_IFR_NVDATA.CHAPType,\r
+          prompt = STRING_TOKEN(STR_CHAP_TYPE_PROMPT),\r
+          help   = STRING_TOKEN(STR_CHAP_TYPE_HELP),  \r
+          option text = STRING_TOKEN(STR_CHAP_TYPE_NONE),   value = ISCSI_CHAP_NONE,   flags = DEFAULT;\r
+          option text = STRING_TOKEN(STR_CHAP_TYPE_UNI),    value = ISCSI_CHAP_UNI,    flags = 0;\r
+          option text = STRING_TOKEN(STR_CHAP_TYPE_MUTUAL), value = ISCSI_CHAP_MUTUAL, flags = 0;\r
+    endoneof;\r
+\r
+    suppressif ideqval ISCSI_CONFIG_IFR_NVDATA.CHAPType == ISCSI_CHAP_NONE; \r
+\r
+    string  varid   = ISCSI_CONFIG_IFR_NVDATA.CHAPName, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_CHAP_NAME),\r
+            help    = STRING_TOKEN(STR_ISCSI_CHAP_NAME),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_CHAP_NAME,\r
+            minsize = 0,\r
+            maxsize = ISCSI_CHAP_NAME_MAX_LEN,\r
+    endstring;\r
+\r
+    string  varid    = ISCSI_CONFIG_IFR_NVDATA.CHAPSecret, \r
+            prompt   = STRING_TOKEN(STR_ISCSI_CHAP_SECRET),\r
+            help     = STRING_TOKEN(STR_ISCSI_CHAP_SECRET_HELP),\r
+            flags    = INTERACTIVE,\r
+            key      = KEY_CHAP_SECRET,\r
+            minsize  = ISCSI_CHAP_SECRET_MIN_LEN,\r
+            maxsize  = ISCSI_CHAP_SECRET_MAX_LEN,\r
+    endstring;\r
+\r
+    endif;\r
+\r
+    suppressif NOT ideqval ISCSI_CONFIG_IFR_NVDATA.CHAPType == ISCSI_CHAP_MUTUAL;\r
+\r
+    string  varid   = ISCSI_CONFIG_IFR_NVDATA.ReverseCHAPName, \r
+            prompt  = STRING_TOKEN(STR_ISCSI_REVERSE_CHAP_NAME),\r
+            help    = STRING_TOKEN(STR_ISCSI_REVERSE_CHAP_NAME),\r
+            flags   = INTERACTIVE,\r
+            key     = KEY_REVERSE_CHAP_NAME,\r
+            minsize = 0,\r
+            maxsize = ISCSI_CHAP_NAME_MAX_LEN,\r
+    endstring;\r
+\r
+    string  varid    = ISCSI_CONFIG_IFR_NVDATA.ReverseCHAPSecret, \r
+            prompt   = STRING_TOKEN(STR_ISCSI_REVERSE_CHAP_SECRET),\r
+            help     = STRING_TOKEN(STR_ISCSI_CHAP_SECRET_HELP),\r
+            flags    = INTERACTIVE,\r
+            key      = KEY_REVERSE_CHAP_SECRET,\r
+            minsize  = ISCSI_CHAP_SECRET_MIN_LEN,\r
+            maxsize  = ISCSI_CHAP_SECRET_MAX_LEN,\r
+    endstring;\r
+\r
+    endif;\r
+\r
+    subtitle text = STRING_TOKEN(STR_NULL); \r
+\r
+    goto FORMID_DEVICE_FORM,  \r
+    prompt = STRING_TOKEN (STR_SAVE_CHANGES),\r
+    help   = STRING_TOKEN (STR_SAVE_CHANGES),\r
+    flags  = INTERACTIVE,\r
+    key    = KEY_SAVE_CHANGES;\r
+\r
+    goto FORMID_MAIN_FORM, \r
+    prompt = STRING_TOKEN (STR_RETURN_MAIN_FORM), \r
+    help   = STRING_TOKEN (STR_RETURN_MAIN_FORM),\r
+    flags  = 0;\r
+\r
+  endform;\r
+\r
+endformset;\r
+\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfigDxeStrings.uni b/MdeModulePkg/Universal/iScsi/IScsiConfigDxeStrings.uni
new file mode 100644 (file)
index 0000000..b0f0250
Binary files /dev/null and b/MdeModulePkg/Universal/iScsi/IScsiConfigDxeStrings.uni differ
diff --git a/MdeModulePkg/Universal/iScsi/IScsiConfigNVDataStruc.h b/MdeModulePkg/Universal/iScsi/IScsiConfigNVDataStruc.h
new file mode 100644 (file)
index 0000000..444cb69
--- /dev/null
@@ -0,0 +1,104 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiConfigNVDataStruc.h\r
\r
+Abstract:\r
\r
+  NVData structure used by the iSCSI configuration component.\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_NVDATASTRUC_H_\r
+#define _ISCSI_NVDATASTRUC_H_\r
+\r
+#define ISCSI_CONFIG_GUID \\r
+  { \\r
+    0x6456ed61, 0x3579, 0x41c9, { 0x8a, 0x26, 0x0a, 0x0b, 0xd6, 0x2b, 0x78, 0xfc } \\r
+  }\r
+\r
+#define VAR_EQ_TEST_NAME    0x100\r
+\r
+#define FORMID_MAIN_FORM    1\r
+#define FORMID_DEVICE_FORM  2\r
+\r
+#define ISCSI_NAME_MAX_SIZE 224\r
+\r
+//\r
+// Vfr has a limit on the size, it's 255 bytes.\r
+//\r
+#define ISCSI_NAME_IFR_MAX_SIZE   126\r
+\r
+#define IP_MIN_SIZE               7\r
+#define IP_MAX_SIZE               15\r
+#define IP4_STR_MAX_SIZE          16\r
+\r
+#define LUN_MIN_SIZE              1\r
+#define LUN_MAX_SIZE              20\r
+\r
+#define ISCSI_CHAP_NONE           0\r
+#define ISCSI_CHAP_UNI            1\r
+#define ISCSI_CHAP_MUTUAL         2\r
+\r
+#define TARGET_PORT_MIN_NUM       0\r
+#define TARGET_PORT_MAX_NUM       65535\r
+\r
+#define DEVICE_ENTRY_LABEL        0x1234\r
+\r
+#define KEY_INITIATOR_NAME        0x01\r
+#define KEY_DHCP_ENABLE           0x02\r
+#define KEY_LOCAL_IP              0x03\r
+#define KEY_SUBNET_MASK           0x04\r
+#define KEY_GATE_WAY              0x05\r
+#define KEY_TARGET_IP             0x06\r
+#define KEY_CHAP_NAME             0x07\r
+#define KEY_CHAP_SECRET           0x08\r
+#define KEY_REVERSE_CHAP_NAME     0x09\r
+#define KEY_REVERSE_CHAP_SECRET   0x0a\r
+#define KEY_SAVE_CHANGES          0x0b\r
+#define KEY_TARGET_NAME           0x0c\r
+#define KEY_BOOT_LUN              0x0d\r
+\r
+#define KEY_DEVICE_ENTRY_BASE     0x1000\r
+\r
+#define ISCSI_LUN_STR_MAX_LEN     21\r
+#define ISCSI_CHAP_SECRET_MIN_LEN 13\r
+#define ISCSI_CHAP_SECRET_MAX_LEN 17\r
+#define ISCSI_CHAP_NAME_MAX_LEN   126\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  CHAR16  InitiatorName[ISCSI_NAME_IFR_MAX_SIZE];\r
+\r
+  UINT8   Enabled;\r
+\r
+  UINT8   InitiatorInfoFromDhcp;\r
+  CHAR16  LocalIp[IP4_STR_MAX_SIZE];\r
+  CHAR16  SubnetMask[IP4_STR_MAX_SIZE];\r
+  CHAR16  Gateway[IP4_STR_MAX_SIZE];\r
+\r
+  CHAR16  TargetName[ISCSI_NAME_IFR_MAX_SIZE];\r
+  CHAR16  TargetIp[IP4_STR_MAX_SIZE];\r
+  UINT16  TargetPort;\r
+  CHAR16  BootLun[ISCSI_LUN_STR_MAX_LEN];\r
+  UINT8   TargetInfoFromDhcp;\r
+\r
+  UINT8   CHAPType;\r
+  CHAR16  CHAPName[ISCSI_CHAP_NAME_MAX_LEN];\r
+  CHAR16  CHAPSecret[ISCSI_CHAP_SECRET_MAX_LEN];\r
+  CHAR16  ReverseCHAPName[ISCSI_CHAP_NAME_MAX_LEN];\r
+  CHAR16  ReverseCHAPSecret[ISCSI_CHAP_SECRET_MAX_LEN];\r
+} ISCSI_CONFIG_IFR_NVDATA;\r
+#pragma pack()\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiDhcp.c b/MdeModulePkg/Universal/iScsi/IScsiDhcp.c
new file mode 100644 (file)
index 0000000..b9b8cea
--- /dev/null
@@ -0,0 +1,498 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiDhcp.c\r
+\r
+Abstract:\r
+\r
+  iSCSI DHCP related configuration routines.\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+STATIC\r
+EFI_STATUS\r
+IScsiDhcpExtractRootPath (\r
+  IN CHAR8                        *RootPath,\r
+  IN UINT8                        Length,\r
+  IN ISCSI_SESSION_CONFIG_NVDATA  *ConfigNvData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Extract the Root Path option and get the required target information.\r
+  \r
+Arguments:\r
+\r
+  RootPath     - The RootPath.\r
+  Length       - Length of the RootPath option payload.\r
+  ConfigNvData - The iSCSI session configuration data read from nonvolatile device.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - All required information is extracted from the RootPath option.\r
+  EFI_NOT_FOUND         - The RootPath is not an iSCSI RootPath.\r
+  EFI_OUT_OF_RESOURCES  - Failed to allocate memory.\r
+  EFI_INVALID_PARAMETER - The RootPath is mal-formatted.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT8                 IScsiRootPathIdLen;\r
+  CHAR8                 *TmpStr;\r
+  ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];\r
+  ISCSI_ROOT_PATH_FIELD *Field;\r
+  UINT32                FieldIndex;\r
+  UINT8                 Index;\r
+\r
+  //\r
+  // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>\r
+  //\r
+  IScsiRootPathIdLen = (UINT8) AsciiStrLen (ISCSI_ROOT_PATH_ID);\r
+\r
+  if ((Length <= IScsiRootPathIdLen) || (NetCompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Skip the iSCSI RootPath ID "iscsi:".\r
+  //\r
+  RootPath += IScsiRootPathIdLen;\r
+  Length  = (UINT8) (Length - IScsiRootPathIdLen);\r
+\r
+  TmpStr  = (CHAR8 *) NetAllocatePool (Length + 1);\r
+  if (TmpStr == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NetCopyMem (TmpStr, RootPath, Length);\r
+  TmpStr[Length]  = '\0';\r
+\r
+  Index           = 0;\r
+  FieldIndex      = 0;\r
+  NetZeroMem (&Fields[0], sizeof (Fields));\r
+\r
+  //\r
+  // Extract the fields in the Root Path option string.\r
+  //\r
+  for (FieldIndex = 0; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {\r
+    if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
+      Fields[FieldIndex].Str = &TmpStr[Index];\r
+    }\r
+\r
+    while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {\r
+      Index++;\r
+    }\r
+\r
+    if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
+      if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {\r
+        TmpStr[Index] = '\0';\r
+        Index++;\r
+      }\r
+\r
+      if (Fields[FieldIndex].Str != NULL) {\r
+        Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);\r
+      }\r
+    }\r
+  }\r
+\r
+  if (FieldIndex != RP_FIELD_IDX_MAX) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||\r
+      (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||\r
+      (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)\r
+      ) {\r
+\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Get the IP address of the target.\r
+  //\r
+  Field   = &Fields[RP_FIELD_IDX_SERVERNAME];\r
+  Status  = IScsiAsciiStrToIp (Field->Str, &ConfigNvData->TargetIp);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Check the protocol type.\r
+  //\r
+  Field = &Fields[RP_FIELD_IDX_PROTOCOL];\r
+  if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Get the port of the iSCSI target.\r
+  //\r
+  Field = &Fields[RP_FIELD_IDX_PORT];\r
+  if (Field->Str != NULL) {\r
+    ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);\r
+  } else {\r
+    ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+  }\r
+  //\r
+  // Get the LUN.\r
+  //\r
+  Field = &Fields[RP_FIELD_IDX_LUN];\r
+  if (Field->Str != NULL) {\r
+    Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  } else {\r
+    NetZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));\r
+  }\r
+  //\r
+  // Get the target iSCSI Name.\r
+  //\r
+  Field = &Fields[RP_FIELD_IDX_TARGETNAME];\r
+\r
+  if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Validate the iSCSI name.\r
+  //\r
+  Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  AsciiStrCpy (ConfigNvData->TargetName, Field->Str);\r
+\r
+ON_EXIT:\r
+\r
+  NetFreePool (TmpStr);\r
+\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+IScsiDhcpSelectOffer (\r
+  IN  EFI_DHCP4_PROTOCOL  * This,\r
+  IN  VOID                *Context,\r
+  IN  EFI_DHCP4_STATE     CurrentState,\r
+  IN  EFI_DHCP4_EVENT     Dhcp4Event,\r
+  IN  EFI_DHCP4_PACKET    * Packet, OPTIONAL\r
+  OUT EFI_DHCP4_PACKET    **NewPacket OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The callback function registerd to the DHCP4 instance which is used to select\r
+  the qualified DHCP OFFER.\r
+  \r
+Arguments:\r
+\r
+  This         - The DHCP4 protocol.\r
+  Context      - The context set when configuring the DHCP4 protocol.\r
+  CurrentState - The current state of the DHCP4 protocol.\r
+  Dhcp4Event   - The event occurs in the current state.\r
+  Packet       - The DHCP packet that is to be sent or already received.\r
+  NewPackt     - The packet used to replace the above Packet.\r
+\r
+Returns:\r
+\r
+  EFI_NOT_READY - The DHCP OFFER packet doesn't match our requirements.\r
+  EFI_SUCCESS   - Either the DHCP OFFER is qualified or we're not intereseted\r
+                  in the Dhcp4Event.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT32                  OptionCount;\r
+  EFI_DHCP4_PACKET_OPTION **OptionList;\r
+  UINT32                  Index;\r
+\r
+  if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  OptionCount = 0;\r
+\r
+  Status      = This->Parse (This, Packet, &OptionCount, NULL);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    \rreturn EFI_NOT_READY;\r
+  }\r
+\r
+  OptionList = NetAllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
+  if (OptionList == NULL) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
+  if (EFI_ERROR (Status)) {\r
+    NetFreePool (OptionList);\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  for (Index = 0; Index < OptionCount; Index++) {\r
+    if (OptionList[Index]->OpCode != DHCP4_TAG_ROOT_PATH) {\r
+      continue;\r
+    }\r
+\r
+    Status = IScsiDhcpExtractRootPath (\r
+              (CHAR8 *) &OptionList[Index]->Data[0],\r
+              OptionList[Index]->Length,\r
+              (ISCSI_SESSION_CONFIG_NVDATA *) Context\r
+              );\r
+\r
+    break;\r
+  }\r
+\r
+  if ((Index == OptionCount)) {\r
+    Status = EFI_NOT_READY;\r
+  }\r
+\r
+  NetFreePool (OptionList);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiParseDhcpAck (\r
+  IN EFI_DHCP4_PROTOCOL         *Dhcp4,\r
+  IN ISCSI_SESSION_CONFIG_DATA  *ConfigData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Parse the DHCP ACK to get the address configuration and DNS information.\r
+  \r
+Arguments:\r
+\r
+  Dhcp4      - The DHCP4 protocol.\r
+  ConfigData - The session configuration data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The DNS information is got from the DHCP ACK.\r
+  EFI_NO_MAPPING        - DHCP failed to acquire address and other information.\r
+  EFI_INVALID_PARAMETER - The DHCP ACK's DNS option is mal-formatted.\r
+  EFI_DEVICE_ERROR      - Some unexpected error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_DHCP4_MODE_DATA     Dhcp4ModeData;\r
+  UINT32                  OptionCount;\r
+  EFI_DHCP4_PACKET_OPTION **OptionList;\r
+  UINT32                  Index;\r
+\r
+  Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Dhcp4ModeData.State != Dhcp4Bound) {\r
+    return EFI_NO_MAPPING;\r
+  }\r
+\r
+  NetCopyMem (&ConfigData->NvData.LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
+  NetCopyMem (&ConfigData->NvData.SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+  NetCopyMem (&ConfigData->NvData.Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  OptionCount = 0;\r
+  OptionList  = NULL;\r
+\r
+  Status      = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  OptionList = NetAllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
+  if (OptionList == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
+  if (EFI_ERROR (Status)) {\r
+    NetFreePool (OptionList);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  for (Index = 0; Index < OptionCount; Index++) {\r
+    //\r
+    // Get DNS server addresses and DHCP server address from this offer.\r
+    //\r
+    if (OptionList[Index]->OpCode == DHCP4_TAG_DNS) {\r
+\r
+      if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        break;\r
+      }\r
+      //\r
+      // Primary DNS server address.\r
+      //\r
+      NetCopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
+\r
+      if (OptionList[Index]->Length > 4) {\r
+        //\r
+        // Secondary DNS server address\r
+        //\r
+        NetCopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));\r
+      }\r
+    } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {\r
+      if (OptionList[Index]->Length != 4) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        break;\r
+      }\r
+\r
+      NetCopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
+    }\r
+  }\r
+\r
+  NetFreePool (OptionList);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiDoDhcp (\r
+  IN EFI_HANDLE                 Image,\r
+  IN EFI_HANDLE                 Controller,\r
+  IN ISCSI_SESSION_CONFIG_DATA  *ConfigData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Parse the DHCP ACK to get the address configuration and DNS information.\r
+  \r
+Arguments:\r
+\r
+  Image      - The handle of the driver image.\r
+  Controller - The handle of the controller;\r
+  ConfigData - The session configuration data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The DNS information is got from the DHCP ACK.\r
+  EFI_NO_MAPPING        - DHCP failed to acquire address and other information.\r
+  EFI_INVALID_PARAMETER - The DHCP ACK's DNS option is mal-formatted.\r
+  EFI_DEVICE_ERROR      - Some unexpected error happened.\r
+\r
+--*/\r
+{\r
+  EFI_HANDLE              Dhcp4Handle;\r
+  EFI_DHCP4_PROTOCOL      *Dhcp4;\r
+  EFI_STATUS              Status;\r
+  EFI_DHCP4_PACKET_OPTION *ParaList;\r
+  EFI_DHCP4_CONFIG_DATA   Dhcp4ConfigData;\r
+\r
+  Dhcp4Handle = NULL;\r
+  Dhcp4       = NULL;\r
+  ParaList    = NULL;\r
+\r
+  //\r
+  // Create a DHCP4 child instance and get the protocol.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+            Controller,\r
+            Image,\r
+            &gEfiDhcp4ServiceBindingProtocolGuid,\r
+            &Dhcp4Handle\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Dhcp4Handle,\r
+                  &gEfiDhcp4ProtocolGuid,\r
+                  (VOID **)&Dhcp4,\r
+                  Image,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  ParaList = NetAllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);\r
+  if (ParaList == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Ask the server to reply with Netmask, Router, DNS and RootPath options.\r
+  //\r
+  ParaList->OpCode  = DHCP4_TAG_PARA_LIST;\r
+  ParaList->Length  = ConfigData->NvData.TargetInfoFromDhcp ? 4 : 3;\r
+  ParaList->Data[0] = DHCP4_TAG_NETMASK;\r
+  ParaList->Data[1] = DHCP4_TAG_ROUTER;\r
+  ParaList->Data[2] = DHCP4_TAG_DNS;\r
+  ParaList->Data[3] = DHCP4_TAG_ROOT_PATH;\r
+\r
+  NetZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
+  Dhcp4ConfigData.OptionCount = 1;\r
+  Dhcp4ConfigData.OptionList  = &ParaList;\r
+\r
+  if (ConfigData->NvData.TargetInfoFromDhcp) {\r
+    //\r
+    // Use callback to select an offer which contains target information.\r
+    //\r
+    Dhcp4ConfigData.Dhcp4Callback   = IScsiDhcpSelectOffer;\r
+    Dhcp4ConfigData.CallbackContext = &ConfigData->NvData;\r
+  }\r
+\r
+  Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Status = Dhcp4->Start (Dhcp4, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Parse the ACK to get required information.\r
+  //\r
+  Status = IScsiParseDhcpAck (Dhcp4, ConfigData);\r
+\r
+ON_EXIT:\r
+\r
+  if (ParaList != NULL) {\r
+    NetFreePool (ParaList);\r
+  }\r
+\r
+  if (Dhcp4 != NULL) {\r
+    Dhcp4->Stop (Dhcp4);\r
+    Dhcp4->Configure (Dhcp4, NULL);\r
+\r
+    gBS->CloseProtocol (\r
+          Dhcp4Handle,\r
+          &gEfiDhcp4ProtocolGuid,\r
+          Image,\r
+          Controller\r
+          );\r
+  }\r
+\r
+  NetLibDestroyServiceChild (\r
+    Controller,\r
+    Image,\r
+    &gEfiDhcp4ServiceBindingProtocolGuid,\r
+    Dhcp4Handle\r
+    );\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiDhcp.h b/MdeModulePkg/Universal/iScsi/IScsiDhcp.h
new file mode 100644 (file)
index 0000000..9312b54
--- /dev/null
@@ -0,0 +1,57 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiDhcp.h\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_DHCP_H_\r
+#define _ISCSI_DHCP_H_\r
+\r
+//#include "Tiano.h"\r
+//#include EFI_PROTOCOL_CONSUMER (Dhcp4)\r
+#include "protocol\Dhcp4.h"\r
+\r
+#define DHCP4_TAG_PARA_LIST             55\r
+#define DHCP4_TAG_NETMASK               1\r
+#define DHCP4_TAG_ROUTER                3\r
+#define DHCP4_TAG_DNS                   6\r
+#define DHCP4_TAG_SERVER_ID             54\r
+#define DHCP4_TAG_ROOT_PATH             17\r
+#define ISCSI_ROOT_PATH_ID              "iscsi:"\r
+#define ISCSI_ROOT_PATH_FIELD_DELIMITER ':'\r
+\r
+enum {\r
+  RP_FIELD_IDX_SERVERNAME = 0,\r
+  RP_FIELD_IDX_PROTOCOL,\r
+  RP_FIELD_IDX_PORT,\r
+  RP_FIELD_IDX_LUN,\r
+  RP_FIELD_IDX_TARGETNAME,\r
+  RP_FIELD_IDX_MAX\r
+};\r
+\r
+typedef struct _ISCSI_ROOT_PATH_FIELD {\r
+  CHAR8 *Str;\r
+  UINT8 Len;\r
+} ISCSI_ROOT_PATH_FIELD;\r
+\r
+EFI_STATUS\r
+IScsiDoDhcp (\r
+  IN EFI_HANDLE                 Image,\r
+  IN EFI_HANDLE                 Controller,\r
+  IN ISCSI_SESSION_CONFIG_DATA  *ConfigData\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiDriver.c b/MdeModulePkg/Universal/iScsi/IScsiDriver.c
new file mode 100644 (file)
index 0000000..68c6cb1
--- /dev/null
@@ -0,0 +1,462 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiDriver.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gIScsiDriverBinding = {\r
+  IScsiDriverBindingSupported,\r
+  IScsiDriverBindingStart,\r
+  IScsiDriverBindingStop,\r
+  0xa,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+EFI_GUID                    mIScsiPrivateGuid   = ISCSI_PRIVATE_GUID;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Test to see if iSCSI driver supports the given controller. \r
+\r
+Arguments:\r
+\r
+  This                - Protocol instance pointer.\r
+  ControllerHandle    - Handle of controller to test.\r
+  RemainingDevicePath - Optional parameter use to pick a specific child device to start.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES          - This driver supports the controller.\r
+  EFI_ALREADY_STARTED - This driver is already running on this device.\r
+  EFI_UNSUPPORTED     - This driver doesn't support the controller.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &mIScsiPrivateGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiTcp4ServiceBindingProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  CurrentDevicePath = RemainingDevicePath;\r
+  if (CurrentDevicePath != NULL) {\r
+    while (!IsDevicePathEnd (CurrentDevicePath)) {\r
+      if ((CurrentDevicePath->Type == MESSAGING_DEVICE_PATH) && (CurrentDevicePath->SubType == MSG_ISCSI_DP)) {\r
+        return EFI_SUCCESS;\r
+      }\r
+\r
+      CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
+    }\r
+\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  * This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Start to manage the controller. \r
+\r
+Arguments:\r
+\r
+  This                - Protocol instance pointer.\r
+  ControllerHandle    - Handle of the controller.\r
+  RemainingDevicePath - Optional parameter use to pick a specific child device to start.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES          - This driver supports this device.\r
+  EFI_ALREADY_STARTED - This driver is already running on this device.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS        Status;\r
+  ISCSI_DRIVER_DATA *Private;\r
+\r
+  //\r
+  // Try to add a port configuration page for this controller.\r
+  //\r
+  IScsiConfigUpdateForm (This->DriverBindingHandle, ControllerHandle, TRUE);\r
+\r
+  Private = IScsiCreateDriverData (This->DriverBindingHandle, ControllerHandle);\r
+  if (Private == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Get the iSCSI configuration data of this controller.\r
+  //\r
+  Status = IScsiGetConfigData (Private);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+  //\r
+  // Try to login and create an iSCSI session according to the configuration.\r
+  //\r
+  Status = IScsiSessionLogin (Private);\r
+  if (Status == EFI_MEDIA_CHANGED) {\r
+    //\r
+    // The specified target is not available and the redirection information is\r
+    // got, login the session again with the updated target address.\r
+    //\r
+    Status = IScsiSessionLogin (Private);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+  //\r
+  // Duplicate the Session's tcp connection device path. The source port field\r
+  // will be set to zero as one iSCSI session is comprised of several iSCSI\r
+  // connections.\r
+  //\r
+  Private->DevicePath = IScsiGetTcpConnDevicePath (Private);\r
+  if (Private->DevicePath == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+  //\r
+  // Install the updated device path onto the ExtScsiPassThruHandle.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Private->ExtScsiPassThruHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  Private->DevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+  //\r
+  // Install the iSCSI private stuff as a flag to indicate this controller\r
+  // is already controlled by iSCSI driver.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &ControllerHandle,\r
+                  &mIScsiPrivateGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &Private->IScsiIdentifier\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+  //\r
+  // Update/Publish the iSCSI Boot Firmware Table.\r
+  //\r
+  IScsiPublishIbft ();\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+\r
+  IScsiSessionAbort (&Private->Session);\r
+  IScsiCleanDriverData (Private);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Release the control of this controller and remove the iSCSI functions.\r
+\r
+Arguments:\r
+\r
+  This                - Protocol instance pointer.\r
+  ControllerHandle    - Handle of controller to stop.\r
+  NumberOfChildren    - Not used.\r
+  ChildHandleBuffer   - Not used.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES          - This driver supports this device.\r
+\r
+--*/\r
+{\r
+  EFI_HANDLE                      IScsiController;\r
+  EFI_STATUS                      Status;\r
+  ISCSI_PRIVATE_PROTOCOL          *IScsiIdentifier;\r
+  ISCSI_DRIVER_DATA               *Private;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru;\r
+  ISCSI_CONNECTION                *Conn;\r
+\r
+  if (NumberOfChildren != 0) {\r
+    //\r
+    // We should have only one child.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandleBuffer[0],\r
+                    &gEfiExtScsiPassThruProtocolGuid,\r
+                    (VOID **) &PassThru,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);\r
+    Conn    = NET_LIST_HEAD (&Private->Session.Conns, ISCSI_CONNECTION, Link);\r
+\r
+    //\r
+    // Previously the TCP4 protocol is opened BY_CHILD_CONTROLLER. Just close\r
+    // the protocol here but not uninstall the device path protocol and\r
+    // EXT SCSI PASS THRU protocol installed on ExtScsiPassThruHandle.\r
+    //\r
+    gBS->CloseProtocol (\r
+          Conn->Tcp4Io.Handle,\r
+          &gEfiTcp4ProtocolGuid,\r
+          Private->Image,\r
+          Private->ExtScsiPassThruHandle\r
+          );\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Get the handle of the controller we are controling.\r
+  //\r
+  IScsiController = NetLibGetNicHandle (ControllerHandle, &gEfiTcp4ProtocolGuid);\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  IScsiController,\r
+                  &mIScsiPrivateGuid,\r
+                  (VOID **)&IScsiIdentifier,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Private = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);\r
+\r
+  //\r
+  // Uninstall the private protocol.\r
+  //\r
+  gBS->UninstallProtocolInterface (\r
+        IScsiController,\r
+        &mIScsiPrivateGuid,\r
+        &Private->IScsiIdentifier\r
+        );\r
+\r
+  //\r
+  // Update the iSCSI Boot Firware Table.\r
+  //\r
+  IScsiPublishIbft ();\r
+\r
+  IScsiSessionAbort (&Private->Session);\r
+  IScsiCleanDriverData (Private);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIScsiUnload (\r
+  IN EFI_HANDLE  ImageHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Unload the iSCSI driver.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - The handle of the driver image.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS      - The driver is unloaded.\r
+  EFI_DEVICE_ERROR - Some unexpected error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       DeviceHandleCount;\r
+  EFI_HANDLE  *DeviceHandleBuffer;\r
+  UINTN       Index;\r
+\r
+  //\r
+  // Try to disonnect the driver from the devices it's controlling.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  AllHandles,\r
+                  NULL,\r
+                  NULL,\r
+                  &DeviceHandleCount,\r
+                  &DeviceHandleBuffer\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    for (Index = 0; Index < DeviceHandleCount; Index++) {\r
+      Status = gBS->DisconnectController (\r
+                      DeviceHandleBuffer[Index],\r
+                      ImageHandle,\r
+                      NULL\r
+                      );\r
+    }\r
+\r
+    if (DeviceHandleBuffer != NULL) {\r
+      NetFreePool (DeviceHandleBuffer);\r
+    }\r
+  }\r
+  //\r
+  // Unload the iSCSI configuration form.\r
+  //\r
+  IScsiConfigFormUnload (gIScsiDriverBinding.DriverBindingHandle);\r
+\r
+  //\r
+  // Uninstall the protocols installed by iSCSI driver.\r
+  //\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  ImageHandle,\r
+                  &gEfiDriverBindingProtocolGuid,\r
+                  &gIScsiDriverBinding,\r
+                  &gEfiComponentName2ProtocolGuid,\r
+                  &gIScsiComponentName2,\r
+                  &gEfiComponentNameProtocolGuid,\r
+                  &gIScsiComponentName,\r
+                  &gEfiIScsiInitiatorNameProtocolGuid,\r
+                  &gIScsiInitiatorName,\r
+                  NULL\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverEntryPoint (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize the global variables publish the driver binding protocol.\r
+\r
+Arguments:\r
+\r
+  ImageHandle - The handle of the driver image.\r
+  SystemTable - The EFI system table.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS      - The protocols are installed.\r
+  EFI_DEVICE_ERROR - Some unexpected error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  //EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+\r
+  //\r
+  // Initialize the EFI Driver Library\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gIScsiDriverBinding,\r
+             ImageHandle,\r
+             &gIScsiComponentName,\r
+             &gIScsiComponentName2\r
+           );\r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &ImageHandle,\r
+                    &gEfiIScsiInitiatorNameProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &gIScsiInitiatorName\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->UninstallMultipleProtocolInterfaces (\r
+            ImageHandle,\r
+            &gEfiDriverBindingProtocolGuid,\r
+            &gIScsiDriverBinding,\r
+            &gEfiComponentName2ProtocolGuid,\r
+            &gIScsiComponentName2,\r
+            &gEfiComponentNameProtocolGuid,\r
+            &gIScsiComponentName,\r
+            NULL\r
+            );\r
+    }\r
+  }\r
+  //\r
+  // Initialize the configuration form of iSCSI.\r
+  //\r
+  IScsiConfigFormInit (gIScsiDriverBinding.DriverBindingHandle);\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiDriver.h b/MdeModulePkg/Universal/iScsi/IScsiDriver.h
new file mode 100644 (file)
index 0000000..5334e34
--- /dev/null
@@ -0,0 +1,123 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiDriver.h\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_DRIVER_H_\r
+#define _ISCSI_DRIVER_H_\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <protocol/DriverBinding.h>\r
+#include <protocol/ScsiPassThruExt.h>\r
+#include <protocol/IScsiInitiatorName.h>\r
+#include <protocol/Ip4Config.h>\r
+#include <protocol/ComponentName.h>\r
+#include <protocol/ComponentName2.h>\r
+\r
+#define ISCSI_PRIVATE_GUID \\r
+  { \\r
+    0xfa3cde4c, 0x87c2, 0x427d, 0xae, 0xde, 0x7d, 0xd0, 0x96, 0xc8, 0x8c, 0x58 \\r
+  }\r
+\r
+#define ISCSI_INITIATOR_NAME_VAR_NAME L"I_NAME"\r
+\r
+extern EFI_COMPONENT_NAME2_PROTOCOL       gIScsiComponentName2;\r
+extern EFI_COMPONENT_NAME_PROTOCOL        gIScsiComponentName;\r
+\r
+extern EFI_ISCSI_INITIATOR_NAME_PROTOCOL  gIScsiInitiatorName;\r
+\r
+extern EFI_GUID                           mIScsiPrivateGuid;\r
+\r
+typedef struct _ISCSI_PRIVATE_PROTOCOL {\r
+  UINT32  Reserved;\r
+} ISCSI_PRIVATE_PROTOCOL;\r
+\r
+//\r
+// EFI Driver Binding Protocol for iSCSI driver.\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiDriverBindingStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN UINTN                        NumberOfChildren,\r
+  IN EFI_HANDLE                   *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol for iSCSI driver.\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL   *This,\r
+  IN  CHAR8                         *Language,\r
+  OUT CHAR16                        **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL   *This,\r
+  IN  EFI_HANDLE                    ControllerHandle,\r
+  IN  EFI_HANDLE                    ChildHandle        OPTIONAL,\r
+  IN  CHAR8                         *Language,\r
+  OUT CHAR16                        **ControllerName\r
+  );\r
+\r
+//\r
+// EFI iSCSI Initiator Name Protocol for iSCSI driver.\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiGetInitiatorName (\r
+  IN     EFI_ISCSI_INITIATOR_NAME_PROTOCOL  *This,\r
+  IN OUT UINTN                              *BufferSize,\r
+  OUT    VOID                               *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiSetInitiatorName (\r
+  IN     EFI_ISCSI_INITIATOR_NAME_PROTOCOL  *This,\r
+  IN OUT UINTN                              *BufferSize,\r
+  OUT    VOID                               *Buffer\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiExtScsiPassThru.c b/MdeModulePkg/Universal/iScsi/IScsiExtScsiPassThru.c
new file mode 100644 (file)
index 0000000..42b29ef
--- /dev/null
@@ -0,0 +1,401 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiExtScsiPassThru.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruFunction (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                          *This,\r
+  IN UINT8                                                    *Target,\r
+  IN UINT64                                                   Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET           *Packet,\r
+  IN EFI_EVENT                                                Event     OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function sends out the SCSI command via iSCSI transport layer and returned\r
+  back the data received from the iSCSI target. \r
+\r
+Arguments:\r
+\r
+  This   - The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  Target - The Target ID of device to send the SCSI Request Packet. \r
+  Lun    - The LUN of the device to send the SCSI Request Packet.\r
+  Packet - The SCSI Request Packet to send to the device.\r
+  Event  - The event used in non-blocking mode, it should be always NULL.\r
+\r
+Returns:\r
+\r
+  EFI_STATUS\r
+\r
+--*/\r
+{\r
+  if (Target[0] != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet == NULL) || (Packet->Cdb == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return IScsiExecuteScsiCommand (This, Target, Lun, Packet);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetNextTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL  *This,\r
+  IN OUT UINT8                        **Target,\r
+  IN OUT UINT64                       *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieve the list of legal Target IDs for SCSI devices on a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This   - The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance..\r
+  Target - On input, a pointer to the Target ID of a SCSI device present on the\r
+           SCSI channel.  On output, a pointer to the Target ID of the next SCSI\r
+           device present on a SCSI channel.  An input value of 0xFFFFFFFF\r
+           retrieves the Target ID of the first SCSI device present on a SCSI channel.\r
+  Lun    - On input, a pointer to the LUN of a SCSI device present on the SCSI\r
+           channel. On output, a pointer to the LUN of the next SCSI device present on \r
+           a SCSI channel.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device \r
+                          on the SCSI channel was returned in Target and Lun.\r
+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.\r
+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
+                           returned on a previous call to GetNextDevice().\r
+\r
+--*/\r
+{\r
+  ISCSI_DRIVER_DATA           *Private;\r
+  ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
+  UINT8                       TargetId[TARGET_MAX_BYTES];\r
+\r
+  Private       = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);\r
+  ConfigNvData  = &Private->Session.ConfigData.NvData;\r
+\r
+  if ((*Target)[0] == 0 && (NetCompareMem (Lun, ConfigNvData->BootLun, sizeof (UINT64)) == 0)) {\r
+    //\r
+    // Only one <Target, Lun> pair per iSCSI Driver instance.\r
+    //\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  NetSetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\r
+  if (NetCompareMem (*Target, TargetId, TARGET_MAX_BYTES) == 0) {\r
+    (*Target)[0] = 0;\r
+    NetCopyMem (Lun, ConfigNvData->BootLun, sizeof (UINT64));\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruBuildDevicePath (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL  *This,\r
+  IN UINT8                            *Target,\r
+  IN UINT64                           Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL     **DevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Allocate and build a device path node for a SCSI device on a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  Target                - The Target ID of the SCSI device for which\r
+                          a device path node is to be allocated and built.\r
+  Lun                   - The LUN of the SCSI device for which a device \r
+                          path node is to be allocated and built.\r
+  DevicePath            - A pointer to a single device path node that \r
+                          describes the SCSI device specified by \r
+                          Target and Lun. This function is responsible \r
+                          for allocating the buffer DevicePath with the boot\r
+                          service AllocatePool().  It is the caller's \r
+                          responsibility to free DevicePath when the caller\r
+                          is finished with DevicePath.    \r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The device path node that describes the SCSI device\r
+                          specified by Target and Lun was allocated and \r
+                          returned in DevicePath.\r
+  EFI_NOT_FOUND         - The SCSI devices specified by Target and Lun does\r
+                          not exist on the SCSI channel.\r
+  EFI_INVALID_PARAMETER - DevicePath is NULL.\r
+  EFI_OUT_OF_RESOURCES  - There are not enough resources to allocate \r
+                          DevicePath.\r
+\r
+--*/\r
+{\r
+  ISCSI_DRIVER_DATA             *Private;\r
+  ISCSI_SESSION                 *Session;\r
+  ISCSI_SESSION_CONFIG_NVDATA   *ConfigNvData;\r
+  ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig;\r
+  EFI_DEV_PATH                  *Node;\r
+  UINTN                         DevPathNodeLen;\r
+\r
+  if ((DevicePath == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Target[0] != 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Private       = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);\r
+  Session       = &Private->Session;\r
+  ConfigNvData  = &Session->ConfigData.NvData;\r
+  AuthConfig    = &Session->AuthData.AuthConfig;\r
+\r
+  if (NetCompareMem (&Lun, ConfigNvData->BootLun, sizeof (UINT64)) != 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  DevPathNodeLen  = sizeof (ISCSI_DEVICE_PATH) + AsciiStrLen (ConfigNvData->TargetName) + 1;\r
+  Node            = NetAllocatePool (DevPathNodeLen);\r
+  if (Node == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Node->DevPath.Type    = MESSAGING_DEVICE_PATH;\r
+  Node->DevPath.SubType = MSG_ISCSI_DP;\r
+  SetDevicePathNodeLength (&Node->DevPath, DevPathNodeLen);\r
+\r
+  //\r
+  // 0 for TCP, others are reserved.\r
+  //\r
+  Node->Iscsi.NetworkProtocol = 0;\r
+\r
+  Node->Iscsi.LoginOption     = 0;\r
+  switch (AuthConfig->CHAPType) {\r
+  case ISCSI_CHAP_NONE:\r
+    Node->Iscsi.LoginOption |= 0x0800;\r
+    break;\r
+\r
+  case ISCSI_CHAP_UNI:\r
+    Node->Iscsi.LoginOption |= 0x1000;\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+\r
+  NetCopyMem (&Node->Iscsi.Lun, ConfigNvData->BootLun, sizeof (UINT64));\r
+  Node->Iscsi.TargetPortalGroupTag = Session->TargetPortalGroupTag;\r
+  AsciiStrCpy ((CHAR8 *) Node + sizeof (ISCSI_DEVICE_PATH), ConfigNvData->TargetName);\r
+\r
+  *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL  *This,\r
+  IN EFI_DEVICE_PATH_PROTOCOL         *DevicePath,\r
+  OUT UINT8                           **Target,\r
+  OUT UINT64                          *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Translate a device path node to a Target ID and LUN.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  DevicePath            - A pointer to the device path node that \r
+                          describes a SCSI device on the SCSI channel.\r
+  Target                - A pointer to the Target ID of a SCSI device \r
+                          on the SCSI channel. \r
+  Lun                   - A pointer to the LUN of a SCSI device on \r
+                          the SCSI channel.    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - DevicePath was successfully translated to a \r
+                          Target ID and LUN, and they were returned \r
+                          in Target and Lun.\r
+  EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.\r
+  EFI_UNSUPPORTED       - This driver does not support the device path \r
+                          node type in DevicePath.\r
+  EFI_NOT_FOUND         - A valid translation from DevicePath to a \r
+                          Target ID and LUN does not exist.\r
+\r
+--*/\r
+{\r
+  ISCSI_DRIVER_DATA           *Private;\r
+  ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;\r
+\r
+  if ((DevicePath == NULL) || (Target == NULL) || (Lun == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
+      (DevicePath->SubType != MSG_ISCSI_DP) ||\r
+      (DevicePathNodeLength (DevicePath) <= sizeof (ISCSI_DEVICE_PATH))\r
+      ) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Private       = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);\r
+  ConfigNvData  = &Private->Session.ConfigData.NvData;\r
+\r
+  NetZeroMem (*Target, TARGET_MAX_BYTES);\r
+\r
+  if (AsciiStrCmp (ConfigNvData->TargetName, (CHAR8 *) DevicePath + sizeof (ISCSI_DEVICE_PATH)) != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  NetCopyMem (Lun, ConfigNvData->BootLun, sizeof (UINT64));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruResetChannel (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL  *This\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI channel.This operation resets all the SCSI devices connected to\r
+  the SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This            - Protocol instance pointer.\r
+\r
+Returns:\r
+\r
+  EFI_UNSUPPORTED - It's not supported.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruResetTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL  *This,\r
+  IN UINT8                            *Target,\r
+  IN UINT64                           Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Resets a SCSI device that is connected to a SCSI channel.\r
+\r
+Arguments:\r
+\r
+  This            - Protocol instance pointer.\r
+  Target          - The Target ID of the SCSI device to reset. \r
+  Lun             - The LUN of the SCSI device to reset.\r
+    \r
+Returns:\r
+\r
+  EFI_UNSUPPORTED - It's not supported.\r
+\r
+--*/\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiExtScsiPassThruGetNextTarget (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL  *This,\r
+  IN OUT UINT8                        **Target\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieve the list of legal Target IDs for SCSI devices on a SCSI channel.\r
+\r
+Arguments:\r
+  This                  - Protocol instance pointer.\r
+  Target                - On input, a pointer to the Target ID of a SCSI \r
+                          device present on the SCSI channel.  On output, \r
+                          a pointer to the Target ID of the next SCSI device\r
+                           present on a SCSI channel.  An input value of \r
+                           0xFFFFFFFF retrieves the Target ID of the first \r
+                           SCSI device present on a SCSI channel.\r
+  Lun                   - On input, a pointer to the LUN of a SCSI device\r
+                          present on the SCSI channel. On output, a pointer\r
+                          to the LUN of the next SCSI device present on \r
+                          a SCSI channel.\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Target ID and Lun of the next SCSI device \r
+                          on the SCSI channel was returned in Target and Lun.\r
+  EFI_NOT_FOUND         - There are no more SCSI devices on this SCSI channel.\r
+  EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not\r
+                          returned on a previous call to GetNextDevice().\r
+\r
+--*/\r
+{\r
+  UINT8 TargetId[TARGET_MAX_BYTES];\r
+\r
+  NetSetMem (TargetId, TARGET_MAX_BYTES, 0xFF);\r
+\r
+  if (NetCompareMem (*Target, TargetId, TARGET_MAX_BYTES) == 0) {\r
+    (*Target)[0] = 0;\r
+    return EFI_SUCCESS;\r
+  } else if ((*Target)[0] == 0) {\r
+    return EFI_NOT_FOUND;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+}\r
+\r
+EFI_EXT_SCSI_PASS_THRU_PROTOCOL gIScsiExtScsiPassThruProtocolTemplate = {\r
+  NULL,\r
+  IScsiExtScsiPassThruFunction,\r
+  IScsiExtScsiPassThruGetNextTargetLun,\r
+  IScsiExtScsiPassThruBuildDevicePath,\r
+  IScsiExtScsiPassThruGetTargetLun,\r
+  IScsiExtScsiPassThruResetChannel,\r
+  IScsiExtScsiPassThruResetTargetLun,\r
+  IScsiExtScsiPassThruGetNextTarget\r
+};\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiExtScsiPassThru.h b/MdeModulePkg/Universal/iScsi/IScsiExtScsiPassThru.h
new file mode 100644 (file)
index 0000000..7cb9be2
--- /dev/null
@@ -0,0 +1,27 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiExtScsiPassThru.h\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_EXT_SCSI_PASS_THRU_H_\r
+#define _ISCSI_EXT_SCSI_PASS_THRU_H_\r
+\r
+#include <protocol/ScsiPassThruExt.h>\r
+\r
+extern EFI_EXT_SCSI_PASS_THRU_PROTOCOL  gIScsiExtScsiPassThruProtocolTemplate;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiIbft.c b/MdeModulePkg/Universal/iScsi/IScsiIbft.c
new file mode 100644 (file)
index 0000000..e5d6324
--- /dev/null
@@ -0,0 +1,645 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiIbft.c\r
+\r
+Abstract:\r
+\r
+  Implementation for iSCSI Boot Firmware Table publication.\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+STATIC\r
+VOID\r
+IScsiInitIbfTableHeader (\r
+  IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER  *Header\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize the header of the iSCSI Boot Firmware Table.\r
+  \r
+Arguments:\r
+\r
+  Header - The header of the iSCSI Boot Firmware Table.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  NetZeroMem (Header, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER));\r
+\r
+  Header->Signature = EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE;\r
+  Header->Length    = IBFT_HEAP_OFFSET;\r
+  Header->Revision  = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_REVISION;\r
+  Header->Checksum  = 0;\r
+\r
+  Header->OemId[0]  = 'I';\r
+  Header->OemId[1]  = 'N';\r
+  Header->OemId[2]  = 'T';\r
+  Header->OemId[3]  = 'E';\r
+  Header->OemId[4]  = 'L';\r
+}\r
+\r
+STATIC\r
+VOID\r
+IScsiInitControlSection (\r
+  IN EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER  *Table,\r
+  IN UINTN                                      HandleCount\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize the control section of the iSCSI Boot Firmware Table.\r
+  \r
+Arguments:\r
+\r
+  Table       - The ACPI table.\r
+  HandleCount - The number of the handles associated with iSCSI sessions, it's\r
+                equal to the number of iSCSI sessions.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE  *Control;\r
+  UINTN                                                 NumOffset;\r
+\r
+  Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+\r
+  NetZeroMem (Control, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE));\r
+\r
+  Control->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_ID;\r
+  Control->Header.Version     = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE_VERSION;\r
+  Control->Header.Length      = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE);\r
+\r
+  //\r
+  // Each session occupies two offsets, one for the NIC section,\r
+  // the other for the Target section.\r
+  //\r
+  NumOffset = 2 * HandleCount;\r
+  if (NumOffset > 4) {\r
+    //\r
+    // Need expand the control section if more than 2 NIC/Target sections\r
+    // exist.\r
+    //\r
+    Control->Header.Length += (UINT16) (NumOffset - 4) * sizeof (UINT16);\r
+  }\r
+}\r
+\r
+STATIC\r
+VOID\r
+IScsiAddHeapItem (\r
+  IN OUT UINT8  **Heap,\r
+  IN     VOID   *Data,\r
+  IN     UINTN  Len\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Add one item into the heap.\r
+  \r
+Arguments:\r
+\r
+  Heap - On input, the current address of the heap; On output, the address of\r
+         the heap after the item is added.\r
+  Data - The data to add into the heap.\r
+  Len  - Length of the Data in byte.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  //\r
+  // Add one byte for the NULL delimiter.\r
+  //\r
+  *Heap -= Len + 1;\r
+\r
+  NetCopyMem (*Heap, Data, Len);\r
+  *(*Heap + Len) = 0;\r
+}\r
+\r
+STATIC\r
+VOID\r
+IScsiFillInitiatorSection (\r
+  IN     EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER  *Table,\r
+  IN OUT UINT8                                      **Heap,\r
+  IN     EFI_HANDLE                                 Handle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Fill the Initiator section of the iSCSI Boot Firmware Table.\r
+  \r
+Arguments:\r
+\r
+  Table  - The ACPI table.\r
+  Heap   - The heap.\r
+  Handle - The handle associated with the iSCSI session.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE    *Control;\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE  *Initiator;\r
+  ISCSI_DRIVER_DATA                                       *DriverData;\r
+  ISCSI_SESSION                                           *Session;\r
+  ISCSI_PRIVATE_PROTOCOL                                  *IScsiIdentifier;\r
+  EFI_STATUS                                              Status;\r
+\r
+  Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+\r
+  //\r
+  // Initiator section immediately follows the control section.\r
+  //\r
+  Initiator = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE *) ((UINT8 *) Control + IBFT_ROUNDUP (Control->Header.Length));\r
+\r
+  Control->InitiatorOffset = (UINT16) ((UINTN) Initiator - (UINTN) Table);\r
+\r
+  NetZeroMem (Initiator, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE));\r
+\r
+  Initiator->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_ID;\r
+  Initiator->Header.Version     = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_VERSION;\r
+  Initiator->Header.Length      = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE);\r
+  Initiator->Header.Flags       = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BLOCK_VALID | EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE_FLAG_BOOT_SELECTED;\r
+\r
+  //\r
+  // Get the identifier from the handle.\r
+  //\r
+  Status = gBS->HandleProtocol (Handle, &mIScsiPrivateGuid, &IScsiIdentifier);\r
+  if (EFI_ERROR (Status)) {\r
+    ASSERT (FALSE);\r
+    return ;\r
+  }\r
+\r
+  DriverData  = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);\r
+  Session     = &DriverData->Session;\r
+\r
+  //\r
+  // Fill the iSCSI Initiator Name into the heap.\r
+  //\r
+  IScsiAddHeapItem (Heap, Session->InitiatorName, Session->InitiatorNameLength - 1);\r
+\r
+  Initiator->IScsiNameLength  = (UINT16) (Session->InitiatorNameLength - 1);\r
+  Initiator->IScsiNameOffset  = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+}\r
+\r
+STATIC\r
+VOID\r
+IScsiMapV4ToV6Addr (\r
+  IN  EFI_IPv4_ADDRESS *V4,\r
+  OUT EFI_IPv6_ADDRESS *V6\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Map the v4 IP address into v6 IP address.\r
+  \r
+Arguments:\r
+\r
+  V4 - The v4 IP address.\r
+  V6 - The v6 IP address.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  UINTN Index;\r
+\r
+  NetZeroMem (V6, sizeof (EFI_IPv6_ADDRESS));\r
+\r
+  V6->Addr[10]  = 0xff;\r
+  V6->Addr[11]  = 0xff;\r
+\r
+  for (Index = 0; Index < 4; Index++) {\r
+    V6->Addr[12 + Index] = V4->Addr[Index];\r
+  }\r
+}\r
+\r
+STATIC\r
+UINT16\r
+IScsiGetNICPciLocation (\r
+  IN EFI_HANDLE  Controller\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the NIC's PCI location and return it accroding to the composited\r
+  format defined in iSCSI Boot Firmware Table.\r
+  \r
+Arguments:\r
+\r
+  Controller - The handle of the controller.\r
+\r
+Returns:\r
+\r
+  UINT16 - The composited representation of the NIC PCI location.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_HANDLE                PciIoHandle;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  UINTN                     Segment;\r
+  UINTN                     Bus;\r
+  UINTN                     Device;\r
+  UINTN                     Function;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &DevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return 0;\r
+  }\r
+\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiPciIoProtocolGuid,\r
+                  &DevicePath,\r
+                  &PciIoHandle\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return 0;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, &PciIo);\r
+  if (EFI_ERROR (Status)) {\r
+    return 0;\r
+  }\r
+\r
+  Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);\r
+  if (EFI_ERROR (Status)) {\r
+    return 0;\r
+  }\r
+\r
+  return (UINT16) ((Bus << 8) | (Device << 3) | Function);\r
+}\r
+\r
+STATIC\r
+EFI_MAC_ADDRESS *\r
+IScsiGetMacAddress (\r
+  IN EFI_HANDLE  Controller\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the MAC address of the controller.\r
+  \r
+Arguments:\r
+\r
+  Controller - The handle of the controller.\r
+\r
+Returns:\r
+\r
+  EFI_MAC_ADDRESS * - The mac address.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Controller,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  &Snp\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return &Snp->Mode->PermanentAddress;\r
+}\r
+\r
+STATIC\r
+VOID\r
+IScsiFillNICAndTargetSections (\r
+  IN     EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER  *Table,\r
+  IN OUT UINT8                                      **Heap,\r
+  IN     UINTN                                      HandleCount,\r
+  IN     EFI_HANDLE                                 *Handles\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Fill the NIC and target sections in iSCSI Boot Firmware Table.\r
+\r
+Arguments:\r
+\r
+  Table       - The buffer of the ACPI table.\r
+  Heap        - The heap buffer used to store the variable length parameters such as iSCSI name.\r
+  HandleCount - The number of handles having iSCSI private protocol installed.\r
+  Handles     - The handle buffer.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE  *Control;\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE      *Nic;\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE   *Target;\r
+  ISCSI_DRIVER_DATA                                     *DriverData;\r
+  ISCSI_SESSION_CONFIG_DATA                             *SessionConfigData;\r
+  ISCSI_CHAP_AUTH_CONFIG_NVDATA                         *AuthConfig;\r
+  UINT16                                                *SectionOffset;\r
+  UINTN                                                 Index;\r
+  UINT16                                                Length;\r
+  EFI_MAC_ADDRESS                                       *Mac;\r
+  ISCSI_PRIVATE_PROTOCOL                                *IScsiIdentifier;\r
+  EFI_STATUS                                            Status;\r
+\r
+  //\r
+  // Get the offset of the first Nic and Target section.\r
+  //\r
+  Control = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_CONTROL_STRUCTURE *) (Table + 1);\r
+  Nic     = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Table +\r
+          Control->InitiatorOffset + IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_INITIATOR_STRUCTURE)));\r
+  Target  = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +\r
+          IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));\r
+\r
+  SectionOffset = &Control->NIC0Offset;\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (Handles[Index], &mIScsiPrivateGuid, &IScsiIdentifier);\r
+    if (EFI_ERROR (Status)) {\r
+      ASSERT (FALSE);\r
+      return ;\r
+    }\r
+\r
+    DriverData        = ISCSI_DRIVER_DATA_FROM_IDENTIFIER (IScsiIdentifier);\r
+    SessionConfigData = &DriverData->Session.ConfigData;\r
+    AuthConfig        = &DriverData->Session.AuthData.AuthConfig;\r
+\r
+    //\r
+    // Fill the Nic section.\r
+    //\r
+    NetZeroMem (Nic, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE));\r
+\r
+    Nic->Header.StructureId = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_ID;\r
+    Nic->Header.Version     = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_VERSION;\r
+    Nic->Header.Length      = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE);\r
+    Nic->Header.Index       = (UINT8) Index;\r
+    Nic->Header.Flags       = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BLOCK_VALID |\r
+                            EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_BOOT_SELECTED |\r
+                            EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE_FLAG_GLOBAL;\r
+\r
+    //\r
+    // Get the subnet mask prefix length.\r
+    //\r
+    Nic->SubnetMaskPrefixLength = IScsiGetSubnetMaskPrefixLength (&SessionConfigData->NvData.SubnetMask);\r
+\r
+    if (SessionConfigData->NvData.InitiatorInfoFromDhcp) {\r
+      Nic->Origin = IpPrefixOriginDhcp;\r
+    } else {\r
+      Nic->Origin = IpPrefixOriginManual;\r
+    }\r
+    //\r
+    // Map the various v4 addresses into v6 addresses.\r
+    //\r
+    IScsiMapV4ToV6Addr (&SessionConfigData->NvData.LocalIp, &Nic->Ip);\r
+    IScsiMapV4ToV6Addr (&SessionConfigData->NvData.Gateway, &Nic->Gateway);\r
+    IScsiMapV4ToV6Addr (&SessionConfigData->PrimaryDns, &Nic->PrimaryDns);\r
+    IScsiMapV4ToV6Addr (&SessionConfigData->SecondaryDns, &Nic->SecondaryDns);\r
+    IScsiMapV4ToV6Addr (&SessionConfigData->DhcpServer, &Nic->DhcpServer);\r
+\r
+    Mac = IScsiGetMacAddress (DriverData->Controller);\r
+    NetCopyMem (Nic->Mac, Mac, sizeof (Nic->Mac));\r
+\r
+    //\r
+    // Get the PCI location of the Nic.\r
+    //\r
+    Nic->PciLocation  = IScsiGetNICPciLocation (DriverData->Controller);\r
+\r
+    *SectionOffset    = (UINT16) ((UINTN) Nic - (UINTN) Table);\r
+    SectionOffset++;\r
+\r
+    //\r
+    // Fill the Target section.\r
+    //\r
+    NetZeroMem (Target, sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE));\r
+\r
+    Target->Header.StructureId  = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_ID;\r
+    Target->Header.Version      = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_VERSION;\r
+    Target->Header.Length       = sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE);\r
+    Target->Header.Index        = (UINT8) Index;\r
+    Target->Header.Flags        = EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BLOCK_VALID | EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE_FLAG_BOOT_SELECTED;\r
+    Target->Port                = SessionConfigData->NvData.TargetPort;\r
+    Target->CHAPType            = AuthConfig->CHAPType;\r
+    Target->NicIndex            = (UINT8) Index;\r
+\r
+    IScsiMapV4ToV6Addr (&SessionConfigData->NvData.TargetIp, &Target->Ip);\r
+    NetCopyMem (Target->BootLun, SessionConfigData->NvData.BootLun, sizeof (Target->BootLun));\r
+\r
+    //\r
+    // Target iSCSI Name, CHAP name/secret, reverse CHAP name/secret.\r
+    //\r
+    Length = (UINT16) AsciiStrLen (SessionConfigData->NvData.TargetName);\r
+    IScsiAddHeapItem (Heap, SessionConfigData->NvData.TargetName, Length);\r
+\r
+    Target->IScsiNameLength = Length;\r
+    Target->IScsiNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+    if (Target->CHAPType != ISCSI_CHAP_NONE) {\r
+      //\r
+      // CHAP Name\r
+      //\r
+      Length = (UINT16) AsciiStrLen (AuthConfig->CHAPName);\r
+      IScsiAddHeapItem (Heap, AuthConfig->CHAPName, Length);\r
+      Target->CHAPNameLength  = Length;\r
+      Target->CHAPNameOffset  = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+      //\r
+      // CHAP Secret\r
+      //\r
+      Length = (UINT16) AsciiStrLen (AuthConfig->CHAPSecret);\r
+      IScsiAddHeapItem (Heap, AuthConfig->CHAPSecret, Length);\r
+      Target->CHAPSecretLength  = Length;\r
+      Target->CHAPSecretOffset  = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+      if (Target->CHAPType == ISCSI_CHAP_MUTUAL) {\r
+        //\r
+        // Reverse CHAP Name\r
+        //\r
+        Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPName);\r
+        IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPName, Length);\r
+        Target->ReverseCHAPNameLength = Length;\r
+        Target->ReverseCHAPNameOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+\r
+        //\r
+        // Reverse CHAP Secret\r
+        //\r
+        Length = (UINT16) AsciiStrLen (AuthConfig->ReverseCHAPSecret);\r
+        IScsiAddHeapItem (Heap, AuthConfig->ReverseCHAPSecret, Length);\r
+        Target->ReverseCHAPSecretLength = Length;\r
+        Target->ReverseCHAPSecretOffset = (UINT16) ((UINTN) *Heap - (UINTN) Table);\r
+      }\r
+    }\r
+\r
+    *SectionOffset = (UINT16) ((UINTN) Target - (UINTN) Table);\r
+    SectionOffset++;\r
+\r
+    //\r
+    // Advance to the next NIC/Target pair\r
+    //\r
+    Nic    = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE *) ((UINTN) Target +\r
+           IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE)));\r
+    Target = (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_TARGET_STRUCTURE *) ((UINTN) Nic +\r
+           IBFT_ROUNDUP (sizeof (EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_NIC_STRUCTURE)));\r
+  }\r
+}\r
+\r
+VOID\r
+IScsiPublishIbft (\r
+  IN VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Publish and remove the iSCSI Boot Firmware Table according to the iSCSI\r
+  session status.\r
+\r
+Arguments:\r
+\r
+  None.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     TableHandle;\r
+  EFI_ACPI_SUPPORT_PROTOCOL                 *AcpiSupport;\r
+  EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_HEADER *Table;\r
+  UINTN                                     HandleCount;\r
+  EFI_HANDLE                                *HandleBuffer;\r
+  UINT8                                     *Heap;\r
+  INTN                                      Index;\r
+  EFI_ACPI_TABLE_VERSION                    Version;\r
+  UINT32                                    Signature;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiAcpiSupportProtocolGuid, NULL, &AcpiSupport);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  //\r
+  // Try to remove the old iSCSI Boot Firmware Table.\r
+  //\r
+  for (Index = 0;; Index++) {\r
+    Status = AcpiSupport->GetAcpiTable (\r
+                            AcpiSupport,\r
+                            Index,\r
+                            &Table,\r
+                            &Version,\r
+                            &TableHandle\r
+                            );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    Signature = Table->Signature;\r
+    NetFreePool (Table);\r
+\r
+    if (Signature == EFI_ACPI_3_0_ISCSI_BOOT_FIRMWARE_TABLE_SIGNATURE) {\r
+      //\r
+      // Remove the table.\r
+      //\r
+      Status = AcpiSupport->SetAcpiTable (\r
+                              AcpiSupport,\r
+                              NULL,\r
+                              FALSE,\r
+                              Version,\r
+                              &TableHandle\r
+                              );\r
+      if (EFI_ERROR (Status)) {\r
+        return ;\r
+      }\r
+\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // Get all iSCSI private protocols.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &mIScsiPrivateGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  //\r
+  // Allocate 4k bytes to hold the ACPI table.\r
+  //\r
+  Table = NetAllocatePool (IBFT_MAX_SIZE);\r
+  if (Table == NULL) {\r
+    return ;\r
+  }\r
+\r
+  Heap = (CHAR8 *) Table + IBFT_HEAP_OFFSET;\r
+\r
+  //\r
+  // Fill in the various section of the iSCSI Boot Firmware Table.\r
+  //\r
+  IScsiInitIbfTableHeader (Table);\r
+  IScsiInitControlSection (Table, HandleCount);\r
+  IScsiFillInitiatorSection (Table, &Heap, HandleBuffer[0]);\r
+  IScsiFillNICAndTargetSections (Table, &Heap, HandleCount, HandleBuffer);\r
+\r
+  NetFreePool (HandleBuffer);\r
+\r
+  TableHandle = 0;\r
+\r
+  //\r
+  // Install or update the iBFT table.\r
+  //\r
+  Status = AcpiSupport->SetAcpiTable (\r
+                          AcpiSupport,\r
+                          Table,\r
+                          TRUE,\r
+                          EFI_ACPI_TABLE_VERSION_3_0,\r
+                          &TableHandle\r
+                          );\r
+  if (!EFI_ERROR (Status)) {\r
+    AcpiSupport->PublishTables (AcpiSupport, EFI_ACPI_TABLE_VERSION_3_0);\r
+  }\r
+\r
+  NetFreePool (Table);\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiIbft.h b/MdeModulePkg/Universal/iScsi/IScsiIbft.h
new file mode 100644 (file)
index 0000000..b925b14
--- /dev/null
@@ -0,0 +1,40 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiIbft.h\r
+\r
+Abstract:\r
+\r
+  Some extra definitions for iBFT.\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_IBFT_H_\r
+#define _ISCSI_IBFT_H_\r
+\r
+#include <industrystandard/IScsiBootFirmwareTable.h>\r
+#include <protocol/AcpiSupport.h>\r
+#include <protocol/PciIo.h>\r
+\r
+#define IBFT_TABLE_VAR_NAME L"iBFT"\r
+#define IBFT_MAX_SIZE       4096\r
+#define IBFT_HEAP_OFFSET    2048\r
+\r
+#define IBFT_ROUNDUP(size)  NET_ROUNDUP ((size), EFI_ACPI_ISCSI_BOOT_FIRMWARE_TABLE_STRUCTURE_ALIGNMENT)\r
+\r
+VOID\r
+IScsiPublishIbft (\r
+  IN VOID\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiImpl.h b/MdeModulePkg/Universal/iScsi/IScsiImpl.h
new file mode 100644 (file)
index 0000000..715f814
--- /dev/null
@@ -0,0 +1,161 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiImpl.h\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_IMPL_H_\r
+#define _ISCSI_IMPL_H_\r
+\r
+#include <Library/NetLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include "IScsiCommon.h"\r
+#include "IScsiDriver.h"\r
+#include "IScsiConfigNVDataStruc.h"\r
+#include "IScsiExtScsiPassThru.h"\r
+#include "IScsiProto.h"\r
+#include "IScsiCHAP.h"\r
+#include "IScsiDhcp.h"\r
+#include "IScsiTcp4Io.h"\r
+#include "IScsiIbft.h"\r
+#include "IScsiMisc.h"\r
+#include "IScsiConfig.h"\r
+\r
+#define ISCSI_SESSION_SIGNATURE EFI_SIGNATURE_32 ('I', 'S', 'S', 'N')\r
+\r
+typedef struct _ISCSI_SESSION {\r
+  UINT32                    Signature;\r
+\r
+  ISCSI_SESSION_CONFIG_DATA ConfigData;\r
+  ISCSI_CHAP_AUTH_DATA      AuthData;\r
+\r
+  CHAR8                     InitiatorName[ISCSI_NAME_MAX_SIZE];\r
+  UINTN                     InitiatorNameLength;\r
+  UINT8                     State;\r
+\r
+  UINT8                     ISID[6];\r
+  UINT16                    TSIH;\r
+\r
+  UINT32                    CmdSN;\r
+  UINT32                    ExpCmdSN;\r
+  UINT32                    MaxCmdSN;\r
+\r
+  UINT32                    InitiatorTaskTag;\r
+  UINT16                    NextCID;\r
+\r
+  NET_LIST_ENTRY            Conns;\r
+  UINT32                    NumConns;\r
+\r
+  NET_LIST_ENTRY            TcbList;\r
+\r
+  //\r
+  // session-wide parameters\r
+  //\r
+  UINT16                    TargetPortalGroupTag;\r
+  UINT32                    MaxConnections;\r
+  BOOLEAN                   InitialR2T;\r
+  BOOLEAN                   ImmediateData;\r
+  UINT32                    MaxBurstLength;\r
+  UINT32                    FirstBurstLength;\r
+  UINT32                    DefaultTime2Wait;\r
+  UINT32                    DefaultTime2Retain;\r
+  UINT16                    MaxOutstandingR2T;\r
+  BOOLEAN                   DataPDUInOrder;\r
+  BOOLEAN                   DataSequenceInOrder;\r
+  UINT8                     ErrorRecoveryLevel;\r
+} ISCSI_SESSION;\r
+\r
+#define ISCSI_CONNECTION_SIGNATURE  EFI_SIGNATURE_32 ('I', 'S', 'C', 'N')\r
+\r
+typedef struct _ISCSI_CONNECTION {\r
+  UINT32            Signature;\r
+  NET_LIST_ENTRY    Link;\r
+\r
+  EFI_EVENT         TimeoutEvent;\r
+\r
+  ISCSI_SESSION     *Session;\r
+\r
+  UINT8             State;\r
+  UINT8             CurrentStage;\r
+  UINT8             NextStage;\r
+\r
+  UINT8             CHAPStep;\r
+\r
+  BOOLEAN           PartialReqSent;\r
+  BOOLEAN           PartialRspRcvd;\r
+\r
+  BOOLEAN           TransitInitiated;\r
+\r
+  UINT16            CID;\r
+  UINT32            ExpStatSN;\r
+\r
+  //\r
+  // queues...\r
+  //\r
+  NET_BUF_QUEUE     RspQue;\r
+\r
+  TCP4_IO           Tcp4Io;\r
+\r
+  //\r
+  // connection-only parameters\r
+  //\r
+  UINT32            MaxRecvDataSegmentLength;\r
+  ISCSI_DIGEST_TYPE HeaderDigest;\r
+  ISCSI_DIGEST_TYPE DataDigest;\r
+} ISCSI_CONNECTION;\r
+\r
+#define ISCSI_DRIVER_DATA_SIGNATURE EFI_SIGNATURE_32 ('I', 'S', 'D', 'A')\r
+\r
+#define ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU(PassThru) \\r
+  CR ( \\r
+  PassThru, \\r
+  ISCSI_DRIVER_DATA, \\r
+  IScsiExtScsiPassThru, \\r
+  ISCSI_DRIVER_DATA_SIGNATURE \\r
+  )\r
+#define ISCSI_DRIVER_DATA_FROM_IDENTIFIER(Identifier) \\r
+  CR ( \\r
+  Identifier, \\r
+  ISCSI_DRIVER_DATA, \\r
+  IScsiIdentifier, \\r
+  ISCSI_DRIVER_DATA_SIGNATURE \\r
+  )\r
+#define ISCSI_DRIVER_DATA_FROM_SESSION(s) \\r
+  CR ( \\r
+  s, \\r
+  ISCSI_DRIVER_DATA, \\r
+  Session, \\r
+  ISCSI_DRIVER_DATA_SIGNATURE \\r
+  )\r
+\r
+typedef struct _ISCSI_DRIVER_DATA {\r
+  UINT32                          Signature;\r
+  EFI_HANDLE                      Image;\r
+  EFI_HANDLE                      Controller;\r
+  ISCSI_PRIVATE_PROTOCOL          IScsiIdentifier;\r
+\r
+  EFI_EVENT                       ExitBootServiceEvent;\r
+\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL IScsiExtScsiPassThru;\r
+  EFI_EXT_SCSI_PASS_THRU_MODE     ExtScsiPassThruMode;\r
+  EFI_HANDLE                      ExtScsiPassThruHandle;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+\r
+  ISCSI_SESSION                   Session;\r
+} ISCSI_DRIVER_DATA;\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiInitiatorName.c b/MdeModulePkg/Universal/iScsi/IScsiInitiatorName.c
new file mode 100644 (file)
index 0000000..f026174
--- /dev/null
@@ -0,0 +1,145 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiInitiatorName.c\r
+\r
+Abstract:\r
+\r
+  Implementation for EFI iSCSI Initiator Name Protocol.\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+EFI_ISCSI_INITIATOR_NAME_PROTOCOL gIScsiInitiatorName = {\r
+  IScsiGetInitiatorName,\r
+  IScsiSetInitiatorName\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiGetInitiatorName (\r
+  IN     EFI_ISCSI_INITIATOR_NAME_PROTOCOL  *This,\r
+  IN OUT UINTN                              *BufferSize,\r
+  OUT    VOID                               *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieves the current set value of iSCSI Initiator Name. \r
+\r
+Arguments:\r
+\r
+  This       - Pointer to the EFI_ISCSI_INITIATOR_NAME_PROTOCOL instance.\r
+  BufferSize - Size of the buffer in bytes pointed to by Buffer / Actual size of\r
+               the variable data buffer.\r
+  Buffer     - Pointer to the buffer for data to be read.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Data was successfully retrieved into the provided \r
+                          buffer and the BufferSize was sufficient to handle the\r
+                          iSCSI initiator name.\r
+  EFI_BUFFER_TOO_SMALL  - BufferSize is too small for the result. BufferSize will\r
+                          be updated with the size required to complete the request.\r
+                          Buffer will not be affected.\r
+  EFI_INVALID_PARAMETER - BufferSize is NULL. BufferSize and Buffer will not be\r
+                          affected.\r
+  EFI_INVALID_PARAMETER - Buffer is NULL. BufferSize and Buffer will not be\r
+                          affected.\r
+  EFI_DEVICE_ERROR      - The iSCSI initiator name could not be retrieved due to\r
+                          a hardware error.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((BufferSize == NULL) || (Buffer == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = gRT->GetVariable (\r
+                  ISCSI_INITIATOR_NAME_VAR_NAME,\r
+                  &gEfiIScsiInitiatorNameProtocolGuid,\r
+                  NULL,\r
+                  BufferSize,\r
+                  Buffer\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+IScsiSetInitiatorName (\r
+  IN     EFI_ISCSI_INITIATOR_NAME_PROTOCOL  *This,\r
+  IN OUT UINTN                              *BufferSize,\r
+  OUT    VOID                               *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Sets the iSSI Initiator Name. \r
+\r
+Arguments:\r
+\r
+  This       - Pointer to the EFI_ISCSI_INITIATOR_NAME_PROTOCOL instance.\r
+  BufferSize - Size of the buffer in bytes pointed to by Buffer.\r
+  Buffer     - Pointer to the buffer for data to be written.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Data was successfully stored by the protocol.\r
+  EFI_UNSUPPORTED       - Platform policies do not allow for data to be written.\r
+  EFI_INVALID_PARAMETER - BufferSize exceeds the maximum allowed limit.\r
+                          BufferSize will be updated with the maximum size\r
+                          required to complete the request.\r
+  EFI_INVALID_PARAMETER - Buffersize is NULL. BufferSize and Buffer will not be\r
+                          affected.\r
+  EFI_INVALID_PARAMETER - Buffer is NULL. BufferSize and Buffer will not be affected.\r
+  EFI_DEVICE_ERROR      - The data could not be stored due to a hardware error.\r
+  EFI_OUT_OF_RESOURCES  - Not enough storage is available to hold the data\r
+  EFI_PROTOCOL_ERROR    - Input iSCSI initiator name does not adhere to RFC 3720\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((BufferSize == NULL) || (Buffer == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*BufferSize > ISCSI_NAME_MAX_SIZE) {\r
+    *BufferSize = ISCSI_NAME_MAX_SIZE;\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // only support iqn iSCSI names.\r
+  //\r
+  Status = IScsiNormalizeName ((CHAR8 *) Buffer, *BufferSize - 1);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gRT->SetVariable (\r
+                  ISCSI_INITIATOR_NAME_VAR_NAME,\r
+                  &gEfiIScsiInitiatorNameProtocolGuid,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                  *BufferSize,\r
+                  Buffer\r
+                  );\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiMisc.c b/MdeModulePkg/Universal/iScsi/IScsiMisc.c
new file mode 100644 (file)
index 0000000..0347d32
--- /dev/null
@@ -0,0 +1,965 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiMisc.c\r
+\r
+Abstract:\r
+\r
+  Miscellaneous routines for iSCSI driver.\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+STATIC CONST CHAR8  IScsiHexString[] = "0123456789ABCDEFabcdef";\r
+\r
+static\r
+BOOLEAN\r
+IsHexDigit (\r
+  OUT UINT8      *Digit,\r
+  IN  CHAR16      Char\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    Determines if a Unicode character is a hexadecimal digit.\r
+    The test is case insensitive.\r
+\r
+  Arguments:\r
+    Digit - Pointer to byte that receives the value of the hex character.\r
+    Char  - Unicode character to test.\r
+\r
+  Returns:\r
+    TRUE  - If the character is a hexadecimal digit.\r
+    FALSE - Otherwise.\r
+\r
+--*/\r
+{\r
+  if ((Char >= L'0') && (Char <= L'9')) {\r
+    *Digit = (UINT8) (Char - L'0');\r
+    return TRUE;\r
+  }\r
+\r
+  if ((Char >= L'A') && (Char <= L'F')) {\r
+    *Digit = (UINT8) (Char - L'A' + 0x0A);\r
+    return TRUE;\r
+  }\r
+\r
+  if ((Char >= L'a') && (Char <= L'f')) {\r
+    *Digit = (UINT8) (Char - L'a' + 0x0A);\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+static\r
+VOID\r
+StrTrim (\r
+  IN OUT CHAR16   *str,\r
+  IN     CHAR16   CharC\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Removes (trims) specified leading and trailing characters from a string.\r
+  \r
+Arguments: \r
+  \r
+  str     - Pointer to the null-terminated string to be trimmed. On return, \r
+            str will hold the trimmed string. \r
+  CharC       - Character will be trimmed from str.\r
+  \r
+Returns:\r
+\r
+--*/\r
+{\r
+  CHAR16  *p1;\r
+  CHAR16  *p2;\r
+  \r
+  if (*str == 0) {\r
+    return;\r
+  }\r
+  \r
+  //\r
+  // Trim off the leading and trailing characters c\r
+  //\r
+  for (p1 = str; *p1 && *p1 == CharC; p1++) {\r
+    ;\r
+  }\r
+  \r
+  p2 = str;\r
+  if (p2 == p1) {\r
+    while (*p1) {\r
+      p2++;\r
+      p1++;\r
+    }\r
+  } else {\r
+    while (*p1) {    \r
+    *p2 = *p1;    \r
+    p1++;\r
+    p2++;\r
+    }\r
+    *p2 = 0;\r
+  }\r
+  \r
+  \r
+  for (p1 = str + StrLen(str) - 1; p1 >= str && *p1 == CharC; p1--) {\r
+    ;\r
+  }\r
+  if  (p1 !=  str + StrLen(str) - 1) { \r
+    *(p1 + 1) = 0;\r
+  }\r
+}\r
+\r
+UINT8\r
+IScsiGetSubnetMaskPrefixLength (\r
+  IN EFI_IPv4_ADDRESS  *SubnetMask\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Calculate the prefix length of the IPv4 subnet mask.\r
+\r
+Arguments:\r
+\r
+  SubnetMask - The IPv4 subnet mask.\r
+\r
+Returns:\r
+\r
+  The prefix length of the subnet mask.\r
+\r
+--*/\r
+{\r
+  UINT8   Len;\r
+  UINT32  ReverseMask;\r
+\r
+  //\r
+  // The SubnetMask is in network byte order.\r
+  //\r
+  ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);\r
+\r
+  //\r
+  // Reverse it.\r
+  //\r
+  ReverseMask = ~ReverseMask;\r
+\r
+  if (ReverseMask & (ReverseMask + 1)) {\r
+    return 0;\r
+  }\r
+\r
+  Len = 0;\r
+\r
+  while (ReverseMask != 0) {\r
+    ReverseMask = ReverseMask >> 1;\r
+    Len++;\r
+  }\r
+\r
+  return 32 - Len;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiAsciiStrToLun (\r
+  IN  CHAR8  *Str,\r
+  OUT UINT8  *Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the hexadecimal encoded LUN string into the 64-bit LUN. \r
+\r
+Arguments:\r
+\r
+  Str - The hexadecimal encoded LUN string.\r
+  Lun - Storage to return the 64-bit LUN.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The 64-bit LUN is stored in Lun.\r
+  EFI_INVALID_PARAMETER - The string is malformatted.\r
+\r
+--*/\r
+{\r
+  UINT32  Index;\r
+  CHAR8   *LunUnitStr[4];\r
+  CHAR8   Digit;\r
+\r
+  NetZeroMem (Lun, 8);\r
+  NetZeroMem (LunUnitStr, sizeof (LunUnitStr));\r
+\r
+  Index         = 0;\r
+  LunUnitStr[0] = Str;\r
+\r
+  if (!IsHexDigit (&Digit, *Str)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  while (*Str != '\0') {\r
+    //\r
+    // Legal representations of LUN:\r
+    //   4752-3A4F-6b7e-2F99,\r
+    //   6734-9-156f-127,\r
+    //   4186-9\r
+    //\r
+    if (*Str == '-') {\r
+      *Str = '\0';\r
+      Index++;\r
+\r
+      if (*(Str + 1) != '\0') {\r
+        if (!IsHexDigit (&Digit, *(Str + 1))) {\r
+          return EFI_INVALID_PARAMETER;\r
+        }\r
+\r
+        LunUnitStr[Index] = Str + 1;\r
+      }\r
+    } else if (!IsHexDigit (&Digit, *Str)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Str++;\r
+  }\r
+\r
+  for (Index = 0; (Index < 4) && (LunUnitStr[Index] != NULL); Index++) {\r
+    if (AsciiStrLen (LunUnitStr[Index]) > 4) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    *((UINT16 *) &Lun[Index * 2]) = HTONS (AsciiStrHexToUintn (LunUnitStr[Index]));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+IScsiLunToUnicodeStr (\r
+  IN UINT8    *Lun,\r
+  OUT CHAR16  *Str\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the 64-bit LUN into the hexadecimal encoded LUN string.\r
+\r
+Arguments:\r
+\r
+  Lun - The 64-bit LUN.\r
+  Str - The storage to return the hexadecimal encoded LUN string.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  UINTN   Index;\r
+  CHAR16  *TempStr;\r
+\r
+  TempStr = Str;\r
+\r
+  for (Index = 0; Index < 4; Index++) {\r
+\r
+    if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {\r
+      StrCpy (TempStr, L"0-");\r
+    } else {\r
+      TempStr[0]  = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4];\r
+      TempStr[1]  = (CHAR16) IScsiHexString[Lun[2 * Index] & 0xf];\r
+      TempStr[2]  = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4];\r
+      TempStr[3]  = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0xf];\r
+      TempStr[4]  = L'-';\r
+      TempStr[5]  = 0;\r
+\r
+      StrTrim (TempStr, L'0');\r
+    }\r
+\r
+    TempStr += StrLen (TempStr);\r
+  }\r
+\r
+  Str[StrLen (Str) - 1] = 0;\r
+\r
+  for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {\r
+    if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {\r
+      Str[Index - 1] = 0;\r
+    } else {\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+CHAR16 *\r
+IScsiAsciiStrToUnicodeStr (\r
+  IN  CHAR8   *Source,\r
+  OUT CHAR16  *Destination\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the ASCII string into a UNICODE string.\r
+\r
+Arguments:\r
+\r
+  Source      - The ASCII string.\r
+  Destination - The storage to return the UNICODE string.\r
+\r
+Returns:\r
+\r
+  Pointer to the UNICODE string.\r
+\r
+--*/\r
+{\r
+  ASSERT (Destination != NULL);\r
+  ASSERT (Source != NULL);\r
+\r
+  while (*Source != '\0') {\r
+    *(Destination++) = (CHAR16) *(Source++);\r
+  }\r
+\r
+  *Destination = '\0';\r
+\r
+  return Destination;\r
+}\r
+\r
+CHAR8 *\r
+IScsiUnicodeStrToAsciiStr (\r
+  IN  CHAR16  *Source,\r
+  OUT CHAR8   *Destination\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the UNICODE string into an ASCII string.\r
+\r
+Arguments:\r
+\r
+  Source      - The UNICODE string.\r
+  Destination - The storage to return the ASCII string.\r
+\r
+Returns:\r
+\r
+  Pointer to the ASCII string.\r
+\r
+--*/\r
+{\r
+  ASSERT (Destination != NULL);\r
+  ASSERT (Source != NULL);\r
+\r
+  while (*Source != '\0') {\r
+    //\r
+    // If any Unicode characters in Source contain\r
+    // non-zero value in the upper 8 bits, then ASSERT().\r
+    //\r
+    ASSERT (*Source < 0x100);\r
+    *(Destination++) = (CHAR8) *(Source++);\r
+  }\r
+\r
+  *Destination = '\0';\r
+\r
+  return Destination;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiAsciiStrToIp (\r
+  IN  CHAR8             *Str,\r
+  OUT EFI_IPv4_ADDRESS  *Ip\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the decimal dotted IPv4 address into the binary IPv4 address.\r
+\r
+Arguments:\r
+\r
+  Str - The UNICODE string.\r
+  Ip  - The storage to return the ASCII string.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The binary IP address is returned in Ip.\r
+  EFI_INVALID_PARAMETER - The IP string is malformatted.\r
+\r
+--*/\r
+{\r
+  UINTN Index;\r
+  UINTN Number;\r
+\r
+  Index = 0;\r
+\r
+  while (*Str) {\r
+\r
+    if (Index > 3) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Number = 0;\r
+    while (NET_IS_DIGIT (*Str)) {\r
+      Number = Number * 10 + (*Str - '0');\r
+      Str++;\r
+    }\r
+\r
+    if (Number > 0xFF) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Ip->Addr[Index] = (UINT8) Number;\r
+\r
+    if ((*Str != '\0') && (*Str != '.')) {\r
+      //\r
+      // The current character should be either the NULL terminator or\r
+      // the dot delimiter.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (*Str == '.') {\r
+      //\r
+      // Skip the delimiter.\r
+      //\r
+      Str++;\r
+    }\r
+\r
+    Index++;\r
+  }\r
+\r
+  if (Index != 4) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+IScsiMacAddrToStr (\r
+  IN  EFI_MAC_ADDRESS  *Mac,\r
+  IN  UINT32           Len,\r
+  OUT CHAR16           *Str\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the mac address into a hexadecimal encoded "-" seperated string.\r
+\r
+Arguments:\r
+\r
+  Mac - The mac address.\r
+  Len - Length in bytes of the mac address.\r
+  Str - The storage to return the mac string.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  UINT32  Index;\r
+\r
+  for (Index = 0; Index < Len; Index++) {\r
+    Str[3 * Index]      = NibbleToHexChar (Mac->Addr[Index] >> 4);\r
+    Str[3 * Index + 1]  = NibbleToHexChar (Mac->Addr[Index]);\r
+    Str[3 * Index + 2]  = L'-';\r
+  }\r
+\r
+  Str[3 * Index - 1] = L'\0';\r
+}\r
+\r
+EFI_STATUS\r
+IScsiBinToHex (\r
+  IN     UINT8  *BinBuffer,\r
+  IN     UINT32 BinLength,\r
+  IN OUT CHAR8  *HexStr,\r
+  IN OUT UINT32 *HexLength\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the binary encoded buffer into a hexadecimal encoded string.\r
+\r
+Arguments:\r
+\r
+  BinBuffer - The buffer containing the binary data.\r
+  BinLength - Length of the binary buffer.\r
+  HexStr    - Pointer to the string.\r
+  HexLength - The length of the string.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The binary data is converted to the hexadecimal string \r
+                         and the length of the string is updated.\r
+  EFI_BUFFER_TOO_SMALL - The string is too small.\r
+\r
+--*/\r
+{\r
+  UINTN Index;\r
+\r
+  if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (((*HexLength) - 3) < BinLength * 2) {\r
+    *HexLength = BinLength * 2 + 3;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  *HexLength = BinLength * 2 + 3;\r
+  //\r
+  // Prefix for Hex String\r
+  //\r
+  HexStr[0] = '0';\r
+  HexStr[1] = 'x';\r
+\r
+  for (Index = 0; Index < BinLength; Index++) {\r
+    HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];\r
+    HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf];\r
+  }\r
+\r
+  HexStr[Index * 2 + 2] = '\0';\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiHexToBin (\r
+  IN OUT UINT8  *BinBuffer,\r
+  IN OUT UINT32 *BinLength,\r
+  IN     CHAR8  *HexStr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the hexadecimal string into a binary encoded buffer.\r
+\r
+Arguments:\r
+\r
+  BinBuffer - The binary buffer.\r
+  BinLength - Length of the binary buffer.\r
+  HexStr    - The hexadecimal string.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The hexadecimal string is converted into a binary \r
+                         encoded buffer.\r
+  EFI_BUFFER_TOO_SMALL - The binary buffer is too small to hold the converted data.s\r
+\r
+--*/\r
+{\r
+  UINTN   Index;\r
+  UINT32  HexCount;\r
+  CHAR8   *HexBuf;\r
+  UINT8   Digit;\r
+  UINT8   Byte;\r
+\r
+  //\r
+  // Find out how many hex characters the string has.\r
+  //\r
+  HexBuf = HexStr;\r
+  if ((HexBuf[0] == '0') && ((HexBuf[1] == 'x') || (HexBuf[1] == 'X'))) {\r
+    HexBuf += 2;\r
+  }\r
+\r
+  for (Index = 0, HexCount = 0; IsHexDigit (&Digit, HexBuf[Index]); Index++, HexCount++)\r
+    ;\r
+\r
+  if (HexCount == 0) {\r
+    *BinLength = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Test if buffer is passed enough.\r
+  //\r
+  if (((HexCount + 1) / 2) > *BinLength) {\r
+    *BinLength = (HexCount + 1) / 2;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  *BinLength = (HexCount + 1) / 2;\r
+\r
+  for (Index = 0; Index < HexCount; Index++) {\r
+\r
+    IsHexDigit (&Digit, HexBuf[HexCount - 1 - Index]);\r
+\r
+    if ((Index & 1) == 0) {\r
+      Byte = Digit;\r
+    } else {\r
+      Byte = BinBuffer[*BinLength - 1 - Index / 2];\r
+      Byte &= 0x0F;\r
+      Byte |= Digit << 4;\r
+    }\r
+\r
+    BinBuffer[*BinLength - 1 - Index / 2] = Byte;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+IScsiGenRandom (\r
+  IN OUT UINT8  *Rand,\r
+  IN     UINTN  RandLength\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Generate random numbers.\r
+\r
+Arguments:\r
+\r
+  Rand       - The buffer to contain random numbers.\r
+  RandLength - The length of the Rand buffer.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  UINT32  Random;\r
+\r
+  while (RandLength > 0) {\r
+    Random  = NET_RANDOM (NetRandomInitSeed ());\r
+    *Rand++ = (UINT8) (Random);\r
+    RandLength--;\r
+  }\r
+}\r
+\r
+ISCSI_DRIVER_DATA *\r
+IScsiCreateDriverData (\r
+  IN EFI_HANDLE  Image,\r
+  IN EFI_HANDLE  Controller\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create the iSCSI driver data..\r
+\r
+Arguments:\r
+\r
+  Image      - The handle of the driver image.\r
+  Controller - The handle of the controller.\r
+\r
+Returns:\r
+\r
+  The iSCSI driver data created.\r
+\r
+--*/\r
+{\r
+  ISCSI_DRIVER_DATA *Private;\r
+  EFI_STATUS        Status;\r
+\r
+  Private = NetAllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));\r
+  if (Private == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Private->Signature  = ISCSI_DRIVER_DATA_SIGNATURE;\r
+  Private->Image      = Image;\r
+  Private->Controller = Controller;\r
+\r
+  //\r
+  // Create an event to be signal when the BS to RT transition is triggerd so\r
+  // as to abort the iSCSI session.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,\r
+                  TPL_CALLBACK,\r
+                  IScsiOnExitBootService,\r
+                  Private,\r
+                  &Private->ExitBootServiceEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    NetFreePool (Private);\r
+    return NULL;\r
+  }\r
+\r
+  NetCopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));\r
+\r
+  //\r
+  // 0 is designated to the TargetId, so use another value for the AdapterId.\r
+  //\r
+  Private->ExtScsiPassThruMode.AdapterId = 2;\r
+  Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;\r
+  Private->ExtScsiPassThruMode.IoAlign  = 4;\r
+  Private->IScsiExtScsiPassThru.Mode    = &Private->ExtScsiPassThruMode;\r
+\r
+  //\r
+  // Install the Ext SCSI PASS THRU protocol.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Private->ExtScsiPassThruHandle,\r
+                  &gEfiExtScsiPassThruProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &Private->IScsiExtScsiPassThru\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseEvent (Private->ExitBootServiceEvent);\r
+    NetFreePool (Private);\r
+\r
+    return NULL;\r
+  }\r
+\r
+  IScsiSessionInit (&Private->Session, FALSE);\r
+\r
+  return Private;\r
+}\r
+\r
+VOID\r
+IScsiCleanDriverData (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clean the iSCSI driver data.\r
+\r
+Arguments:\r
+\r
+  Private - The iSCSI driver data.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+  if (Private->DevicePath != NULL) {\r
+    gBS->UninstallProtocolInterface (\r
+          Private->ExtScsiPassThruHandle,\r
+          &gEfiDevicePathProtocolGuid,\r
+          Private->DevicePath\r
+          );\r
+\r
+    NetFreePool (Private->DevicePath);\r
+  }\r
+\r
+  if (Private->ExtScsiPassThruHandle != NULL) {\r
+    gBS->UninstallProtocolInterface (\r
+          Private->ExtScsiPassThruHandle,\r
+          &gEfiExtScsiPassThruProtocolGuid,\r
+          &Private->IScsiExtScsiPassThru\r
+          );\r
+  }\r
+\r
+  gBS->CloseEvent (Private->ExitBootServiceEvent);\r
+\r
+  NetFreePool (Private);\r
+}\r
+\r
+EFI_STATUS\r
+IScsiGetConfigData (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the various configuration data of this iSCSI instance.\r
+\r
+Arguments:\r
+\r
+  Private - The iSCSI driver data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS   - The configuration of this instance is got.\r
+  EFI_NOT_FOUND - This iSCSI instance is not configured yet.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  ISCSI_SESSION               *Session;\r
+  UINTN                       BufferSize;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
+  EFI_SIMPLE_NETWORK_MODE     *Mode;\r
+  CHAR16                      MacString[65];\r
+\r
+  //\r
+  // get the iSCSI Initiator Name\r
+  //\r
+  Session                       = &Private->Session;\r
+  Session->InitiatorNameLength  = ISCSI_NAME_MAX_SIZE;\r
+  Status = gIScsiInitiatorName.Get (\r
+                                &gIScsiInitiatorName,\r
+                                &Session->InitiatorNameLength,\r
+                                Session->InitiatorName\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Private->Controller,\r
+                  &gEfiSimpleNetworkProtocolGuid,\r
+                  &Snp\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Mode = Snp->Mode;\r
+\r
+  //\r
+  // Get the mac string, it's the name of various variable\r
+  //\r
+  IScsiMacAddrToStr (&Mode->PermanentAddress, Mode->HwAddressSize, MacString);\r
+\r
+  //\r
+  // Get the normal configuration.\r
+  //\r
+  BufferSize = sizeof (Session->ConfigData.NvData);\r
+  Status = gRT->GetVariable (\r
+                  MacString,\r
+                  &gEfiIScsiInitiatorNameProtocolGuid,\r
+                  NULL,\r
+                  &BufferSize,\r
+                  &Session->ConfigData.NvData\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (!Session->ConfigData.NvData.Enabled) {\r
+    return EFI_ABORTED;\r
+  }\r
+  //\r
+  // Get the CHAP Auth information.\r
+  //\r
+  BufferSize = sizeof (Session->AuthData.AuthConfig);\r
+  Status = gRT->GetVariable (\r
+                  MacString,\r
+                  &mIScsiCHAPAuthInfoGuid,\r
+                  NULL,\r
+                  &BufferSize,\r
+                  &Session->AuthData.AuthConfig\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status) && Session->ConfigData.NvData.InitiatorInfoFromDhcp) {\r
+    //\r
+    // Start dhcp.\r
+    //\r
+    Status = IScsiDoDhcp (Private->Image, Private->Controller, &Session->ConfigData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+IScsiGetTcpConnDevicePath (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the device path of the iSCSI tcp connection and update it.\r
+\r
+Arguments:\r
+\r
+  Private - The iSCSI driver data.\r
+\r
+Returns:\r
+\r
+  The updated device path.\r
+\r
+--*/\r
+{\r
+  ISCSI_SESSION             *Session;\r
+  ISCSI_CONNECTION          *Conn;\r
+  TCP4_IO                   *Tcp4Io;\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
+  EFI_STATUS                Status;\r
+  EFI_DEV_PATH              *DPathNode;\r
+\r
+  Session = &Private->Session;\r
+  if (Session->State != SESSION_STATE_LOGGED_IN) {\r
+    return NULL;\r
+  }\r
+\r
+  Conn = NET_LIST_USER_STRUCT_S (\r
+          Session->Conns.ForwardLink,\r
+          ISCSI_CONNECTION,\r
+          Link,\r
+          ISCSI_CONNECTION_SIGNATURE\r
+          );\r
+  Tcp4Io = &Conn->Tcp4Io;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  Tcp4Io->Handle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &DevicePath\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+  //\r
+  // Duplicate it.\r
+  //\r
+  DevicePath  = DuplicateDevicePath (DevicePath);\r
+\r
+  DPathNode   = (EFI_DEV_PATH *) DevicePath;\r
+\r
+  while (!IsDevicePathEnd (&DPathNode->DevPath)) {\r
+    if ((DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) &&\r
+        (DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP)\r
+        ) {\r
+\r
+      DPathNode->Ipv4.LocalPort       = 0;\r
+      DPathNode->Ipv4.StaticIpAddress = !Session->ConfigData.NvData.InitiatorInfoFromDhcp;\r
+      break;\r
+    }\r
+\r
+    DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);\r
+  }\r
+\r
+  return DevicePath;\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+IScsiOnExitBootService (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Abort the session when the transition from BS to RT is initiated.\r
+\r
+Arguments:\r
+\r
+  Event   - The event signaled.\r
+  Context - The iSCSI driver data.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  ISCSI_DRIVER_DATA *Private;\r
+\r
+  Private = (ISCSI_DRIVER_DATA *) Context;\r
+  gBS->CloseEvent (Private->ExitBootServiceEvent);\r
+\r
+  IScsiSessionAbort (&Private->Session);\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiMisc.h b/MdeModulePkg/Universal/iScsi/IScsiMisc.h
new file mode 100644 (file)
index 0000000..33c5184
--- /dev/null
@@ -0,0 +1,143 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiMisc.h\r
+\r
+Abstract:\r
+\r
+  Miscellaneous definitions for iSCSI driver.\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_MISC_H_\r
+#define _ISCSI_MISC_H_\r
+\r
+#pragma pack(1)\r
+typedef struct _ISCSI_SESSION_CONFIG_NVDATA {\r
+  BOOLEAN           Enabled;\r
+\r
+  BOOLEAN           InitiatorInfoFromDhcp;\r
+  EFI_IPv4_ADDRESS  LocalIp;\r
+  EFI_IPv4_ADDRESS  SubnetMask;\r
+  EFI_IPv4_ADDRESS  Gateway;\r
+\r
+  BOOLEAN           TargetInfoFromDhcp;\r
+  CHAR8             TargetName[ISCSI_NAME_MAX_SIZE];\r
+  EFI_IPv4_ADDRESS  TargetIp;\r
+  UINT16            TargetPort;\r
+  UINT8             BootLun[8];\r
+} ISCSI_SESSION_CONFIG_NVDATA;\r
+#pragma pack()\r
+\r
+typedef struct _ISCSI_SESSION_CONFIG_DATA {\r
+  ISCSI_SESSION_CONFIG_NVDATA NvData;\r
+\r
+  EFI_IPv4_ADDRESS            PrimaryDns;\r
+  EFI_IPv4_ADDRESS            SecondaryDns;\r
+  EFI_IPv4_ADDRESS            DhcpServer;\r
+} ISCSI_SESSION_CONFIG_DATA;\r
+\r
+UINT8\r
+IScsiGetSubnetMaskPrefixLength (\r
+  IN EFI_IPv4_ADDRESS  *SubnetMask\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiAsciiStrToLun (\r
+  IN  CHAR8  *Str,\r
+  OUT UINT8  *Lun\r
+  );\r
+\r
+VOID\r
+IScsiLunToUnicodeStr (\r
+  IN UINT8    *Lun,\r
+  OUT CHAR16  *String\r
+  );\r
+\r
+CHAR16                    *\r
+IScsiAsciiStrToUnicodeStr (\r
+  IN  CHAR8   *Source,\r
+  OUT CHAR16  *Destination\r
+  );\r
+\r
+CHAR8                     *\r
+IScsiUnicodeStrToAsciiStr (\r
+  IN  CHAR16  *Source,\r
+  OUT CHAR8   *Destination\r
+  );\r
+\r
+VOID\r
+IScsiMacAddrToStr (\r
+  IN  EFI_MAC_ADDRESS  *Mac,\r
+  IN  UINT32           Len,\r
+  OUT CHAR16           *Str\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiAsciiStrToIp (\r
+  IN  CHAR8             *Str,\r
+  OUT EFI_IPv4_ADDRESS  *Ip\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiBinToHex (\r
+  IN     UINT8  *BinBuffer,\r
+  IN     UINT32 BinLength,\r
+  IN OUT CHAR8  *HexStr,\r
+  IN OUT UINT32 *HexLength\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiHexToBin (\r
+  IN OUT UINT8  *BinBuffer,\r
+  IN OUT UINT32 *BinLength,\r
+  IN     CHAR8  *HexStr\r
+  );\r
+\r
+VOID\r
+IScsiGenRandom (\r
+  IN OUT UINT8  *Rand,\r
+  IN     UINTN  RandLength\r
+  );\r
+\r
+ISCSI_DRIVER_DATA         *\r
+IScsiCreateDriverData (\r
+  IN EFI_HANDLE  Image,\r
+  IN EFI_HANDLE  Controller\r
+  );\r
+\r
+VOID\r
+IScsiCleanDriverData (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiGetConfigData (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  );\r
+\r
+EFI_DEVICE_PATH_PROTOCOL  *\r
+IScsiGetTcpConnDevicePath (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+IScsiOnExitBootService (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  );\r
+\r
+extern CHAR16 NibbleToHexChar(UINT8 Nibble);\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiProto.c b/MdeModulePkg/Universal/iScsi/IScsiProto.c
new file mode 100644 (file)
index 0000000..4cef3dc
--- /dev/null
@@ -0,0 +1,3080 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiProto.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+static UINT32 mDataSegPad = 0;\r
+\r
+VOID\r
+IScsiAttatchConnection (\r
+  IN ISCSI_SESSION     *Session,\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Attach the iSCSI connection to the iSCSI session. \r
+\r
+Arguments:\r
+\r
+  Session - The iSCSI session.\r
+  Conn    - The iSCSI connection.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  NetListInsertTail (&Session->Conns, &Conn->Link);\r
+  Conn->Session = Session;\r
+  Session->NumConns++;\r
+}\r
+\r
+VOID\r
+IScsiDetatchConnection (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Detach the iSCSI connection from the session it belongs to. \r
+\r
+Arguments:\r
+\r
+  Conn - The iSCSI connection.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  NetListRemoveEntry (&Conn->Link);\r
+  Conn->Session->NumConns--;\r
+  Conn->Session = NULL;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiCheckSN (\r
+  IN UINT32  *ExpSN,\r
+  IN UINT32  NewSN\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check the sequence number according to RFC3720. \r
+\r
+Arguments:\r
+\r
+  ExpSN - The currently expected sequence number.\r
+  NewSN - The sequence number to check.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - The check passed and the ExpSN is increased.\r
+\r
+--*/\r
+{\r
+  if (!ISCSI_SEQ_EQ (NewSN, *ExpSN)) {\r
+    if (ISCSI_SEQ_LT (NewSN, *ExpSN)) {\r
+      //\r
+      // Duplicate\r
+      //\r
+      return EFI_NOT_READY;\r
+    } else {\r
+      return EFI_PROTOCOL_ERROR;\r
+    }\r
+  } else {\r
+    //\r
+    // Advance the ExpSN\r
+    //\r
+    (*ExpSN)++;\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+VOID\r
+IScsiUpdateCmdSN (\r
+  IN ISCSI_SESSION  *Session,\r
+  IN UINT32         MaxCmdSN,\r
+  IN UINT32         ExpCmdSN\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Update the sequence numbers for the iSCSI command.\r
+\r
+Arguments:\r
+\r
+  Session  - The iSCSI session.\r
+  MaxCmdSN - Maximum CmdSN from the target.\r
+  ExpCmdSN - Next expected CmdSN from the target.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  if (ISCSI_SEQ_LT (MaxCmdSN, ExpCmdSN - 1)) {\r
+    return ;\r
+  }\r
+\r
+  if (ISCSI_SEQ_GT (MaxCmdSN, Session->MaxCmdSN)) {\r
+    Session->MaxCmdSN = MaxCmdSN;\r
+  }\r
+\r
+  if (ISCSI_SEQ_GT (ExpCmdSN, Session->ExpCmdSN)) {\r
+    Session->ExpCmdSN = ExpCmdSN;\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+IScsiConnLogin (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function does the iSCSI connection login.\r
+\r
+Arguments:\r
+\r
+  Conn - The iSCSI connection to login.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS        - The iSCSI connection is logged into the iSCSI target.\r
+  EFI_TIMEOUT        - Timeout happened during the login procedure.\r
+  EFI_PROTOCOL_ERROR - Some kind of iSCSI protocol error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Start the timer, wait 16 seconds to establish the TCP connection.\r
+  //\r
+  Status = gBS->SetTimer (Conn->TimeoutEvent, TimerRelative, 16 * TICKS_PER_SECOND);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // try to establish the tcp connection\r
+  //\r
+  Status = Tcp4IoConnect (&Conn->Tcp4Io, Conn->TimeoutEvent);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  gBS->SetTimer (Conn->TimeoutEvent, TimerCancel, 0);\r
+  Conn->State = CONN_STATE_IN_LOGIN;\r
+\r
+  //\r
+  // connection is established, start the iSCSI Login\r
+  //\r
+  do {\r
+    Status = IScsiSendLoginReq (Conn);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    Status = IScsiReceiveLoginRsp (Conn);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  } while (Conn->CurrentStage != ISCSI_FULL_FEATURE_PHASE);\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+IScsiConnReset (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Reset the iSCSI connection.\r
+\r
+Arguments:\r
+\r
+  Conn - The iSCSI connection to reset.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  Tcp4IoReset (&Conn->Tcp4Io);\r
+}\r
+\r
+ISCSI_CONNECTION *\r
+IScsiCreateConnection (\r
+  IN ISCSI_DRIVER_DATA  *Private,\r
+  IN ISCSI_SESSION      *Session\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create a TCP connection for the iSCSI session.\r
+\r
+Arguments:\r
+\r
+  Private - The iSCSI driver data.\r
+  Session - Maximum CmdSN from the target.\r
+\r
+Returns:\r
+\r
+  The newly created iSCSI connection.\r
+\r
+--*/\r
+{\r
+  ISCSI_CONNECTION    *Conn;\r
+  TCP4_IO_CONFIG_DATA Tcp4IoConfig;\r
+  EFI_STATUS          Status;\r
+\r
+  Conn = NetAllocatePool (sizeof (ISCSI_CONNECTION));\r
+  if (Conn == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Conn->Signature       = ISCSI_CONNECTION_SIGNATURE;\r
+  Conn->State           = CONN_STATE_FREE;\r
+  Conn->CurrentStage    = ISCSI_SECURITY_NEGOTIATION;\r
+  Conn->NextStage       = ISCSI_LOGIN_OPERATIONAL_NEGOTIATION;\r
+  Conn->CHAPStep        = ISCSI_CHAP_INITIAL;\r
+  Conn->ExpStatSN       = 0;\r
+  Conn->PartialReqSent  = FALSE;\r
+  Conn->PartialRspRcvd  = FALSE;\r
+  Conn->CID             = Session->NextCID++;\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EFI_EVENT_TIMER,\r
+                  NET_TPL_TIMER,\r
+                  NULL,\r
+                  NULL,\r
+                  &Conn->TimeoutEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    NetFreePool (Conn);\r
+    return NULL;\r
+  }\r
+\r
+  NetbufQueInit (&Conn->RspQue);\r
+\r
+  //\r
+  // set the default connection-only parameters\r
+  //\r
+  Conn->MaxRecvDataSegmentLength  = MAX_RECV_DATA_SEG_LEN_IN_FFP;\r
+  Conn->HeaderDigest              = ISCSI_DIGEST_NONE;\r
+  Conn->DataDigest                = ISCSI_DIGEST_NONE;\r
+\r
+  NetCopyMem (&Tcp4IoConfig.LocalIp, &Session->ConfigData.NvData.LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
+  NetCopyMem (&Tcp4IoConfig.SubnetMask, &Session->ConfigData.NvData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+  NetCopyMem (&Tcp4IoConfig.Gateway, &Session->ConfigData.NvData.Gateway, sizeof (EFI_IPv4_ADDRESS));\r
+  NetCopyMem (&Tcp4IoConfig.RemoteIp, &Session->ConfigData.NvData.TargetIp, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  Tcp4IoConfig.RemotePort = Session->ConfigData.NvData.TargetPort;\r
+\r
+  //\r
+  // Create the tcp4 IO for this connection\r
+  //\r
+  Status = Tcp4IoCreateSocket (\r
+            Private->Image,\r
+            Private->Controller,\r
+            &Tcp4IoConfig,\r
+            &Conn->Tcp4Io\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseEvent (Conn->TimeoutEvent);\r
+    NetFreePool (Conn);\r
+    Conn = NULL;\r
+  }\r
+\r
+  return Conn;\r
+}\r
+\r
+VOID\r
+IScsiDestroyConnection (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destroy an iSCSI connection.\r
+\r
+Arguments:\r
+\r
+  Conn - The connection to destroy.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  Tcp4IoDestroySocket (&Conn->Tcp4Io);\r
+  NetbufQueFlush (&Conn->RspQue);\r
+  gBS->CloseEvent (Conn->TimeoutEvent);\r
+  NetFreePool (Conn);\r
+}\r
+\r
+EFI_STATUS\r
+IScsiSessionLogin (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Login the iSCSI session.\r
+\r
+Arguments:\r
+\r
+  Private - The iSCSI driver data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The iSCSI session login procedure finished.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+  EFI_PROTOCOL_ERROR   - Some kind of iSCSI protocol error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS        Status;\r
+  ISCSI_SESSION     *Session;\r
+  ISCSI_CONNECTION  *Conn;\r
+  EFI_TCP4_PROTOCOL *Tcp4;\r
+\r
+  Session = &Private->Session;\r
+\r
+  //\r
+  // Create a connection for the session.\r
+  //\r
+  Conn = IScsiCreateConnection (Private, Session);\r
+  if (Conn == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  IScsiAttatchConnection (Session, Conn);\r
+\r
+  //\r
+  // Login througth the newly created connection.\r
+  //\r
+  Status = IScsiConnLogin (Conn);\r
+  if (EFI_ERROR (Status)) {\r
+    IScsiConnReset (Conn);\r
+    IScsiDetatchConnection (Conn);\r
+    IScsiDestroyConnection (Conn);\r
+  } else {\r
+    Session->State = SESSION_STATE_LOGGED_IN;\r
+\r
+    gBS->OpenProtocol (\r
+          Conn->Tcp4Io.Handle,\r
+          &gEfiTcp4ProtocolGuid,\r
+          (VOID **)&Tcp4,\r
+          Private->Image,\r
+          Private->ExtScsiPassThruHandle,\r
+          EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+          );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiSendLoginReq (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Build and send the iSCSI login request to the iSCSI target according to\r
+  the current login stage.\r
+\r
+Arguments:\r
+\r
+  Conn - The connection in the iSCSI login phase.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The iSCSI login request PDU is built and sent on this\r
+                         connection.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+  EFI_PROTOCOL_ERROR   - Some kind of iSCSI protocol error happened.\r
+\r
+--*/\r
+{\r
+  NET_BUF     *Pdu;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // build the Login Request PDU\r
+  //\r
+  Pdu = IScsiPrepareLoginReq (Conn);\r
+  if (Pdu == NULL) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Send it to the iSCSI target.\r
+  //\r
+  Status = Tcp4IoTransmit (&Conn->Tcp4Io, Pdu);\r
+\r
+  NetbufFree (Pdu);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiReceiveLoginRsp (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Receive and process the iSCSI login response.\r
+\r
+Arguments:\r
+\r
+  Conn - The connection in the iSCSI login phase.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The iSCSI login response PDU is received and processed.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+  EFI_PROTOCOL_ERROR   - Some kind of iSCSI protocol error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  NET_BUF     *Pdu;\r
+\r
+  //\r
+  // Receive the iSCSI login response.\r
+  //\r
+  Status = IScsiReceivePdu (Conn, &Pdu, NULL, FALSE, FALSE, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // A Login Response is received, process it.\r
+  //\r
+  Status = IScsiProcessLoginRsp (Conn, Pdu);\r
+\r
+  NetbufFree (Pdu);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiAddKeyValuePair (\r
+  IN NET_BUF          *Pdu,\r
+  IN CHAR8            *Key,\r
+  IN CHAR8            *Value\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Add an iSCSI key-value pair as a string into the data segment of the Login Request PDU.\r
+  The DataSegmentLength and the actual size of the net buffer containing this PDU will be\r
+  updated.\r
+\r
+Arguments:\r
+\r
+  Pdu   - The iSCSI PDU whose data segment the key-value pair will be added to.\r
+  Key   - The key name string.\r
+  Value - The value string.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The key-valu pair is added to the PDU's datasegment and\r
+                         the correspondence length fields are updated.\r
+  EFI_OUT_OF_RESOURCES - There is not enough space in the PDU to add the key-value\r
+                         pair.\r
+\r
+--*/\r
+{\r
+  UINT32              DataSegLen;\r
+  UINT32              KeyLen;\r
+  UINT32              ValueLen;\r
+  UINT32              TotalLen;\r
+  ISCSI_LOGIN_REQUEST *LoginReq;\r
+  CHAR8               *Data;\r
+\r
+  LoginReq    = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, NULL);\r
+  DataSegLen  = NTOH24 (LoginReq->DataSegmentLength);\r
+\r
+  KeyLen      = (UINT32) AsciiStrLen (Key);\r
+  ValueLen    = (UINT32) AsciiStrLen (Value);\r
+\r
+  //\r
+  // 1 byte for the key value separator '=' and 1 byte for the null\r
+  // delimiter after the value.\r
+  //\r
+  TotalLen = KeyLen + 1 + ValueLen + 1;\r
+\r
+  //\r
+  // Allocate the space for the key-value pair.\r
+  //\r
+  Data = NetbufAllocSpace (Pdu, TotalLen, NET_BUF_TAIL);\r
+  if (Data == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Add the key.\r
+  //\r
+  NetCopyMem (Data, Key, KeyLen);\r
+  Data += KeyLen;\r
+\r
+  *Data = '=';\r
+  Data++;\r
+\r
+  //\r
+  // Add the value.\r
+  //\r
+  NetCopyMem (Data, Value, ValueLen);\r
+  Data += ValueLen;\r
+\r
+  *Data = '\0';\r
+\r
+  //\r
+  // update the DataSegmentLength\r
+  //\r
+  ISCSI_SET_DATASEG_LEN (LoginReq, DataSegLen + TotalLen);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+NET_BUF *\r
+IScsiPrepareLoginReq (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Prepare the iSCSI login request to be sent according to the current login status.\r
+\r
+Arguments:\r
+\r
+  Conn - The connection in the iSCSI login phase.\r
+\r
+Returns:\r
+\r
+  The pointer to the net buffer containing the iSCSI login request built.\r
+\r
+--*/\r
+{\r
+  ISCSI_SESSION       *Session;\r
+  NET_BUF             *Nbuf;\r
+  ISCSI_LOGIN_REQUEST *LoginReq;\r
+  EFI_STATUS          Status;\r
+\r
+  Session = Conn->Session;\r
+\r
+  Nbuf    = NetbufAlloc (sizeof (ISCSI_LOGIN_REQUEST) + DEFAULT_MAX_RECV_DATA_SEG_LEN);\r
+  if (Nbuf == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufAllocSpace (Nbuf, sizeof (ISCSI_LOGIN_REQUEST), NET_BUF_TAIL);\r
+  NetZeroMem (LoginReq, sizeof (ISCSI_LOGIN_REQUEST));\r
+\r
+  //\r
+  // Init the login request pdu\r
+  //\r
+  ISCSI_SET_OPCODE (LoginReq, ISCSI_OPCODE_LOGIN_REQ, ISCSI_REQ_IMMEDIATE);\r
+  ISCSI_SET_STAGES (LoginReq, Conn->CurrentStage, Conn->NextStage);\r
+  LoginReq->VersionMax        = ISCSI_VERSION_MAX;\r
+  LoginReq->VersionMin        = ISCSI_VERSION_MIN;\r
+  LoginReq->TSIH              = HTONS (Session->TSIH);\r
+  LoginReq->InitiatorTaskTag  = HTONL (Session->InitiatorTaskTag);\r
+  LoginReq->CID               = HTONS (Conn->CID);\r
+  LoginReq->CmdSN             = HTONL (Session->CmdSN);\r
+\r
+  //\r
+  // For the first Login Request on a coonection this is ExpStatSN for the\r
+  // old connection and this field is only valid if the Login Request restarts\r
+  // a connection.\r
+  // For subsequent Login Requests it is used to acknowledge the Login Responses\r
+  // with their increasing StatSN values.\r
+  //\r
+  LoginReq->ExpStatSN = HTONL (Conn->ExpStatSN);\r
+  NetCopyMem (LoginReq->ISID, Session->ISID, sizeof (LoginReq->ISID));\r
+\r
+  if (Conn->PartialRspRcvd) {\r
+    //\r
+    // A partial response, initiator must send an empty Login Request.\r
+    //\r
+    return Nbuf;\r
+  }\r
+\r
+  switch (Conn->CurrentStage) {\r
+  case ISCSI_SECURITY_NEGOTIATION:\r
+    Status = IScsiCHAPToSendReq (Conn, Nbuf);\r
+    break;\r
+\r
+  case ISCSI_LOGIN_OPERATIONAL_NEGOTIATION:\r
+    Status = IScsiFillOpParams (Conn, Nbuf);\r
+    ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+    break;\r
+\r
+  default:\r
+    //\r
+    // something error happens...\r
+    //\r
+    Status = EFI_DEVICE_ERROR;\r
+    break;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    NetbufFree (Nbuf);\r
+    Nbuf = NULL;\r
+  } else {\r
+    //\r
+    // Pad the data segment if needed.\r
+    //\r
+    IScsiPadSegment (Nbuf, ISCSI_GET_DATASEG_LEN (LoginReq));\r
+    //\r
+    // Check whether we will issue the stage transition signal?\r
+    //\r
+    Conn->TransitInitiated = ISCSI_FLAG_ON (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+  }\r
+\r
+  return Nbuf;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiProcessLoginRsp (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN NET_BUF           *Pdu\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Process the iSCSI Login Response.\r
+\r
+Arguments:\r
+\r
+  Conn - The connection on which the iSCSI login response is received.\r
+  Pdu  - The iSCSI login response PDU.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS        - The iSCSI login response PDU is processed and all check are passed.\r
+  EFI_PROTOCOL_ERROR - Some kind of iSCSI protocol error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  ISCSI_SESSION         *Session;\r
+  ISCSI_LOGIN_RESPONSE  *LoginRsp;\r
+  BOOLEAN               Transit;\r
+  BOOLEAN               Continue;\r
+  UINT8                 CurrentStage;\r
+  UINT8                 NextStage;\r
+  UINT8                 *DataSeg;\r
+  UINT32                DataSegLen;\r
+\r
+  Session   = Conn->Session;\r
+\r
+  LoginRsp  = (ISCSI_LOGIN_RESPONSE *) NetbufGetByte (Pdu, 0, NULL);\r
+  if (!ISCSI_CHECK_OPCODE (LoginRsp, ISCSI_OPCODE_LOGIN_RSP)) {\r
+    //\r
+    // It's not a Login Response\r
+    //\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+  //\r
+  // Get the data segment if any.\r
+  //\r
+  DataSegLen = ISCSI_GET_DATASEG_LEN (LoginRsp);\r
+  if (DataSegLen != 0) {\r
+    DataSeg = NetbufGetByte (Pdu, sizeof (ISCSI_LOGIN_RESPONSE), NULL);\r
+  } else {\r
+    DataSeg = NULL;\r
+  }\r
+  //\r
+  // Check the status class in the login response PDU.\r
+  //\r
+  switch (LoginRsp->StatusClass) {\r
+  case ISCSI_LOGIN_STATUS_SUCCESS:\r
+    //\r
+    // Just break here, the response and the data segment will be processed later.\r
+    //\r
+    break;\r
+\r
+  case ISCSI_LOGIN_STATUS_REDIRECTION:\r
+    //\r
+    // The target may be moved to a different address\r
+    //\r
+    if (DataSeg == NULL) {\r
+      return EFI_PROTOCOL_ERROR;\r
+    }\r
+    //\r
+    // Process the TargetAddress key-value strings in the data segment to update the\r
+    // target address info.\r
+    //\r
+    Status = IScsiUpdateTargetAddress (Session, DataSeg, DataSegLen);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Session will be restarted on this error status because the Target is\r
+    // redirected by this Login Response.\r
+    //\r
+    return EFI_MEDIA_CHANGED;\r
+\r
+  default:\r
+    //\r
+    // Initiator Error, Target Error, or any other undefined error code.\r
+    //\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+  //\r
+  // The status is sucess, extract the wanted fields from the header segment.\r
+  //\r
+  Transit                     = ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_TRANSIT);\r
+  Continue                    = ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_CONTINUE);\r
+\r
+  CurrentStage                = ISCSI_GET_CURRENT_STAGE (LoginRsp);\r
+  NextStage                   = ISCSI_GET_NEXT_STAGE (LoginRsp);\r
+\r
+  LoginRsp->InitiatorTaskTag  = NTOHL (LoginRsp->InitiatorTaskTag);\r
+\r
+  if ((Transit && Continue) ||\r
+      (CurrentStage != Conn->CurrentStage) ||\r
+      (!Conn->TransitInitiated && Transit) ||\r
+      (Transit && (NextStage != Conn->NextStage)) ||\r
+      (NetCompareMem (Session->ISID, LoginRsp->ISID, sizeof (LoginRsp->ISID)) != 0) ||\r
+      (LoginRsp->InitiatorTaskTag != Session->InitiatorTaskTag)\r
+      ) {\r
+    //\r
+    // A Login Response with the C bit set to 1 MUST have the T bit set to 0;\r
+    // The CSG in the Login Response MUST be the same with the I-end of this connection;\r
+    // The T bit can't be 1 if the last Login Response sent by the initiator doesn't\r
+    // initiate the transistion;\r
+    // The NSG MUST be the same with the I-end of this connection if Transit is required.\r
+    // The ISID in the Login Response MUST be the same with this session.\r
+    //\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  LoginRsp->StatSN    = NTOHL (LoginRsp->StatSN);\r
+  LoginRsp->ExpCmdSN  = NTOHL (LoginRsp->ExpCmdSN);\r
+  LoginRsp->MaxCmdSN  = NTOHL (LoginRsp->MaxCmdSN);\r
+\r
+  if ((Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION) && (Conn->CHAPStep == ISCSI_CHAP_INITIAL)) {\r
+    //\r
+    // It's the initial Login Response, initialize the local ExpStatSN, MaxCmdSN\r
+    // and ExpCmdSN.\r
+    //\r
+    Conn->ExpStatSN   = LoginRsp->StatSN + 1;\r
+    Session->MaxCmdSN = LoginRsp->MaxCmdSN;\r
+    Session->ExpCmdSN = LoginRsp->ExpCmdSN;\r
+  } else {\r
+    //\r
+    // Check the StatSN of this PDU\r
+    //\r
+    Status = IScsiCheckSN (&Conn->ExpStatSN, LoginRsp->StatSN);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Update the MaxCmdSN and ExpCmdSN\r
+      //\r
+      IScsiUpdateCmdSN (Session, LoginRsp->MaxCmdSN, LoginRsp->ExpCmdSN);\r
+    } else {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // Trim off the header segment.\r
+  //\r
+  NetbufTrim (Pdu, sizeof (ISCSI_LOGIN_RESPONSE), NET_BUF_HEAD);\r
+\r
+  //\r
+  // Queue this login response first in case it's a partial response so that\r
+  // later when the full response list is received we can combine these scattered\r
+  // responses' data segment and then process it.\r
+  //\r
+  NET_GET_REF (Pdu);\r
+  NetbufQueAppend (&Conn->RspQue, Pdu);\r
+\r
+  Conn->PartialRspRcvd = Continue;\r
+  if (Continue) {\r
+    //\r
+    // It's a partial response, have to wait for another or more Request/Response\r
+    // conversations to get the full response.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  switch (CurrentStage) {\r
+  case ISCSI_SECURITY_NEGOTIATION:\r
+    //\r
+    // In security negotiation stage, let CHAP module handle it.\r
+    //\r
+    Status = IScsiCHAPOnRspReceived (Conn, Transit);\r
+    break;\r
+\r
+  case ISCSI_LOGIN_OPERATIONAL_NEGOTIATION:\r
+    //\r
+    // Response received with negotiation resonse on iSCSI parameters, check them.\r
+    //\r
+    Status = IScsiCheckOpParams (Conn, Transit);\r
+    break;\r
+\r
+  default:\r
+    //\r
+    // Should never get here.\r
+    //\r
+    Status = EFI_PROTOCOL_ERROR;\r
+    break;\r
+  }\r
+\r
+  if (Transit && (Status == EFI_SUCCESS)) {\r
+    //\r
+    // Do the state transition.\r
+    //\r
+    Conn->CurrentStage = Conn->NextStage;\r
+\r
+    if (Conn->CurrentStage == ISCSI_LOGIN_OPERATIONAL_NEGOTIATION) {\r
+      Conn->NextStage = ISCSI_FULL_FEATURE_PHASE;\r
+    } else {\r
+      //\r
+      // CurrentStage is iSCSI Full Feature, it's the Login-Final Response,\r
+      // get the TSIH from the Login Response.\r
+      //\r
+      Session->TSIH = NTOHS (LoginRsp->TSIH);\r
+    }\r
+  }\r
+  //\r
+  // Flush the response(s) received.\r
+  //\r
+  NetbufQueFlush (&Conn->RspQue);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiUpdateTargetAddress (\r
+  IN ISCSI_SESSION  *Session,\r
+  IN CHAR8          *Data,\r
+  IN UINT32         Len\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Updated the target information according the data received in the iSCSI\r
+  login response with an target redirection status.\r
+\r
+Arguments:\r
+\r
+  Session - The iSCSI session.\r
+  Data    - The data segment which should contain the TargetAddress key-value list.\r
+  Len     - Length of the data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The target address is updated.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+  EFI_NOT_FOUND        - The TargetAddress key is not found.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY  *KeyValueList;\r
+  CHAR8           *TargetAddress;\r
+  CHAR8           *IpStr;\r
+  EFI_STATUS      Status;\r
+  UINTN           Number;\r
+\r
+  KeyValueList = IScsiBuildKeyValueList (Data, Len);\r
+  if (KeyValueList == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  while (TRUE) {\r
+    TargetAddress = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_ADDRESS);\r
+    if (TargetAddress == NULL) {\r
+      break;\r
+    }\r
+\r
+    if (!NET_IS_DIGIT (TargetAddress[0])) {\r
+      //\r
+      // The domainname of the target may be presented in three formats: a DNS host name,\r
+      // a dotted-decimal IPv4 address, or a bracketed IPv6 address. Only accept dotted\r
+      // IPv4 address.\r
+      //\r
+      continue;\r
+    }\r
+\r
+    IpStr = TargetAddress;\r
+\r
+    while (*TargetAddress && (*TargetAddress != ':') && (*TargetAddress != ',')) {\r
+      //\r
+      // NULL, ':' or ',' ends the IPv4 string.\r
+      //\r
+      TargetAddress++;\r
+    }\r
+\r
+    if (*TargetAddress == ',') {\r
+      //\r
+      // Comma and the portal group tag MUST be ommitted if the TargetAddress is sent\r
+      // as the result of a redirection.\r
+      //\r
+      continue;\r
+    } else if (*TargetAddress == ':') {\r
+      *TargetAddress = '\0';\r
+\r
+      TargetAddress++;\r
+\r
+      Number = AsciiStrDecimalToUintn (TargetAddress);\r
+      if (Number > 0xFFFF) {\r
+        continue;\r
+      } else {\r
+        Session->ConfigData.NvData.TargetPort = (UINT16) Number;\r
+      }\r
+    } else {\r
+      //\r
+      // The string only contains the IPv4 address. Use the well known port.\r
+      //\r
+      Session->ConfigData.NvData.TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+    }\r
+    //\r
+    // Update the target IP address.\r
+    //\r
+    Status = IScsiAsciiStrToIp (IpStr, &Session->ConfigData.NvData.TargetIp);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    } else {\r
+      break;\r
+    }\r
+  }\r
+\r
+  IScsiFreeKeyValueList (KeyValueList);\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+IScsiFreeNbufList (\r
+  VOID *Arg\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The callback function to free the net buffer list.\r
+\r
+Arguments:\r
+\r
+  Arg - The opaque parameter.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  ASSERT (Arg != NULL);\r
+\r
+  NetbufFreeList ((NET_LIST_ENTRY *) Arg);\r
+  NetFreePool (Arg);\r
+}\r
+\r
+VOID\r
+IScsiNbufExtFree (\r
+  VOID *Arg\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The callback function called in NetBufFree, it does nothing.\r
+\r
+Arguments:\r
+\r
+  Arg - The opaque parameter.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+}\r
+\r
+EFI_STATUS\r
+IScsiReceivePdu (\r
+  IN ISCSI_CONNECTION                      *Conn,\r
+  OUT NET_BUF                              **Pdu,\r
+  IN ISCSI_IN_BUFFER_CONTEXT               *Context, OPTIONAL\r
+  IN BOOLEAN                               HeaderDigest,\r
+  IN BOOLEAN                               DataDigest,\r
+  IN EFI_EVENT                             TimeoutEvent OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Receive an iSCSI response PDU. An iSCSI response PDU contains an iSCSI PDU header and\r
+  an optional data segment. The two parts will be put into two blocks of buffers in the\r
+  net buffer. The digest check will be conducted in this function if needed and the digests\r
+  will be trimmed from the PDU buffer.\r
+\r
+Arguments:\r
+\r
+  Conn         - The iSCSI connection to receive data from.\r
+  Pdu          - The received iSCSI pdu.\r
+  Context      - The context used to describe information on the caller provided\r
+                 buffer to receive data segment of the iSCSI pdu, it's optional.\r
+  HeaderDigest - Whether there will be header digest received.\r
+  DataDigest   - Whether there will be data digest.\r
+  TimeoutEvent - The timeout event, it's optional.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - An iSCSI pdu is received.\r
+  EFI_TIMEOUT - Timeout happenend.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY  *NbufList;\r
+  UINT32          Len;\r
+  NET_BUF         *PduHdr;\r
+  UINT8           *Header;\r
+  EFI_STATUS      Status;\r
+  UINT32          PadLen;\r
+  UINT32          InDataOffset;\r
+  NET_FRAGMENT    Fragment[2];\r
+  UINT32          FragmentCount;\r
+  NET_BUF         *DataSeg;\r
+  UINT32          PadAndCRC32[2];\r
+\r
+  NbufList = NetAllocatePool (sizeof (NET_LIST_ENTRY));\r
+  if (NbufList == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NetListInit (NbufList);\r
+\r
+  //\r
+  // The header digest will be received together with the PDU header if exists.\r
+  //\r
+  Len     = sizeof (ISCSI_BASIC_HEADER) + (HeaderDigest ? sizeof (UINT32) : 0);\r
+  PduHdr  = NetbufAlloc (Len);\r
+  if (PduHdr == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);\r
+  NetListInsertTail (NbufList, &PduHdr->List);\r
+\r
+  //\r
+  // First step, receive the BHS of the PDU.\r
+  //\r
+  Status = Tcp4IoReceive (&Conn->Tcp4Io, PduHdr, FALSE, TimeoutEvent);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (HeaderDigest) {\r
+    //\r
+    // TODO: check the header-digest.\r
+    //\r
+    //\r
+    // Trim off the digest.\r
+    //\r
+    NetbufTrim (PduHdr, sizeof (UINT32), NET_BUF_TAIL);\r
+  }\r
+\r
+  Len = ISCSI_GET_DATASEG_LEN (Header);\r
+  if (Len == 0) {\r
+    //\r
+    // No data segment.\r
+    //\r
+    goto FORM_PDU;\r
+  }\r
+  //\r
+  // Get the length of the padding bytes of the data segment.\r
+  //\r
+  PadLen = ISCSI_GET_PAD_LEN (Len);\r
+\r
+  switch (ISCSI_GET_OPCODE (Header)) {\r
+  case ISCSI_OPCODE_SCSI_DATA_IN:\r
+    //\r
+    // Try to use the buffer described by Context if the PDU is an\r
+    // iSCSI SCSI data in pdu so as to reduce memory copy overhead.\r
+    //\r
+    InDataOffset = ISCSI_GET_BUFFER_OFFSET (Header);\r
+    if ((Context == NULL) || ((InDataOffset + Len) > Context->InDataLen)) {\r
+      Status = EFI_PROTOCOL_ERROR;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Fragment[0].Len   = Len;\r
+    Fragment[0].Bulk  = Context->InData + InDataOffset;\r
+\r
+    if (DataDigest || (PadLen != 0)) {\r
+      //\r
+      // The data segment is padded, use two fragments to receive it.\r
+      // The first to receive the useful data. The second to receive the padding.\r
+      //\r
+      Fragment[1].Len   = PadLen + (DataDigest ? sizeof (UINT32) : 0);\r
+      Fragment[1].Bulk  = (UINT8 *) ((UINTN) &PadAndCRC32[1] - PadLen);\r
+\r
+      FragmentCount     = 2;\r
+    } else {\r
+      FragmentCount = 1;\r
+    }\r
+\r
+    DataSeg = NetbufFromExt (&Fragment[0], FragmentCount, 0, 0, IScsiNbufExtFree, NULL);\r
+    if (DataSeg == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    break;\r
+\r
+  case ISCSI_OPCODE_SCSI_RSP:\r
+  case ISCSI_OPCODE_NOP_IN:\r
+  case ISCSI_OPCODE_LOGIN_RSP:\r
+  case ISCSI_OPCODE_TEXT_RSP:\r
+  case ISCSI_OPCODE_ASYNC_MSG:\r
+  case ISCSI_OPCODE_REJECT:\r
+  case ISCSI_OPCODE_VENDOR_T0:\r
+  case ISCSI_OPCODE_VENDOR_T1:\r
+  case ISCSI_OPCODE_VENDOR_T2:\r
+    //\r
+    // Allocate buffer to receive the data segment.\r
+    //\r
+    Len += PadLen + (DataDigest ? sizeof (UINT32) : 0);\r
+    DataSeg = NetbufAlloc (Len);\r
+    if (DataSeg == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);\r
+    break;\r
+\r
+  default:\r
+    Status = EFI_PROTOCOL_ERROR;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  NetListInsertTail (NbufList, &DataSeg->List);\r
+\r
+  //\r
+  // Receive the data segment with the data digest if any.\r
+  //\r
+  Status = Tcp4IoReceive (&Conn->Tcp4Io, DataSeg, FALSE, TimeoutEvent);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (DataDigest) {\r
+    //\r
+    // TODO: Check the data digest.\r
+    //\r
+    NetbufTrim (DataSeg, sizeof (UINT32), NET_BUF_TAIL);\r
+  }\r
+\r
+  if (PadLen != 0) {\r
+    //\r
+    // Trim off the padding bytes in the data segment.\r
+    //\r
+    NetbufTrim (DataSeg, PadLen, NET_BUF_TAIL);\r
+  }\r
+\r
+FORM_PDU:\r
+  //\r
+  // Form the pdu from a list of pdu segments.\r
+  //\r
+  *Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);\r
+  if (*Pdu == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Free the Nbufs in this NbufList and the NbufList itself.\r
+    //\r
+    IScsiFreeNbufList (NbufList);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiCheckOpParams (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN BOOLEAN           Transit\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check and get the result of the prameter negotiation.\r
+\r
+Arguments:\r
+\r
+  Conn - The connection in iSCSI login.\r
+  Pdu  - The iSCSI response PDU containing the parameter list.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS        - The parmeter check is passed and negotiation is finished.\r
+  EFI_PROTOCOL_ERROR - Some kind of iSCSI protocol error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS      Status;\r
+  NET_LIST_ENTRY  *KeyValueList;\r
+  CHAR8           *Data;\r
+  UINT32          Len;\r
+  ISCSI_SESSION   *Session;\r
+  CHAR8           *Value;\r
+  UINTN           NumericValue;\r
+\r
+  ASSERT (Conn->RspQue.BufNum != 0);\r
+\r
+  Session = Conn->Session;\r
+\r
+  Len     = Conn->RspQue.BufSize;\r
+  Data    = NetAllocatePool (Len);\r
+  if (Data == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
+\r
+  Status = EFI_PROTOCOL_ERROR;\r
+\r
+  //\r
+  // Extract the Key-Value pairs into a list.\r
+  //\r
+  KeyValueList = IScsiBuildKeyValueList (Data, Len);\r
+  if (KeyValueList == NULL) {\r
+    NetFreePool (Data);\r
+    return Status;\r
+  }\r
+  //\r
+  // HeaderDigest\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_HEADER_DIGEST);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (AsciiStrCmp (Value, "CRC32") == 0) {\r
+    if (Conn->HeaderDigest != ISCSI_DIGEST_CRC32) {\r
+      goto ON_ERROR;\r
+    }\r
+  } else if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) == 0) {\r
+    Conn->HeaderDigest = ISCSI_DIGEST_NONE;\r
+  } else {\r
+    goto ON_ERROR;\r
+  }\r
+  //\r
+  // DataDigest\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_DIGEST);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (AsciiStrCmp (Value, "CRC32") == 0) {\r
+    if (Conn->DataDigest != ISCSI_DIGEST_CRC32) {\r
+      goto ON_ERROR;\r
+    }\r
+  } else if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) == 0) {\r
+    Conn->DataDigest = ISCSI_DIGEST_NONE;\r
+  } else {\r
+    goto ON_ERROR;\r
+  }\r
+  //\r
+  // ErrorRecoveryLevel, result fuction is Minimum.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_ERROR_RECOVERY_LEVEL);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  NumericValue = AsciiStrDecimalToUintn (Value);\r
+  if (NumericValue > 2) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Session->ErrorRecoveryLevel = (UINT8) MIN (Session->ErrorRecoveryLevel, NumericValue);\r
+\r
+  //\r
+  // InitialR2T, result function is OR.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_INITIAL_R2T);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Session->InitialR2T = Session->InitialR2T || (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);\r
+\r
+  //\r
+  // ImmediateData, result function is AND.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_IMMEDIATE_DATA);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Session->ImmediateData = Session->ImmediateData && (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);\r
+\r
+  //\r
+  // MaxRecvDataSegmentLength, result function is Mininum.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_RECV_DATA_SEGMENT_LENGTH);\r
+  if (Value != NULL) {\r
+    //\r
+    // MaxRecvDataSegmentLength is declarative.\r
+    //\r
+    NumericValue                    = AsciiStrDecimalToUintn (Value);\r
+\r
+    Conn->MaxRecvDataSegmentLength  = (UINT32) MIN (Conn->MaxRecvDataSegmentLength, NumericValue);\r
+  }\r
+  //\r
+  // MaxBurstLength, result funtion is Mininum.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_BURST_LENGTH);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  NumericValue            = AsciiStrDecimalToUintn (Value);\r
+  Session->MaxBurstLength = (UINT32) MIN (Session->MaxBurstLength, NumericValue);\r
+\r
+  //\r
+  // FirstBurstLength, result function is Minimum. Irrelevant when InitialR2T=Yes and\r
+  // ImmediateData=No.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_FIRST_BURST_LENGTH);\r
+  if ((Value == NULL) && !(Session->InitialR2T && !Session->ImmediateData)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  NumericValue              = AsciiStrDecimalToUintn (Value);\r
+  Session->FirstBurstLength = (UINT32) MIN (Session->FirstBurstLength, NumericValue);\r
+\r
+  //\r
+  // MaxConnections, result function is Minimum.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_CONNECTIONS);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  NumericValue = AsciiStrDecimalToUintn (Value);\r
+  if ((NumericValue == 0) || (NumericValue > 65535)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Session->MaxConnections = (UINT32) MIN (Session->MaxConnections, NumericValue);\r
+\r
+  //\r
+  // DataPDUInOrder, result function is OR.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_PDU_IN_ORDER);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Session->DataPDUInOrder = Session->DataPDUInOrder || (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);\r
+\r
+  //\r
+  // DataSequenceInorder, result function is OR.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Session->DataSequenceInOrder = Session->DataSequenceInOrder || (BOOLEAN) (AsciiStrCmp (Value, "Yes") == 0);\r
+\r
+  //\r
+  // DefaultTime2Wait, result function is Maximum.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DEFAULT_TIME2WAIT);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  NumericValue = AsciiStrDecimalToUintn (Value);\r
+  if (NumericValue == 0) {\r
+    Session->DefaultTime2Wait = 0;\r
+  } else if (NumericValue > 3600) {\r
+    goto ON_ERROR;\r
+  } else {\r
+    Session->DefaultTime2Wait = (UINT32) MAX (Session->DefaultTime2Wait, NumericValue);\r
+  }\r
+  //\r
+  // DefaultTime2Retain, result function is Minimum.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DEFAULT_TIME2RETAIN);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  NumericValue = AsciiStrDecimalToUintn (Value);\r
+  if (NumericValue == 0) {\r
+    Session->DefaultTime2Retain = 0;\r
+  } else if (NumericValue > 3600) {\r
+    goto ON_ERROR;\r
+  } else {\r
+    Session->DefaultTime2Retain = (UINT32) MIN (Session->DefaultTime2Retain, NumericValue);\r
+  }\r
+  //\r
+  // MaxOutstandingR2T, result function is Minimum.\r
+  //\r
+  Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_OUTSTANDING_R2T);\r
+  if (Value == NULL) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  NumericValue = AsciiStrDecimalToUintn (Value);\r
+  if ((NumericValue == 0) || (NumericValue > 65535)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Session->MaxOutstandingR2T = (UINT16) MIN (Session->MaxOutstandingR2T, NumericValue);\r
+\r
+  //\r
+  // Remove declarative key-value paris if any.\r
+  //\r
+  IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_SESSION_TYPE);\r
+  IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_ALIAS);\r
+  IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
+\r
+  if (NetListIsEmpty (KeyValueList)) {\r
+    //\r
+    // Succeed if no more keys in the list.\r
+    //\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+ON_ERROR:\r
+\r
+  IScsiFreeKeyValueList (KeyValueList);\r
+\r
+  NetFreePool (Data);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiFillOpParams (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN NET_BUF           *Pdu\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Fill the oprational prameters.\r
+\r
+Arguments:\r
+\r
+  Conn - The connection in iSCSI login.\r
+  Pdu  - The iSCSI login request PDU to fill the parameters.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The parmeters are filled into the iSCSI login request PDU.\r
+  EFI_OUT_OF_RESOURCES - There is not enough space in the PDU to hold the parameters.\r
+\r
+--*/\r
+{\r
+  ISCSI_SESSION *Session;\r
+  CHAR8         Value[256];\r
+\r
+  Session = Conn->Session;\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%a", (Conn->HeaderDigest == ISCSI_DIGEST_CRC32) ? "None,CRC32" : "None");\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_HEADER_DIGEST, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%a", (Conn->DataDigest == ISCSI_DIGEST_CRC32) ? "None,CRC32" : "None");\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_DIGEST, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%d", Session->ErrorRecoveryLevel);\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_ERROR_RECOVERY_LEVEL, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%a", Session->InitialR2T ? "Yes" : "No");\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_INITIAL_R2T, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%a", Session->ImmediateData ? "Yes" : "No");\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_IMMEDIATE_DATA, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%d", Conn->MaxRecvDataSegmentLength);\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_RECV_DATA_SEGMENT_LENGTH, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxBurstLength);\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_BURST_LENGTH, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%d", Session->FirstBurstLength);\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_FIRST_BURST_LENGTH, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxConnections);\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_CONNECTIONS, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%a", Session->DataPDUInOrder ? "Yes" : "No");\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_PDU_IN_ORDER, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%a", Session->DataSequenceInOrder ? "Yes" : "No");\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%d", Session->DefaultTime2Wait);\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DEFAULT_TIME2WAIT, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%d", Session->DefaultTime2Retain);\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DEFAULT_TIME2RETAIN, Value);\r
+\r
+  AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxOutstandingR2T);\r
+  IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_OUTSTANDING_R2T, Value);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiPadSegment (\r
+  IN NET_BUF  *Pdu,\r
+  IN UINT32   Len\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Pad the iSCSI AHS or data segment to an integer number of 4 byte words.\r
+\r
+Arguments:\r
+\r
+  Pdu - The iSCSI pdu which contains segments to pad.\r
+  Len - The length of the last semgnet in the PDU.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The segment is padded or no need to pad it.\r
+  EFI_OUT_OF_RESOURCES - There is not enough remaining free space to add the\r
+                         padding bytes.\r
+\r
+--*/\r
+{\r
+  UINT32  PadLen;\r
+  UINT8   *Data;\r
+\r
+  PadLen = ISCSI_GET_PAD_LEN (Len);\r
+\r
+  if (PadLen != 0) {\r
+    Data = NetbufAllocSpace (Pdu, PadLen, NET_BUF_TAIL);\r
+    if (Data == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    NetZeroMem (Data, PadLen);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+NET_LIST_ENTRY *\r
+IScsiBuildKeyValueList (\r
+  IN CHAR8  *Data,\r
+  IN UINT32 Len\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Build a key-value list from the data segment.\r
+\r
+Arguments:\r
+\r
+  Data - The data segment containing the key-value pairs.\r
+  Len  - Length of the data segment.\r
+\r
+Returns:\r
+\r
+  The key-value list.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY        *ListHead;\r
+  ISCSI_KEY_VALUE_PAIR  *KeyValuePair;\r
+\r
+  ListHead = NetAllocatePool (sizeof (NET_LIST_ENTRY));\r
+  if (ListHead == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  NetListInit (ListHead);\r
+\r
+  while (Len > 0) {\r
+    KeyValuePair = NetAllocatePool (sizeof (ISCSI_KEY_VALUE_PAIR));\r
+    if (KeyValuePair == NULL) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    NetListInit (&KeyValuePair->List);\r
+\r
+    KeyValuePair->Key = Data;\r
+\r
+    while ((Len > 0) && (*Data != '=')) {\r
+      Len--;\r
+      Data++;\r
+    }\r
+\r
+    if (*Data == '=') {\r
+      *Data = '\0';\r
+\r
+      Data++;\r
+      Len--;\r
+    } else {\r
+      NetFreePool (KeyValuePair);\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    KeyValuePair->Value = Data;\r
+\r
+    NetListInsertTail (ListHead, &KeyValuePair->List);;\r
+\r
+    Data += AsciiStrLen (KeyValuePair->Value) + 1;\r
+    Len -= (UINT32) AsciiStrLen (KeyValuePair->Value) + 1;\r
+  }\r
+\r
+  return ListHead;\r
+\r
+ON_ERROR:\r
+\r
+  IScsiFreeKeyValueList (ListHead);\r
+\r
+  return NULL;\r
+}\r
+\r
+CHAR8 *\r
+IScsiGetValueByKeyFromList (\r
+  IN NET_LIST_ENTRY  *KeyValueList,\r
+  IN CHAR8           *Key\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the value string by the key name from the key-value list. If found,\r
+  the key-value entry will be removed from the list.\r
+\r
+Arguments:\r
+\r
+  KeyValueList - The key-value list.\r
+  Key          - The key name to find.\r
+\r
+Returns:\r
+\r
+  The value string.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY        *Entry;\r
+  ISCSI_KEY_VALUE_PAIR  *KeyValuePair;\r
+  CHAR8                 *Value;\r
+\r
+  Value = NULL;\r
+\r
+  NET_LIST_FOR_EACH (Entry, KeyValueList) {\r
+    KeyValuePair = NET_LIST_USER_STRUCT (Entry, ISCSI_KEY_VALUE_PAIR, List);\r
+\r
+    if (AsciiStrCmp (KeyValuePair->Key, Key) == 0) {\r
+      Value = KeyValuePair->Value;\r
+\r
+      NetListRemoveEntry (&KeyValuePair->List);\r
+      NetFreePool (KeyValuePair);\r
+      break;\r
+    }\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+VOID\r
+IScsiFreeKeyValueList (\r
+  IN NET_LIST_ENTRY  *KeyValueList\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Free the key-value list.\r
+\r
+Arguments:\r
+\r
+  KeyValueList - The key-value list.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY        *Entry;\r
+  ISCSI_KEY_VALUE_PAIR  *KeyValuePair;\r
+\r
+  while (!NetListIsEmpty (KeyValueList)) {\r
+    Entry         = NetListRemoveHead (KeyValueList);\r
+    KeyValuePair  = NET_LIST_USER_STRUCT (Entry, ISCSI_KEY_VALUE_PAIR, List);\r
+\r
+    NetFreePool (KeyValuePair);\r
+  }\r
+\r
+  NetFreePool (KeyValueList);\r
+}\r
+\r
+EFI_STATUS\r
+IScsiNormalizeName (\r
+  IN CHAR8  *Name,\r
+  IN UINTN  Len\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Normalize the iSCSI name according to RFC.\r
+\r
+Arguments:\r
+\r
+  Name - The iSCSI name.\r
+  Len  - length of the iSCSI name.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS        - The iSCSI name is valid and normalized.\r
+  EFI_PROTOCOL_ERROR - The iSCSI name is mal-formatted or not in the IQN format.\r
+\r
+--*/\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Index < Len; Index++) {\r
+    if (NET_IS_UPPER_CASE_CHAR (Name[Index])) {\r
+      //\r
+      // Convert the upper-case characters to lower-case ones\r
+      //\r
+      Name[Index] = Name[Index] - 'A' + 'a';\r
+    }\r
+\r
+    if (!NET_IS_LOWER_CASE_CHAR (Name[Index]) &&\r
+        !NET_IS_DIGIT (Name[Index]) &&\r
+        (Name[Index] != '-') &&\r
+        (Name[Index] != '.') &&\r
+        (Name[Index] != ':')\r
+        ) {\r
+      //\r
+      // ASCII dash, dot, colon lower-case characters and digit characters\r
+      // are allowed.\r
+      //\r
+      return EFI_PROTOCOL_ERROR;\r
+    }\r
+  }\r
+\r
+  if ((Len < 4) || (NetCompareMem (Name, "iqn.", 4) != 0)) {\r
+    //\r
+    // Only IQN format is accepted now.\r
+    //\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiNewTcb (\r
+  IN  ISCSI_CONNECTION  *Conn,\r
+  OUT ISCSI_TCB         **Tcb\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create an iSCSI task control block.\r
+\r
+Arguments:\r
+\r
+  Conn - The connection on which the task control block will be created.\r
+  Tcb  - The newly created task control block.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The task control block is created.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+\r
+--*/\r
+{\r
+  ISCSI_SESSION *Session;\r
+  ISCSI_TCB     *NewTcb;\r
+\r
+  ASSERT (Tcb != NULL);\r
+\r
+  Session = Conn->Session;\r
+\r
+  if (ISCSI_SEQ_GT (Session->CmdSN, Session->MaxCmdSN)) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  NewTcb = NetAllocateZeroPool (sizeof (ISCSI_TCB));\r
+  if (NewTcb == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NetListInit (&NewTcb->Link);\r
+\r
+  NewTcb->SoFarInOrder      = TRUE;\r
+  NewTcb->InitiatorTaskTag  = Session->InitiatorTaskTag;\r
+  NewTcb->CmdSN             = Session->CmdSN;\r
+  NewTcb->Conn              = Conn;\r
+\r
+  NetListInsertTail (&Session->TcbList, &NewTcb->Link);\r
+\r
+  //\r
+  // Advance the initiator task tag.\r
+  //\r
+  Session->InitiatorTaskTag++;\r
+  Session->CmdSN++;\r
+\r
+  *Tcb = NewTcb;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+IScsiDelTcb (\r
+  IN ISCSI_TCB  *Tcb\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Delete the tcb from the connection and destroy it.\r
+\r
+Arguments:\r
+\r
+  Tcb - The tcb to delete.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  NetListRemoveEntry (&Tcb->Link);\r
+\r
+  NetFreePool (Tcb);\r
+}\r
+\r
+ISCSI_TCB *\r
+IScsiFindTcbByITT (\r
+  IN NET_LIST_ENTRY  *TcbList,\r
+  IN UINT32          InitiatorTaskTag\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Find the task control block by the initator task tag.\r
+\r
+Arguments:\r
+\r
+  TcbList          - The tcb list.\r
+  InitiatorTaskTag - The initiator task tag.\r
+\r
+Returns:\r
+\r
+  The task control block found.\r
+\r
+--*/\r
+{\r
+  ISCSI_TCB       *Tcb;\r
+  NET_LIST_ENTRY  *Entry;\r
+\r
+  Tcb = NULL;\r
+\r
+  NET_LIST_FOR_EACH (Entry, TcbList) {\r
+    Tcb = NET_LIST_USER_STRUCT (Entry, ISCSI_TCB, Link);\r
+\r
+    if (Tcb->InitiatorTaskTag == InitiatorTaskTag) {\r
+      break;\r
+    }\r
+\r
+    Tcb = NULL;\r
+  }\r
+\r
+  return Tcb;\r
+}\r
+\r
+NET_BUF *\r
+IScsiNewDataSegment (\r
+  IN UINT8    *Data,\r
+  IN UINT32   Len,\r
+  IN BOOLEAN  DataDigest\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create a data segment, pad it and calculate the CRC if needed.\r
+\r
+Arguments:\r
+\r
+  Data       - The data to fill into the data segment.\r
+  Len        - Length of the data.\r
+  DataDigest - Whether to calculate CRC for this data segment.\r
+\r
+Returns:\r
+\r
+  The net buffer wrapping the data segment.\r
+\r
+--*/\r
+{\r
+  NET_FRAGMENT  Fragment[2];\r
+  UINT32        FragmentCount;\r
+  UINT32        PadLen;\r
+  NET_BUF       *DataSeg;\r
+\r
+  Fragment[0].Len   = Len;\r
+  Fragment[0].Bulk  = Data;\r
+\r
+  PadLen            = ISCSI_GET_PAD_LEN (Len);\r
+  if (PadLen != 0) {\r
+    Fragment[1].Len   = PadLen;\r
+    Fragment[1].Bulk  = (UINT8 *) &mDataSegPad;\r
+\r
+    FragmentCount     = 2;\r
+  } else {\r
+    FragmentCount = 1;\r
+  }\r
+\r
+  DataSeg = NetbufFromExt (&Fragment[0], FragmentCount, 0, 0, IScsiNbufExtFree, NULL);\r
+\r
+  return DataSeg;\r
+}\r
+\r
+NET_BUF *\r
+IScsiNewScsiCmdPdu (\r
+  IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
+  IN UINT64                                     Lun,\r
+  IN ISCSI_TCB                                  *Tcb\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create a iSCSI SCSI command PDU to encapsulate the command issued\r
+  by SCSI through the EXT SCSI PASS THRU Protocol.\r
+\r
+Arguments:\r
+\r
+  Packet - The EXT SCSI PASS THRU request packet containing the SCSI command.\r
+  Lun    - The LUN.\r
+  Tcb    - The tcb assocated with this SCSI command.\r
+\r
+Returns:\r
+\r
+  The created iSCSI SCSI command PDU.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY                  *NbufList;\r
+  NET_BUF                         *Pdu;\r
+  NET_BUF                         *PduHeader;\r
+  NET_BUF                         *DataSeg;\r
+  SCSI_COMMAND                    *ScsiCmd;\r
+  UINT8                           AHSLength;\r
+  UINT32                          Length;\r
+  ISCSI_ADDITIONAL_HEADER         *Header;\r
+  ISCSI_BI_EXP_READ_DATA_LEN_AHS  *BiExpReadDataLenAHS;\r
+  ISCSI_SESSION                   *Session;\r
+  UINT32                          ImmediateDataLen;\r
+\r
+  AHSLength = 0;\r
+\r
+  if (Packet->DataDirection == DataBi) {\r
+    //\r
+    // Bi directional Read/Write command, the bidirectional expected\r
+    // read data length AHS is required.\r
+    //\r
+    AHSLength += sizeof (ISCSI_BI_EXP_READ_DATA_LEN_AHS);\r
+  }\r
+\r
+  if (Packet->CdbLength > 16) {\r
+    //\r
+    // The CDB exceeds 16 bytes, an extended CDB AHS is required.\r
+    //\r
+    AHSLength += ISCSI_ROUNDUP (Packet->CdbLength - 16) + sizeof (ISCSI_ADDITIONAL_HEADER);\r
+  }\r
+\r
+  Length    = sizeof (SCSI_COMMAND) + AHSLength;\r
+  PduHeader = NetbufAlloc (Length);\r
+  if (PduHeader == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  ScsiCmd = (SCSI_COMMAND *) NetbufAllocSpace (PduHeader, Length, NET_BUF_TAIL);\r
+  Header  = (ISCSI_ADDITIONAL_HEADER *) (ScsiCmd + 1);\r
+\r
+  NetZeroMem (ScsiCmd, Length);\r
+\r
+  ISCSI_SET_OPCODE (ScsiCmd, ISCSI_OPCODE_SCSI_CMD, 0);\r
+  ISCSI_SET_FLAG (ScsiCmd, ISCSI_TASK_ATTR_SIMPLE);\r
+\r
+  //\r
+  // Set the READ/WRITE flags according to the IO type of this request.\r
+  //\r
+  switch (Packet->DataDirection) {\r
+  case DataIn:\r
+    ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_READ);\r
+    ScsiCmd->ExpDataXferLength = NTOHL (Packet->InTransferLength);\r
+    break;\r
+\r
+  case DataOut:\r
+    ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_WRITE);\r
+    ScsiCmd->ExpDataXferLength = NTOHL (Packet->OutTransferLength);\r
+    break;\r
+\r
+  case DataBi:\r
+    ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_READ | SCSI_CMD_PDU_FLAG_WRITE);\r
+    ScsiCmd->ExpDataXferLength = NTOHL (Packet->OutTransferLength);\r
+\r
+    //\r
+    // Fill the bidirectional expected read data length AHS.\r
+    //\r
+    BiExpReadDataLenAHS                     = (ISCSI_BI_EXP_READ_DATA_LEN_AHS *) Header;\r
+    Header = (ISCSI_ADDITIONAL_HEADER *) (BiExpReadDataLenAHS + 1);\r
+\r
+    BiExpReadDataLenAHS->Length = NTOHS (5);\r
+    BiExpReadDataLenAHS->Type = ISCSI_AHS_TYPE_BI_EXP_READ_DATA_LEN;\r
+    BiExpReadDataLenAHS->ExpReadDataLength = NTOHL (Packet->InTransferLength);\r
+\r
+    break;\r
+  }\r
+\r
+  ScsiCmd->TotalAHSLength = AHSLength;\r
+  NetCopyMem (ScsiCmd->Lun, &Lun, sizeof (ScsiCmd->Lun));\r
+  ScsiCmd->InitiatorTaskTag = NTOHL (Tcb->InitiatorTaskTag);\r
+  ScsiCmd->CmdSN            = NTOHL (Tcb->CmdSN);\r
+  ScsiCmd->ExpStatSN        = NTOHL (Tcb->Conn->ExpStatSN);\r
+\r
+  NetCopyMem (ScsiCmd->CDB, Packet->Cdb, sizeof (ScsiCmd->CDB));\r
+\r
+  if (Packet->CdbLength > 16) {\r
+    Header->Length  = NTOHS (Packet->CdbLength - 15);\r
+    Header->Type    = ISCSI_AHS_TYPE_EXT_CDB;\r
+\r
+    NetCopyMem (Header + 1, (UINT8 *) Packet->Cdb + 16, Packet->CdbLength - 16);\r
+  }\r
+\r
+  Pdu               = PduHeader;\r
+  Session           = Tcb->Conn->Session;\r
+  ImmediateDataLen  = 0;\r
+\r
+  if (Session->ImmediateData && (Packet->OutTransferLength != 0)) {\r
+    //\r
+    // Send immediate data in this SCSI Command PDU. The length of the immeidate\r
+    // data is the minimum of FirstBurstLength, the data length to be xfered and\r
+    // the MaxRecvdataSegmentLength on this connection.\r
+    //\r
+    ImmediateDataLen  = MIN (Session->FirstBurstLength, Packet->OutTransferLength);\r
+    ImmediateDataLen  = MIN (ImmediateDataLen, Tcb->Conn->MaxRecvDataSegmentLength);\r
+\r
+    //\r
+    // Update the data segment length in the PDU header.\r
+    //\r
+    ISCSI_SET_DATASEG_LEN (ScsiCmd, ImmediateDataLen);\r
+\r
+    //\r
+    // Create the data segment.\r
+    //\r
+    DataSeg = IScsiNewDataSegment ((UINT8 *) Packet->OutDataBuffer, ImmediateDataLen, FALSE);\r
+    if (DataSeg == NULL) {\r
+      NetbufFree (PduHeader);\r
+      Pdu = NULL;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    NbufList = NetAllocatePool (sizeof (NET_LIST_ENTRY));\r
+    if (NbufList == NULL) {\r
+      NetbufFree (PduHeader);\r
+      NetbufFree (DataSeg);\r
+\r
+      Pdu = NULL;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    NetListInit (NbufList);\r
+    NetListInsertTail (NbufList, &PduHeader->List);\r
+    NetListInsertTail (NbufList, &DataSeg->List);\r
+\r
+    Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);\r
+    if (Pdu == NULL) {\r
+      IScsiFreeNbufList (NbufList);\r
+    }\r
+  }\r
+\r
+  if (Session->InitialR2T ||\r
+      (ImmediateDataLen == Session->FirstBurstLength) ||\r
+      (ImmediateDataLen == Packet->OutTransferLength)\r
+      ) {\r
+    //\r
+    // Unsolicited data out sequence is not allowed,\r
+    // or FirstBustLength data is already sent out by immediate data\r
+    // or all the OUT data accompany this SCSI packet is sent as\r
+    // immediate data, the final flag should be set on this SCSI Command\r
+    // PDU.\r
+    //\r
+    ISCSI_SET_FLAG (ScsiCmd, ISCSI_BHS_FLAG_FINAL);\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  return Pdu;\r
+}\r
+\r
+NET_BUF *\r
+IScsiNewDataOutPdu (\r
+  IN UINT8      *Data,\r
+  IN UINT32     Len,\r
+  IN UINT32     DataSN,\r
+  IN ISCSI_TCB  *Tcb,\r
+  IN UINT64     Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create a new iSCSI SCSI Data Out PDU.\r
+\r
+Arguments:\r
+\r
+  Data   - The data to put into the Data Out PDU.\r
+  Len    - Length of the data.\r
+  DataSN - The DataSN of the Data Out PDU.\r
+  Tcb    - The task control block of this Data Out PDU.\r
+  Lun    - The LUN.\r
+\r
+Returns:\r
+\r
+  The net buffer wrapping the Data Out PDU.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY      *NbufList;\r
+  NET_BUF             *PduHdr;\r
+  NET_BUF             *DataSeg;\r
+  NET_BUF             *Pdu;\r
+  ISCSI_SCSI_DATA_OUT *DataOutHdr;\r
+  ISCSI_XFER_CONTEXT  *XferContext;\r
+\r
+  NbufList = NetAllocatePool (sizeof (NET_LIST_ENTRY));\r
+  if (NbufList == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  NetListInit (NbufList);\r
+\r
+  //\r
+  // Allocate memory for the BHS.\r
+  //\r
+  PduHdr = NetbufAlloc (sizeof (ISCSI_SCSI_DATA_OUT));\r
+  if (PduHdr == NULL) {\r
+    NetFreePool (NbufList);\r
+    return NULL;\r
+  }\r
+  //\r
+  // Insert the BHS into the buffer list.\r
+  //\r
+  NetListInsertTail (NbufList, &PduHdr->List);\r
+\r
+  DataOutHdr  = (ISCSI_SCSI_DATA_OUT *) NetbufAllocSpace (PduHdr, sizeof (ISCSI_SCSI_DATA_OUT), NET_BUF_TAIL);\r
+  XferContext = &Tcb->XferContext;\r
+\r
+  NetZeroMem (DataOutHdr, sizeof (ISCSI_SCSI_DATA_OUT));\r
+\r
+  //\r
+  // Set the flags and fields of the Data Out PDU BHS.\r
+  //\r
+  ISCSI_SET_OPCODE (DataOutHdr, ISCSI_OPCODE_SCSI_DATA_OUT, 0);\r
+  ISCSI_SET_DATASEG_LEN (DataOutHdr, Len);\r
+\r
+  DataOutHdr->InitiatorTaskTag  = HTONL (Tcb->InitiatorTaskTag);\r
+  DataOutHdr->TargetTransferTag = HTONL (XferContext->TargetTransferTag);\r
+  DataOutHdr->ExpStatSN         = HTONL (Tcb->Conn->ExpStatSN);\r
+  DataOutHdr->DataSN            = HTONL (DataSN);\r
+  DataOutHdr->BufferOffset      = HTONL (XferContext->Offset);\r
+\r
+  if (XferContext->TargetTransferTag != ISCSI_RESERVED_TAG) {\r
+    NetCopyMem (&DataOutHdr->Lun, &Lun, sizeof (DataOutHdr->Lun));\r
+  }\r
+  //\r
+  // Build the data segment for this Data Out PDU.\r
+  //\r
+  DataSeg = IScsiNewDataSegment (Data, Len, FALSE);\r
+  if (DataSeg == NULL) {\r
+    IScsiFreeNbufList (NbufList);\r
+    return NULL;\r
+  }\r
+  //\r
+  // Put the data segment into the buffer list and combine it with the BHS\r
+  // into a full Data Out PDU.\r
+  //\r
+  NetListInsertTail (NbufList, &DataSeg->List);\r
+  Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);\r
+  if (Pdu == NULL) {\r
+    IScsiFreeNbufList (NbufList);\r
+  }\r
+\r
+  return Pdu;\r
+}\r
+\r
+NET_LIST_ENTRY *\r
+IScsiGenerateDataOutPduSequence (\r
+  IN UINT8      *Data,\r
+  IN ISCSI_TCB  *Tcb,\r
+  IN UINT64     Lun\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Generate a consecutive sequence of iSCSI SCSI Data Out PDUs.\r
+\r
+Arguments:\r
+\r
+  Data - The data  which will be carried by the sequence of iSCSI SCSI Data Out PDUs.\r
+  Tcb  - The task control block of the data to send out.\r
+  Lun  - The LUN the data will be sent to.\r
+\r
+Returns:\r
+\r
+  A list of net buffers with each of them wraps an iSCSI SCSI Data Out PDU.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY      *PduList;\r
+  UINT32              DataSN;\r
+  UINT32              DataLen;\r
+  NET_BUF             *DataOutPdu;\r
+  ISCSI_CONNECTION    *Conn;\r
+  ISCSI_XFER_CONTEXT  *XferContext;\r
+\r
+  PduList = NetAllocatePool (sizeof (NET_LIST_ENTRY));\r
+  if (PduList == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  NetListInit (PduList);\r
+\r
+  DataSN      = 0;\r
+  Conn        = Tcb->Conn;\r
+  DataOutPdu  = NULL;\r
+  XferContext = &Tcb->XferContext;\r
+\r
+  while (XferContext->DesiredLength > 0) {\r
+    //\r
+    // Determine the length of data this Data Out PDU can carry.\r
+    //\r
+    DataLen = MIN (XferContext->DesiredLength, Conn->MaxRecvDataSegmentLength);\r
+    Data += DataLen;\r
+\r
+    //\r
+    // Create a Data Out PDU.\r
+    //\r
+    DataOutPdu = IScsiNewDataOutPdu (Data, DataLen, DataSN, Tcb, Lun);\r
+    if (DataOutPdu == NULL) {\r
+      IScsiFreeNbufList (PduList);\r
+      PduList = NULL;\r
+\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    NetListInsertTail (PduList, &DataOutPdu->List);\r
+\r
+    //\r
+    // Update the context and DataSN.\r
+    //\r
+    XferContext->Offset += DataLen;\r
+    XferContext->DesiredLength -= DataLen;\r
+    DataSN++;\r
+  }\r
+  //\r
+  // Set the F bit for the last data out PDU in this sequence.\r
+  //\r
+  ISCSI_SET_FLAG (NetbufGetByte (DataOutPdu, 0, NULL), ISCSI_BHS_FLAG_FINAL);\r
+\r
+ON_EXIT:\r
+\r
+  return PduList;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiSendDataOutPduSequence (\r
+  IN UINT8      *Data,\r
+  IN UINT64     Lun,\r
+  IN ISCSI_TCB  *Tcb\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Send the Data in a sequence of Data Out PDUs one by one.\r
+\r
+Arguments:\r
+\r
+  Data - The data to carry by Data Out PDUs.\r
+  Lun  - The LUN the data will be sent to.\r
+  Tcb  - The task control block.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES           - The data is sent out to the LUN.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+\r
+--*/\r
+{\r
+  NET_LIST_ENTRY  *DataOutPduList;\r
+  NET_LIST_ENTRY  *Entry;\r
+  NET_BUF         *Pdu;\r
+  EFI_STATUS      Status;\r
+\r
+  //\r
+  // Generate the Data Out PDU sequence.\r
+  //\r
+  DataOutPduList = IScsiGenerateDataOutPduSequence (Data, Tcb, Lun);\r
+  if (DataOutPduList == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Send the Data Out PDU's one by one.\r
+  //\r
+  NET_LIST_FOR_EACH (Entry, DataOutPduList) {\r
+    Pdu     = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
+\r
+    Status  = Tcp4IoTransmit (&Tcb->Conn->Tcp4Io, Pdu);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  IScsiFreeNbufList (DataOutPduList);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiOnDataInRcvd (\r
+  IN NET_BUF                                         *Pdu,\r
+  IN ISCSI_TCB                                       *Tcb,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Process the received iSCSI SCSI Data In PDU.\r
+\r
+Arguments:\r
+\r
+  Pdu    - The Data In PDU received.\r
+  Tcb    - The task control block.\r
+  Packet - The EXT SCSI PASS THRU request packet.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES          - The check on the Data IN PDU is passed and some update\r
+                        actions are taken.\r
+  EFI_PROTOCOL_ERROR  - Some kind of iSCSI protocol errror happened.\r
+\r
+--*/\r
+{\r
+  ISCSI_SCSI_DATA_IN  *DataInHdr;\r
+  EFI_STATUS          Status;\r
+\r
+  DataInHdr                   = (ISCSI_SCSI_DATA_IN *) NetbufGetByte (Pdu, 0, NULL);\r
+\r
+  DataInHdr->InitiatorTaskTag = NTOHL (DataInHdr->InitiatorTaskTag);\r
+  DataInHdr->ExpCmdSN         = NTOHL (DataInHdr->ExpCmdSN);\r
+  DataInHdr->MaxCmdSN         = NTOHL (DataInHdr->MaxCmdSN);\r
+  DataInHdr->DataSN           = NTOHL (DataInHdr->DataSN);\r
+\r
+  //\r
+  // Check the DataSN.\r
+  //\r
+  Status = IScsiCheckSN (&Tcb->ExpDataSN, DataInHdr->DataSN);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (DataInHdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+  //\r
+  // Update the command related sequence numbers.\r
+  //\r
+  IScsiUpdateCmdSN (Tcb->Conn->Session, DataInHdr->MaxCmdSN, DataInHdr->ExpCmdSN);\r
+\r
+  if (ISCSI_FLAG_ON (DataInHdr, SCSI_DATA_IN_PDU_FLAG_STATUS_VALID)) {\r
+    if (!ISCSI_FLAG_ON (DataInHdr, ISCSI_BHS_FLAG_FINAL)) {\r
+      //\r
+      // The S bit is on but the F bit is off.\r
+      //\r
+      return EFI_PROTOCOL_ERROR;\r
+    }\r
+\r
+    Tcb->StatusXferd = TRUE;\r
+\r
+    if (ISCSI_FLAG_ON (DataInHdr, SCSI_DATA_IN_PDU_FLAG_OVERFLOW | SCSI_DATA_IN_PDU_FLAG_UNDERFLOW)) {\r
+      //\r
+      // Underflow and Overflow are mutual flags.\r
+      //\r
+      return EFI_PROTOCOL_ERROR;\r
+    }\r
+    //\r
+    // S bit is on, the StatSN is valid.\r
+    //\r
+    Status = IScsiCheckSN (&Tcb->Conn->ExpStatSN, NTOHL (DataInHdr->StatSN));\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Packet->HostAdapterStatus = 0;\r
+    Packet->TargetStatus      = DataInHdr->Status;\r
+\r
+    if (ISCSI_FLAG_ON (DataInHdr, SCSI_RSP_PDU_FLAG_OVERFLOW)) {\r
+      Packet->InTransferLength += NTOHL (DataInHdr->ResidualCount);\r
+      Status = EFI_BAD_BUFFER_SIZE;\r
+    }\r
+\r
+    if (ISCSI_FLAG_ON (DataInHdr, SCSI_RSP_PDU_FLAG_UNDERFLOW)) {\r
+      Packet->InTransferLength -= NTOHL (DataInHdr->ResidualCount);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiOnR2TRcvd (\r
+  IN NET_BUF                                         *Pdu,\r
+  IN ISCSI_TCB                                       *Tcb,\r
+  IN UINT64                                          Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Process the received iSCSI R2T PDU.\r
+\r
+Arguments:\r
+\r
+  Pdu    - The R2T PDU received.\r
+  Tcb    - The task control block.\r
+  Lun    - The Lun.\r
+  Packet - The EXT SCSI PASS THRU request packet.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES          - The R2T PDU is valid and the solicited data is sent out.\r
+  EFI_PROTOCOL_ERROR  - Some kind of iSCSI protocol errror happened.\r
+\r
+--*/\r
+{\r
+  ISCSI_READY_TO_TRANSFER *R2THdr;\r
+  EFI_STATUS              Status;\r
+  ISCSI_XFER_CONTEXT      *XferContext;\r
+  UINT8                   *Data;\r
+\r
+  R2THdr = (ISCSI_READY_TO_TRANSFER *) NetbufGetByte (Pdu, 0, NULL);\r
+\r
+  R2THdr->InitiatorTaskTag = NTOHL (R2THdr->InitiatorTaskTag);\r
+  R2THdr->TargetTransferTag = NTOHL (R2THdr->TargetTransferTag);\r
+  R2THdr->StatSN = NTOHL (R2THdr->StatSN);\r
+  R2THdr->R2TSN = NTOHL (R2THdr->R2TSN);\r
+  R2THdr->BufferOffset = NTOHL (R2THdr->BufferOffset);\r
+  R2THdr->DesiredDataTransferLength = NTOHL (R2THdr->DesiredDataTransferLength);\r
+\r
+  if ((R2THdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) || !ISCSI_SEQ_EQ (R2THdr->StatSN, Tcb->Conn->ExpStatSN)) {\r
+    return EFI_PROTOCOL_ERROR;;\r
+  }\r
+  //\r
+  // Check the sequence number.\r
+  //\r
+  Status = IScsiCheckSN (&Tcb->ExpDataSN, R2THdr->R2TSN);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  XferContext                     = &Tcb->XferContext;\r
+  XferContext->TargetTransferTag  = R2THdr->TargetTransferTag;\r
+  XferContext->Offset             = R2THdr->BufferOffset;\r
+  XferContext->DesiredLength      = R2THdr->DesiredDataTransferLength;\r
+\r
+  if (((XferContext->Offset + XferContext->DesiredLength) > Packet->OutTransferLength) ||\r
+      (XferContext->DesiredLength > Tcb->Conn->Session->MaxBurstLength)\r
+      ) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+  //\r
+  // Send the data solicited by this R2T.\r
+  //\r
+  Data    = (UINT8 *) Packet->OutDataBuffer + XferContext->Offset;\r
+  Status  = IScsiSendDataOutPduSequence (Data, Lun, Tcb);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiOnScsiRspRcvd (\r
+  IN NET_BUF                                         *Pdu,\r
+  IN ISCSI_TCB                                       *Tcb,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Process the received iSCSI SCSI Response PDU.\r
+\r
+Arguments:\r
+\r
+  Pdu    - The Response PDU received.\r
+  Tcb    - The task control block.\r
+  Packet - The EXT SCSI PASS THRU request packet.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES         - The Response PDU is processed.\r
+  EFI_PROTOCOL_ERROR - Some kind of iSCSI protocol errror happened.\r
+\r
+--*/\r
+{\r
+  SCSI_RESPONSE     *ScsiRspHdr;\r
+  ISCSI_SENSE_DATA  *SenseData;\r
+  EFI_STATUS        Status;\r
+  UINT32            DataSegLen;\r
+\r
+  ScsiRspHdr                    = (SCSI_RESPONSE *) NetbufGetByte (Pdu, 0, NULL);\r
+\r
+  ScsiRspHdr->InitiatorTaskTag  = NTOHL (ScsiRspHdr->InitiatorTaskTag);\r
+  if (ScsiRspHdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  ScsiRspHdr->StatSN  = NTOHL (ScsiRspHdr->StatSN);\r
+\r
+  Status              = IScsiCheckSN (&Tcb->Conn->ExpStatSN, ScsiRspHdr->StatSN);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ScsiRspHdr->MaxCmdSN  = NTOHL (ScsiRspHdr->MaxCmdSN);\r
+  ScsiRspHdr->ExpCmdSN  = NTOHL (ScsiRspHdr->ExpCmdSN);\r
+  IScsiUpdateCmdSN (Tcb->Conn->Session, ScsiRspHdr->MaxCmdSN, ScsiRspHdr->ExpCmdSN);\r
+\r
+  Tcb->StatusXferd          = TRUE;\r
+\r
+  Packet->HostAdapterStatus = ScsiRspHdr->Response;\r
+  if (Packet->HostAdapterStatus != ISCSI_SERVICE_RSP_COMMAND_COMPLETE_AT_TARGET) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Packet->TargetStatus = ScsiRspHdr->Status;\r
+\r
+  if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_OVERFLOW | SCSI_RSP_PDU_FLAG_BI_READ_UNDERFLOW) ||\r
+      ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_OVERFLOW | SCSI_RSP_PDU_FLAG_UNDERFLOW)\r
+        ) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_OVERFLOW)) {\r
+    Packet->InTransferLength += NTOHL (ScsiRspHdr->BiReadResidualCount);\r
+    Status = EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_UNDERFLOW)) {\r
+    Packet->InTransferLength -= NTOHL (ScsiRspHdr->BiReadResidualCount);\r
+  }\r
+\r
+  if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_OVERFLOW)) {\r
+    if (Packet->DataDirection == DataIn) {\r
+      Packet->InTransferLength += NTOHL (ScsiRspHdr->ResidualCount);\r
+    } else {\r
+      Packet->OutTransferLength += NTOHL (ScsiRspHdr->ResidualCount);\r
+    }\r
+\r
+    Status = EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_UNDERFLOW)) {\r
+    if (Packet->DataDirection == DataIn) {\r
+      Packet->InTransferLength -= NTOHL (ScsiRspHdr->ResidualCount);\r
+    } else {\r
+      Packet->OutTransferLength -= NTOHL (ScsiRspHdr->ResidualCount);\r
+    }\r
+  }\r
+\r
+  DataSegLen = ISCSI_GET_DATASEG_LEN (ScsiRspHdr);\r
+  if (DataSegLen != 0) {\r
+    SenseData               = (ISCSI_SENSE_DATA *) NetbufGetByte (Pdu, sizeof (SCSI_RESPONSE), NULL);\r
+\r
+    SenseData->Length       = NTOHS (SenseData->Length);\r
+\r
+    Packet->SenseDataLength = (UINT8) MIN (SenseData->Length, Packet->SenseDataLength);\r
+    if (Packet->SenseDataLength != 0) {\r
+      NetCopyMem (Packet->SenseData, &SenseData->Data[0], Packet->SenseDataLength);\r
+    }\r
+  } else {\r
+    Packet->SenseDataLength = 0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiOnNopInRcvd (\r
+  IN NET_BUF    *Pdu,\r
+  IN ISCSI_TCB  *Tcb\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Process the received NOP In PDU.\r
+\r
+Arguments:\r
+\r
+  Pdu    - The NOP In PDU received.\r
+  Tcb    - The task control block.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES          - The NOP In PDU is processed and the related sequence\r
+                        numbers are updated.\r
+  EFI_PROTOCOL_ERROR  - Some kind of iSCSI protocol errror happened.\r
+\r
+--*/\r
+{\r
+  ISCSI_NOP_IN  *NopInHdr;\r
+  EFI_STATUS    Status;\r
+\r
+  NopInHdr            = (ISCSI_NOP_IN *) NetbufGetByte (Pdu, 0, NULL);\r
+\r
+  NopInHdr->StatSN    = NTOHL (NopInHdr->StatSN);\r
+  NopInHdr->ExpCmdSN  = NTOHL (NopInHdr->ExpCmdSN);\r
+  NopInHdr->MaxCmdSN  = NTOHL (NopInHdr->MaxCmdSN);\r
+\r
+  if (NopInHdr->InitiatorTaskTag == ISCSI_RESERVED_TAG) {\r
+    if (NopInHdr->StatSN != Tcb->Conn->ExpStatSN) {\r
+      return EFI_PROTOCOL_ERROR;\r
+    }\r
+  } else {\r
+    Status = IScsiCheckSN (&Tcb->Conn->ExpStatSN, NopInHdr->StatSN);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  IScsiUpdateCmdSN (Tcb->Conn->Session, NopInHdr->MaxCmdSN, NopInHdr->ExpCmdSN);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiExecuteScsiCommand (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                 *PassThru,\r
+  IN UINT8                                           *Target,\r
+  IN UINT64                                          Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Execute the SCSI command issued through the EXT SCSI PASS THRU protocol.\r
+\r
+Arguments:\r
+\r
+  PassThru - The EXT SCSI PASS THRU protocol.\r
+  Target   - The target ID.\r
+  Lun      - The LUN.\r
+  Packet   - The request packet containing IO request, SCSI command buffer and\r
+             buffers to read/write.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES       - The SCSI command is executed and the result is updated to \r
+                     the Packet.\r
+  EFI_DEVICE_ERROR - Some unexpected error happened.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS              Status;\r
+  ISCSI_DRIVER_DATA       *Private;\r
+  ISCSI_SESSION           *Session;\r
+  EFI_EVENT               TimeoutEvent;\r
+  ISCSI_CONNECTION        *Conn;\r
+  ISCSI_TCB               *Tcb;\r
+  NET_BUF                 *Pdu;\r
+  ISCSI_XFER_CONTEXT      *XferContext;\r
+  UINT8                   *Data;\r
+  ISCSI_IN_BUFFER_CONTEXT InBufferContext;\r
+  UINT64                  Timeout;\r
+\r
+  Private       = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);\r
+  Session       = &Private->Session;\r
+  Status        = EFI_SUCCESS;\r
+  Tcb           = NULL;\r
+  TimeoutEvent  = NULL;\r
+\r
+  if (Session->State != SESSION_STATE_LOGGED_IN) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Conn = NET_LIST_USER_STRUCT_S (\r
+          Session->Conns.ForwardLink,\r
+          ISCSI_CONNECTION,\r
+          Link,\r
+          ISCSI_CONNECTION_SIGNATURE\r
+          );\r
+\r
+  if (Packet->Timeout != 0) {\r
+    Timeout = MultU64x32 (Packet->Timeout, 2);\r
+    //\r
+    // Start the timeout timer.\r
+    //\r
+    Status = gBS->SetTimer (Conn->TimeoutEvent, TimerRelative, Timeout);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    TimeoutEvent = Conn->TimeoutEvent;\r
+  }\r
+\r
+  Status = IScsiNewTcb (Conn, &Tcb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+  //\r
+  // Encapsulate the SCSI request packet into an iSCSI SCSI Command PDU.\r
+  //\r
+  Pdu = IScsiNewScsiCmdPdu (Packet, Lun, Tcb);\r
+  if (Pdu == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  XferContext         = &Tcb->XferContext;\r
+  XferContext->Offset = ISCSI_GET_DATASEG_LEN (NetbufGetByte (Pdu, 0, NULL));\r
+\r
+  //\r
+  // Transmit the SCSI Command PDU.\r
+  //\r
+  Status = Tcp4IoTransmit (&Conn->Tcp4Io, Pdu);\r
+\r
+  NetbufFree (Pdu);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  if (!Session->InitialR2T &&\r
+      (XferContext->Offset < Session->FirstBurstLength) &&\r
+      (XferContext->Offset < Packet->OutTransferLength)\r
+      ) {\r
+    //\r
+    // Unsolicited Data-Out sequence is allowed, there is remaining SCSI\r
+    // OUT data and the limit of FirstBurstLength is not reached.\r
+    //\r
+    XferContext->TargetTransferTag = ISCSI_RESERVED_TAG;\r
+    XferContext->DesiredLength = MIN (\r
+                                  Session->FirstBurstLength,\r
+                                  Packet->OutTransferLength - XferContext->Offset\r
+                                  );\r
+\r
+    Data    = (UINT8 *) Packet->OutDataBuffer + XferContext->Offset;\r
+    Status  = IScsiSendDataOutPduSequence (Data, Lun, Tcb);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
+\r
+  InBufferContext.InData    = (UINT8 *) Packet->InDataBuffer;\r
+  InBufferContext.InDataLen = Packet->InTransferLength;\r
+\r
+  while (!Tcb->StatusXferd) {\r
+    //\r
+    // try to receive PDU from target.\r
+    //\r
+    Status = IScsiReceivePdu (Conn, &Pdu, &InBufferContext, FALSE, FALSE, TimeoutEvent);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    switch (ISCSI_GET_OPCODE (NetbufGetByte (Pdu, 0, NULL))) {\r
+    case ISCSI_OPCODE_SCSI_DATA_IN:\r
+      Status = IScsiOnDataInRcvd (Pdu, Tcb, Packet);\r
+      break;\r
+\r
+    case ISCSI_OPCODE_R2T:\r
+      Status = IScsiOnR2TRcvd (Pdu, Tcb, Lun, Packet);\r
+      break;\r
+\r
+    case ISCSI_OPCODE_SCSI_RSP:\r
+      Status = IScsiOnScsiRspRcvd (Pdu, Tcb, Packet);\r
+      break;\r
+\r
+    case ISCSI_OPCODE_NOP_IN:\r
+      Status = IScsiOnNopInRcvd (Pdu, Tcb);\r
+      break;\r
+\r
+    case ISCSI_OPCODE_VENDOR_T0:\r
+    case ISCSI_OPCODE_VENDOR_T1:\r
+    case ISCSI_OPCODE_VENDOR_T2:\r
+      //\r
+      // These messages are vendor specific, skip them.\r
+      //\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_PROTOCOL_ERROR;\r
+      break;\r
+    }\r
+\r
+    NetbufFree (Pdu);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  if (TimeoutEvent != NULL) {\r
+    gBS->SetTimer (TimeoutEvent, TimerCancel, 0);\r
+  }\r
+\r
+  if (Tcb != NULL) {\r
+    IScsiDelTcb (Tcb);\r
+  }\r
+\r
+  if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
+    //\r
+    // Reinstate the session.\r
+    //\r
+    if (EFI_ERROR (IScsiSessionReinstatement (Private))) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiSessionReinstatement (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Reinstate the session on some error.\r
+\r
+Arguments:\r
+\r
+  Private - The iSCSI driver data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES - The session is reinstated from some error.\r
+  other      - Reinstatement failed.\r
+\r
+--*/\r
+{\r
+  ISCSI_SESSION *Session;\r
+  EFI_STATUS    Status;\r
+\r
+  Session = &Private->Session;\r
+  ASSERT (Session->State == SESSION_STATE_LOGGED_IN);\r
+\r
+  //\r
+  // Abort the session and re-init it.\r
+  //\r
+  IScsiSessionAbort (Session);\r
+  IScsiSessionInit (Session, TRUE);\r
+\r
+  //\r
+  // Login again.\r
+  //\r
+  Status = IScsiSessionLogin (Private);\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+IScsiSessionInit (\r
+  IN ISCSI_SESSION  *Session,\r
+  IN BOOLEAN        Recovery\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialize some session parameters before login.\r
+\r
+Arguments:\r
+\r
+  Session  - The iSCSI session.\r
+  Recovery - Whether the request is from a fresh new start or recovery.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  UINT32  Random;\r
+\r
+  if (!Recovery) {\r
+    Session->Signature  = ISCSI_SESSION_SIGNATURE;\r
+    Session->State      = SESSION_STATE_FREE;\r
+\r
+    Random              = NET_RANDOM (NetRandomInitSeed ());\r
+\r
+    Session->ISID[0]    = ISID_BYTE_0;\r
+    Session->ISID[1]    = ISID_BYTE_1;\r
+    Session->ISID[2]    = ISID_BYTE_2;\r
+    Session->ISID[3]    = ISID_BYTE_3;\r
+    Session->ISID[4]    = (UINT8) Random;\r
+    Session->ISID[5]    = (UINT8) (Random >> 8);\r
+\r
+    NetListInit (&Session->Conns);\r
+    NetListInit (&Session->TcbList);\r
+  }\r
+\r
+  Session->TSIH                 = 0;\r
+\r
+  Session->CmdSN                = 1;\r
+  Session->InitiatorTaskTag     = 1;\r
+  Session->NextCID              = 1;\r
+\r
+  Session->TargetPortalGroupTag = 0;\r
+  Session->MaxConnections       = ISCSI_MAX_CONNS_PER_SESSION;\r
+  Session->InitialR2T           = FALSE;\r
+  Session->ImmediateData        = TRUE;\r
+  Session->MaxBurstLength       = 262144;\r
+  Session->FirstBurstLength     = MAX_RECV_DATA_SEG_LEN_IN_FFP;\r
+  Session->DefaultTime2Wait     = 2;\r
+  Session->DefaultTime2Retain   = 20;\r
+  Session->MaxOutstandingR2T    = DEFAULT_MAX_OUTSTANDING_R2T;\r
+  Session->DataPDUInOrder       = TRUE;\r
+  Session->DataSequenceInOrder  = TRUE;\r
+  Session->ErrorRecoveryLevel   = 0;\r
+}\r
+\r
+EFI_STATUS\r
+IScsiSessionAbort (\r
+  IN ISCSI_SESSION  *Session\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Abort the iSCSI session, that is, reset all the connection and free the\r
+  resources.\r
+\r
+Arguments:\r
+\r
+  Session - The iSCSI session.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCES - The session is aborted.\r
+\r
+--*/\r
+{\r
+  ISCSI_DRIVER_DATA *Private;\r
+  ISCSI_CONNECTION  *Conn;\r
+\r
+  if (Session->State != SESSION_STATE_LOGGED_IN) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ASSERT (!NetListIsEmpty (&Session->Conns));\r
+\r
+  Private = ISCSI_DRIVER_DATA_FROM_SESSION (Session);\r
+\r
+  while (!NetListIsEmpty (&Session->Conns)) {\r
+    Conn = NET_LIST_USER_STRUCT_S (\r
+            Session->Conns.ForwardLink,\r
+            ISCSI_CONNECTION,\r
+            Link,\r
+            ISCSI_CONNECTION_SIGNATURE\r
+            );\r
+\r
+    gBS->CloseProtocol (\r
+          Conn->Tcp4Io.Handle,\r
+          &gEfiTcp4ProtocolGuid,\r
+          Private->Image,\r
+          Private->ExtScsiPassThruHandle\r
+          );\r
+\r
+    IScsiConnReset (Conn);\r
+\r
+    IScsiDetatchConnection (Conn);\r
+    IScsiDestroyConnection (Conn);\r
+  }\r
+\r
+  Session->State = SESSION_STATE_FAILED;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiProto.h b/MdeModulePkg/Universal/iScsi/IScsiProto.h
new file mode 100644 (file)
index 0000000..59608fc
--- /dev/null
@@ -0,0 +1,786 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiProto.h\r
+\r
+Abstract:\r
+\r
+  Protocol definitions for iSCSI driver, mainly from RFC3720.\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_PROTO_H_\r
+#define _ISCSI_PROTO_H_\r
+\r
+#include <protocol/ScsiPassThruExt.h>\r
+\r
+//\r
+// RFC 1982 Serial Number Arithmetic, SERIAL_BITS = 32\r
+//\r
+#define ISCSI_SEQ_EQ(s1, s2)  ((s1) == (s2))\r
+#define ISCSI_SEQ_LT(s1, s2) \\r
+    ( \\r
+      (((INT32) (s1) < (INT32) (s2)) && (s2 - s1) < (1 << 31)) || \\r
+      (((INT32) (s1) > (INT32) (s2)) && (s1 - s2) > (1 << 31)) \\r
+    )\r
+#define ISCSI_SEQ_GT(s1, s2) \\r
+    ( \\r
+      (((INT32) (s1) < (INT32) (s2)) && (s2 - s1) > (1 << 31)) || \\r
+      (((INT32) (s1) > (INT32) (s2)) && (s1 - s2) < (1 << 31)) \\r
+    )\r
+\r
+#define ISCSI_WELL_KNOWN_PORT                   3260\r
+#define ISCSI_MAX_CONNS_PER_SESSION             1\r
+\r
+#define DEFAULT_MAX_RECV_DATA_SEG_LEN           8192\r
+#define MAX_RECV_DATA_SEG_LEN_IN_FFP            65536\r
+#define DEFAULT_MAX_OUTSTANDING_R2T             1\r
+\r
+#define ISCSI_VERSION_MAX                       0x00\r
+#define ISCSI_VERSION_MIN                       0x00\r
+\r
+#define ISID_BYTE_0                             0 // OUI format\r
+#define ISID_BYTE_1                             0\r
+#define ISID_BYTE_2                             0xaa\r
+#define ISID_BYTE_3                             0x1\r
+\r
+#define ISCSI_KEY_AUTH_METHOD                   "AuthMethod"\r
+#define ISCSI_KEY_HEADER_DIGEST                 "HeaderDigest"\r
+#define ISCSI_KEY_DATA_DIGEST                   "DataDigest"\r
+#define ISCSI_KEY_MAX_CONNECTIONS               "MaxConnections"\r
+#define ISCSI_KEY_TARGET_NAME                   "TargetName"\r
+#define ISCSI_KEY_INITIATOR_NAME                "InitiatorName"\r
+#define ISCSI_KEY_TARGET_ALIAS                  "TargetAlias"\r
+#define ISCSI_KEY_INITIATOR_ALIAS               "InitiatorAlias"\r
+#define ISCSI_KEY_TARGET_ADDRESS                "TargetAddress"\r
+#define ISCSI_KEY_INITIAL_R2T                   "InitialR2T"\r
+#define ISCSI_KEY_IMMEDIATE_DATA                "ImmediateData"\r
+#define ISCSI_KEY_TARGET_PORTAL_GROUP_TAG       "TargetPortalGroupTag"\r
+#define ISCSI_KEY_MAX_BURST_LENGTH              "MaxBurstLength"\r
+#define ISCSI_KEY_FIRST_BURST_LENGTH            "FirstBurstLength"\r
+#define ISCSI_KEY_DEFAULT_TIME2WAIT             "DefaultTime2Wait"\r
+#define ISCSI_KEY_DEFAULT_TIME2RETAIN           "DefaultTime2Retain"\r
+#define ISCSI_KEY_MAX_OUTSTANDING_R2T           "MaxOutstandingR2T"\r
+#define ISCSI_KEY_DATA_PDU_IN_ORDER             "DataPDUInOrder"\r
+#define ISCSI_KEY_DATA_SEQUENCE_IN_ORDER        "DataSequenceInOrder"\r
+#define ISCSI_KEY_ERROR_RECOVERY_LEVEL          "ErrorRecoveryLevel"\r
+#define ISCSI_KEY_SESSION_TYPE                  "SessionType"\r
+#define ISCSI_KEY_MAX_RECV_DATA_SEGMENT_LENGTH  "MaxRecvDataSegmentLength"\r
+\r
+#define ISCSI_KEY_VALUE_NONE                    "None"\r
+\r
+//\r
+// connection state for initiator\r
+//\r
+typedef enum {\r
+  CONN_STATE_FREE,\r
+  CONN_STATE_XPT_WAIT,\r
+  CONN_STATE_IN_LOGIN,\r
+  CONN_STATE_LOGGED_IN,\r
+  CONN_STATE_IN_LOGOUT,\r
+  CONN_STATE_LOGOUT_REQUESTED,\r
+  CONN_STATE_CLEANUP_WAIT,\r
+  CONN_STATE_IN_CLEANUP\r
+} CONNECTION_STATE;\r
+\r
+//\r
+// session state for initiator\r
+//\r
+typedef enum {\r
+  SESSION_STATE_FREE,\r
+  SESSION_STATE_LOGGED_IN,\r
+  SESSION_STATE_FAILED\r
+} SESSION_STATE;\r
+\r
+typedef enum {\r
+  DataIn  = 0,\r
+  DataOut = 1,\r
+  DataBi  = 2\r
+} DATA_DIRECTION;\r
+\r
+#define ISCSI_RESERVED_TAG                  0xffffffff\r
+\r
+#define ISCSI_REQ_IMMEDIATE                 0x40\r
+#define ISCSI_OPCODE_MASK                   0x3F\r
+\r
+#define ISCSI_SET_OPCODE(PduHdr, Op, Flgs)  ((((ISCSI_BASIC_HEADER *) (PduHdr))->OpCode) = ((Op) | (Flgs)))\r
+#define ISCSI_GET_OPCODE(PduHdr)            ((((ISCSI_BASIC_HEADER *) (PduHdr))->OpCode) & ISCSI_OPCODE_MASK)\r
+#define ISCSI_CHECK_OPCODE(PduHdr, Op)      ((((PduHdr)->OpCode) & ISCSI_OPCODE_MASK) == (Op))\r
+#define ISCSI_IMMEDIATE_ON(PduHdr)          ((PduHdr)->OpCode & ISCSI_REQ_IMMEDIATE)\r
+#define ISCSI_SET_FLAG(PduHdr, Flag)        (((ISCSI_BASIC_HEADER *) (PduHdr))->Flags |= (Flag))\r
+#define ISCSI_CLEAR_FLAG(PduHdr, Flag)      (((ISCSI_BASIC_HEADER *) (PduHdr))->Flags &= ~(Flag))\r
+#define ISCSI_FLAG_ON(PduHdr, Flag)         ((((ISCSI_BASIC_HEADER *) (PduHdr))->Flags & (Flag)) == (Flag))\r
+#define ISCSI_SET_STAGES(PduHdr, Cur, Nxt)  ((PduHdr)->Flags |= ((Cur) << 2 | (Nxt)))\r
+#define ISCSI_GET_CURRENT_STAGE(PduHdr)     (((PduHdr)->Flags >> 2) & 0x3)\r
+#define ISCSI_GET_NEXT_STAGE(PduHdr)        (((PduHdr)->Flags) & 0x3)\r
+\r
+#define ISCSI_GET_PAD_LEN(DataLen)          ((~(DataLen) + 1) & 0x3)\r
+#define ISCSI_ROUNDUP(DataLen)              (((DataLen) + 3) &~(0x3))\r
+\r
+#define HTON24(Dst, Src) \\r
+  do { \\r
+    (Dst)[0]  = (UINT8) ((Src) >> 16) & 0xFF; \\r
+    (Dst)[1]  = (UINT8) ((Src) >> 8) & 0xFF; \\r
+    (Dst)[2]  = (UINT8) (Src) & 0xFF; \\r
+  } while (0);\r
+\r
+#define NTOH24(src)                         (((src)[0] << 16) | ((src)[1] << 8) | ((src)[2]))\r
+\r
+#define ISCSI_GET_DATASEG_LEN(PduHdr)       NTOH24 (((ISCSI_BASIC_HEADER *) (PduHdr))->DataSegmentLength)\r
+#define ISCSI_SET_DATASEG_LEN(PduHdr, Len)  HTON24 (((ISCSI_BASIC_HEADER *) (PduHdr))->DataSegmentLength, (Len))\r
+\r
+//\r
+// initiator opcodes\r
+//\r
+#define ISCSI_OPCODE_NOP_OUT        0x00\r
+#define ISCSI_OPCODE_SCSI_CMD       0x01\r
+#define ISCSI_OPCODE_SCSI_TMF_REQ   0x02\r
+#define ISCSI_OPCODE_LOGIN_REQ      0x03\r
+#define ISCSI_OPCODE_TEXT_REQ       0x04\r
+#define ISCSI_OPCODE_SCSI_DATA_OUT  0x05\r
+#define ISCSI_OPCODE_LOGOUT_REQ     0x06\r
+#define ISCSI_OPCODE_SNACK_REQ      0x10\r
+#define ISCSI_OPCODE_VENDOR_I0      0x1c\r
+#define ISCSI_OPCODE_VENDOR_I1      0x1d\r
+#define ISCSI_OPCODE_VENDOR_I2      0x1e\r
+\r
+//\r
+// target opcodes\r
+//\r
+#define ISCSI_OPCODE_NOP_IN       0x20\r
+#define ISCSI_OPCODE_SCSI_RSP     0x21\r
+#define ISCSI_OPCODE_SCSI_TMF_RSP 0x22\r
+#define ISCSI_OPCODE_LOGIN_RSP    0x23\r
+#define ISCSI_OPCODE_TEXT_RSP     0x24\r
+#define ISCSI_OPCODE_SCSI_DATA_IN 0x25\r
+#define ISCSI_OPCODE_LOGOUT_RSP   0x26\r
+#define ISCSI_OPCODE_R2T          0x31\r
+#define ISCSI_OPCODE_ASYNC_MSG    0x32\r
+#define ISCSI_OPCODE_VENDOR_T0    0x3c\r
+#define ISCSI_OPCODE_VENDOR_T1    0x3d\r
+#define ISCSI_OPCODE_VENDOR_T2    0x3e\r
+#define ISCSI_OPCODE_REJECT       0x3f\r
+\r
+#define ISCSI_BHS_FLAG_FINAL      0x80\r
+\r
+//\r
+// iSCSI Basic Header Segment\r
+//\r
+typedef struct _ISCSI_BASIC_HEADER {\r
+  UINT8   OpCode;\r
+  UINT8   Flags;\r
+  UINT16  OpCodeSpecific1;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  OpCodeSpecific2[7];\r
+} ISCSI_BASIC_HEADER;\r
+\r
+//\r
+// Defined AHS types, others are reserved.\r
+//\r
+#define ISCSI_AHS_TYPE_EXT_CDB              0x1\r
+#define ISCSI_AHS_TYPE_BI_EXP_READ_DATA_LEN 0x2\r
+\r
+typedef struct _ISCSI_ADDTIONAL_HEADER {\r
+  UINT16  Length;\r
+  UINT8   Type;\r
+  UINT8   TypeSpecific[1];\r
+} ISCSI_ADDITIONAL_HEADER;\r
+\r
+typedef struct _ISCSI_BI_EXP_READ_DATA_LEN_AHS {\r
+  UINT16  Length;\r
+  UINT8   Type;\r
+  UINT8   Reserved;\r
+  UINT32  ExpReadDataLength;\r
+} ISCSI_BI_EXP_READ_DATA_LEN_AHS;\r
+\r
+#define SCSI_CMD_PDU_FLAG_READ        0x40\r
+#define SCSI_CMD_PDU_FLAG_WRITE       0x20\r
+\r
+#define ISCSI_CMD_PDU_TASK_ATTR_MASK  0x07\r
+\r
+//\r
+// task attributes\r
+//\r
+#define ISCSI_TASK_ATTR_UNTAGGED  0x00\r
+#define ISCSI_TASK_ATTR_SIMPLE    0x01\r
+#define ISCSI_TASK_ATTR_ORDERD    0x02\r
+#define ISCSI_TASK_ATTR_HOQ       0x03\r
+#define ISCSI_TASK_ATTR_ACA       0x04\r
+\r
+//\r
+// SCSI Command\r
+//\r
+typedef struct _SCSI_COMMAND {\r
+  UINT8   OpCode;\r
+  UINT8   Flags;\r
+  UINT16  Reserved;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  ExpDataXferLength;\r
+  UINT32  CmdSN;\r
+  UINT32  ExpStatSN;\r
+  UINT8   CDB[16];\r
+} SCSI_COMMAND;\r
+\r
+//\r
+// flag bit definitions in SCSI response\r
+//\r
+#define SCSI_RSP_PDU_FLAG_BI_READ_OVERFLOW  0x10\r
+#define SCSI_RSP_PDU_FLAG_BI_READ_UNDERFLOW 0x08\r
+#define SCSI_RSP_PDU_FLAG_OVERFLOW          0x04\r
+#define SCSI_RSP_PDU_FLAG_UNDERFLOW         0x02\r
+\r
+//\r
+// iSCSI service response codes\r
+//\r
+#define ISCSI_SERVICE_RSP_COMMAND_COMPLETE_AT_TARGET  0x00\r
+#define ISCSI_SERVICE_RSP_TARGET_FAILURE              0x01\r
+\r
+//\r
+// SCSI Response\r
+//\r
+typedef struct _SCSI_RESPONSE {\r
+  UINT8   OpCode;\r
+  UINT8   Flags;\r
+  UINT8   Response;\r
+  UINT8   Status;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Reserved[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  SNACKTag;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT32  ExpDataSN;\r
+  UINT32  BiReadResidualCount;\r
+  UINT32  ResidualCount;\r
+} SCSI_RESPONSE;\r
+\r
+typedef struct _ISCSI_SENSE_DATA {\r
+  UINT16  Length;\r
+  UINT8   Data[2];\r
+} ISCSI_SENSE_DATA;\r
+\r
+//\r
+// iSCSI Task Managment Function Request\r
+//\r
+typedef struct _ISCSI_TMF_REQUEST {\r
+  UINT8   OpCode;\r
+  UINT8   Fuction;\r
+  UINT16  Reserved1;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  ReferencedTaskTag;\r
+  UINT32  CmdSN;\r
+  UINT32  ExpStatSN;\r
+  UINT32  RefCmdSN;\r
+  UINT32  ExpDataSN;\r
+  UINT32  Reserved2[2];\r
+} ISCSI_TMF_REQUEST;\r
+\r
+#define ISCSI_TMF_RSP_PDU_RSP_FUNCTION_COMPLETE           0\r
+#define ISCSI_TMF_RSP_PDU_RSP_TASK_NOT_EXIST              1\r
+#define ISCSI_TMF_RSP_PDU_RSP_LUN_NOT_EXIST               2\r
+#define ISCSI_TMF_RSP_PDU_RSP_TASK_STILL_ALLEGIANT        3\r
+#define ISCSI_TMF_RSP_PDU_RSP_TASK_REASSGIN_NOT_SUPPORTED 4\r
+#define ISCSI_TMF_RSP_PDU_RSP_NOT_SUPPORTED               5\r
+#define ISCSI_TMF_RSP_PDU_RSP_FUNCTION_AHTH_FAILED        6\r
+#define ISCSI_TMF_RSP_PDU_RSP_FUNCTION_REJECTED           255\r
+\r
+//\r
+// iSCSI Task Management Function Response\r
+//\r
+typedef struct _ISCSI_TMF_RESPONSE {\r
+  UINT8   OpCode;\r
+  UINT8   Reserved1;\r
+  UINT8   Response;\r
+  UINT8   Reserved2;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT32  Reserver3[2];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  Reserved4;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT32  Reserved[3];\r
+} ISCSI_TMF_RESPONSE;\r
+\r
+//\r
+// SCSI Data-Out\r
+//\r
+typedef struct _ISCSI_SCSI_DATA_OUT {\r
+  UINT8   OpCode;\r
+  UINT8   Reserved1[3];\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  TargetTransferTag;\r
+  UINT32  Reserved2;\r
+  UINT32  ExpStatSN;\r
+  UINT32  Reserved3;\r
+  UINT32  DataSN;\r
+  UINT32  BufferOffset;\r
+  UINT32  Reserved4;\r
+} ISCSI_SCSI_DATA_OUT;\r
+\r
+#define SCSI_DATA_IN_PDU_FLAG_ACKKNOWLEDGE  0x40\r
+#define SCSI_DATA_IN_PDU_FLAG_OVERFLOW      SCSI_RSP_PDU_FLAG_OVERFLOW\r
+#define SCSI_DATA_IN_PDU_FLAG_UNDERFLOW     SCSI_RSP_PDU_FLAG_UNDERFLOW\r
+#define SCSI_DATA_IN_PDU_FLAG_STATUS_VALID  0x01\r
+//\r
+// SCSI Data-In\r
+//\r
+typedef struct _ISCSI_SCSI_DATA_IN {\r
+  UINT8   OpCode;\r
+  UINT8   Flags;\r
+  UINT8   Reserved1;\r
+  UINT8   Status;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  TargetTransferTag;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT32  DataSN;\r
+  UINT32  BufferOffset;\r
+  UINT32  ResidualCount;\r
+} ISCSI_SCSI_DATA_IN;\r
+\r
+#define ISCSI_GET_BUFFER_OFFSET(PduHdr) NTOHL (((ISCSI_SCSI_DATA_IN *) (PduHdr))->BufferOffset)\r
+//\r
+// Ready To Transfer\r
+//\r
+typedef struct _ISCSI_READY_TO_TRANSFER {\r
+  UINT8   OpCode;\r
+  UINT8   Reserved1[3];\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  TargetTransferTag;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT32  R2TSN;\r
+  UINT32  BufferOffset;\r
+  UINT32  DesiredDataTransferLength;\r
+} ISCSI_READY_TO_TRANSFER;\r
+\r
+typedef struct _ISCSI_ASYNC_MESSAGE {\r
+  UINT8   OpCode;\r
+  UINT8   Reserved1[8];\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  Reserved2;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT8   AsyncEvent;\r
+  UINT8   AsyncVCode;\r
+  UINT16  Parameter1;\r
+  UINT16  Parameter2;\r
+  UINT16  Parameter3;\r
+  UINT32  Reserved3;\r
+} ISCSI_ASYNC_MESSAGE;\r
+\r
+#define ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT  0x80\r
+#define ISCSI_LOGIN_REQ_PDU_FLAG_CONTINUE 0x40\r
+\r
+//\r
+// Login Request\r
+//\r
+typedef struct _ISCSI_LOGIN_REQUEST {\r
+  UINT8   OpCode;\r
+  UINT8   Flags;\r
+  UINT8   VersionMax;\r
+  UINT8   VersionMin;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   ISID[6];\r
+  UINT16  TSIH;\r
+  UINT32  InitiatorTaskTag;\r
+  UINT16  CID;\r
+  UINT16  Reserved1;\r
+  UINT32  CmdSN;\r
+  UINT32  ExpStatSN;\r
+  UINT32  Reserved2[4];\r
+} ISCSI_LOGIN_REQUEST;\r
+\r
+#define ISCSI_LOGIN_RSP_PDU_FLAG_TRANSIT    ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT\r
+#define ISCSI_LOGIN_RSP_PDU_FLAG_CONTINUE   ISCSI_LOGIN_REQ_PDU_FLAG_CONTINUE\r
+\r
+#define ISCSI_LOGIN_STATUS_SUCCESS          0\r
+#define ISCSI_LOGIN_STATUS_REDIRECTION      1\r
+#define ISCSI_LOGIN_STATUS_INITIATOR_ERROR  2\r
+#define ISCSI_LOGIN_STATUS_TARGET_ERROR     3\r
+\r
+//\r
+// Login Response\r
+//\r
+typedef struct _ISCSI_LOGIN_RESPONSE {\r
+  UINT8   OpCode;\r
+  UINT8   Flags;\r
+  UINT8   VersionMax;\r
+  UINT8   VersionActive;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   ISID[6];\r
+  UINT16  TSIH;\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  Reserved1;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT8   StatusClass;\r
+  UINT8   StatusDetail;\r
+  UINT8   Reserved2[10];\r
+} ISCSI_LOGIN_RESPONSE;\r
+\r
+#define ISCSI_LOGOUT_REASON_CLOSE_SESSION                   0\r
+#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION                1\r
+#define ISCSI_LOGOUT_REASON_REMOVE_CONNECTION_FOR_RECOVERY  2\r
+\r
+//\r
+// Logout Request\r
+//\r
+typedef struct _ISCSI_LOGOUT_REQUEST {\r
+  UINT8   OpCode;\r
+  UINT8   ReasonCode;\r
+  UINT16  Reserved1;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT32  Reserved2[2];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT16  CID;\r
+  UINT16  Reserved3;\r
+  UINT32  CmdSN;\r
+  UINT32  ExpStatSN;\r
+  UINT32  Reserved4[4];\r
+} ISCSI_LOGOUT_REQUEST;\r
+\r
+#define ISCSI_LOGOUT_RESPONSE_SESSION_CLOSED_SUCCESS  0\r
+#define ISCSI_LOGOUT_RESPONSE_CID_NOT_FOUND           1\r
+#define ISCSI_LOGOUT_RESPONSE_RECOVERY_NOT_SUPPORTED  2\r
+#define ISCSI_LOGOUT_RESPONSE_CLEANUP_FAILED          3\r
+\r
+//\r
+// Logout Response\r
+//\r
+typedef struct _ISCSI_LOGOUT_RESPONSE {\r
+  UINT8   OpCode;\r
+  UINT8   Reserved1;\r
+  UINT8   Response;\r
+  UINT8   Reserved2;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT32  Reserved3[2];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  Reserved4;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT32  Reserved5;\r
+  UINT16  Time2Wait;\r
+  UINT16  Time2Retain;\r
+  UINT32  Reserved6;\r
+} ISCSI_LOGOUT_RESPONSE;\r
+\r
+#define ISCSI_SNACK_REQUEST_TYPE_DATA_OR_R2T  0\r
+#define ISCSI_SNACK_REQUEST_TYPE_STATUS       1\r
+#define ISCSI_SNACK_REQUEST_TYPE_DATA_ACK     2\r
+#define ISCSI_SNACK_REQUEST_TYPE_RDATA        3\r
+\r
+//\r
+// SNACK Request\r
+//\r
+typedef struct _ISCSI_SNACK_REQUEST {\r
+  UINT8   OpCode;\r
+  UINT8   Type;\r
+  UINT16  Reserved1;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  TargetTransferTag;\r
+  UINT32  Reserved2;\r
+  UINT32  ExpStatSN;\r
+  UINT32  Reserved[2];\r
+  UINT32  BegRun;\r
+  UINT32  RunLength;\r
+} ISCSI_SNACK_REQUEST;\r
+\r
+//\r
+// Reject\r
+//\r
+typedef struct _ISCSI_REJECT {\r
+  UINT8   OpCode;\r
+  UINT8   Reserved1;\r
+  UINT8   Reason;\r
+  UINT8   Reserved2;\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT32  Reserved3[2];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  Reserved4;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT32  DataSN;\r
+  UINT32  Reserved5[2];\r
+} ISCSI_REJECT;\r
+\r
+//\r
+// NOP-Out\r
+//\r
+typedef struct _ISCSI_NOP_OUT {\r
+  UINT8   OpCode;\r
+  UINT8   Reserved1[3];\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  TargetTransferTag;\r
+  UINT32  CmdSN;\r
+  UINT32  ExpStatSN;\r
+  UINT32  Reserved2[4];\r
+} ISCSI_NOP_OUT;\r
+\r
+//\r
+// NOP-In\r
+//\r
+typedef struct _ISCSI_NOP_IN {\r
+  UINT8   OpCode;\r
+  UINT8   Reserved1[3];\r
+  UINT8   TotalAHSLength;\r
+  UINT8   DataSegmentLength[3];\r
+  UINT8   Lun[8];\r
+  UINT32  InitiatorTaskTag;\r
+  UINT32  TargetTransferTag;\r
+  UINT32  StatSN;\r
+  UINT32  ExpCmdSN;\r
+  UINT32  MaxCmdSN;\r
+  UINT32  Reserved2[3];\r
+} ISCSI_NOP_IN;\r
+\r
+#define ISCSI_SECURITY_NEGOTIATION          0\r
+#define ISCSI_LOGIN_OPERATIONAL_NEGOTIATION 1\r
+#define ISCSI_FULL_FEATURE_PHASE            3\r
+\r
+typedef enum {\r
+  ISCSI_DIGEST_NONE,\r
+  ISCSI_DIGEST_CRC32\r
+} ISCSI_DIGEST_TYPE;\r
+\r
+typedef struct _ISCSI_XFER_CONTEXT {\r
+  UINT32  TargetTransferTag;\r
+  UINT32  Offset;\r
+  UINT32  DesiredLength;\r
+  UINT32  ExpDataSN;\r
+} ISCSI_XFER_CONTEXT;\r
+\r
+typedef struct _ISCSI_IN_BUFFER_CONTEXT {\r
+  UINT8   *InData;\r
+  UINT32  InDataLen;\r
+} ISCSI_IN_BUFFER_CONTEXT;\r
+\r
+typedef struct _ISCSI_TCB {\r
+  NET_LIST_ENTRY      Link;\r
+\r
+  BOOLEAN             SoFarInOrder;\r
+  UINT32              ExpDataSN;\r
+  BOOLEAN             FbitReceived;\r
+  BOOLEAN             StatusXferd;\r
+  UINT32              ActiveR2Ts;\r
+  UINT32              Response;\r
+  CHAR8               *Reason;\r
+  UINT32              InitiatorTaskTag;\r
+  UINT32              CmdSN;\r
+  UINT32              SNACKTag;\r
+\r
+  ISCSI_XFER_CONTEXT  XferContext;\r
+\r
+  ISCSI_CONNECTION    *Conn;\r
+} ISCSI_TCB;\r
+\r
+typedef struct _ISCSI_KEY_VALUE_PAIR {\r
+  NET_LIST_ENTRY  List;\r
+\r
+  CHAR8           *Key;\r
+  CHAR8           *Value;\r
+} ISCSI_KEY_VALUE_PAIR;\r
+\r
+//\r
+// function prototypes.\r
+//\r
+VOID\r
+IScsiAttatchConnection (\r
+  IN ISCSI_SESSION     *Session,\r
+  IN ISCSI_CONNECTION  *Conn\r
+  );\r
+\r
+VOID\r
+IScsiDetatchConnection (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiConnLogin (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  );\r
+\r
+ISCSI_CONNECTION  *\r
+IScsiCreateConnection (\r
+  IN ISCSI_DRIVER_DATA  *Private,\r
+  IN ISCSI_SESSION      *Session\r
+  );\r
+\r
+VOID\r
+IScsiDestroyConnection (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiSessionLogin (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiSendLoginReq (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiReceiveLoginRsp (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiAddKeyValuePair (\r
+  IN NET_BUF          *Pdu,\r
+  IN CHAR8            *Key,\r
+  IN CHAR8            *Value\r
+  );\r
+\r
+NET_BUF           *\r
+IScsiPrepareLoginReq (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiProcessLoginRsp (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN NET_BUF           *Pdu\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiUpdateTargetAddress (\r
+  IN ISCSI_SESSION  *Session,\r
+  IN CHAR8          *Data,\r
+  IN UINT32         Len\r
+  );\r
+\r
+VOID\r
+IScsiFreeNbufList (\r
+  VOID *Arg\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiReceivePdu (\r
+  IN ISCSI_CONNECTION                      *Conn,\r
+  OUT NET_BUF                              **Pdu,\r
+  IN ISCSI_IN_BUFFER_CONTEXT               *Context, OPTIONAL\r
+  IN BOOLEAN                               HeaderDigest,\r
+  IN BOOLEAN                               DataDigest,\r
+  IN EFI_EVENT                             TimeoutEvent OPTIONAL\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiCheckOpParams (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN BOOLEAN           Transit\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiFillOpParams (\r
+  IN ISCSI_CONNECTION  *Conn,\r
+  IN NET_BUF           *Pdu\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiPadSegment (\r
+  IN NET_BUF  *Pdu,\r
+  IN UINT32   Len\r
+  );\r
+\r
+NET_LIST_ENTRY    *\r
+IScsiBuildKeyValueList (\r
+  IN CHAR8  *Data,\r
+  IN UINT32 Len\r
+  );\r
+\r
+CHAR8             *\r
+IScsiGetValueByKeyFromList (\r
+  IN NET_LIST_ENTRY  *KeyValueList,\r
+  IN CHAR8           *Key\r
+  );\r
+\r
+VOID\r
+IScsiFreeKeyValueList (\r
+  IN NET_LIST_ENTRY  *KeyValueList\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiNormalizeName (\r
+  IN CHAR8  *Name,\r
+  IN UINTN  Len\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiExecuteScsiCommand (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                 *PassThru,\r
+  IN UINT8                                           *Target,\r
+  IN UINT64                                          Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiSessionReinstatement (\r
+  IN ISCSI_DRIVER_DATA  *Private\r
+  );\r
+\r
+VOID\r
+IScsiSessionInit (\r
+  IN ISCSI_SESSION  *Session,\r
+  IN BOOLEAN        Recovery\r
+  );\r
+\r
+EFI_STATUS\r
+IScsiSessionAbort (\r
+  IN ISCSI_SESSION  *Session\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiTcp4Io.c b/MdeModulePkg/Universal/iScsi/IScsiTcp4Io.c
new file mode 100644 (file)
index 0000000..b5b85a7
--- /dev/null
@@ -0,0 +1,550 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiTcp4Io.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include "IScsiImpl.h"\r
+\r
+VOID\r
+EFIAPI\r
+Tcp4IoCommonNotify (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  The common notify function associated with various Tcp4Io events. \r
+\r
+Arguments:\r
+\r
+  Event   - The event signaled.\r
+  Contect - The context.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  *((BOOLEAN *) Context) = TRUE;\r
+}\r
+\r
+EFI_STATUS\r
+Tcp4IoCreateSocket (\r
+  IN EFI_HANDLE           Image,\r
+  IN EFI_HANDLE           Controller,\r
+  IN TCP4_IO_CONFIG_DATA  *ConfigData,\r
+  IN TCP4_IO              *Tcp4Io\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create a TCP socket with the specified configuration data. \r
+\r
+Arguments:\r
+\r
+  Image      - The handle of the driver image.\r
+  Controller - The handle of the controller.\r
+  ConfigData - The Tcp4 configuration data.\r
+  Tcp4Io     - The Tcp4Io.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - The TCP socket is created and configured.\r
+  other       - Failed to create the TCP socket or configure it.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_TCP4_PROTOCOL     *Tcp4;\r
+  EFI_TCP4_CONFIG_DATA  Tcp4ConfigData;\r
+  EFI_TCP4_OPTION       ControlOption;\r
+  EFI_TCP4_ACCESS_POINT *AccessPoint;\r
+\r
+  Tcp4Io->Handle = NULL;\r
+  Tcp4Io->ConnToken.CompletionToken.Event = NULL;\r
+  Tcp4Io->TxToken.CompletionToken.Event = NULL;\r
+  Tcp4Io->RxToken.CompletionToken.Event = NULL;\r
+  Tcp4Io->CloseToken.CompletionToken.Event = NULL;\r
+  Tcp4 = NULL;\r
+\r
+  //\r
+  // Create the TCP4 child instance and get the TCP4 protocol.\r
+  //\r
+  Status = NetLibCreateServiceChild (\r
+            Controller,\r
+            Image,\r
+            &gEfiTcp4ServiceBindingProtocolGuid,\r
+            &Tcp4Io->Handle\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Tcp4Io->Handle,\r
+                  &gEfiTcp4ProtocolGuid,\r
+                  (VOID **)&Tcp4Io->Tcp4,\r
+                  Image,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Tcp4Io->Image       = Image;\r
+  Tcp4Io->Controller  = Controller;\r
+  Tcp4                = Tcp4Io->Tcp4;\r
+\r
+  //\r
+  // Set the configuration parameters.\r
+  //\r
+  ControlOption.ReceiveBufferSize       = 0x200000;\r
+  ControlOption.SendBufferSize          = 0x200000;\r
+  ControlOption.MaxSynBackLog           = 0;\r
+  ControlOption.ConnectionTimeout       = 0;\r
+  ControlOption.DataRetries             = 6;\r
+  ControlOption.FinTimeout              = 0;\r
+  ControlOption.TimeWaitTimeout         = 0;\r
+  ControlOption.KeepAliveProbes         = 4;\r
+  ControlOption.KeepAliveTime           = 0;\r
+  ControlOption.KeepAliveInterval       = 0;\r
+  ControlOption.EnableNagle             = FALSE;\r
+  ControlOption.EnableTimeStamp         = FALSE;\r
+  ControlOption.EnableWindowScaling     = TRUE;\r
+  ControlOption.EnableSelectiveAck      = FALSE;\r
+  ControlOption.EnablePathMtuDiscovery  = FALSE;\r
+\r
+  Tcp4ConfigData.TypeOfService          = 8;\r
+  Tcp4ConfigData.TimeToLive             = 255;\r
+  Tcp4ConfigData.ControlOption          = &ControlOption;\r
+\r
+  AccessPoint = &Tcp4ConfigData.AccessPoint;\r
+\r
+  AccessPoint->UseDefaultAddress = FALSE;\r
+  AccessPoint->StationPort = 0;\r
+  AccessPoint->RemotePort = ConfigData->RemotePort;\r
+  AccessPoint->ActiveFlag = TRUE;\r
+\r
+  NetCopyMem (&AccessPoint->StationAddress, &ConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
+  NetCopyMem (&AccessPoint->SubnetMask, &ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+  NetCopyMem (&AccessPoint->RemoteAddress, &ConfigData->RemoteIp, sizeof (EFI_IPv4_ADDRESS));\r
+\r
+  //\r
+  // Configure the TCP4 protocol.\r
+  //\r
+  Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  if (!EFI_IP4_EQUAL (&ConfigData->Gateway, &mZeroIp4Addr)) {\r
+    //\r
+    // the gateway is not zero, add the default route by hand\r
+    //\r
+    Status = Tcp4->Routes (Tcp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &ConfigData->Gateway);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+  }\r
+  //\r
+  // Create events for variuos asynchronous operations.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EFI_EVENT_NOTIFY_SIGNAL,\r
+                  NET_TPL_EVENT,\r
+                  Tcp4IoCommonNotify,\r
+                  &Tcp4Io->IsConnDone,\r
+                  &Tcp4Io->ConnToken.CompletionToken.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EFI_EVENT_NOTIFY_SIGNAL,\r
+                  NET_TPL_EVENT,\r
+                  Tcp4IoCommonNotify,\r
+                  &Tcp4Io->IsTxDone,\r
+                  &Tcp4Io->TxToken.CompletionToken.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EFI_EVENT_NOTIFY_SIGNAL,\r
+                  NET_TPL_EVENT,\r
+                  Tcp4IoCommonNotify,\r
+                  &Tcp4Io->IsRxDone,\r
+                  &Tcp4Io->RxToken.CompletionToken.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EFI_EVENT_NOTIFY_SIGNAL,\r
+                  NET_TPL_EVENT,\r
+                  Tcp4IoCommonNotify,\r
+                  &Tcp4Io->IsCloseDone,\r
+                  &Tcp4Io->CloseToken.CompletionToken.Event\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_ERROR;\r
+  }\r
+\r
+  Tcp4Io->IsTxDone  = FALSE;\r
+  Tcp4Io->IsRxDone  = FALSE;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+\r
+  if (Tcp4Io->RxToken.CompletionToken.Event != NULL) {\r
+    gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);\r
+  }\r
+\r
+  if (Tcp4Io->TxToken.CompletionToken.Event != NULL) {\r
+    gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);\r
+  }\r
+\r
+  if (Tcp4Io->ConnToken.CompletionToken.Event != NULL) {\r
+    gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);\r
+  }\r
+\r
+  if (Tcp4 != NULL) {\r
+    Tcp4->Configure (Tcp4, NULL);\r
+\r
+    gBS->CloseProtocol (\r
+          Tcp4Io->Handle,\r
+          &gEfiTcp4ProtocolGuid,\r
+          Image,\r
+          Controller\r
+          );\r
+  }\r
+\r
+  NetLibDestroyServiceChild (\r
+    Controller,\r
+    Image,\r
+    &gEfiTcp4ServiceBindingProtocolGuid,\r
+    Tcp4Io->Handle\r
+    );\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+Tcp4IoDestroySocket (\r
+  IN TCP4_IO  *Tcp4Io\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Destroy the socket. \r
+\r
+Arguments:\r
+\r
+  Tcp4Io - The Tcp4Io which wraps the socket to be destroyeds.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_TCP4_PROTOCOL *Tcp4;\r
+\r
+  Tcp4 = Tcp4Io->Tcp4;\r
+\r
+  Tcp4->Configure (Tcp4, NULL);\r
+\r
+  gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);\r
+  gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);\r
+  gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);\r
+\r
+  gBS->CloseProtocol (\r
+        Tcp4Io->Handle,\r
+        &gEfiTcp4ProtocolGuid,\r
+        Tcp4Io->Image,\r
+        Tcp4Io->Controller\r
+        );\r
+\r
+  NetLibDestroyServiceChild (\r
+    Tcp4Io->Controller,\r
+    Tcp4Io->Image,\r
+    &gEfiTcp4ServiceBindingProtocolGuid,\r
+    Tcp4Io->Handle\r
+    );\r
+}\r
+\r
+EFI_STATUS\r
+Tcp4IoConnect (\r
+  IN TCP4_IO    *Tcp4Io,\r
+  IN EFI_EVENT  Timeout\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Connect to the other endpoint of the TCP socket.\r
+\r
+Arguments:\r
+\r
+  Tcp4Io  - The Tcp4Io wrapping the TCP socket.\r
+  Timeout - The time to wait for connection done.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_TCP4_PROTOCOL *Tcp4;\r
+  EFI_STATUS        Status;\r
+\r
+  Tcp4Io->IsConnDone  = FALSE;\r
+  Tcp4                = Tcp4Io->Tcp4;\r
+  Status              = Tcp4->Connect (Tcp4, &Tcp4Io->ConnToken);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  while (!Tcp4Io->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {\r
+    Tcp4->Poll (Tcp4);\r
+  }\r
+\r
+  if (!Tcp4Io->IsConnDone) {\r
+    Status = EFI_TIMEOUT;\r
+  } else {\r
+    Status = Tcp4Io->ConnToken.CompletionToken.Status;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+Tcp4IoReset (\r
+  IN TCP4_IO  *Tcp4Io\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Reset the socket.\r
+\r
+Arguments:\r
+\r
+  Tcp4Io - The Tcp4Io wrapping the TCP socket.\r
+\r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS        Status;\r
+  EFI_TCP4_PROTOCOL *Tcp4;\r
+\r
+  Tcp4Io->CloseToken.AbortOnClose = TRUE;\r
+  Tcp4Io->IsCloseDone             = FALSE;\r
+\r
+  Tcp4 = Tcp4Io->Tcp4;\r
+  Status = Tcp4->Close (Tcp4, &Tcp4Io->CloseToken);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  while (!Tcp4Io->IsCloseDone) {\r
+    Tcp4->Poll (Tcp4);\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+Tcp4IoTransmit (\r
+  IN TCP4_IO  *Tcp4Io,\r
+  IN NET_BUF  *Packet\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Transmit the Packet to the other endpoint of the socket.\r
+\r
+Arguments:\r
+\r
+  Tcp4Io - The Tcp4Io wrapping the TCP socket.\r
+  Packet - The packet to transmit\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The packet is trasmitted.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
+\r
+--*/\r
+{\r
+  EFI_TCP4_TRANSMIT_DATA  *TxData;\r
+  EFI_TCP4_PROTOCOL       *Tcp4;\r
+  EFI_STATUS              Status;\r
+\r
+  TxData = NetAllocatePool (sizeof (EFI_TCP4_TRANSMIT_DATA) + (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA));\r
+  if (TxData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  TxData->Push        = TRUE;\r
+  TxData->Urgent      = FALSE;\r
+  TxData->DataLength  = Packet->TotalSize;\r
+\r
+  //\r
+  // Build the fragment table.\r
+  //\r
+  TxData->FragmentCount = Packet->BlockOpNum;\r
+  NetbufBuildExt (Packet, (NET_FRAGMENT *) &TxData->FragmentTable[0], &TxData->FragmentCount);\r
+\r
+  Tcp4Io->TxToken.Packet.TxData = TxData;\r
+\r
+  //\r
+  // Trasnmit the packet.\r
+  //\r
+  Tcp4    = Tcp4Io->Tcp4;\r
+  Status  = Tcp4->Transmit (Tcp4, &Tcp4Io->TxToken);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  while (!Tcp4Io->IsTxDone) {\r
+    Tcp4->Poll (Tcp4);\r
+  }\r
+\r
+  Tcp4Io->IsTxDone  = FALSE;\r
+\r
+  Status            = Tcp4Io->TxToken.CompletionToken.Status;\r
+\r
+ON_EXIT:\r
+\r
+  NetFreePool (TxData);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+Tcp4IoReceive (\r
+  IN TCP4_IO    *Tcp4Io,\r
+  IN NET_BUF    *Packet,\r
+  IN BOOLEAN    AsyncMode,\r
+  IN EFI_EVENT  Timeout\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Receive data from the socket.\r
+\r
+Arguments:\r
+\r
+  Tcp4Io    - The Tcp4Io which wraps the socket to be destroyeds.\r
+  Packet    - The buffer to hold the data copy from the soket rx buffer.\r
+  AsyncMode - Is this receive asyncronous or not.\r
+  Timeout   - The time to wait for receiving the amount of data the Packet\r
+              can hold.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS          - The required amount of data is received from the socket.\r
+  EFI_OUT_OF_RESOURCES - Failed to allocate momery.\r
+  EFI_TIMEOUT          - Failed to receive the required amount of data in the\r
+                         specified time period.\r
+\r
+--*/\r
+{\r
+  EFI_TCP4_PROTOCOL     *Tcp4;\r
+  EFI_TCP4_RECEIVE_DATA RxData;\r
+  EFI_STATUS            Status;\r
+  NET_FRAGMENT          *Fragment;\r
+  UINT32                FragmentCount;\r
+  UINT32                CurrentFragment;\r
+\r
+  FragmentCount = Packet->BlockOpNum;\r
+  Fragment      = NetAllocatePool (FragmentCount * sizeof (NET_FRAGMENT));\r
+  if (Fragment == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Build the fragment table.\r
+  //\r
+  NetbufBuildExt (Packet, Fragment, &FragmentCount);\r
+\r
+  RxData.FragmentCount          = 1;\r
+  Tcp4Io->RxToken.Packet.RxData = &RxData;\r
+  CurrentFragment               = 0;\r
+  Tcp4                          = Tcp4Io->Tcp4;\r
+  Status                        = EFI_SUCCESS;\r
+\r
+  while (CurrentFragment < FragmentCount) {\r
+    RxData.DataLength                       = Fragment[CurrentFragment].Len;\r
+    RxData.FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;\r
+    RxData.FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;\r
+\r
+    Status = Tcp4->Receive (Tcp4, &Tcp4Io->RxToken);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    while (!Tcp4Io->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
+      //\r
+      // Poll until some data is received or something error happens.\r
+      //\r
+      Tcp4->Poll (Tcp4);\r
+    }\r
+\r
+    if (!Tcp4Io->IsRxDone) {\r
+      //\r
+      // Timeout occurs, cancel the receive request.\r
+      //\r
+      Tcp4->Cancel (Tcp4, &Tcp4Io->RxToken.CompletionToken);\r
+\r
+      Status = EFI_TIMEOUT;\r
+      goto ON_EXIT;\r
+    } else {\r
+      Tcp4Io->IsRxDone = FALSE;\r
+    }\r
+\r
+    if (EFI_ERROR (Tcp4Io->RxToken.CompletionToken.Status)) {\r
+      Status = Tcp4Io->RxToken.CompletionToken.Status;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Fragment[CurrentFragment].Len -= RxData.FragmentTable[0].FragmentLength;\r
+    if (Fragment[CurrentFragment].Len == 0) {\r
+      CurrentFragment++;\r
+    } else {\r
+      Fragment[CurrentFragment].Bulk += RxData.FragmentTable[0].FragmentLength;\r
+    }\r
+  }\r
+\r
+ON_EXIT:\r
+\r
+  NetFreePool (Fragment);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Universal/iScsi/IScsiTcp4Io.h b/MdeModulePkg/Universal/iScsi/IScsiTcp4Io.h
new file mode 100644 (file)
index 0000000..c983e05
--- /dev/null
@@ -0,0 +1,93 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  IScsiTcp4Io.h\r
+\r
+Abstract:\r
+\r
+  iSCSI Tcp4 IO related definitions.\r
+\r
+--*/\r
+\r
+#ifndef _ISCSI_TCP4_IO_H_\r
+#define _ISCSI_TCP4_IO_H_\r
+\r
+#include <Library/NetLib.h>\r
+#include <protocol/Tcp4.h>\r
+\r
+typedef struct _TCP4_IO_CONFIG_DATA {\r
+  EFI_IPv4_ADDRESS  LocalIp;\r
+  EFI_IPv4_ADDRESS  SubnetMask;\r
+  EFI_IPv4_ADDRESS  Gateway;\r
+\r
+  EFI_IPv4_ADDRESS  RemoteIp;\r
+  UINT16            RemotePort;\r
+} TCP4_IO_CONFIG_DATA;\r
+\r
+typedef struct _TCP4_IO {\r
+  EFI_HANDLE                Image;\r
+  EFI_HANDLE                Controller;\r
+\r
+  EFI_HANDLE                Handle;\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+\r
+  EFI_TCP4_CONNECTION_TOKEN ConnToken;\r
+  EFI_TCP4_IO_TOKEN         TxToken;\r
+  EFI_TCP4_IO_TOKEN         RxToken;\r
+  EFI_TCP4_CLOSE_TOKEN      CloseToken;\r
+\r
+  BOOLEAN                   IsConnDone;\r
+  BOOLEAN                   IsTxDone;\r
+  BOOLEAN                   IsRxDone;\r
+  BOOLEAN                   IsCloseDone;\r
+} TCP4_IO;\r
+\r
+EFI_STATUS\r
+Tcp4IoCreateSocket (\r
+  IN EFI_HANDLE           Image,\r
+  IN EFI_HANDLE           Controller,\r
+  IN TCP4_IO_CONFIG_DATA  *ConfigData,\r
+  IN TCP4_IO              *Tcp4Io\r
+  );\r
+\r
+VOID\r
+Tcp4IoDestroySocket (\r
+  IN TCP4_IO  *Tcp4Io\r
+  );\r
+\r
+EFI_STATUS\r
+Tcp4IoConnect (\r
+  IN TCP4_IO    *Tcp4Io,\r
+  IN EFI_EVENT  Timeout\r
+  );\r
+\r
+VOID\r
+Tcp4IoReset (\r
+  IN TCP4_IO  *Tcp4Io\r
+  );\r
+\r
+EFI_STATUS\r
+Tcp4IoTransmit (\r
+  IN TCP4_IO  *Tcp4Io,\r
+  IN NET_BUF  *Packet\r
+  );\r
+\r
+EFI_STATUS\r
+Tcp4IoReceive (\r
+  IN TCP4_IO    *Tcp4Io,\r
+  IN NET_BUF    *Packet,\r
+  IN BOOLEAN    AsyncMode,\r
+  IN EFI_EVENT  Timeout\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Universal/iScsi/Md5.c b/MdeModulePkg/Universal/iScsi/Md5.c
new file mode 100644 (file)
index 0000000..d283c62
--- /dev/null
@@ -0,0 +1,335 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  Md5.c\r
+\r
+Abstract:\r
+\r
+  Implementation of MD5 algorithm\r
+\r
+--*/\r
+\r
+#include "Md5.h"\r
+\r
+STATIC CONST UINT32  MD5_K[][2] = {\r
+  { 0, 1 },\r
+  { 1, 5 },\r
+  { 5, 3 },\r
+  { 0, 7 }\r
+};\r
+\r
+STATIC CONST UINT32  MD5_S[][4] = {\r
+  { 7, 22, 17, 12 },\r
+  { 5, 20, 14, 9 },\r
+  { 4, 23, 16 ,11 },\r
+  { 6, 21, 15, 10 },\r
+};\r
+\r
+STATIC CONST UINT32  MD5_T[] = {\r
+  0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,\r
+  0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,\r
+  0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,\r
+  0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,\r
+  0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,\r
+  0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,\r
+  0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,\r
+  0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,\r
+  0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,\r
+  0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,\r
+  0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,\r
+  0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,\r
+  0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,\r
+  0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,\r
+  0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,\r
+  0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391\r
+};\r
+\r
+STATIC CONST UINT8 Md5HashPadding[] =\r
+{\r
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \r
+};\r
+\r
+//\r
+// ROTATE_LEFT rotates x left n bits.\r
+//\r
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))\r
+\r
+#define SA            S[j & 3]\r
+#define SB            S[(j + 1) & 3]\r
+#define SC            S[(j + 2) & 3]\r
+#define SD            S[(j + 3) & 3]\r
+\r
+//\r
+// TF1, TF2, TF3, TF4 are basic MD5 transform functions\r
+//\r
+UINT32 TF1 (UINT32 A, UINT32 B, UINT32 C)\r
+{\r
+  return (A & B) | (~A & C);\r
+}\r
+\r
+UINT32 TF2 (UINT32 A, UINT32 B, UINT32 C)\r
+{\r
+  return (A & C) | (B & ~C);\r
+}\r
+\r
+UINT32 TF3 (UINT32 A, UINT32 B, UINT32 C)\r
+{\r
+  return A ^ B ^ C;\r
+}\r
+\r
+UINT32 TF4 (UINT32 A, UINT32 B, UINT32 C)\r
+{\r
+  return B ^ (A | ~C);\r
+}\r
+\r
+typedef\r
+UINT32\r
+(*MD5_TRANSFORM_FUNC) (\r
+  IN UINT32  A,\r
+  IN UINT32  B,\r
+  IN UINT32  C\r
+  );\r
+\r
+STATIC CONST MD5_TRANSFORM_FUNC MD5_F[] = {\r
+  TF1,\r
+  TF2,\r
+  TF3,\r
+  TF4\r
+};\r
+\r
+STATIC\r
+VOID\r
+MD5Transform (\r
+  IN MD5_CTX  *Md5Ctx\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Md5Ctx  - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  UINT32  i;\r
+  UINT32  j;\r
+  UINT32  S[MD5_HASHSIZE >> 2];\r
+  UINT32  *X;\r
+  UINT32  k;\r
+  UINT32  t;\r
+\r
+  X = (UINT32 *) Md5Ctx->M;\r
+\r
+  //\r
+  // Copy MD5 states to S\r
+  //\r
+  NetCopyMem (S, Md5Ctx->States, MD5_HASHSIZE);\r
+\r
+  t = 0;\r
+  for (i = 0; i < 4; i++) {\r
+    k = MD5_K[i][0];\r
+    for (j = 16; j > 0; j--) {\r
+      SA += (*MD5_F[i]) (SB, SC, SD) + X[k] + MD5_T[t];\r
+      SA  = ROTATE_LEFT (SA, MD5_S[i][j & 3]);\r
+      SA += SB;\r
+\r
+      k += MD5_K[i][1];\r
+      k &= 15;\r
+\r
+      t++;\r
+    }\r
+  }\r
+\r
+  for (i = 0; i < 4; i++) {\r
+    Md5Ctx->States[i] += S[i];\r
+  }\r
+}\r
+\r
+STATIC\r
+VOID\r
+MD5UpdateBlock (\r
+  IN MD5_CTX      *Md5Ctx,\r
+  IN CONST UINT8  *Data,\r
+  IN       UINTN  DataLen\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Md5Ctx  - GC_TODO: add argument description\r
+  Data    - GC_TODO: add argument description\r
+  DataLen - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  UINTN Limit;\r
+\r
+  for (Limit = 64 - Md5Ctx->Count; DataLen >= 64 - Md5Ctx->Count; Limit = 64) {\r
+    NetCopyMem (Md5Ctx->M + Md5Ctx->Count, (VOID *)Data, Limit);\r
+    MD5Transform (Md5Ctx);\r
+    \r
+    Md5Ctx->Count = 0;\r
+    Data         += Limit;\r
+    DataLen      -= Limit;\r
+  }\r
+\r
+  NetCopyMem (Md5Ctx->M + Md5Ctx->Count, (VOID *)Data, DataLen);\r
+  Md5Ctx->Count += DataLen;\r
+}\r
+\r
+EFI_STATUS\r
+MD5Init (\r
+  IN MD5_CTX  *Md5Ctx\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Md5Ctx  - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+{\r
+  NetZeroMem (Md5Ctx, sizeof (*Md5Ctx));\r
+\r
+  //\r
+  // Set magic initialization constants.\r
+  //\r
+  Md5Ctx->States[0] = 0x67452301;\r
+  Md5Ctx->States[1] = 0xefcdab89;\r
+  Md5Ctx->States[2] = 0x98badcfe;\r
+  Md5Ctx->States[3] = 0x10325476;  \r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+MD5Update (\r
+  IN  MD5_CTX  *Md5Ctx,\r
+  IN  VOID     *Data,\r
+  IN  UINTN    DataLen\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Md5Ctx  - GC_TODO: add argument description\r
+  Data    - GC_TODO: add argument description\r
+  DataLen - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+{\r
+  if (EFI_ERROR (Md5Ctx->Status)) {\r
+    return Md5Ctx->Status;\r
+  }\r
+\r
+  MD5UpdateBlock (Md5Ctx, (CONST UINT8 *) Data, DataLen);\r
+  Md5Ctx->Length += DataLen;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+MD5Final (\r
+  IN  MD5_CTX  *Md5Ctx,\r
+  OUT UINT8    *HashVal\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Md5Ctx  - GC_TODO: add argument description\r
+  HashVal - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+{\r
+  UINTN PadLength;\r
+\r
+  if (Md5Ctx->Status == EFI_ALREADY_STARTED) {\r
+    //\r
+    // Store Hashed value & Zeroize sensitive context information.\r
+    //\r
+    NetCopyMem (HashVal, (UINT8 *) Md5Ctx->States, MD5_HASHSIZE);\r
+    NetZeroMem ((UINT8 *)Md5Ctx, sizeof (*Md5Ctx));\r
+    \r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Md5Ctx->Status)) {\r
+    return Md5Ctx->Status;\r
+  }\r
+\r
+  PadLength  = Md5Ctx->Count >= 56 ? 120 : 56;\r
+  PadLength -= Md5Ctx->Count;\r
+  MD5UpdateBlock (Md5Ctx, Md5HashPadding, PadLength);\r
+  Md5Ctx->Length = LShiftU64 (Md5Ctx->Length, 3);\r
+  MD5UpdateBlock (Md5Ctx, (CONST UINT8 *) &Md5Ctx->Length, 8);\r
+\r
+  NetZeroMem (Md5Ctx->M, sizeof (Md5Ctx->M));\r
+  Md5Ctx->Length  = 0;\r
+  Md5Ctx->Status  = EFI_ALREADY_STARTED;\r
+  return MD5Final (Md5Ctx, HashVal);\r
+}\r
+\r
diff --git a/MdeModulePkg/Universal/iScsi/Md5.h b/MdeModulePkg/Universal/iScsi/Md5.h
new file mode 100644 (file)
index 0000000..ee06fd7
--- /dev/null
@@ -0,0 +1,108 @@
+/*++\r
+\r
+Copyright (c)  2007 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  Md5.h\r
+\r
+Abstract:\r
+\r
+  Header file for Md5\r
+\r
+--*/\r
+\r
+#ifndef _MD5_H_\r
+#define _MD5_H_\r
+\r
+#include <uefi/UefiBaseType.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/NetLib.h>\r
+\r
+#define MD5_HASHSIZE  16\r
+\r
+typedef struct _MD5_CTX {\r
+  EFI_STATUS  Status;\r
+  UINT64      Length;\r
+  UINT32      States[MD5_HASHSIZE / sizeof (UINT32)];\r
+  UINT8       M[64];\r
+  UINTN       Count;\r
+} MD5_CTX;\r
+\r
+EFI_STATUS\r
+MD5Init (\r
+  IN MD5_CTX  *Md5Ctx\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Md5Ctx  - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+MD5Update (\r
+  IN MD5_CTX  *Md5Ctx,\r
+  IN VOID     *Data,\r
+  IN UINTN    DataLen\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Md5Ctx  - GC_TODO: add argument description\r
+  Data    - GC_TODO: add argument description\r
+  DataLen - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+MD5Final (\r
+  IN  MD5_CTX  *Md5Ctx,\r
+  OUT UINT8    *HashVal\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Md5Ctx  - GC_TODO: add argument description\r
+  HashVal - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS - GC_TODO: Add description for return value\r
+\r
+--*/\r
+;\r
+\r
+#endif // _MD5_H\r