git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10418 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			488 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			488 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   The wrap of TCP/IP Socket interface.
 | |
| 
 | |
| Copyright (c) 2004 - 2009, 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 "IScsiImpl.h"
 | |
| 
 | |
| /**
 | |
|   The common notify function associated with various Tcp4Io events. 
 | |
| 
 | |
|   @param[in]  Event   The event signaled.
 | |
|   @param[in]  Context The context.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| Tcp4IoCommonNotify (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   *((BOOLEAN *) Context) = TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create a TCP socket with the specified configuration data. 
 | |
| 
 | |
|   @param[in]  Image      The handle of the driver image.
 | |
|   @param[in]  Controller The handle of the controller.
 | |
|   @param[in]  ConfigData The Tcp4 configuration data.
 | |
|   @param[in]  Tcp4Io     The Tcp4Io.
 | |
|   
 | |
|   @retval EFI_SUCCESS    The TCP socket is created and configured.
 | |
|   @retval Others         Failed to create the TCP socket or configure it.
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4IoCreateSocket (
 | |
|   IN EFI_HANDLE           Image,
 | |
|   IN EFI_HANDLE           Controller,
 | |
|   IN TCP4_IO_CONFIG_DATA  *ConfigData,
 | |
|   IN TCP4_IO              *Tcp4Io
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_TCP4_PROTOCOL     *Tcp4;
 | |
|   EFI_TCP4_CONFIG_DATA  Tcp4ConfigData;
 | |
|   EFI_TCP4_OPTION       ControlOption;
 | |
|   EFI_TCP4_ACCESS_POINT *AccessPoint;
 | |
| 
 | |
|   Tcp4Io->Handle = NULL;
 | |
|   Tcp4Io->ConnToken.CompletionToken.Event = NULL;
 | |
|   Tcp4Io->TxToken.CompletionToken.Event = NULL;
 | |
|   Tcp4Io->RxToken.CompletionToken.Event = NULL;
 | |
|   Tcp4Io->CloseToken.CompletionToken.Event = NULL;
 | |
|   Tcp4 = NULL;
 | |
| 
 | |
|   //
 | |
|   // Create the TCP4 child instance and get the TCP4 protocol.
 | |
|   //
 | |
|   Status = NetLibCreateServiceChild (
 | |
|             Controller,
 | |
|             Image,
 | |
|             &gEfiTcp4ServiceBindingProtocolGuid,
 | |
|             &Tcp4Io->Handle
 | |
|             );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Tcp4Io->Handle,
 | |
|                   &gEfiTcp4ProtocolGuid,
 | |
|                   (VOID **)&Tcp4Io->Tcp4,
 | |
|                   Image,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   Tcp4Io->Image       = Image;
 | |
|   Tcp4Io->Controller  = Controller;
 | |
|   Tcp4                = Tcp4Io->Tcp4;
 | |
| 
 | |
|   //
 | |
|   // Set the configuration parameters.
 | |
|   //
 | |
|   ControlOption.ReceiveBufferSize       = 0x200000;
 | |
|   ControlOption.SendBufferSize          = 0x200000;
 | |
|   ControlOption.MaxSynBackLog           = 0;
 | |
|   ControlOption.ConnectionTimeout       = 0;
 | |
|   ControlOption.DataRetries             = 6;
 | |
|   ControlOption.FinTimeout              = 0;
 | |
|   ControlOption.TimeWaitTimeout         = 0;
 | |
|   ControlOption.KeepAliveProbes         = 4;
 | |
|   ControlOption.KeepAliveTime           = 0;
 | |
|   ControlOption.KeepAliveInterval       = 0;
 | |
|   ControlOption.EnableNagle             = FALSE;
 | |
|   ControlOption.EnableTimeStamp         = FALSE;
 | |
|   ControlOption.EnableWindowScaling     = TRUE;
 | |
|   ControlOption.EnableSelectiveAck      = FALSE;
 | |
|   ControlOption.EnablePathMtuDiscovery  = FALSE;
 | |
| 
 | |
|   Tcp4ConfigData.TypeOfService          = 8;
 | |
|   Tcp4ConfigData.TimeToLive             = 255;
 | |
|   Tcp4ConfigData.ControlOption          = &ControlOption;
 | |
| 
 | |
|   AccessPoint = &Tcp4ConfigData.AccessPoint;
 | |
| 
 | |
|   AccessPoint->UseDefaultAddress = FALSE;
 | |
|   AccessPoint->StationPort = 0;
 | |
|   AccessPoint->RemotePort = ConfigData->RemotePort;
 | |
|   AccessPoint->ActiveFlag = TRUE;
 | |
| 
 | |
|   CopyMem (&AccessPoint->StationAddress, &ConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));
 | |
|   CopyMem (&AccessPoint->SubnetMask, &ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | |
|   CopyMem (&AccessPoint->RemoteAddress, &ConfigData->RemoteIp, sizeof (EFI_IPv4_ADDRESS));
 | |
| 
 | |
|   //
 | |
|   // Configure the TCP4 protocol.
 | |
|   //
 | |
|   Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   if (!EFI_IP4_EQUAL (&ConfigData->Gateway, &mZeroIp4Addr)) {
 | |
|     //
 | |
|     // the gateway is not zero, add the default route by hand
 | |
|     //
 | |
|     Status = Tcp4->Routes (Tcp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &ConfigData->Gateway);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_ERROR;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Create events for variuos asynchronous operations.
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   Tcp4IoCommonNotify,
 | |
|                   &Tcp4Io->IsConnDone,
 | |
|                   &Tcp4Io->ConnToken.CompletionToken.Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   Tcp4IoCommonNotify,
 | |
|                   &Tcp4Io->IsTxDone,
 | |
|                   &Tcp4Io->TxToken.CompletionToken.Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   Tcp4IoCommonNotify,
 | |
|                   &Tcp4Io->IsRxDone,
 | |
|                   &Tcp4Io->RxToken.CompletionToken.Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   Tcp4IoCommonNotify,
 | |
|                   &Tcp4Io->IsCloseDone,
 | |
|                   &Tcp4Io->CloseToken.CompletionToken.Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   Tcp4Io->IsTxDone  = FALSE;
 | |
|   Tcp4Io->IsRxDone  = FALSE;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| ON_ERROR:
 | |
| 
 | |
|   if (Tcp4Io->RxToken.CompletionToken.Event != NULL) {
 | |
|     gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);
 | |
|   }
 | |
| 
 | |
|   if (Tcp4Io->TxToken.CompletionToken.Event != NULL) {
 | |
|     gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);
 | |
|   }
 | |
| 
 | |
|   if (Tcp4Io->ConnToken.CompletionToken.Event != NULL) {
 | |
|     gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);
 | |
|   }
 | |
| 
 | |
|   if (Tcp4 != NULL) {
 | |
|     Tcp4->Configure (Tcp4, NULL);
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|           Tcp4Io->Handle,
 | |
|           &gEfiTcp4ProtocolGuid,
 | |
|           Image,
 | |
|           Controller
 | |
|           );
 | |
|   }
 | |
| 
 | |
|   NetLibDestroyServiceChild (
 | |
|     Controller,
 | |
|     Image,
 | |
|     &gEfiTcp4ServiceBindingProtocolGuid,
 | |
|     Tcp4Io->Handle
 | |
|     );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Destroy the socket. 
 | |
| 
 | |
|   @param[in]  Tcp4Io The Tcp4Io which wraps the socket to be destroyeds.
 | |
| **/
 | |
