]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/IScsiDxe/IScsiProto.c
NetworkPkg: Bug fix of iSCSI to support MPIO
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiProto.c
index 72c90a7fe8c997550a639318810964e187b8b1eb..4c4e3c28e7b17e8eead28ea2f18c6c25e552630c 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The implementation of iSCSI protocol based on RFC3720.\r
 \r
-Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2014, 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
@@ -228,7 +228,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
@@ -259,15 +259,16 @@ IScsiCreateConnection (
     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
     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 +309,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
@@ -379,7 +472,7 @@ IScsiSessionLogin (
   if (!EFI_ERROR (Status)) {\r
     Session->State = SESSION_STATE_LOGGED_IN;\r
 \r
-    if (!mPrivate->Ipv6Flag) {\r
+    if (!Conn->Ipv6Flag) {\r
       ProtocolGuid = &gEfiTcp4ProtocolGuid;      \r
     } else {\r
       ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
@@ -395,6 +488,10 @@ IScsiSessionLogin (
                     );\r
 \r
     ASSERT_EFI_ERROR (Status);\r
+\r
+    if (Conn->Ipv6Flag) {\r
+      Status = IScsiGetIp6NicInfo (Conn);\r
+    }\r
   }\r
 \r
   return Status;\r
@@ -507,6 +604,8 @@ IScsiReceiveLoginRsp (
   EFI_STATUS  Status;\r
   NET_BUF     *Pdu;\r
 \r
+  Pdu = NULL;\r
+\r
   //\r
   // Receive the iSCSI login response.\r
   //\r
@@ -2723,6 +2822,7 @@ IScsiOnNopInRcvd (
   @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
@@ -2755,7 +2855,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
@@ -2900,15 +3001,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
@@ -2929,7 +3021,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