]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/IScsiDxe/IScsiProto.c
NetworkPkg: Clean up source files
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiProto.c
index 2ab4da8cdac22fa9330f3f44f9a5d98b8d7b319e..7619360568d8efd6de55f41764b1bf7a79bc8d02 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The implementation of iSCSI protocol based on RFC3720.\r
 \r
-Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
 which accompanies this distribution.  The full text of the license may be found at\r
@@ -17,7 +17,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 UINT32 mDataSegPad = 0;\r
 \r
 /**\r
-  Attach the iSCSI connection to the iSCSI session. \r
+  Attach the iSCSI connection to the iSCSI session.\r
 \r
   @param[in, out]  Session The iSCSI session.\r
   @param[in, out]  Conn    The iSCSI connection.\r
@@ -35,7 +35,7 @@ IScsiAttatchConnection (
 }\r
 \r
 /**\r
-  Detach the iSCSI connection from the session it belongs to. \r
+  Detach the iSCSI connection from the session it belongs to.\r
 \r
   @param[in, out]  Conn The iSCSI connection.\r
 \r
@@ -52,7 +52,7 @@ IScsiDetatchConnection (
 \r
 \r
 /**\r
-  Check the sequence number according to RFC3720. \r
+  Check the sequence number according to RFC3720.\r
 \r
   @param[in, out]  ExpSN   The currently expected sequence number.\r
   @param[in]       NewSN   The sequence number to check.\r
@@ -124,7 +124,7 @@ IScsiUpdateCmdSN (
 \r
   @retval EFI_SUCCESS        The iSCSI connection is logged into the iSCSI target.\r
   @retval EFI_TIMEOUT        Timeout occurred during the login procedure.\r
-  @retval Others             Other errors as indicated.  \r
+  @retval Others             Other errors as indicated.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -138,7 +138,11 @@ IScsiConnLogin (
   //\r
   // Start the timer, and wait Timeout seconds to establish the TCP connection.\r
   //\r
-  Status = gBS->SetTimer (Conn->TimeoutEvent, TimerRelative, Timeout * TICKS_PER_MS);\r
+  Status = gBS->SetTimer (\r
+                  Conn->TimeoutEvent,\r
+                  TimerRelative,\r
+                  MultU64x32 (Timeout, TICKS_PER_MS)\r
+                  );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -228,7 +232,7 @@ IScsiCreateConnection (
   Conn->PartialRspRcvd  = FALSE;\r
   Conn->ParamNegotiated = FALSE;\r
   Conn->Cid             = Session->NextCid++;\r
-  Conn->Ipv6Flag        = mPrivate->Ipv6Flag;\r
+  Conn->Ipv6Flag        = NvData->IpMode == IP_MODE_IP6 || Session->ConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6;\r
 \r
   Status = gBS->CreateEvent (\r
                   EVT_TIMER,\r
@@ -251,23 +255,41 @@ IScsiCreateConnection (
   Conn->HeaderDigest              = IScsiDigestNone;\r
   Conn->DataDigest                = IScsiDigestNone;\r
 \r
+  if (NvData->DnsMode) {\r
+    //\r
+    // perform dns process if target address expressed by domain name.\r
+    //\r
+    if (!Conn->Ipv6Flag) {\r
+      Status = IScsiDns4 (Private->Image, Private->Controller, NvData);\r
+    } else {\r
+      Status = IScsiDns6 (Private->Image, Private->Controller, NvData);\r
+    }\r
+\r
+    if (EFI_ERROR(Status)) {\r
+      DEBUG ((EFI_D_ERROR, "The configuration of Target address or DNS server address is invalid!\n"));\r
+      FreePool (Conn);\r
+      return NULL;\r
+    }\r
+  }\r
+\r
   if (!Conn->Ipv6Flag) {\r
     Tcp4IoConfig = &TcpIoConfig.Tcp4IoConfigData;\r
-    \r
+\r
     CopyMem (&Tcp4IoConfig->LocalIp, &NvData->LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
     CopyMem (&Tcp4IoConfig->SubnetMask, &NvData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
     CopyMem (&Tcp4IoConfig->Gateway, &NvData->Gateway, sizeof (EFI_IPv4_ADDRESS));\r
     CopyMem (&Tcp4IoConfig->RemoteIp, &NvData->TargetIp, sizeof (EFI_IPv4_ADDRESS));\r
 \r
-    Tcp4IoConfig->RemotePort = NvData->TargetPort;\r
-    Tcp4IoConfig->ActiveFlag = TRUE;\r
-\r
+    Tcp4IoConfig->RemotePort  = NvData->TargetPort;\r
+    Tcp4IoConfig->ActiveFlag  = TRUE;\r
+    Tcp4IoConfig->StationPort = 0;\r
   } else {\r
     Tcp6IoConfig = &TcpIoConfig.Tcp6IoConfigData;\r
-  \r
+\r
     CopyMem (&Tcp6IoConfig->RemoteIp, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS));\r
-    Tcp6IoConfig->RemotePort = NvData->TargetPort;\r
-    Tcp6IoConfig->ActiveFlag = TRUE;\r
+    Tcp6IoConfig->RemotePort  = NvData->TargetPort;\r
+    Tcp6IoConfig->ActiveFlag  = TRUE;\r
+    Tcp6IoConfig->StationPort = 0;\r
   }\r
 \r
   //\r
@@ -308,6 +330,98 @@ IScsiDestroyConnection (
   FreePool (Conn);\r
 }\r
 \r
+/**\r
+  Retrieve the IPv6 Address/Prefix/Gateway from the established TCP connection, these informations\r
+  will be filled in the iSCSI Boot Firmware Table.\r
+\r
+  @param[in]  Conn             The connection used in the iSCSI login phase.\r
+\r
+  @retval     EFI_SUCCESS      Get the NIC information successfully.\r
+  @retval     Others           Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+IScsiGetIp6NicInfo (\r
+  IN ISCSI_CONNECTION  *Conn\r
+  )\r
+{\r
+  ISCSI_SESSION_CONFIG_NVDATA  *NvData;\r
+  EFI_TCP6_PROTOCOL            *Tcp6;\r
+  EFI_IP6_MODE_DATA            Ip6ModeData;\r
+  EFI_STATUS                   Status;\r
+  EFI_IPv6_ADDRESS             *TargetIp;\r
+  UINTN                        Index;\r
+  UINT8                        SubnetPrefixLength;\r
+  UINTN                        RouteEntry;\r
+\r
+  NvData   = &Conn->Session->ConfigData->SessionConfigData;\r
+  TargetIp = &NvData->TargetIp.v6;\r
+  Tcp6     = Conn->TcpIo.Tcp.Tcp6;\r
+\r
+  ZeroMem (&Ip6ModeData, sizeof (EFI_IP6_MODE_DATA));\r
+  Status = Tcp6->GetModeData (\r
+                   Tcp6,\r
+                   NULL,\r
+                   NULL,\r
+                   &Ip6ModeData,\r
+                   NULL,\r
+                   NULL\r
+                   );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (!Ip6ModeData.IsConfigured) {\r
+    Status = EFI_ABORTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  IP6_COPY_ADDRESS (&NvData->LocalIp, &Ip6ModeData.ConfigData.StationAddress);\r
+\r
+  NvData->PrefixLength = 0;\r
+  for (Index = 0; Index < Ip6ModeData.AddressCount; Index++) {\r
+    if (EFI_IP6_EQUAL (&NvData->LocalIp.v6, &Ip6ModeData.AddressList[Index].Address)) {\r
+      NvData->PrefixLength = Ip6ModeData.AddressList[Index].PrefixLength;\r
+      break;\r
+    }\r
+  }\r
+\r
+  SubnetPrefixLength = 0;\r
+  RouteEntry = Ip6ModeData.RouteCount;\r
+  for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {\r
+    if (NetIp6IsNetEqual (TargetIp, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {\r
+      if (SubnetPrefixLength < Ip6ModeData.RouteTable[Index].PrefixLength) {\r
+        SubnetPrefixLength = Ip6ModeData.RouteTable[Index].PrefixLength;\r
+        RouteEntry = Index;\r
+      }\r
+    }\r
+  }\r
+  if (RouteEntry != Ip6ModeData.RouteCount) {\r
+    IP6_COPY_ADDRESS (&NvData->Gateway, &Ip6ModeData.RouteTable[RouteEntry].Gateway);\r
+  }\r
+\r
+ON_EXIT:\r
+  if (Ip6ModeData.AddressList != NULL) {\r
+    FreePool (Ip6ModeData.AddressList);\r
+  }\r
+  if (Ip6ModeData.GroupTable!= NULL) {\r
+    FreePool (Ip6ModeData.GroupTable);\r
+  }\r
+  if (Ip6ModeData.RouteTable!= NULL) {\r
+    FreePool (Ip6ModeData.RouteTable);\r
+  }\r
+  if (Ip6ModeData.NeighborCache!= NULL) {\r
+    FreePool (Ip6ModeData.NeighborCache);\r
+  }\r
+  if (Ip6ModeData.PrefixTable!= NULL) {\r
+    FreePool (Ip6ModeData.PrefixTable);\r
+  }\r
+  if (Ip6ModeData.IcmpTypeList!= NULL) {\r
+    FreePool (Ip6ModeData.IcmpTypeList);\r
+  }\r
+\r
+  return Status;\r
+}\r
 \r
 /**\r
   Login the iSCSI session.\r
@@ -330,14 +444,14 @@ IScsiSessionLogin (
   VOID              *Tcp;\r
   EFI_GUID          *ProtocolGuid;\r
   UINT8             RetryCount;\r
-  BOOLEAN           MediaPresent;\r
+  EFI_STATUS        MediaStatus;\r
 \r
   //\r
   // Check media status before session login.\r
   //\r
-  MediaPresent = TRUE;\r
-  NetLibDetectMedia (Session->Private->Controller, &MediaPresent);\r
-  if (!MediaPresent) {\r
+  MediaStatus = EFI_SUCCESS;\r
+  NetLibDetectMediaWaitTimeout (Session->Private->Controller, ISCSI_CHECK_MEDIA_LOGIN_WAITING_TIME, &MediaStatus);\r
+  if (MediaStatus != EFI_SUCCESS) {\r
     return EFI_NO_MEDIA;\r
   }\r
 \r
@@ -379,8 +493,8 @@ IScsiSessionLogin (
   if (!EFI_ERROR (Status)) {\r
     Session->State = SESSION_STATE_LOGGED_IN;\r
 \r
-    if (!mPrivate->Ipv6Flag) {\r
-      ProtocolGuid = &gEfiTcp4ProtocolGuid;      \r
+    if (!Conn->Ipv6Flag) {\r
+      ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
     } else {\r
       ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
     }\r
@@ -391,10 +505,14 @@ IScsiSessionLogin (
                     (VOID **) &Tcp,\r
                     Session->Private->Image,\r
                     Session->Private->ExtScsiPassThruHandle,\r
-                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER                    \r
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
                     );\r
 \r
     ASSERT_EFI_ERROR (Status);\r
+\r
+    if (Conn->Ipv6Flag) {\r
+      Status = IScsiGetIp6NicInfo (Conn);\r
+    }\r
   }\r
 \r
   return Status;\r
@@ -494,7 +612,7 @@ IScsiSendLoginReq (
   Receive and process the iSCSI login response.\r
 \r
   @param[in]  Conn             The connection in the iSCSI login phase.\r
-  \r
+\r
   @retval EFI_SUCCESS          The iSCSI login response PDU is received and processed.\r
   @retval Others               Other errors as indicated.\r
 \r
@@ -507,6 +625,8 @@ IScsiReceiveLoginRsp (
   EFI_STATUS  Status;\r
   NET_BUF     *Pdu;\r
 \r
+  Pdu = NULL;\r
+\r
   //\r
   // Receive the iSCSI login response.\r
   //\r
@@ -514,6 +634,8 @@ IScsiReceiveLoginRsp (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+  ASSERT (Pdu != NULL);\r
+\r
   //\r
   // A Login Response is received; process it.\r
   //\r
@@ -539,6 +661,7 @@ IScsiReceiveLoginRsp (
                                the correspondence length fields are updated.\r
   @retval EFI_OUT_OF_RESOURCES There is not enough space in the PDU to add the key-value\r
                                pair.\r
+  @retval EFI_PROTOCOL_ERROR   There is no such data in the net buffer.\r
 **/\r
 EFI_STATUS\r
 IScsiAddKeyValuePair (\r
@@ -555,6 +678,9 @@ IScsiAddKeyValuePair (
   CHAR8               *Data;\r
 \r
   LoginReq    = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, NULL);\r
+  if (LoginReq == NULL) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
   DataSegLen  = NTOH24 (LoginReq->DataSegmentLength);\r
 \r
   KeyLen      = (UINT32) AsciiStrLen (Key);\r
@@ -626,7 +752,10 @@ IScsiPrepareLoginReq (
   }\r
 \r
   LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufAllocSpace (Nbuf, sizeof (ISCSI_LOGIN_REQUEST), NET_BUF_TAIL);\r
-  ASSERT (LoginReq != NULL);\r
+  if (LoginReq == NULL) {\r
+    NetbufFree (Nbuf);\r
+    return NULL;\r
+  }\r
   ZeroMem (LoginReq, sizeof (ISCSI_LOGIN_REQUEST));\r
 \r
   //\r
@@ -664,7 +793,7 @@ IScsiPrepareLoginReq (
   case ISCSI_SECURITY_NEGOTIATION:\r
     //\r
     // Both none authentication and CHAP authentication share the CHAP path.\r
-    // \r
+    //\r
     //\r
     if (Session->AuthType != ISCSI_AUTH_TYPE_KRB) {\r
       Status = IScsiCHAPToSendReq (Conn, Nbuf);\r
@@ -674,12 +803,12 @@ IScsiPrepareLoginReq (
 \r
   case ISCSI_LOGIN_OPERATIONAL_NEGOTIATION:\r
     //\r
-    // Only negotiate the paramter once.\r
+    // Only negotiate the parameter once.\r
     //\r
     if (!Conn->ParamNegotiated) {\r
       IScsiFillOpParams (Conn, Nbuf);\r
     }\r
-    \r
+\r
     ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
     break;\r
 \r
@@ -741,6 +870,9 @@ IScsiProcessLoginRsp (
   Session   = Conn->Session;\r
 \r
   LoginRsp  = (ISCSI_LOGIN_RESPONSE *) NetbufGetByte (Pdu, 0, NULL);\r
+  if (LoginRsp == NULL) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
   if (!ISCSI_CHECK_OPCODE (LoginRsp, ISCSI_OPCODE_LOGIN_RSP)) {\r
     //\r
     // It is not a Login Response.\r
@@ -832,7 +964,7 @@ IScsiProcessLoginRsp (
     // the value presented in CmdSN as the target value for ExpCmdSN.\r
     //\r
     if ((Session->State == SESSION_STATE_FREE) && (Session->CmdSN != LoginRsp->ExpCmdSN)) {\r
-      return EFI_PROTOCOL_ERROR;     \r
+      return EFI_PROTOCOL_ERROR;\r
     }\r
 \r
     //\r
@@ -940,7 +1072,7 @@ IScsiProcessLoginRsp (
   @param[in]      Data         The data segment that should contain the\r
                                TargetAddress key-value list.\r
   @param[in]      Len          Length of the data.\r
-  \r
+\r
   @retval EFI_SUCCESS          The target address is updated.\r
   @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
   @retval EFI_NOT_FOUND        The TargetAddress key is not found.\r
@@ -954,12 +1086,13 @@ IScsiUpdateTargetAddress (
   IN     UINT32                Len\r
   )\r
 {\r
-  LIST_ENTRY      *KeyValueList;\r
-  CHAR8           *TargetAddress;\r
-  CHAR8           *IpStr;\r
-  EFI_STATUS      Status;\r
-  UINTN           Number;\r
-  UINT8           IpMode;\r
+  LIST_ENTRY                   *KeyValueList;\r
+  CHAR8                        *TargetAddress;\r
+  CHAR8                        *IpStr;\r
+  EFI_STATUS                   Status;\r
+  UINTN                        Number;\r
+  UINT8                        IpMode;\r
+  ISCSI_SESSION_CONFIG_NVDATA  *NvData;\r
 \r
   KeyValueList = IScsiBuildKeyValueList (Data, Len);\r
   if (KeyValueList == NULL) {\r
@@ -967,6 +1100,7 @@ IScsiUpdateTargetAddress (
   }\r
 \r
   Status = EFI_NOT_FOUND;\r
+  NvData = &Session->ConfigData->SessionConfigData;\r
 \r
   while (TRUE) {\r
     TargetAddress = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_ADDRESS);\r
@@ -974,24 +1108,60 @@ IScsiUpdateTargetAddress (
       break;\r
     }\r
 \r
-    if (!NET_IS_DIGIT (TargetAddress[0])) {\r
+    //\r
+    // RFC 3720 defines format of the TargetAddress=domainname[:port][,portal-group-tag]\r
+    // The domainname can be specified as either a DNS host name, adotted-decimal IPv4 address,\r
+    // or a bracketed IPv6 address as specified in [RFC2732].\r
+    //\r
+    if (NET_IS_DIGIT (TargetAddress[0])) {\r
+      //\r
+      // The domainname of the target is presented in a dotted-decimal IPv4 address format.\r
+      //\r
+      IpStr = TargetAddress;\r
+\r
+      while ((*TargetAddress != '\0') && (*TargetAddress != ':') && (*TargetAddress != ',')) {\r
+        //\r
+        // NULL, ':', or ',' ends the IPv4 string.\r
+        //\r
+        TargetAddress++;\r
+      }\r
+    } else if (*TargetAddress == ISCSI_REDIRECT_ADDR_START_DELIMITER){\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
+      // The domainname of the target is presented in a bracketed IPv6 address format.\r
       //\r
-      continue;\r
-    }\r
+      TargetAddress ++;\r
+      IpStr = TargetAddress;\r
+      while ((*TargetAddress != '\0') && (*TargetAddress != ISCSI_REDIRECT_ADDR_END_DELIMITER)) {\r
+        //\r
+        // ']' ends the IPv6 string.\r
+        //\r
+        TargetAddress++;\r
+      }\r
+\r
+      if (*TargetAddress != ISCSI_REDIRECT_ADDR_END_DELIMITER) {\r
+        continue;\r
+      }\r
 \r
-    IpStr = TargetAddress;\r
+      *TargetAddress = '\0';\r
+      TargetAddress ++;\r
 \r
-    while ((*TargetAddress != 0) && (*TargetAddress != ':') && (*TargetAddress != ',')) {\r
+    } else {\r
       //\r
-      // NULL, ':', or ',' ends the IPv4 string.\r
+      // The domainname of the target is presented in the format of a DNS host name.\r
       //\r
-      TargetAddress++;\r
+      IpStr = TargetAddress;\r
+\r
+      while ((*TargetAddress != '\0') && (*TargetAddress != ':') && (*TargetAddress != ',')) {\r
+        TargetAddress++;\r
+      }\r
+      NvData->DnsMode = TRUE;\r
     }\r
 \r
+    //\r
+    // Save the origial user setting which specifies the proxy/virtual iSCSI target.\r
+    //\r
+    NvData->OriginalTargetPort = NvData->TargetPort;\r
+\r
     if (*TargetAddress == ',') {\r
       //\r
       // Comma and the portal group tag MUST be ommitted if the TargetAddress is sent\r
@@ -1007,33 +1177,51 @@ IScsiUpdateTargetAddress (
       if (Number > 0xFFFF) {\r
         continue;\r
       } else {\r
-        Session->ConfigData->SessionConfigData.TargetPort = (UINT16) Number;\r
+        NvData->TargetPort = (UINT16) Number;\r
       }\r
     } else {\r
       //\r
-      // The string only contains the IPv4 address. Use the well-known port.\r
+      // The string only contains the Target address. Use the well-known port.\r
       //\r
-      Session->ConfigData->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;\r
+      NvData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
     }\r
+\r
+    //\r
+    // Save the origial user setting which specifies the proxy/virtual iSCSI target.\r
+    //\r
+    CopyMem (&NvData->OriginalTargetIp, &NvData->TargetIp, sizeof (EFI_IP_ADDRESS));\r
+\r
     //\r
     // Update the target IP address.\r
     //\r
-    if (Session->ConfigData->SessionConfigData.IpMode < IP_MODE_AUTOCONFIG) {\r
-      IpMode = Session->ConfigData->SessionConfigData.IpMode;\r
+    if (NvData->IpMode < IP_MODE_AUTOCONFIG) {\r
+      IpMode = NvData->IpMode;\r
     } else {\r
       IpMode = Session->ConfigData->AutoConfigureMode;\r
     }\r
 \r
-    Status = IScsiAsciiStrToIp (\r
-               IpStr,\r
-               IpMode,\r
-               &Session->ConfigData->SessionConfigData.TargetIp\r
-               );\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      continue;\r
+    if (NvData->DnsMode) {\r
+      //\r
+      // Target address is expressed as URL format, just save it and\r
+      // do DNS resolution when creating a TCP connection.\r
+      //\r
+      if (AsciiStrSize (IpStr) > sizeof (Session->ConfigData->SessionConfigData.TargetUrl)){\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+      CopyMem (&Session->ConfigData->SessionConfigData.TargetUrl, IpStr, AsciiStrSize (IpStr));\r
     } else {\r
-      break;\r
+      Status = IScsiAsciiStrToIp (\r
+                 IpStr,\r
+                 IpMode,\r
+                 &Session->ConfigData->SessionConfigData.TargetIp\r
+                 );\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      } else {\r
+        NvData->RedirectFlag = TRUE;\r
+        break;\r
+      }\r
     }\r
   }\r
 \r
@@ -1137,7 +1325,10 @@ IScsiReceivePdu (
   }\r
 \r
   Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);\r
-  ASSERT (Header != NULL);\r
+  if (Header == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto ON_EXIT;\r
+  }\r
   InsertTailList (NbufList, &PduHdr->List);\r
 \r
   //\r
@@ -1174,7 +1365,7 @@ IScsiReceivePdu (
   switch (ISCSI_GET_OPCODE (Header)) {\r
   case ISCSI_OPCODE_SCSI_DATA_IN:\r
     //\r
-    // To reduce memory copy overhead, try to use the buffer described by Context \r
+    // To reduce memory copy overhead, try to use the buffer described by Context\r
     // if the PDU is an iSCSI SCSI data.\r
     //\r
     InDataOffset = ISCSI_GET_BUFFER_OFFSET (Header);\r
@@ -1282,7 +1473,7 @@ ON_EXIT:
 \r
 \r
 /**\r
-  Check and get the result of the prameter negotiation.\r
+  Check and get the result of the parameter negotiation.\r
 \r
   @param[in, out]  Conn          The connection in iSCSI login.\r
 \r
@@ -1522,7 +1713,7 @@ IScsiCheckOpParams (
   IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_ALIAS);\r
   IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
 \r
-  \r
+\r
   //\r
   // Remove the key-value that may not needed for result function is OR.\r
   //\r
@@ -1530,6 +1721,12 @@ IScsiCheckOpParams (
   IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_PDU_IN_ORDER);\r
   IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER);\r
 \r
+  //\r
+  // Remove irrelevant parameter, if any.\r
+  //\r
+  if (Session->InitialR2T && !Session->ImmediateData) {\r
+    IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_FIRST_BURST_LENGTH);\r
+  }\r
 \r
   if (IsListEmpty (KeyValueList)) {\r
     //\r
@@ -1549,7 +1746,7 @@ ON_ERROR:
 \r
 \r
 /**\r
-  Fill the oprational parameters.\r
+  Fill the operational parameters.\r
 \r
   @param[in]       Conn    The connection in iSCSI login.\r
   @param[in, out]  Pdu     The iSCSI login request PDU to fill the parameters.\r
@@ -1979,7 +2176,7 @@ IScsiNewDataSegment (
 \r
   @param[in]  Packet The EXT SCSI PASS THRU request packet containing the SCSI command.\r
   @param[in]  Lun    The LUN.\r
-  @param[in]  Tcb    The tcb assocated with this SCSI command.\r
+  @param[in]  Tcb    The tcb associated with this SCSI command.\r
 \r
   @return The  created iSCSI SCSI command PDU.\r
   @retval NULL Other errors as indicated.\r
@@ -2031,7 +2228,7 @@ IScsiNewScsiCmdPdu (
   if (ScsiCmd == NULL) {\r
     NetbufFree (PduHeader);\r
     return NULL;\r
-  }    \r
+  }\r
   Header  = (ISCSI_ADDITIONAL_HEADER *) (ScsiCmd + 1);\r
 \r
   ZeroMem (ScsiCmd, Length);\r
@@ -2202,7 +2399,10 @@ IScsiNewDataOutPdu (
   InsertTailList (NbufList, &PduHdr->List);\r
 \r
   DataOutHdr  = (ISCSI_SCSI_DATA_OUT *) NetbufAllocSpace (PduHdr, sizeof (ISCSI_SCSI_DATA_OUT), NET_BUF_TAIL);\r
-  ASSERT (DataOutHdr != NULL);\r
+  if (DataOutHdr == NULL) {\r
+    IScsiFreeNbufList (NbufList);\r
+    return NULL;\r
+  }\r
   XferContext = &Tcb->XferContext;\r
 \r
   ZeroMem (DataOutHdr, sizeof (ISCSI_SCSI_DATA_OUT));\r
@@ -2268,6 +2468,7 @@ IScsiGenerateDataOutPduSequence (
   NET_BUF             *DataOutPdu;\r
   ISCSI_CONNECTION    *Conn;\r
   ISCSI_XFER_CONTEXT  *XferContext;\r
+  UINT8               *DataOutPacket;\r
 \r
   PduList = AllocatePool (sizeof (LIST_ENTRY));\r
   if (PduList == NULL) {\r
@@ -2311,7 +2512,14 @@ IScsiGenerateDataOutPduSequence (
   //\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
+  DataOutPacket = NetbufGetByte (DataOutPdu, 0, NULL);\r
+  if (DataOutPacket == NULL) {\r
+    IScsiFreeNbufList (PduList);\r
+    PduList = NULL;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  ISCSI_SET_FLAG (DataOutPacket, ISCSI_BHS_FLAG_FINAL);\r
 \r
 ON_EXIT:\r
 \r
@@ -2396,6 +2604,9 @@ IScsiOnDataInRcvd (
   EFI_STATUS          Status;\r
 \r
   DataInHdr                   = (ISCSI_SCSI_DATA_IN *) NetbufGetByte (Pdu, 0, NULL);\r
+  if (DataInHdr == NULL) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
 \r
   DataInHdr->InitiatorTaskTag = NTOHL (DataInHdr->InitiatorTaskTag);\r
   DataInHdr->ExpCmdSN         = NTOHL (DataInHdr->ExpCmdSN);\r
@@ -2486,6 +2697,9 @@ IScsiOnR2TRcvd (
   UINT8                   *Data;\r
 \r
   R2THdr = (ISCSI_READY_TO_TRANSFER *) NetbufGetByte (Pdu, 0, NULL);\r
+  if (R2THdr == NULL) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
 \r
   R2THdr->InitiatorTaskTag = NTOHL (R2THdr->InitiatorTaskTag);\r
   R2THdr->TargetTransferTag = NTOHL (R2THdr->TargetTransferTag);\r
@@ -2551,6 +2765,9 @@ IScsiOnScsiRspRcvd (
   UINT32            DataSegLen;\r
 \r
   ScsiRspHdr                    = (SCSI_RESPONSE *) NetbufGetByte (Pdu, 0, NULL);\r
+  if (ScsiRspHdr == NULL) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
 \r
   ScsiRspHdr->InitiatorTaskTag  = NTOHL (ScsiRspHdr->InitiatorTaskTag);\r
   if (ScsiRspHdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) {\r
@@ -2613,6 +2830,9 @@ IScsiOnScsiRspRcvd (
   DataSegLen = ISCSI_GET_DATASEG_LEN (ScsiRspHdr);\r
   if (DataSegLen != 0) {\r
     SenseData               = (ISCSI_SENSE_DATA *) NetbufGetByte (Pdu, sizeof (SCSI_RESPONSE), NULL);\r
+    if (SenseData == NULL) {\r
+      return EFI_PROTOCOL_ERROR;\r
+    }\r
 \r
     SenseData->Length       = NTOHS (SenseData->Length);\r
 \r
@@ -2649,6 +2869,9 @@ IScsiOnNopInRcvd (
   EFI_STATUS    Status;\r
 \r
   NopInHdr            = (ISCSI_NOP_IN *) NetbufGetByte (Pdu, 0, NULL);\r
+  if (NopInHdr == NULL) {\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
 \r
   NopInHdr->StatSN    = NTOHL (NopInHdr->StatSN);\r
   NopInHdr->ExpCmdSN  = NTOHL (NopInHdr->ExpCmdSN);\r
@@ -2679,11 +2902,13 @@ IScsiOnNopInRcvd (
   @param[in]       Lun       The LUN.\r
   @param[in, out]  Packet    The request packet containing IO request, SCSI command\r
                              buffer and buffers to read/write.\r
-                             \r
-  @retval EFI_SUCCES           The SCSI command is executed and the result is updated to \r
+\r
+  @retval EFI_SUCCES           The SCSI command is executed and the result is updated to\r
                                the Packet.\r
   @retval EFI_DEVICE_ERROR     Session state was not as required.\r
   @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
+  @retval EFI_PROTOCOL_ERROR   There is no such data in the net buffer.\r
+  @retval EFI_NOT_READY        The target can not accept new commands.\r
   @retval Others               Other errors as indicated.\r
 \r
 **/\r
@@ -2716,7 +2941,8 @@ IScsiExecuteScsiCommand (
   Timeout       = 0;\r
 \r
   if (Session->State != SESSION_STATE_LOGGED_IN) {\r
-    return EFI_DEVICE_ERROR;\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto ON_EXIT;\r
   }\r
 \r
   Conn = NET_LIST_USER_STRUCT_S (\r
@@ -2745,6 +2971,11 @@ IScsiExecuteScsiCommand (
 \r
   XferContext         = &Tcb->XferContext;\r
   PduHdr              = NetbufGetByte (Pdu, 0, NULL);\r
+  if (PduHdr == NULL) {\r
+    Status = EFI_PROTOCOL_ERROR;\r
+    NetbufFree (Pdu);\r
+    goto ON_EXIT;\r
+  }\r
   XferContext->Offset = ISCSI_GET_DATASEG_LEN (PduHdr);\r
 \r
   //\r
@@ -2803,7 +3034,13 @@ IScsiExecuteScsiCommand (
       goto ON_EXIT;\r
     }\r
 \r
-    switch (ISCSI_GET_OPCODE (NetbufGetByte (Pdu, 0, NULL))) {\r
+    PduHdr = NetbufGetByte (Pdu, 0, NULL);\r
+    if (PduHdr == NULL) {\r
+      Status = EFI_PROTOCOL_ERROR;\r
+      NetbufFree (Pdu);\r
+      goto ON_EXIT;\r
+    }\r
+    switch (ISCSI_GET_OPCODE (PduHdr)) {\r
     case ISCSI_OPCODE_SCSI_DATA_IN:\r
       Status = IScsiOnDataInRcvd (Pdu, Tcb, Packet);\r
       break;\r
@@ -2850,15 +3087,6 @@ ON_EXIT:
     IScsiDelTcb (Tcb);\r
   }\r
 \r
-  if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
-    //\r
-    // Reinstate the session.\r
-    //\r
-    if (EFI_ERROR (IScsiSessionReinstatement (Session))) {\r
-      Status = EFI_DEVICE_ERROR;\r
-    }\r
-  }\r
-\r
   return Status;\r
 }\r
 \r
@@ -2879,7 +3107,7 @@ IScsiSessionReinstatement (
 {\r
   EFI_STATUS    Status;\r
 \r
-  ASSERT (Session->State == SESSION_STATE_LOGGED_IN);\r
+  ASSERT (Session->State != SESSION_STATE_FREE);\r
 \r
   //\r
   // Abort the session and re-init it.\r
@@ -2969,7 +3197,7 @@ IScsiSessionAbort (
     if (!Conn->Ipv6Flag) {\r
       ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
     } else {\r
-      ProtocolGuid = &gEfiTcp6ProtocolGuid;    \r
+      ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
     }\r
 \r
     gBS->CloseProtocol (\r