| VOID
 | |
| Tcp4IoDestroySocket (
 | |
|   IN TCP4_IO  *Tcp4Io
 | |
|   )
 | |
| {
 | |
|   EFI_TCP4_PROTOCOL *Tcp4;
 | |
| 
 | |
|   Tcp4 = Tcp4Io->Tcp4;
 | |
| 
 | |
|   Tcp4->Configure (Tcp4, NULL);
 | |
| 
 | |
|   gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);
 | |
|   gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);
 | |
|   gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|         Tcp4Io->Handle,
 | |
|         &gEfiTcp4ProtocolGuid,
 | |
|         Tcp4Io->Image,
 | |
|         Tcp4Io->Controller
 | |
|         );
 | |
| 
 | |
|   NetLibDestroyServiceChild (
 | |
|     Tcp4Io->Controller,
 | |
|     Tcp4Io->Image,
 | |
|     &gEfiTcp4ServiceBindingProtocolGuid,
 | |
|     Tcp4Io->Handle
 | |
|     );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Connect to the other endpoint of the TCP socket.
 | |
| 
 | |
|   @param[in, out]  Tcp4Io    The Tcp4Io wrapping the TCP socket.
 | |
|   @param[in]       Timeout   The time to wait for connection done.
 | |
|   
 | |
