mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 06:39:42 +00:00 
			
		
		
		
	 d1102dba72
			
		
	
	
		d1102dba72
		
	
	
	
	
		
			
			1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			1032 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1032 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Interface function of the Socket.
 | |
| 
 | |
| Copyright (c) 2005 - 2018, 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<BR>
 | |
| 
 | |
| 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 "SockImpl.h"
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Check whether the Event is in the List.
 | |
| 
 | |
|   @param  List                 Pointer to the token list to be searched.
 | |
|   @param  Event                The event to be checked.
 | |
| 
 | |
|   @retval  TRUE                The specific Event exists in the List.
 | |
|   @retval  FALSE               The specific Event is not in the List.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| SockTokenExistedInList (
 | |
|   IN LIST_ENTRY     *List,
 | |
|   IN EFI_EVENT      Event
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY      *ListEntry;
 | |
|   SOCK_TOKEN      *SockToken;
 | |
| 
 | |
|   NET_LIST_FOR_EACH (ListEntry, List) {
 | |
|     SockToken = NET_LIST_USER_STRUCT (
 | |
|                   ListEntry,
 | |
|                   SOCK_TOKEN,
 | |
|                   TokenList
 | |
|                   );
 | |
| 
 | |
|     if (Event == SockToken->Token->Event) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Call SockTokenExistedInList() to check whether the Event is
 | |
|   in the related socket's lists.
 | |
| 
 | |
|   @param  Sock                 Pointer to the instance's socket.
 | |
|   @param  Event                The event to be checked.
 | |
| 
 | |
|   @retval  TRUE                The Event exists in related socket's lists.
 | |
|   @retval  FALSE               The Event is not in related socket's lists.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| SockTokenExisted (
 | |
|   IN SOCKET    *Sock,
 | |
|   IN EFI_EVENT Event
 | |
|   )
 | |
| {
 | |
| 
 | |
|   if (SockTokenExistedInList (&Sock->SndTokenList, Event) ||
 | |
|       SockTokenExistedInList (&Sock->ProcessingSndTokenList, Event) ||
 | |
|       SockTokenExistedInList (&Sock->RcvTokenList, Event) ||
 | |
|       SockTokenExistedInList (&Sock->ListenTokenList, Event)) {
 | |
| 
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   if ((Sock->ConnectionToken != NULL) &&
 | |
|       (Sock->ConnectionToken->Event == Event)) {
 | |
| 
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   if ((Sock->CloseToken != NULL) && (Sock->CloseToken->Event == Event)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Buffer a token into the specific list of socket Sock.
 | |
| 
 | |
|   @param  Sock                 Pointer to the instance's socket.
 | |
|   @param  List                 Pointer to the list to store the token.
 | |
|   @param  Token                Pointer to the token to be buffered.
 | |
|   @param  DataLen              The data length of the buffer contained in Token.
 | |
| 
 | |
|   @return Pointer to the token that wraps Token. If NULL, error condition occurred.
 | |
| 
 | |
| **/
 | |
| SOCK_TOKEN *
 | |
| SockBufferToken (
 | |
|   IN SOCKET         *Sock,
 | |
|   IN LIST_ENTRY     *List,
 | |
|   IN VOID           *Token,
 | |
|   IN UINT32         DataLen
 | |
|   )
 | |
| {
 | |
|   SOCK_TOKEN  *SockToken;
 | |
| 
 | |
|   SockToken = AllocatePool (sizeof (SOCK_TOKEN));
 | |
|   if (NULL == SockToken) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockBufferIOToken: No Memory "
 | |
|       "to allocate SockToken\n"));
 | |
| 
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   SockToken->Sock           = Sock;
 | |
|   SockToken->Token          = (SOCK_COMPLETION_TOKEN *) Token;
 | |
|   SockToken->RemainDataLen  = DataLen;
 | |
|   InsertTailList (List, &SockToken->TokenList);
 | |
| 
 | |
|   return SockToken;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Destroy the socket Sock and its associated protocol control block.
 | |
| 
 | |
|   @param  Sock                 The socket to be destroyed.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The socket Sock is destroyed successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockDestroyChild (
 | |
|   IN SOCKET *Sock
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS       Status;
 | |
|   TCP4_PROTO_DATA  *ProtoData;
 | |
|   TCP_CB           *Tcb;
 | |
|   VOID             *SockProtocol;
 | |
| 
 | |
|   ASSERT ((Sock != NULL) && (Sock->ProtoHandler != NULL));
 | |
| 
 | |
|   if (Sock->InDestroy) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   Sock->InDestroy = TRUE;
 | |
| 
 | |
|   ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
 | |
|   Tcb       = ProtoData->TcpPcb;
 | |
| 
 | |
|   ASSERT (Tcb != NULL);
 | |
| 
 | |
|   //
 | |
|   // Close the IP protocol.
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|          Tcb->IpInfo->ChildHandle,
 | |
|          &gEfiIp4ProtocolGuid,
 | |
|          ProtoData->TcpService->IpIo->Image,
 | |
|          Sock->SockHandle
 | |
|          );
 | |
| 
 | |
|   if (Sock->DestroyCallback != NULL) {
 | |
|     Sock->DestroyCallback (Sock, Sock->Context);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Retrieve the protocol installed on this sock
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Sock->SockHandle,
 | |
|                   &gEfiTcp4ProtocolGuid,
 | |
|                   &SockProtocol,
 | |
|                   Sock->DriverBinding,
 | |
|                   Sock->SockHandle,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockDestroyChild: Open protocol installed "
 | |
|       "on socket failed with %r\n", Status));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Uninstall the protocol installed on this sock
 | |
|   // in the light of Sock->SockType
 | |
|   //
 | |
|   gBS->UninstallMultipleProtocolInterfaces (
 | |
|         Sock->SockHandle,
 | |
|         &gEfiTcp4ProtocolGuid,
 | |
|         SockProtocol,
 | |
|         NULL
 | |
|         );
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockDestroyChild: Get the lock to "
 | |
|       "access socket failed with %r\n", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // force protocol layer to detach the PCB
 | |
|   //
 | |
|   Status = Sock->ProtoHandler (Sock, SOCK_DETACH, NULL);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockDestroyChild: Protocol detach socket"
 | |
|       " failed with %r\n", Status));
 | |
| 
 | |
|     Sock->InDestroy = FALSE;
 | |
|   } else if (SOCK_IS_CONFIGURED (Sock)) {
 | |
| 
 | |
|     SockConnFlush (Sock);
 | |
|     SockSetState (Sock, SO_CLOSED);
 | |
| 
 | |
|     Sock->ConfigureState = SO_UNCONFIGURED;
 | |
|   }
 | |
