2. Remove the GetTime() call when receiving Udp4/6 packets. Signed-off-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye, Ting <ting.ye@intel.com> Reviewed-by: Wu, Jiaxin <jiaxin.wu@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15497 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1007 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1007 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  The driver binding and service binding protocol for the TCP driver.
 | 
						|
 | 
						|
  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  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.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "TcpMain.h"
 | 
						|
 | 
						|
UINT16                        mTcp4RandomPort;
 | 
						|
UINT16                        mTcp6RandomPort;
 | 
						|
 | 
						|
TCP_HEARTBEAT_TIMER           mTcpTimer = {
 | 
						|
  NULL,
 | 
						|
  0
 | 
						|
};
 | 
						|
 | 
						|
EFI_TCP4_PROTOCOL             gTcp4ProtocolTemplate = {
 | 
						|
  Tcp4GetModeData,
 | 
						|
  Tcp4Configure,
 | 
						|
  Tcp4Routes,
 | 
						|
  Tcp4Connect,
 | 
						|
  Tcp4Accept,
 | 
						|
  Tcp4Transmit,
 | 
						|
  Tcp4Receive,
 | 
						|
  Tcp4Close,
 | 
						|
  Tcp4Cancel,
 | 
						|
  Tcp4Poll
 | 
						|
};
 | 
						|
 | 
						|
EFI_TCP6_PROTOCOL             gTcp6ProtocolTemplate = {
 | 
						|
  Tcp6GetModeData,
 | 
						|
  Tcp6Configure,
 | 
						|
  Tcp6Connect,
 | 
						|
  Tcp6Accept,
 | 
						|
  Tcp6Transmit,
 | 
						|
  Tcp6Receive,
 | 
						|
  Tcp6Close,
 | 
						|
  Tcp6Cancel,
 | 
						|
  Tcp6Poll
 | 
						|
};
 | 
						|
 | 
						|
