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