| 
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   SockDestroy (Sock);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Create a socket and its associated protocol control block
 | |
|   with the intial data SockInitData and protocol specific
 | |
|   data ProtoData.
 | |
| 
 | |
|   @param  SockInitData         Inital data to setting the socket.
 | |
| 
 | |
|   @return Pointer to the newly created socket. If NULL, error condition occured.
 | |
| 
 | |
| **/
 | |
| SOCKET *
 | |
| SockCreateChild (
 | |
|   IN SOCK_INIT_DATA *SockInitData
 | |
|   )
 | |
| {
 | |
|   SOCKET      *Sock;
 | |
|   VOID        *SockProtocol;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // create a new socket
 | |
|   //
 | |
|   Sock = SockCreate (SockInitData);
 | |
|   if (NULL == Sock) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockCreateChild: No resource to "
 | |
|       "create a new socket\n"));
 | |
| 
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockCreateChild: Get the lock to "
 | |
|       "access socket failed with %r\n", Status));
 | |
| 
 | |
|     goto ERROR;
 | |
|   }
 | |
|   //
 | |
|   // inform the protocol layer to attach the socket
 | |
|   // with a new protocol control block
 | |
|   //
 | |
|   Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockCreateChild: Protocol failed to"
 | |
|       " attach a socket with %r\n", Status));
 | |
| 
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   return Sock;
 | |
| 
 | |
| ERROR:
 | |
| 
 | |
|   if (Sock->DestroyCallback != NULL) {
 | |
|     Sock->DestroyCallback (Sock, Sock->Context);
 | |
|   }
 | |
| 
 | |