|   @retval EFI_SUCCESS          Connect to the other endpoint of the TCP socket successfully.
 | |
|   @retval EFI_TIMEOUT          Failed to connect to the other endpoint of the TCP socket in the                               specified time period.
 | |
|   @retval Others               Other errors as indicated.
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4IoConnect (
 | |
|   IN OUT TCP4_IO    *Tcp4Io,
 | |
|   IN EFI_EVENT      Timeout
 | |
|   )
 | |
| {
 | |
|   EFI_TCP4_PROTOCOL *Tcp4;
 | |
|   EFI_STATUS        Status;
 | |
| 
 | |
|   Tcp4Io->IsConnDone  = FALSE;
 | |
|   Tcp4                = Tcp4Io->Tcp4;
 | |
|   Status              = Tcp4->Connect (Tcp4, &Tcp4Io->ConnToken);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   while (!Tcp4Io->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {
 | |
|     Tcp4->Poll (Tcp4);
 | |
|   }
 | |
| 
 | |
|   if (!Tcp4Io->IsConnDone) {
 | |
|     Status = EFI_TIMEOUT;
 | |
|   } else {
 | |
|     Status = Tcp4Io->ConnToken.CompletionToken.Status;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reset the socket.
 | |
| 
 | |
|   @param[in, out]  Tcp4Io The Tcp4Io wrapping the TCP socket.
 | |
| **/
 | |
| VOID
 | |
| Tcp4IoReset (
 | |
|   IN OUT TCP4_IO  *Tcp4Io
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   EFI_TCP4_PROTOCOL *Tcp4;
 | |
| 
 | |
|   Tcp4Io->CloseToken.AbortOnClose = TRUE;
 | |
|   Tcp4Io->IsCloseDone             = FALSE;
 | |
| 
 | |
|   Tcp4 = Tcp4Io->Tcp4;
 | |
|   Status = Tcp4->Close (Tcp4, &Tcp4Io->CloseToken);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   while (!Tcp4Io->IsCloseDone) {
 | |
|     Tcp4->Poll (Tcp4);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Transmit the Packet to the other endpoint of the socket.
 | |
| 
 | |
|   @param[in]   Tcp4Io          The Tcp4Io wrapping the TCP socket.
 | |
|   @param[in]   Packet          The packet to transmit.
 | |
|   
 | |
|   @retval EFI_SUCCESS          The packet is trasmitted.
 | |
|   @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
 | |
|   @retval Others               Other errors as indicated.
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4IoTransmit (
 | |
|   IN TCP4_IO  *Tcp4Io,
 | |
|   IN NET_BUF  *Packet
 | |
|   )
 | |
| {
 | |
|   EFI_TCP4_TRANSMIT_DATA  *TxData;
 | |
|   EFI_TCP4_PROTOCOL       *Tcp4;
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   TxData = AllocatePool (sizeof (EFI_TCP4_TRANSMIT_DATA) + (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA));
 | |
|   if (TxData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   TxData->Push        = TRUE;
 | |
|   TxData->Urgent      = FALSE;
 | |
|   TxData->DataLength  = Packet->TotalSize;
 | |
| 
 | |
|   //
 | |
|   // Build the fragment table.
 | |
|   //
 | |
|   TxData->FragmentCount = Packet->BlockOpNum;
 | |
|   NetbufBuildExt (Packet, (NET_FRAGMENT *) &TxData->FragmentTable[0], &TxData->FragmentCount);
 | |
| 
 | |
|   Tcp4Io->TxToken.Packet.TxData = TxData;
 | |
| 
 | |
|   //
 | |
|   // Trasnmit the packet.
 | |
|   //
 | |
|   Tcp4    = Tcp4Io->Tcp4;
 | |
|   Status  = Tcp4->Transmit (Tcp4, &Tcp4Io->TxToken);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   while (!Tcp4Io->IsTxDone) {
 | |
|     Tcp4->Poll (Tcp4);
 | |
|   }
 | |
| 
 | |
|   Tcp4Io->IsTxDone  = FALSE;
 | |
| 
 | |
|   Status            = Tcp4Io->TxToken.CompletionToken.Status;
 | |
| 
 | |
| ON_EXIT:
 | |
| 
 | |
|   FreePool (TxData);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Receive data from the socket.
 | |
| 
 | |
|   @param[in]  Tcp4Io           The Tcp4Io which wraps the socket to be destroyed.
 | |
|   @param[in]  Packet           The buffer to hold the data copy from the soket rx buffer.
 | |
|   @param[in]  AsyncMode        Is this receive asyncronous or not.
 | |
|   @param[in]  Timeout          The time to wait for receiving the amount of data the Packet
 | |
|                                can hold.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The required amount of data is received from the socket.
 | |
|   @retval EFI_OUT_OF_RESOURCES Failed to allocate momery.
 | |
|   @retval EFI_TIMEOUT          Failed to receive the required amount of data in the
 | |
|                                specified time period.
 | |
|   @retval Others               Other errors as indicated.
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4IoReceive (
 | |
|   IN TCP4_IO    *Tcp4Io,
 | |
|   IN NET_BUF    *Packet,
 | |
|   IN BOOLEAN    AsyncMode,
 | |
|   IN EFI_EVENT  Timeout
 | |
|   )
 | |
| {
 | |
|   EFI_TCP4_PROTOCOL     *Tcp4;
 | |
|   EFI_TCP4_RECEIVE_DATA RxData;
 | |
|   EFI_STATUS            Status;
 | |
|   NET_FRAGMENT          *Fragment;
 | |
|   UINT32                FragmentCount;
 | |
|   UINT32                CurrentFragment;
 | |
| 
 | |
|   FragmentCount = Packet->BlockOpNum;
 | |
|   Fragment      = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
 | |
|   if (Fragment == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Build the fragment table.
 | |
|   //
 | |
|   NetbufBuildExt (Packet, Fragment, &FragmentCount);
 | |
| 
 | |
|   RxData.FragmentCount          = 1;
 | |
|   Tcp4Io->RxToken.Packet.RxData = &RxData;
 | |
|   CurrentFragment               = 0;
 | |
|   Tcp4                          = Tcp4Io->Tcp4;
 | |
|   Status                        = EFI_SUCCESS;
 | |
| 
 | |
|   while (CurrentFragment < FragmentCount) {
 | |
|     RxData.DataLength                       = Fragment[CurrentFragment].Len;
 | |
|     RxData.FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
 | |
|     RxData.FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
 | |
| 
 | |
|     Status = Tcp4->Receive (Tcp4, &Tcp4Io->RxToken);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     while (!Tcp4Io->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
 | |
|       //
 | |
|       // Poll until some data is received or something error happens.
 | |
|       //
 | |
|       Tcp4->Poll (Tcp4);
 | |
|     }
 | |
| 
 | |
|     if (!Tcp4Io->IsRxDone) {
 | |
|       //
 | |
|       // Timeout occurs, cancel the receive request.
 | |
|       //
 | |
|       Tcp4->Cancel (Tcp4, &Tcp4Io->RxToken.CompletionToken);
 | |
| 
 | |
|       Status = EFI_TIMEOUT;
 | |
|       goto ON_EXIT;
 | |
|     } else {
 | |
|       Tcp4Io->IsRxDone = FALSE;
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Tcp4Io->RxToken.CompletionToken.Status)) {
 | |
|       Status = Tcp4Io->RxToken.CompletionToken.Status;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     Fragment[CurrentFragment].Len -= RxData.FragmentTable[0].FragmentLength;
 | |
|     if (Fragment[CurrentFragment].Len == 0) {
 | |
|       CurrentFragment++;
 | |
|     } else {
 | |
|       Fragment[CurrentFragment].Bulk += RxData.FragmentTable[0].FragmentLength;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   Tcp4Io->RxToken.Packet.RxData = NULL;
 | |
|   FreePool (Fragment);
 | |
| 
 | |
|   return Status;
 | |
| }
 |