]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4If.c
BaseTools:Change the path of the file that Binary Cache
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4If.c
index 67116363331c0a272e09d47382dc6c203c0f61d4..44b8d9fc8faf64aeb736eb23e6adc366a908f3ce 100644 (file)
@@ -1,14 +1,8 @@
 /** @file\r
   Implement IP4 pesudo interface.\r
-  \r
-Copyright (c) 2005 - 2013, 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
-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
+Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -68,7 +62,7 @@ Ip4OnArpResolvedDpc (
   @param  Event             The Arp request event.\r
   @param  Context           The context of the callback, a point to the ARP\r
                             queue.\r
-                                \r
+\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -138,8 +132,9 @@ Ip4CancelFrameArp (
   @param[in]  CallBack          Call back function to execute if transmission\r
                                 finished.\r
   @param[in]  Context           Opaque parameter to the call back.\r
+  @param[in]  IpSb              The pointer to the IP4 service binding instance.\r
 \r
-  @retval   Token               The wrapped token if succeed \r
+  @retval   Token               The wrapped token if succeed\r
   @retval   NULL                The wrapped token if NULL\r
 \r
 **/\r
@@ -149,7 +144,8 @@ Ip4WrapLinkTxToken (
   IN IP4_PROTOCOL           *IpInstance     OPTIONAL,\r
   IN NET_BUF                *Packet,\r
   IN IP4_FRAME_CALLBACK     CallBack,\r
-  IN VOID                   *Context\r
+  IN VOID                   *Context,\r
+  IN IP4_SERVICE            *IpSb\r
   )\r
 {\r
   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;\r
@@ -170,6 +166,7 @@ Ip4WrapLinkTxToken (
 \r
   Token->Interface  = Interface;\r
   Token->IpInstance = IpInstance;\r
+  Token->IpSb       = IpSb;\r
   Token->CallBack   = CallBack;\r
   Token->Packet     = Packet;\r
   Token->Context    = Context;\r
@@ -423,12 +420,12 @@ Ip4CancelFrameArp (
   either queued on ARP queues or that have already been delivered to\r
   MNP and not yet recycled.\r
 \r
-  @param[in]  Interface         Interface to remove the frames from\r
+  @param[in]  Interface         Interface to remove the frames from.\r
   @param[in]  IoStatus          The transmit status returned to the frames'\r
-                                callback\r
+                                callback.\r
   @param[in]  FrameToCancel     Function to select the frame to cancel, NULL to\r
-                                select all\r
-  @param[in]  Context           Opaque parameters passed to FrameToCancel\r
+                                select all.\r
+  @param[in]  Context           Opaque parameters passed to FrameToCancel.\r
 \r
 **/\r
 VOID\r
@@ -476,10 +473,10 @@ Ip4CancelFrames (
   the interface is configured.\r
 \r
   @param[in]  Mnp               The shared MNP child of this IP4 service binding\r
-                                instance\r
+                                instance.\r
   @param[in]  Controller        The controller this IP4 service binding instance\r
                                 is installed. Most like the UNDI handle.\r
-  @param[in]  ImageHandle       This driver's image handle\r
+  @param[in]  ImageHandle       This driver's image handle.\r
 \r
   @return Point to the created IP4_INTERFACE, otherwise NULL.\r
 \r
@@ -542,9 +539,9 @@ Ip4CreateInterface (
   Set the interface's address, create and configure\r
   the ARP child if necessary.\r
 \r
-  @param  Interface         The interface to set the address\r
-  @param  IpAddr            The interface's IP address\r
-  @param  SubnetMask        The interface's netmask\r
+  @param  Interface         The interface to set the address.\r
+  @param  IpAddr            The interface's IP address.\r
+  @param  SubnetMask        The interface's netmask.\r
 \r
   @retval EFI_SUCCESS           The interface is configured with Ip/netmask pair,\r
                                 and a ARP is created for it.\r
@@ -560,14 +557,9 @@ Ip4SetAddress (
 {\r
   EFI_ARP_CONFIG_DATA       ArpConfig;\r
   EFI_STATUS                Status;\r
-  INTN                      Type;\r
-  INTN                      Len;\r
-  IP4_ADDR                  Netmask;\r
 \r
   NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);\r
 \r
-  ASSERT (!Interface->Configured);\r
-\r
   //\r
   // Set the ip/netmask, then compute the subnet broadcast\r
   // and network broadcast for easy access. When computing\r
@@ -579,19 +571,37 @@ Ip4SetAddress (
   Interface->Ip             = IpAddr;\r
   Interface->SubnetMask     = SubnetMask;\r
   Interface->SubnetBrdcast  = (IpAddr | ~SubnetMask);\r
+  Interface->NetBrdcast     = (IpAddr | ~SubnetMask);\r
+\r
+  //\r
+  // Do clean up for Arp child\r
+  //\r
+  if (Interface->ArpHandle != NULL) {\r
+    if (Interface->Arp != NULL) {\r
+      gBS->CloseProtocol (\r
+             Interface->ArpHandle,\r
+             &gEfiArpProtocolGuid,\r
+             Interface->Image,\r
+             Interface->Controller\r
+             );\r
+\r
+      Interface->Arp = NULL;\r
+    }\r
+\r
+    NetLibDestroyServiceChild (\r
+      Interface->Controller,\r
+      Interface->Image,\r
+      &gEfiArpServiceBindingProtocolGuid,\r
+      &Interface->ArpHandle\r
+      );\r
 \r
-  Type                      = NetGetIpClass (IpAddr);\r
-  Len                       = NetGetMaskLength (SubnetMask);\r
-  Netmask                   = gIp4AllMasks[MIN ((Len - 1), Type << 3)];\r
-  Interface->NetBrdcast     = (IpAddr | ~Netmask);\r
+    Interface->ArpHandle = NULL;\r
+  }\r
 \r
   //\r
   // If the address is NOT all zero, create then configure an ARP child.\r
   // Pay attention: DHCP configures its station address as 0.0.0.0/0\r
   //\r
-  Interface->Arp            = NULL;\r
-  Interface->ArpHandle      = NULL;\r
-\r
   if (IpAddr != IP4_ALLZERO_ADDRESS) {\r
     Status = NetLibCreateServiceChild (\r
                Interface->Controller,\r
@@ -601,7 +611,7 @@ Ip4SetAddress (
                );\r
 \r
     if (EFI_ERROR (Status)) {\r
-      return Status;;\r
+      return Status;\r
     }\r
 \r
     Status = gBS->OpenProtocol (\r
@@ -629,11 +639,11 @@ Ip4SetAddress (
 \r
     if (EFI_ERROR (Status)) {\r
       gBS->CloseProtocol (\r
-            Interface->ArpHandle,\r
-            &gEfiArpProtocolGuid,\r
-            Interface->Image,\r
-            Interface->Controller\r
-            );\r
+             Interface->ArpHandle,\r
+             &gEfiArpProtocolGuid,\r
+             Interface->Image,\r
+             Interface->Controller\r
+             );\r
 \r
       goto ON_ERROR;\r
     }\r
@@ -719,7 +729,7 @@ Ip4CancelReceive (
   Because the IpInstance is optional, the caller must remove\r
   IpInstance from the interface's instance list itself.\r
 \r
-  @param[in]  Interface         The interface used by the IpInstance\r
+  @param[in]  Interface         The interface used by the IpInstance.\r
   @param[in]  IpInstance        The Ip instance that free the interface. NULL if\r
                                 the Ip driver is releasing the default interface.\r
 \r
@@ -740,11 +750,24 @@ Ip4FreeInterface (
   //\r
   Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, IpInstance);\r
 \r
+  if (--Interface->RefCnt > 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   //\r
-  // Destroy the ARP instance if this is the last IP instance that\r
-  // has the address.\r
+  // Destroy the interface if this is the last IP instance that\r
+  // has the address. Remove all the system transmitted packets\r
+  // from this interface, cancel the receive request if there is\r
+  // one, and destroy the ARP requests.\r
   //\r
-  if (Interface->Arp != NULL && IsListEmpty (&Interface->IpInstances)) {\r
+  Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);\r
+  Ip4CancelReceive (Interface);\r
+\r
+  ASSERT (IsListEmpty (&Interface->IpInstances));\r
+  ASSERT (IsListEmpty (&Interface->ArpQues));\r
+  ASSERT (IsListEmpty (&Interface->SentFrames));\r
+\r
+  if (Interface->Arp != NULL) {\r
     gBS->CloseProtocol (\r
           Interface->ArpHandle,\r
           &gEfiArpProtocolGuid,\r
@@ -758,34 +781,97 @@ Ip4FreeInterface (
       &gEfiArpServiceBindingProtocolGuid,\r
       Interface->ArpHandle\r
       );\r
-    Interface->Arp = NULL;\r
-  }\r
-  \r
-  if (--Interface->RefCnt > 0) {\r
-    return EFI_SUCCESS;\r
   }\r
 \r
-  //\r
-  // Destroy the interface if it is not referenced by any IP instance (for common Interface)\r
-  // or the IP service (for the DefaultInterface). Remove all the system transmitted packets\r
-  // from this interface, cancel the receive request if there is one.\r
-  //\r
-  Ip4CancelFrames (Interface, EFI_ABORTED, Ip4CancelInstanceFrame, NULL);\r
-  Ip4CancelReceive (Interface);\r
-\r
-  ASSERT (IsListEmpty (&Interface->IpInstances));\r
-  ASSERT (IsListEmpty (&Interface->ArpQues));\r
-  ASSERT (IsListEmpty (&Interface->SentFrames));\r
-\r
   RemoveEntryList (&Interface->Link);\r
   FreePool (Interface);\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  This function tries to send all the queued frames in ArpQue to the default gateway if\r
+  the ARP resolve for direct destination address is failed when using /32 subnet mask.\r
+\r
+  @param[in]   ArpQue           The ARP queue of a failed request.\r
+\r
+  @retval EFI_SUCCESS           All the queued frames have been send to the default route.\r
+  @retval Others                Failed to send the queued frames.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4SendFrameToDefaultRoute (\r
+  IN  IP4_ARP_QUE               *ArpQue\r
+  )\r
+{\r
+  LIST_ENTRY                *Entry;\r
+  LIST_ENTRY                *Next;\r
+  IP4_ROUTE_CACHE_ENTRY     *RtCacheEntry;\r
+  IP4_LINK_TX_TOKEN         *Token;\r
+  IP4_ADDR                  Gateway;\r
+  EFI_STATUS                Status;\r
+  IP4_ROUTE_ENTRY           *DefaultRoute;\r
+\r
+  //\r
+  // ARP resolve failed when using /32 subnet mask.\r
+  //\r
+  NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {\r
+    RemoveEntryList (Entry);\r
+    Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);\r
+    ASSERT (Token->Interface->SubnetMask == IP4_ALLONE_ADDRESS);\r
+    //\r
+    // Find the default gateway IP address. The default route was saved to the RtCacheEntry->Tag in Ip4Route().\r
+    //\r
+    RtCacheEntry = NULL;\r
+    if (Token->IpInstance != NULL) {\r
+      RtCacheEntry = Ip4FindRouteCache (Token->IpInstance->RouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);\r
+    }\r
+    if (RtCacheEntry == NULL) {\r
+      RtCacheEntry = Ip4FindRouteCache (Token->IpSb->DefaultRouteTable, NTOHL (ArpQue->Ip), Token->Interface->Ip);\r
+    }\r
+    if (RtCacheEntry == NULL) {\r
+      Status= EFI_NO_MAPPING;\r
+      goto ON_ERROR;\r
+    }\r
+    DefaultRoute = (IP4_ROUTE_ENTRY*)RtCacheEntry->Tag;\r
+    if (DefaultRoute == NULL) {\r
+      Status= EFI_NO_MAPPING;\r
+      goto ON_ERROR;\r
+    }\r
+    //\r
+    // Try to send the frame to the default route.\r
+    //\r
+    Gateway = DefaultRoute->NextHop;\r
+    if (ArpQue->Ip == Gateway) {\r
+      //\r
+      // ARP resolve for the default route is failed, return error to caller.\r
+      //\r
+      Status= EFI_NO_MAPPING;\r
+      goto ON_ERROR;\r
+    }\r
+    RtCacheEntry->NextHop = Gateway;\r
+    Status = Ip4SendFrame (Token->Interface,Token->IpInstance,Token->Packet,Gateway,Token->CallBack,Token->Context,Token->IpSb);\r
+    if (EFI_ERROR (Status)) {\r
+      Status= EFI_NO_MAPPING;\r
+      goto ON_ERROR;\r
+    }\r
+    Ip4FreeRouteCacheEntry (RtCacheEntry);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ON_ERROR:\r
+  if (RtCacheEntry != NULL) {\r
+    Ip4FreeRouteCacheEntry (RtCacheEntry);\r
+  }\r
+  Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);\r
+  Ip4FreeLinkTxToken (Token);\r
+  return Status;\r
+}\r
+\r
 \r
 /**\r
-  Callback function when ARP request are finished. It will cancelled\r
+  Callback function when ARP request are finished. It will cancel\r
   all the queued frame if the ARP requests failed. Or transmit them\r
   if the request succeed.\r
 \r
@@ -805,6 +891,7 @@ Ip4OnArpResolvedDpc (
   IP4_INTERFACE             *Interface;\r
   IP4_LINK_TX_TOKEN         *Token;\r
   EFI_STATUS                Status;\r
+  EFI_STATUS                IoStatus;\r
 \r
   ArpQue = (IP4_ARP_QUE *) Context;\r
   NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);\r
@@ -812,14 +899,23 @@ Ip4OnArpResolvedDpc (
   RemoveEntryList (&ArpQue->Link);\r
 \r
   //\r
-  // ARP resolve failed for some reason. Release all the frame\r
-  // and ARP queue itself. Ip4FreeArpQue will call the frame's\r
-  // owner back.\r
+  // ARP resolve failed for some reason.\r
   //\r
   if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {\r
-    Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);\r
-\r
-    return ;\r
+    if (ArpQue->Interface->SubnetMask != IP4_ALLONE_ADDRESS) {\r
+      //\r
+      // Release all the frame and ARP queue itself. Ip4FreeArpQue will call the frame's\r
+      // owner back.\r
+      //\r
+      IoStatus = EFI_NO_MAPPING;\r
+    } else {\r
+      //\r
+      // ARP resolve failed when using 32bit subnet mask, try to send the packets to the\r
+      // default route.\r
+      //\r
+      IoStatus = Ip4SendFrameToDefaultRoute (ArpQue);\r
+    }\r
+    goto ON_EXIT;\r
   }\r
 \r
   //\r
@@ -827,6 +923,7 @@ Ip4OnArpResolvedDpc (
   // queue. It isn't necessary for us to cache the ARP binding because\r
   // we always check the ARP cache first before transmit.\r
   //\r
+  IoStatus = EFI_SUCCESS;\r
   Interface = ArpQue->Interface;\r
 \r
   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {\r
@@ -846,7 +943,7 @@ Ip4OnArpResolvedDpc (
 \r
     Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);\r
     if (EFI_ERROR (Status)) {\r
-      RemoveEntryList (Entry);\r
+      RemoveEntryList (&Token->Link);\r
       Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);\r
 \r
       Ip4FreeLinkTxToken (Token);\r
@@ -854,7 +951,8 @@ Ip4OnArpResolvedDpc (
     }\r
   }\r
 \r
-  Ip4FreeArpQue (ArpQue, EFI_SUCCESS);\r
+ON_EXIT:\r
+  Ip4FreeArpQue (ArpQue, IoStatus);\r
 }\r
 \r
 /**\r
@@ -863,7 +961,7 @@ Ip4OnArpResolvedDpc (
   @param  Event             The Arp request event.\r
   @param  Context           The context of the callback, a point to the ARP\r
                             queue.\r
-                                \r
+\r
 **/\r
 VOID\r
 EFIAPI\r
@@ -948,6 +1046,7 @@ Ip4OnFrameSent (
                                 to.\r
   @param[in]  CallBack          Function to call back when transmit finished.\r
   @param[in]  Context           Opaque parameter to the call back.\r
+  @param[in]  IpSb              The pointer to the IP4 service binding instance.\r
 \r
   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to send the frame\r
   @retval EFI_NO_MAPPING        Can't resolve the MAC for the nexthop\r
@@ -962,7 +1061,8 @@ Ip4SendFrame (
   IN  NET_BUF               *Packet,\r
   IN  IP4_ADDR              NextHop,\r
   IN  IP4_FRAME_CALLBACK    CallBack,\r
-  IN  VOID                  *Context\r
+  IN  VOID                  *Context,\r
+  IN IP4_SERVICE            *IpSb\r
   )\r
 {\r
   IP4_LINK_TX_TOKEN         *Token;\r
@@ -973,7 +1073,7 @@ Ip4SendFrame (
 \r
   ASSERT (Interface->Configured);\r
 \r
-  Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);\r
+  Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context, IpSb);\r
 \r
   if (Token == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
@@ -1072,7 +1172,7 @@ SEND_NOW:
   InsertTailList (&Interface->SentFrames, &Token->Link);\r
   Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);\r
   if (EFI_ERROR (Status)) {\r
-    RemoveEntryList (&Interface->SentFrames);\r
+    RemoveEntryList (&Token->Link);\r
     goto ON_ERROR;\r
   }\r
 \r
@@ -1199,14 +1299,14 @@ Ip4OnFrameReceived (
 /**\r
   Request to receive the packet from the interface.\r
 \r
-  @param[in]  Interface         The interface to receive the frames from\r
+  @param[in]  Interface         The interface to receive the frames from.\r
   @param[in]  IpInstance        The instance that requests the receive. NULL for\r
                                 the driver itself.\r
   @param[in]  CallBack          Function to call when receive finished.\r
-  @param[in]  Context           Opaque parameter to the callback\r
+  @param[in]  Context           Opaque parameter to the callback.\r
 \r
   @retval EFI_ALREADY_STARTED   There is already a pending receive request.\r
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to receive.\r
   @retval EFI_SUCCESS           The recieve request has been started.\r
   @retval other                 Other error occurs.\r
 \r