|   gBS->OpenProtocol (
 | |
|          Sock->SockHandle,
 | |
|          &gEfiTcp4ProtocolGuid,
 | |
|          &SockProtocol,
 | |
|          Sock->DriverBinding,
 | |
|          Sock->SockHandle,
 | |
|          EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|          );
 | |
|   //
 | |
|   // Uninstall the protocol installed on this sock
 | |
|   //
 | |
|   gBS->UninstallMultipleProtocolInterfaces (
 | |
|         Sock->SockHandle,
 | |
|         &gEfiTcp4ProtocolGuid,
 | |
|         SockProtocol,
 | |
|         NULL
 | |
|         );
 | |
|    SockDestroy (Sock);
 | |
|    return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Configure the specific socket Sock using configuration data ConfigData.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket to be configured.
 | |
|   @param  ConfigData           Pointer to the configuration data.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The socket is configured successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket or the
 | |
|                                socket is already configured.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockConfigure (
 | |
|   IN SOCKET *Sock,
 | |
|   IN VOID   *ConfigData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockConfigure: Get the access for "
 | |
|       "socket failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_CONFIGURED (Sock)) {
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto OnExit;
 | |
|   }
 | |
| 
 | |
|   ASSERT (Sock->State == SO_CLOSED);
 | |
| 
 | |
|   Status = Sock->ProtoHandler (Sock, SOCK_CONFIGURE, ConfigData);
 | |
| 
 | |
| OnExit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initiate a connection establishment process.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket to initiate the initate the
 | |
|                                connection.
 | |
|   @param  Token                Pointer to the token used for the connection
 | |
|                                operation.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The connection is initialized successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the
 | |
|                                socket is closed, or the socket is not configured to
 | |
|                                be an active one, or the token is already in one of
 | |
|                                this socket's lists.
 | |
|   @retval EFI_NO_MAPPING       The IP address configuration operation is not
 | |
|                                finished.
 | |
|   @retval EFI_NOT_STARTED      The socket is not configured.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockConnect (
 | |
|   IN SOCKET *Sock,
 | |
|   IN VOID   *Token
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_EVENT   Event;
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockConnect: Get the access for "
 | |
|       "socket failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_NO_MAPPING (Sock)) {
 | |
|     Status = EFI_NO_MAPPING;
 | |
|     goto OnExit;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_UNCONFIGURED (Sock)) {
 | |
| 
 | |
|     Status = EFI_NOT_STARTED;
 | |
|     goto OnExit;
 | |
|   }
 | |
| 
 | |
|   if (!SOCK_IS_CLOSED (Sock) || !SOCK_IS_CONFIGURED_ACTIVE (Sock)) {
 | |
| 
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto OnExit;
 | |
|   }
 | |
| 
 | |
|   Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
 | |
| 
 | |
|   if (SockTokenExisted (Sock, Event)) {
 | |
| 
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto OnExit;
 | |
|   }
 | |
| 
 | |
|   Sock->ConnectionToken = (SOCK_COMPLETION_TOKEN *) Token;
 | |
|   SockSetState (Sock, SO_CONNECTING);
 | |
|   Status = Sock->ProtoHandler (Sock, SOCK_CONNECT, NULL);
 | |
| 
 | |
| OnExit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Issue a listen token to get an existed connected network instance
 | |
|   or wait for a connection if there is none.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket to accept connections.
 | |
|   @param  Token                The token to accept a connection.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Either a connection is accpeted or the Token is
 | |
|                                buffered for further acception.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the
 | |
|                                socket is closed, or the socket is not configured to
 | |
|                                be a passive one, or the token is already in one of
 | |
|                                this socket's lists.
 | |
|   @retval EFI_NO_MAPPING       The IP address configuration operation is not
 | |
|                                finished.
 | |
|   @retval EFI_NOT_STARTED      The socket is not configured.
 | |
|   @retval EFI_OUT_OF_RESOURCE  Failed to buffer the Token due to memory limit.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockAccept (
 | |
|   IN SOCKET *Sock,
 | |
|   IN VOID   *Token
 | |
|   )
 | |
| {
 | |
|   EFI_TCP4_LISTEN_TOKEN *ListenToken;
 | |
|   LIST_ENTRY            *ListEntry;
 | |
|   EFI_STATUS            Status;
 | |
|   SOCKET                *Socket;
 | |
|   EFI_EVENT             Event;
 | |
| 
 | |
|   ASSERT (SockStream == Sock->Type);
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockAccept: Get the access for socket"
 | |
|       " failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_NO_MAPPING (Sock)) {
 | |
|     Status = EFI_NO_MAPPING;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_UNCONFIGURED (Sock)) {
 | |
| 
 | |
|     Status = EFI_NOT_STARTED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (!SOCK_IS_LISTENING (Sock)) {
 | |
| 
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
 | |
| 
 | |
|   if (SockTokenExisted (Sock, Event)) {
 | |
| 
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;
 | |
| 
 | |
|   //
 | |
|   // Check if a connection has already in this Sock->ConnectionList
 | |
|   //
 | |
|   NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {
 | |
| 
 | |
|     Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);
 | |
| 
 | |
|     if (SOCK_IS_CONNECTED (Socket)) {
 | |
|       ListenToken->NewChildHandle = Socket->SockHandle;
 | |
|       SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);
 | |
| 
 | |
|       RemoveEntryList (ListEntry);
 | |
| 
 | |
|       ASSERT (Socket->Parent != NULL);
 | |
| 
 | |
|       Socket->Parent->ConnCnt--;
 | |
| 
 | |
|       DEBUG (
 | |
|         (EFI_D_NET,
 | |
|         "SockAccept: Accept a socket, now conncount is %d",
 | |
|         Socket->Parent->ConnCnt)
 | |
|         );
 | |
|       Socket->Parent = NULL;
 | |
| 
 | |
|       goto Exit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Buffer this token for latter incoming connection request
 | |
|   //
 | |
|   if (NULL == SockBufferToken (Sock, &(Sock->ListenTokenList), Token, 0)) {
 | |
| 
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Issue a token with data to the socket to send out.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket to process the token with
 | |
|                                data.
 | |
|   @param  Token                The token with data that needs to send out.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The token is processed successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the
 | |
|                                socket is closed, or the socket is not in a
 | |
|                                synchronized state , or the token is already in one
 | |
|                                of this socket's lists.
 | |
|   @retval EFI_NO_MAPPING       The IP address configuration operation is not
 | |
|                                finished.
 | |
|   @retval EFI_NOT_STARTED      The socket is not configured.
 | |
|   @retval EFI_OUT_OF_RESOURCE  Failed to buffer the token due to memory limit.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockSend (
 | |
|   IN SOCKET *Sock,
 | |
|   IN VOID   *Token
 | |
|   )
 | |
| {
 | |
|   SOCK_IO_TOKEN           *SndToken;
 | |
|   EFI_EVENT               Event;
 | |
|   UINT32                  FreeSpace;
 | |
|   EFI_TCP4_TRANSMIT_DATA  *TxData;
 | |
|   EFI_STATUS              Status;
 | |
|   SOCK_TOKEN              *SockToken;
 | |
|   UINT32                  DataLen;
 | |
| 
 | |
|   ASSERT (SockStream == Sock->Type);
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockSend: Get the access for socket"
 | |
|       " failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_NO_MAPPING (Sock)) {
 | |
|     Status = EFI_NO_MAPPING;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   SndToken  = (SOCK_IO_TOKEN *) Token;
 | |
|   TxData    = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;
 | |
| 
 | |
|   if (SOCK_IS_UNCONFIGURED (Sock)) {
 | |
|     Status = EFI_NOT_STARTED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {
 | |
| 
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // check if a token is already in the token buffer
 | |
|   //
 | |
|   Event = SndToken->Token.Event;
 | |
| 
 | |
|   if (SockTokenExisted (Sock, Event)) {
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   DataLen = (UINT32) TxData->DataLength;
 | |
| 
 | |
|   //
 | |
|   // process this sending token now or buffer it only?
 | |
|   //
 | |
|   FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);
 | |
| 
 | |
|   if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {
 | |
| 
 | |
|     SockToken = SockBufferToken (
 | |
|                   Sock,
 | |
|                   &Sock->SndTokenList,
 | |
|                   SndToken,
 | |
|                   DataLen
 | |
|                   );
 | |
| 
 | |
|     if (NULL == SockToken) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   } else {
 | |
| 
 | |
|     SockToken = SockBufferToken (
 | |
|                   Sock,
 | |
|                   &Sock->ProcessingSndTokenList,
 | |
|                   SndToken,
 | |
|                   DataLen
 | |
|                   );
 | |
| 
 | |
|     if (NULL == SockToken) {
 | |
|       DEBUG ((EFI_D_ERROR, "SockSend: Failed to buffer IO token into"
 | |
|         " socket processing SndToken List\n", Status));
 | |
| 
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = SockProcessTcpSndData (Sock, TxData);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "SockSend: Failed to process "
 | |
|         "Snd Data\n", Status));
 | |
| 
 | |
|       RemoveEntryList (&(SockToken->TokenList));
 | |
|       FreePool (SockToken);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Issue a token to get data from the socket.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket to get data from.
 | |
|   @param  Token                The token to store the received data from the
 | |
|                                socket.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The token is processed successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the
 | |
|                                socket is closed, or the socket is not in a
 | |
|                                synchronized state , or the token is already in one
 | |
|                                of this socket's lists.
 | |
|   @retval EFI_NO_MAPPING       The IP address configuration operation is not
 | |
|                                finished.
 | |
|   @retval EFI_NOT_STARTED      The socket is not configured.
 | |
|   @retval EFI_CONNECTION_FIN   The connection is closed and there is no more data.
 | |
|   @retval EFI_OUT_OF_RESOURCE  Failed to buffer the token due to memory limit.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockRcv (
 | |
|   IN SOCKET *Sock,
 | |
|   IN VOID   *Token
 | |
|   )
 | |
| {
 | |
|   SOCK_IO_TOKEN *RcvToken;
 | |
|   UINT32        RcvdBytes;
 | |
|   EFI_STATUS    Status;
 | |
|   EFI_EVENT     Event;
 | |
| 
 | |
|   ASSERT (SockStream == Sock->Type);
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockRcv: Get the access for socket"
 | |
|       " failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_NO_MAPPING (Sock)) {
 | |
| 
 | |
|     Status = EFI_NO_MAPPING;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_UNCONFIGURED (Sock)) {
 | |
| 
 | |
|     Status = EFI_NOT_STARTED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {
 | |
| 
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   RcvToken = (SOCK_IO_TOKEN *) Token;
 | |
| 
 | |
|   //
 | |
|   // check if a token is already in the token buffer of this socket
 | |
|   //
 | |
|   Event = RcvToken->Token.Event;
 | |
|   if (SockTokenExisted (Sock, Event)) {
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   RcvToken  = (SOCK_IO_TOKEN *) Token;
 | |
|   RcvdBytes = GET_RCV_DATASIZE (Sock);
 | |
| 
 | |
|   //
 | |
|   // check whether an error has happened before
 | |
|   //
 | |
|   if (EFI_ABORTED != Sock->SockError) {
 | |
| 
 | |
|     SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);
 | |
|     Sock->SockError = EFI_ABORTED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // check whether can not receive and there is no any
 | |
|   // data buffered in Sock->RcvBuffer
 | |
|   //
 | |
|   if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {
 | |
| 
 | |
|     Status = EFI_CONNECTION_FIN;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (RcvdBytes != 0) {
 | |
|     SockProcessRcvToken (Sock, RcvToken);
 | |
| 
 | |
|     Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);
 | |
|   } else {
 | |
| 
 | |
|     if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {
 | |
|       Status = EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset the socket and its associated protocol control block.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket to be flushed.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The socket is flushed successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockFlush (
 | |
|   IN SOCKET *Sock
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   ASSERT (SockStream == Sock->Type);
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockFlush: Get the access for socket"
 | |
|       " failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (!SOCK_IS_CONFIGURED (Sock)) {
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockFlush: Protocol failed handling"
 | |
|       " SOCK_FLUSH with %r", Status));
 | |
| 
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   SOCK_ERROR (Sock, EFI_ABORTED);
 | |
|   SockConnFlush (Sock);
 | |
|   SockSetState (Sock, SO_CLOSED);
 | |
| 
 | |
|   Sock->ConfigureState = SO_UNCONFIGURED;
 | |
| 
 | |
| Exit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Close or abort the socket associated connection.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket of the connection to close or
 | |
|                                abort.
 | |
|   @param  Token                The token for close operation.
 | |
|   @param  OnAbort              TRUE for aborting the connection, FALSE to close it.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The close or abort operation is initialized
 | |
|                                successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket, or the
 | |
|                                socket is closed, or the socket is not in a
 | |
|                                synchronized state , or the token is already in one
 | |
|                                of this socket's lists.
 | |
|   @retval EFI_NO_MAPPING       The IP address configuration operation is not
 | |
|                                finished.
 | |
|   @retval EFI_NOT_STARTED      The socket is not configured.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockClose (
 | |
|   IN SOCKET  *Sock,
 | |
|   IN VOID    *Token,
 | |
|   IN BOOLEAN OnAbort
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_EVENT   Event;
 | |
| 
 | |
|   ASSERT (SockStream == Sock->Type);
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "SockClose: Get the access for socket"
 | |
|       " failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_NO_MAPPING (Sock)) {
 | |
|     Status = EFI_NO_MAPPING;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_UNCONFIGURED (Sock)) {
 | |
|     Status = EFI_NOT_STARTED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_DISCONNECTING (Sock)) {
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;
 | |
| 
 | |
|   if (SockTokenExisted (Sock, Event)) {
 | |
|     Status = EFI_ACCESS_DENIED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Sock->CloseToken = Token;
 | |
|   SockSetState (Sock, SO_DISCONNECTING);
 | |
| 
 | |
|   if (OnAbort) {
 | |
|     Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);
 | |
|   } else {
 | |
|     Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);
 | |
|   }
 | |
| 
 | |
| Exit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get the mode data of the low layer protocol.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket to get mode data from.
 | |
|   @param  Mode                 Pointer to the data to store the low layer mode
 | |
|                                information.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The mode data is got successfully.
 | |
|   @retval EFI_NOT_STARTED      The socket is not configured.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockGetMode (
 | |
|   IN     SOCKET *Sock,
 | |
|   IN OUT VOID   *Mode
 | |
|   )
 | |
| {
 | |
|   return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Configure the low level protocol to join a multicast group for
 | |
|   this socket's connection.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket of the connection to join the
 | |
|                                specific multicast group.
 | |
|   @param  GroupInfo            Pointer to the multicast group info.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The configuration is done successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.
 | |
|   @retval EFI_NOT_STARTED      The socket is not configured.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockGroup (
 | |
|   IN SOCKET *Sock,
 | |
|   IN VOID   *GroupInfo
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "SockGroup: Get the access for socket"
 | |
|       " failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_UNCONFIGURED (Sock)) {
 | |
|     Status = EFI_NOT_STARTED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Status = Sock->ProtoHandler (Sock, SOCK_GROUP, GroupInfo);
 | |
| 
 | |
| Exit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add or remove route information in IP route table associated
 | |
|   with this socket.
 | |
| 
 | |
|   @param  Sock                 Pointer to the socket associated with the IP route
 | |
|                                table to operate on.
 | |
|   @param  RouteInfo            Pointer to the route information to be processed.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The route table is updated successfully.
 | |
|   @retval EFI_ACCESS_DENIED    Failed to get the lock to access the socket.
 | |
|   @retval EFI_NO_MAPPING       The IP address configuration operation is  not
 | |
|                                finished.
 | |
|   @retval EFI_NOT_STARTED      The socket is not configured.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockRoute (
 | |
|   IN SOCKET    *Sock,
 | |
|   IN VOID      *RouteInfo
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Status = EfiAcquireLockOrFail (&(Sock->Lock));
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "SockRoute: Get the access for socket"
 | |
|       " failed with %r", Status));
 | |
| 
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_NO_MAPPING (Sock)) {
 | |
|     Status = EFI_NO_MAPPING;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   if (SOCK_IS_UNCONFIGURED (Sock)) {
 | |
|     Status = EFI_NOT_STARTED;
 | |
|     goto Exit;
 | |
|   }
 | |
| 
 | |
|   Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);
 | |
| 
 | |
| Exit:
 | |
|   EfiReleaseLock (&(Sock->Lock));
 | |
|   return Status;
 | |
| }
 |