SOCK_INIT_DATA                mTcpDefaultSockData = {
 | 
						|
  SockStream,
 | 
						|
  SO_CLOSED,
 | 
						|
  NULL,
 | 
						|
  TCP_BACKLOG,
 | 
						|
  TCP_SND_BUF_SIZE,
 | 
						|
  TCP_RCV_BUF_SIZE,
 | 
						|
  IP_VERSION_4,
 | 
						|
  NULL,
 | 
						|
  TcpCreateSocketCallback,
 | 
						|
  TcpDestroySocketCallback,
 | 
						|
  NULL,
 | 
						|
  NULL,
 | 
						|
  0,
 | 
						|
  TcpDispatcher,
 | 
						|
  NULL,
 | 
						|
};
 | 
						|
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL   gTcp4DriverBinding = {
 | 
						|
  Tcp4DriverBindingSupported,
 | 
						|
  Tcp4DriverBindingStart,
 | 
						|
  Tcp4DriverBindingStop,
 | 
						|
  0xa,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
EFI_DRIVER_BINDING_PROTOCOL   gTcp6DriverBinding = {
 | 
						|
  Tcp6DriverBindingSupported,
 | 
						|
  Tcp6DriverBindingStart,
 | 
						|
  Tcp6DriverBindingStop,
 | 
						|
  0xa,
 | 
						|
  NULL,
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
EFI_SERVICE_BINDING_PROTOCOL  gTcpServiceBinding = {
 | 
						|
  TcpServiceBindingCreateChild,
 | 
						|
  TcpServiceBindingDestroyChild
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Create and start the heartbeat timer for the TCP driver.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The timer was successfully created and started.
 | 
						|
  @retval other                  The timer was not created.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TcpCreateTimer (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (mTcpTimer.RefCnt == 0) {
 | 
						|
 | 
						|
    Status = gBS->CreateEvent (
 | 
						|
                    EVT_TIMER | EVT_NOTIFY_SIGNAL,
 | 
						|
                    TPL_NOTIFY,
 | 
						|
                    TcpTicking,
 | 
						|
                    NULL,
 | 
						|
                    &mTcpTimer.TimerEvent
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
 | 
						|
      Status = gBS->SetTimer (
 | 
						|
                      mTcpTimer.TimerEvent,
 | 
						|
                      TimerPeriodic,
 | 
						|
                      (UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)
 | 
						|
                      );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
 | 
						|
    mTcpTimer.RefCnt++;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Stop and destroy the heartbeat timer for TCP driver.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpDestroyTimer (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (mTcpTimer.RefCnt > 0);
 | 
						|
 | 
						|
  mTcpTimer.RefCnt--;
 | 
						|
 | 
						|
  if (mTcpTimer.RefCnt > 0) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->SetTimer (mTcpTimer.TimerEvent, TimerCancel, 0);
 | 
						|
  gBS->CloseEvent (mTcpTimer.TimerEvent);
 | 
						|
  mTcpTimer.TimerEvent = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The entry point for Tcp driver, which is used to install Tcp driver on the ImageHandle.
 | 
						|
 | 
						|
  @param[in]  ImageHandle   The firmware allocated handle for this driver image.
 | 
						|
  @param[in]  SystemTable   Pointer to the EFI system table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The driver loaded.
 | 
						|
  @retval other         The driver did not load.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpDriverEntryPoint (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      Seed;
 | 
						|
 | 
						|
  //
 | 
						|
  // Install the TCP Driver Binding Protocol
 | 
						|
  //
 | 
						|
  Status = EfiLibInstallDriverBindingComponentName2 (
 | 
						|
             ImageHandle,
 | 
						|
             SystemTable,
 | 
						|
             &gTcp4DriverBinding,
 | 
						|
             ImageHandle,
 | 
						|
             &gTcpComponentName,
 | 
						|
             &gTcpComponentName2
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Install the TCP Driver Binding Protocol
 | 
						|
  //
 | 
						|
  Status = EfiLibInstallDriverBindingComponentName2 (
 | 
						|
             ImageHandle,
 | 
						|
             SystemTable,
 | 
						|
             &gTcp6DriverBinding,
 | 
						|
             NULL,
 | 
						|
             &gTcpComponentName,
 | 
						|
             &gTcpComponentName2
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->UninstallMultipleProtocolInterfaces (
 | 
						|
           ImageHandle,
 | 
						|
           &gEfiDriverBindingProtocolGuid,
 | 
						|
           &gTcp4DriverBinding,
 | 
						|
           &gEfiComponentName2ProtocolGuid,
 | 
						|
           &gTcpComponentName2,
 | 
						|
           &gEfiComponentNameProtocolGuid,
 | 
						|
           &gTcpComponentName,
 | 
						|
           NULL
 | 
						|
           );
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize ISS and random port.
 | 
						|
  //
 | 
						|
  Seed            = NetRandomInitSeed ();
 | 
						|
  mTcpGlobalIss   = NET_RANDOM (Seed) % mTcpGlobalIss;
 | 
						|
  mTcp4RandomPort = (UINT16) (TCP_PORT_KNOWN + (NET_RANDOM (Seed) % TCP_PORT_KNOWN));
 | 
						|
  mTcp6RandomPort = mTcp4RandomPort;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create a new TCP4 or TCP6 driver service binding protocol
 | 
						|
 | 
						|
  @param[in]  Controller         Controller handle of device to bind driver to.
 | 
						|
  @param[in]  Image              The TCP driver's image handle.
 | 
						|
  @param[in]  IpVersion          IP_VERSION_4 or IP_VERSION_6.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.
 | 
						|
  @retval EFI_SUCCESS            A new IP6 service binding private was created.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TcpCreateService (
 | 
						|
  IN EFI_HANDLE  Controller,
 | 
						|
  IN EFI_HANDLE  Image,
 | 
						|
  IN UINT8       IpVersion
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  EFI_GUID           *IpServiceBindingGuid;
 | 
						|
  EFI_GUID           *TcpServiceBindingGuid;
 | 
						|
  TCP_SERVICE_DATA   *TcpServiceData;
 | 
						|
  IP_IO_OPEN_DATA    OpenData;
 | 
						|
 | 
						|
  if (IpVersion == IP_VERSION_4) {
 | 
						|
    IpServiceBindingGuid  = &gEfiIp4ServiceBindingProtocolGuid;
 | 
						|
    TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
 | 
						|
  } else {
 | 
						|
    IpServiceBindingGuid  = &gEfiIp6ServiceBindingProtocolGuid;
 | 
						|
    TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  TcpServiceBindingGuid,
 | 
						|
                  NULL,
 | 
						|
                  Image,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    return EFI_ALREADY_STARTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Controller,
 | 
						|
                  IpServiceBindingGuid,
 | 
						|
                  NULL,
 | 
						|
                  Image,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create the TCP service data.
 | 
						|
  //
 | 
						|
  TcpServiceData = AllocateZeroPool (sizeof (TCP_SERVICE_DATA));
 | 
						|
  if (TcpServiceData == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpServiceData->Signature            = TCP_DRIVER_SIGNATURE;
 | 
						|
  TcpServiceData->ControllerHandle     = Controller;
 | 
						|
  TcpServiceData->DriverBindingHandle  = Image;
 | 
						|
  TcpServiceData->IpVersion            = IpVersion;
 | 
						|
  CopyMem (
 | 
						|
    &TcpServiceData->ServiceBinding,
 | 
						|
    &gTcpServiceBinding,
 | 
						|
    sizeof (EFI_SERVICE_BINDING_PROTOCOL)
 | 
						|
    );
 | 
						|
 | 
						|
  TcpServiceData->IpIo = IpIoCreate (Image, Controller, IpVersion);
 | 
						|
  if (TcpServiceData->IpIo == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  InitializeListHead (&TcpServiceData->SocketList);
 | 
						|
  ZeroMem (&OpenData, sizeof (IP_IO_OPEN_DATA));
 | 
						|
 | 
						|
  if (IpVersion == IP_VERSION_4) {
 | 
						|
    CopyMem (
 | 
						|
      &OpenData.IpConfigData.Ip4CfgData,
 | 
						|
      &mIp4IoDefaultIpConfigData,
 | 
						|
      sizeof (EFI_IP4_CONFIG_DATA)
 | 
						|
      );
 | 
						|
    OpenData.IpConfigData.Ip4CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
 | 
						|
  } else {
 | 
						|
    CopyMem (
 | 
						|
      &OpenData.IpConfigData.Ip6CfgData,
 | 
						|
      &mIp6IoDefaultIpConfigData,
 | 
						|
      sizeof (EFI_IP6_CONFIG_DATA)
 | 
						|
      );
 | 
						|
    OpenData.IpConfigData.Ip6CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
 | 
						|
  }
 | 
						|
 | 
						|
  OpenData.PktRcvdNotify  = TcpRxCallback;
 | 
						|
  Status                  = IpIoOpen (TcpServiceData->IpIo, &OpenData);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = TcpCreateTimer ();
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &Controller,
 | 
						|
                  TcpServiceBindingGuid,
 | 
						|
                  &TcpServiceData->ServiceBinding,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    TcpDestroyTimer ();
 | 
						|
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
 | 
						|
  if (TcpServiceData->IpIo != NULL) {
 | 
						|
    IpIoDestroy (TcpServiceData->IpIo);
 | 
						|
    TcpServiceData->IpIo = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (TcpServiceData);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Callback function which provided by user to remove one node in NetDestroyLinkList process.
 | 
						|
  
 | 
						|
  @param[in]    Entry           The entry to be removed.
 | 
						|
  @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The entry has been removed successfully.
 | 
						|
  @retval Others                Fail to remove the entry.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpDestroyChildEntryInHandleBuffer (
 | 
						|
  IN LIST_ENTRY         *Entry,
 | 
						|
  IN VOID               *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  SOCKET                        *Sock;
 | 
						|
  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
 | 
						|
  UINTN                         NumberOfChildren;
 | 
						|
  EFI_HANDLE                    *ChildHandleBuffer;
 | 
						|
 | 
						|
  if (Entry == NULL || Context == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Sock = NET_LIST_USER_STRUCT_S (Entry, SOCKET, Link, SOCK_SIGNATURE);
 | 
						|
  ServiceBinding    = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
 | 
						|
  NumberOfChildren  = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
 | 
						|
  ChildHandleBuffer = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
 | 
						|
 | 
						|
  if (!NetIsInHandleBuffer (Sock->SockHandle, NumberOfChildren, ChildHandleBuffer)) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return ServiceBinding->DestroyChild (ServiceBinding, Sock->SockHandle);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Destroy a TCP6 or TCP4 service binding instance. It will release all
 | 
						|
  the resources allocated by the instance.
 | 
						|
 | 
						|
  @param[in]  Controller         Controller handle of device to bind driver to.
 | 
						|
  @param[in]  ImageHandle        The TCP driver's image handle.
 | 
						|
  @param[in]  NumberOfChildren   Number of Handles in ChildHandleBuffer. If number
 | 
						|
                                 of children is zero stop the entire bus driver.
 | 
						|
  @param[in]  ChildHandleBuffer  An array of child handles to be freed. May be NULL
 | 
						|
                                 if NumberOfChildren is 0.  
 | 
						|
  @param[in]  IpVersion          IP_VERSION_4 or IP_VERSION_6
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The resources used by the instance were cleaned up.
 | 
						|
  @retval Others                 Failed to clean up some of the resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TcpDestroyService (
 | 
						|
  IN EFI_HANDLE  Controller,
 | 
						|
  IN EFI_HANDLE  ImageHandle,
 | 
						|
  IN UINTN       NumberOfChildren,
 | 
						|
  IN EFI_HANDLE  *ChildHandleBuffer, OPTIONAL
 | 
						|
  IN UINT8       IpVersion
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HANDLE                    NicHandle;
 | 
						|
  EFI_GUID                      *IpProtocolGuid;
 | 
						|
  EFI_GUID                      *ServiceBindingGuid;
 | 
						|
  EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
 | 
						|
  TCP_SERVICE_DATA              *TcpServiceData;
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  LIST_ENTRY                    *List;
 | 
						|
  TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT  Context;
 | 
						|
 | 
						|
  ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
 | 
						|
 | 
						|
  if (IpVersion == IP_VERSION_4) {
 | 
						|
    IpProtocolGuid     = &gEfiIp4ProtocolGuid;
 | 
						|
    ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
 | 
						|
  } else {
 | 
						|
    IpProtocolGuid     = &gEfiIp6ProtocolGuid;
 | 
						|
    ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
 | 
						|
  }
 | 
						|
 | 
						|
  NicHandle = NetLibGetNicHandle (Controller, IpProtocolGuid);
 | 
						|
  if (NicHandle == NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  NicHandle,
 | 
						|
                  ServiceBindingGuid,
 | 
						|
                  (VOID **) &ServiceBinding,
 | 
						|
                  ImageHandle,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpServiceData = TCP_SERVICE_FROM_THIS (ServiceBinding);
 | 
						|
 | 
						|
  if (NumberOfChildren != 0) {
 | 
						|
    List = &TcpServiceData->SocketList;
 | 
						|
    Context.ServiceBinding = ServiceBinding;
 | 
						|
    Context.NumberOfChildren = NumberOfChildren;
 | 
						|
    Context.ChildHandleBuffer = ChildHandleBuffer;
 | 
						|
    Status = NetDestroyLinkList (
 | 
						|
               List,
 | 
						|
               TcpDestroyChildEntryInHandleBuffer,
 | 
						|
               &Context,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
  } else if (IsListEmpty (&TcpServiceData->SocketList)) {
 | 
						|
    //
 | 
						|
    // Uninstall TCP servicebinding protocol
 | 
						|
    //
 | 
						|
    gBS->UninstallMultipleProtocolInterfaces (
 | 
						|
           NicHandle,
 | 
						|
           ServiceBindingGuid,
 | 
						|
           ServiceBinding,
 | 
						|
           NULL
 | 
						|
           );
 | 
						|
 | 
						|
    //
 | 
						|
    // Destroy the IpIO consumed by TCP driver
 | 
						|
    //
 | 
						|
    IpIoDestroy (TcpServiceData->IpIo);
 | 
						|
    TcpServiceData->IpIo = NULL;
 | 
						|
 | 
						|
    //
 | 
						|
    // Destroy the heartbeat timer.
 | 
						|
    //
 | 
						|
    TcpDestroyTimer ();
 | 
						|
 | 
						|
    //
 | 
						|
    // Release the TCP service data
 | 
						|
    //
 | 
						|
    FreePool (TcpServiceData);
 | 
						|
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Test to see if this driver supports ControllerHandle.
 | 
						|
 | 
						|
  @param[in]  This                Protocol instance pointer.
 | 
						|
  @param[in]  ControllerHandle    Handle of device to test.
 | 
						|
  @param[in]  RemainingDevicePath Optional parameter use to pick a specific
 | 
						|
                                  child device to start.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             This driver supports this device.
 | 
						|
  @retval EFI_ALREADY_STARTED     This driver is already running on this device.
 | 
						|
  @retval other                   This driver does not support this device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Tcp4DriverBindingSupported (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Test for the Tcp4ServiceBinding Protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiTcp4ServiceBindingProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    return EFI_ALREADY_STARTED;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Test for the Ip4ServiceBinding Protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiIp4ServiceBindingProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Start this driver on ControllerHandle.
 | 
						|
 | 
						|
  @param[in]  This                   Protocol instance pointer.
 | 
						|
  @param[in]  ControllerHandle       Handle of device to bind driver to.
 | 
						|
  @param[in]  RemainingDevicePath    Optional parameter use to pick a specific child
 | 
						|
                                     device to start.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The driver is added to ControllerHandle.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   There are not enough resources to start the
 | 
						|
                                 driver.
 | 
						|
  @retval other                  The driver cannot be added to ControllerHandle.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Tcp4DriverBindingStart (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4);
 | 
						|
  if ((Status == EFI_ALREADY_STARTED) || (Status == EFI_UNSUPPORTED)) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Stop this driver on ControllerHandle.
 | 
						|
 | 
						|
  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
 | 
						|
  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
 | 
						|
                                support a bus specific I/O protocol for the driver
 | 
						|
                                to use to stop the device.
 | 
						|
  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
 | 
						|
  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
 | 
						|
                                if NumberOfChildren is 0.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The device was stopped.
 | 
						|
  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Tcp4DriverBindingStop (
 | 
						|
  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN  EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN  UINTN                        NumberOfChildren,
 | 
						|
  IN  EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  return TcpDestroyService (
 | 
						|
           ControllerHandle,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           NumberOfChildren,
 | 
						|
           ChildHandleBuffer,
 | 
						|
           IP_VERSION_4
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Test to see if this driver supports ControllerHandle.
 | 
						|
 | 
						|
  @param[in]  This                Protocol instance pointer.
 | 
						|
  @param[in]  ControllerHandle    Handle of device to test.
 | 
						|
  @param[in]  RemainingDevicePath Optional parameter use to pick a specific
 | 
						|
                                  child device to start.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             This driver supports this device.
 | 
						|
  @retval EFI_ALREADY_STARTED     This driver is already running on this device.
 | 
						|
  @retval other                   This driver does not support this device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Tcp6DriverBindingSupported (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Test for the Tcp6ServiceBinding Protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiTcp6ServiceBindingProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    return EFI_ALREADY_STARTED;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Test for the Ip6ServiceBinding Protocol
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiIp6ServiceBindingProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                  );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Start this driver on ControllerHandle.
 | 
						|
 | 
						|
  @param[in]  This                   Protocol instance pointer.
 | 
						|
  @param[in]  ControllerHandle       Handle of device to bind driver to.
 | 
						|
  @param[in]  RemainingDevicePath    Optional parameter use to pick a specific child
 | 
						|
                                     device to start.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The driver is added to ControllerHandle.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   There are not enough resources to start the
 | 
						|
                                 driver.
 | 
						|
  @retval other                  The driver cannot be added to ControllerHandle.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Tcp6DriverBindingStart (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6);
 | 
						|
  if ((Status == EFI_ALREADY_STARTED) || (Status == EFI_UNSUPPORTED)) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Stop this driver on ControllerHandle.
 | 
						|
 | 
						|
  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
 | 
						|
  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
 | 
						|
                                support a bus specific I/O protocol for the driver
 | 
						|
                                to use to stop the device.
 | 
						|
  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
 | 
						|
  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
 | 
						|
                                if NumberOfChildren is 0.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The device was stopped.
 | 
						|
  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
Tcp6DriverBindingStop (
 | 
						|
  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN  EFI_HANDLE                   ControllerHandle,
 | 
						|
  IN  UINTN                        NumberOfChildren,
 | 
						|
  IN  EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  return TcpDestroyService (
 | 
						|
           ControllerHandle,
 | 
						|
           This->DriverBindingHandle,
 | 
						|
           NumberOfChildren,
 | 
						|
           ChildHandleBuffer,
 | 
						|
           IP_VERSION_6
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The Callback funtion called after the TCP socket was created.
 | 
						|
 | 
						|
  @param[in]  This            Pointer to the socket just created
 | 
						|
  @param[in]  Context         Context of the socket
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         This protocol installed successfully.
 | 
						|
  @retval other               An error occured.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TcpCreateSocketCallback (
 | 
						|
  IN SOCKET  *This,
 | 
						|
  IN VOID    *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  TCP_SERVICE_DATA  *TcpServiceData;
 | 
						|
  EFI_GUID          *IpProtocolGuid;
 | 
						|
  VOID              *Ip;
 | 
						|
 | 
						|
  if (This->IpVersion == IP_VERSION_4) {
 | 
						|
    IpProtocolGuid = &gEfiIp4ProtocolGuid;
 | 
						|
  } else {
 | 
						|
    IpProtocolGuid = &gEfiIp6ProtocolGuid;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
 | 
						|
 | 
						|
  //
 | 
						|
  // Open the default IP protocol of IP_IO BY_DRIVER.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  TcpServiceData->IpIo->ChildHandle,
 | 
						|
                  IpProtocolGuid,
 | 
						|
                  &Ip,
 | 
						|
                  TcpServiceData->DriverBindingHandle,
 | 
						|
                  This->SockHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Open the device path on the handle where service binding resides on.
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  TcpServiceData->ControllerHandle,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **) &This->ParentDevicePath,
 | 
						|
                  TcpServiceData->DriverBindingHandle,
 | 
						|
                  This->SockHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           TcpServiceData->IpIo->ChildHandle,
 | 
						|
           IpProtocolGuid,
 | 
						|
           TcpServiceData->DriverBindingHandle,
 | 
						|
           This->SockHandle
 | 
						|
           );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Insert this socket into the SocketList.
 | 
						|
    //
 | 
						|
    InsertTailList (&TcpServiceData->SocketList, &This->Link);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The callback function called before the TCP socket was to be destroyed.
 | 
						|
 | 
						|
  @param[in]  This                   The TCP socket to be destroyed.
 | 
						|
  @param[in]  Context                The context of the socket.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
TcpDestroySocketCallback (
 | 
						|
  IN SOCKET  *This,
 | 
						|
  IN VOID    *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  TCP_SERVICE_DATA  *TcpServiceData;
 | 
						|
  EFI_GUID          *IpProtocolGuid;
 | 
						|
 | 
						|
  if (This->IpVersion == IP_VERSION_4) {
 | 
						|
    IpProtocolGuid = &gEfiIp4ProtocolGuid;
 | 
						|
  } else {
 | 
						|
    IpProtocolGuid = &gEfiIp6ProtocolGuid;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
 | 
						|
 | 
						|
  //
 | 
						|
  // Remove this node from the list.
 | 
						|
  //
 | 
						|
  RemoveEntryList (&This->Link);
 | 
						|
 | 
						|
  //
 | 
						|
  // Close the IP protocol.
 | 
						|
  //
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         TcpServiceData->IpIo->ChildHandle,
 | 
						|
         IpProtocolGuid,
 | 
						|
         TcpServiceData->DriverBindingHandle,
 | 
						|
         This->SockHandle
 | 
						|
         );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Creates a child handle with a set of TCP services.
 | 
						|
 | 
						|
  The CreateChild() function installs a protocol on ChildHandle.
 | 
						|
  If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
 | 
						|
  If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
 | 
						|
 | 
						|
  @param[in]      This          Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
 | 
						|
  @param[in, out] ChildHandle   Pointer to the handle of the child to create.
 | 
						|
                                If it is NULL, then a new handle is created.
 | 
						|
                                If it is a pointer to an existing UEFI handle,
 | 
						|
                                then the protocol is added to the existing UEFI handle.
 | 
						|
 | 
						|
  @retval EFI_SUCCES            The protocol was added to ChildHandle.
 | 
						|
  @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  There are not enough resources availabe to create
 | 
						|
                                the child.
 | 
						|
  @retval other                 The child handle was not created.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpServiceBindingCreateChild (
 | 
						|
  IN     EFI_SERVICE_BINDING_PROTOCOL  *This,
 | 
						|
  IN OUT EFI_HANDLE                    *ChildHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  SOCKET            *Sock;
 | 
						|
  TCP_SERVICE_DATA  *TcpServiceData;
 | 
						|
  TCP_PROTO_DATA    TcpProto;
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  EFI_TPL           OldTpl;
 | 
						|
 | 
						|
  if (NULL == This || NULL == ChildHandle) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | 
						|
 | 
						|
  Status              = EFI_SUCCESS;
 | 
						|
  TcpServiceData      = TCP_SERVICE_FROM_THIS (This);
 | 
						|
  TcpProto.TcpService = TcpServiceData;
 | 
						|
  TcpProto.TcpPcb     = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create a tcp instance with defualt Tcp default
 | 
						|
  // sock init data and TcpProto
 | 
						|
  //
 | 
						|
  mTcpDefaultSockData.ProtoData     = &TcpProto;
 | 
						|
  mTcpDefaultSockData.DataSize      = sizeof (TCP_PROTO_DATA);
 | 
						|
  mTcpDefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;
 | 
						|
  mTcpDefaultSockData.IpVersion     = TcpServiceData->IpVersion;
 | 
						|
 | 
						|
  if (TcpServiceData->IpVersion == IP_VERSION_4) {
 | 
						|
    mTcpDefaultSockData.Protocol = &gTcp4ProtocolTemplate;
 | 
						|
  } else {
 | 
						|
    mTcpDefaultSockData.Protocol = &gTcp6ProtocolTemplate;
 | 
						|
  }
 | 
						|
 | 
						|
  Sock = SockCreateChild (&mTcpDefaultSockData);
 | 
						|
  if (NULL == Sock) {
 | 
						|
    DEBUG (
 | 
						|
      (EFI_D_ERROR,
 | 
						|
      "TcpDriverBindingCreateChild: No resource to create a Tcp Child\n")
 | 
						|
      );
 | 
						|
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
  } else {
 | 
						|
    *ChildHandle = Sock->SockHandle;
 | 
						|
  }
 | 
						|
 | 
						|
  mTcpDefaultSockData.ProtoData  = NULL;
 | 
						|
 | 
						|
  gBS->RestoreTPL (OldTpl);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Destroys a child handle with a set of TCP services.
 | 
						|
 | 
						|
  The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
 | 
						|
  that was installed by CreateChild() from ChildHandle. If the removed protocol is the
 | 
						|
  last protocol on ChildHandle, then ChildHandle is destroyed.
 | 
						|
 | 
						|
  @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
 | 
						|
  @param  ChildHandle Handle of the child to be destroyed.
 | 
						|
 | 
						|
  @retval EFI_SUCCES            The protocol was removed from ChildHandle.
 | 
						|
  @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
 | 
						|
  @retval EFI_INVALID_PARAMETER Child handle is NULL.
 | 
						|
  @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
 | 
						|
                                because its services are being used.
 | 
						|
  @retval other                 The child handle was not destroyed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpServiceBindingDestroyChild (
 | 
						|
  IN EFI_SERVICE_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                    ChildHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  VOID        *Tcp;
 | 
						|
  SOCKET      *Sock;
 | 
						|
 | 
						|
  if (NULL == This || NULL == ChildHandle) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // retrieve the Tcp4 protocol from ChildHandle
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ChildHandle,
 | 
						|
                  &gEfiTcp4ProtocolGuid,
 | 
						|
                  &Tcp,
 | 
						|
                  gTcp4DriverBinding.DriverBindingHandle,
 | 
						|
                  ChildHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // No Tcp4, try the Tcp6 protocol
 | 
						|
    //
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    ChildHandle,
 | 
						|
                    &gEfiTcp6ProtocolGuid,
 | 
						|
                    &Tcp,
 | 
						|
                    gTcp6DriverBinding.DriverBindingHandle,
 | 
						|
                    ChildHandle,
 | 
						|
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // destroy this sock and related Tcp protocol control
 | 
						|
    // block
 | 
						|
    //
 | 
						|
    Sock = SOCK_FROM_THIS (Tcp);
 | 
						|
 | 
						|
    SockDestroyChild (Sock);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |