--- /dev/null
+/** @file\r
+ Interface function of the Socket.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SockImpl.h"\r
+\r
+/**\r
+ Check whether the Event is in the List.\r
+\r
+ @param[in] List Pointer to the token list to be searched.\r
+ @param[in] Event The event to be checked.\r
+\r
+ @retval TRUE The specific Event exists in the List.\r
+ @retval FALSE The specific Event is not in the List.\r
+\r
+**/\r
+BOOLEAN\r
+SockTokenExistedInList (\r
+ IN LIST_ENTRY *List,\r
+ IN EFI_EVENT Event\r
+ )\r
+{\r
+ LIST_ENTRY *ListEntry;\r
+ SOCK_TOKEN *SockToken;\r
+\r
+ NET_LIST_FOR_EACH (ListEntry, List) {\r
+ SockToken = NET_LIST_USER_STRUCT (\r
+ ListEntry,\r
+ SOCK_TOKEN,\r
+ TokenList\r
+ );\r
+\r
+ if (Event == SockToken->Token->Event) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Call SockTokenExistedInList() to check whether the Event is\r
+ in the related socket's lists.\r
+\r
+ @param[in] Sock Pointer to the instance's socket.\r
+ @param[in] Event The event to be checked.\r
+\r
+ @retval TRUE The Event exists in related socket's lists.\r
+ @retval FALSE The Event is not in related socket's lists.\r
+\r
+**/\r
+BOOLEAN\r
+SockTokenExisted (\r
+ IN SOCKET *Sock,\r
+ IN EFI_EVENT Event\r
+ )\r
+{\r
+\r
+ if (SockTokenExistedInList (&Sock->SndTokenList, Event) ||\r
+ SockTokenExistedInList (&Sock->ProcessingSndTokenList, Event) ||\r
+ SockTokenExistedInList (&Sock->RcvTokenList, Event) ||\r
+ SockTokenExistedInList (&Sock->ListenTokenList, Event)\r
+ ) {\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ if ((Sock->ConnectionToken != NULL) && (Sock->ConnectionToken->Event == Event)) {\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ if ((Sock->CloseToken != NULL) && (Sock->CloseToken->Event == Event)) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Buffer a token into the specific list of the socket Sock.\r
+\r
+ @param[in] Sock Pointer to the instance's socket.\r
+ @param[in] List Pointer to the list to store the token.\r
+ @param[in] Token Pointer to the token to be buffered.\r
+ @param[in] DataLen The data length of the buffer contained in Token.\r
+\r
+ @return Pointer to the token that wraps Token. If NULL, an error condition occurred.\r
+\r
+**/\r
+SOCK_TOKEN *\r
+SockBufferToken (\r
+ IN SOCKET *Sock,\r
+ IN LIST_ENTRY *List,\r
+ IN VOID *Token,\r
+ IN UINT32 DataLen\r
+ )\r
+{\r
+ SOCK_TOKEN *SockToken;\r
+\r
+ SockToken = AllocateZeroPool (sizeof (SOCK_TOKEN));\r
+ if (NULL == SockToken) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockBufferIOToken: No Memory to allocate SockToken\n")\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+\r
+ SockToken->Sock = Sock;\r
+ SockToken->Token = (SOCK_COMPLETION_TOKEN *) Token;\r
+ SockToken->RemainDataLen = DataLen;\r
+ InsertTailList (List, &SockToken->TokenList);\r
+\r
+ return SockToken;\r
+}\r
+\r
+/**\r
+ Destory the socket Sock and its associated protocol control block.\r
+\r
+ @param[in, out] Sock The socket to be destroyed.\r
+\r
+ @retval EFI_SUCCESS The socket Sock was destroyed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
+\r
+**/\r
+EFI_STATUS\r
+SockDestroyChild (\r
+ IN OUT SOCKET *Sock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT ((Sock != NULL) && (Sock->ProtoHandler != NULL));\r
+\r
+ if (Sock->IsDestroyed) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Sock->IsDestroyed = TRUE;\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockDestroyChild: Get the lock to access socket failed with %r\n",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // force protocol layer to detach the PCB\r
+ //\r
+ Status = Sock->ProtoHandler (Sock, SOCK_DETACH, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockDestroyChild: Protocol detach socket failed with %r\n",\r
+ Status)\r
+ );\r
+\r
+ Sock->IsDestroyed = FALSE;\r
+ } else if (SOCK_IS_CONFIGURED (Sock)) {\r
+\r
+ SockConnFlush (Sock);\r
+ SockSetState (Sock, SO_CLOSED);\r
+\r
+ Sock->ConfigureState = SO_UNCONFIGURED;\r
+ }\r
+\r
+ EfiReleaseLock (&(Sock->Lock));\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SockDestroy (Sock);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create a socket and its associated protocol control block\r
+ with the intial data SockInitData and protocol specific\r
+ data ProtoData.\r
+\r
+ @param[in] SockInitData Inital data to setting the socket.\r
+\r
+ @return Pointer to the newly created socket. If NULL, an error condition occured.\r
+\r
+**/\r
+SOCKET *\r
+SockCreateChild (\r
+ IN SOCK_INIT_DATA *SockInitData\r
+ )\r
+{\r
+ SOCKET *Sock;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // create a new socket\r
+ //\r
+ Sock = SockCreate (SockInitData);\r
+ if (NULL == Sock) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockCreateChild: No resource to create a new socket\n")\r
+ );\r
+\r
+ return NULL;\r
+ }\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockCreateChild: Get the lock to access socket failed with %r\n",\r
+ Status)\r
+ );\r
+\r
+ SockDestroy (Sock);\r
+ return NULL;\r
+ }\r
+ //\r
+ // inform the protocol layer to attach the socket\r
+ // with a new protocol control block\r
+ //\r
+ Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockCreateChild: Protocol failed to attach a socket with %r\n",\r
+ Status)\r
+ );\r
+\r
+ SockDestroy (Sock);\r
+ Sock = NULL;\r
+ }\r
+\r
+ EfiReleaseLock (&(Sock->Lock));\r
+ return Sock;\r
+}\r
+\r
+/**\r
+ Configure the specific socket Sock using configuration data ConfigData.\r
+\r
+ @param[in] Sock Pointer to the socket to be configured.\r
+ @param[in] ConfigData Pointer to the configuration data.\r
+\r
+ @retval EFI_SUCCESS The socket configured successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is already configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockConfigure (\r
+ IN SOCKET *Sock,\r
+ IN VOID *ConfigData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockConfigure: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_CONFIGURED (Sock)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto OnExit;\r
+ }\r
+\r
+ ASSERT (Sock->State == SO_CLOSED);\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_CONFIGURE, ConfigData);\r
+\r
+OnExit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initiate a connection establishment process.\r
+\r
+ @param[in] Sock Pointer to the socket to initiate the initate the\r
+ connection.\r
+ @param[in] Token Pointer to the token used for the connection\r
+ operation.\r
+\r
+ @retval EFI_SUCCESS The connection initialized successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not configured to\r
+ be an active one, or the token is already in one of\r
+ this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockConnect (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockConnect: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto OnExit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto OnExit;\r
+ }\r
+\r
+ if (!SOCK_IS_CLOSED (Sock) || !SOCK_IS_CONFIGURED_ACTIVE (Sock)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto OnExit;\r
+ }\r
+\r
+ Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+ if (SockTokenExisted (Sock, Event)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto OnExit;\r
+ }\r
+\r
+ Sock->ConnectionToken = (SOCK_COMPLETION_TOKEN *) Token;\r
+ SockSetState (Sock, SO_CONNECTING);\r
+ Status = Sock->ProtoHandler (Sock, SOCK_CONNECT, NULL);\r
+\r
+OnExit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Issue a listen token to get an existed connected network instance\r
+ or wait for a connection if there is none.\r
+\r
+ @param[in] Sock Pointer to the socket to accept connections.\r
+ @param[in] Token The token to accept a connection.\r
+\r
+ @retval EFI_SUCCESS Either a connection is accpeted or the Token is\r
+ buffered for further acception.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not configured to\r
+ be a passive one, or the token is already in one of\r
+ this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+ @retval EFI_OUT_OF_RESOURCE Failed to buffer the Token due to memory limits.\r
+\r
+**/\r
+EFI_STATUS\r
+SockAccept (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token\r
+ )\r
+{\r
+ EFI_TCP4_LISTEN_TOKEN *ListenToken;\r
+ LIST_ENTRY *ListEntry;\r
+ EFI_STATUS Status;\r
+ SOCKET *Socket;\r
+ EFI_EVENT Event;\r
+\r
+ ASSERT (SockStream == Sock->Type);\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockAccept: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!SOCK_IS_LISTENING (Sock)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+ if (SockTokenExisted (Sock, Event)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ ListenToken = (EFI_TCP4_LISTEN_TOKEN *) Token;\r
+\r
+ //\r
+ // Check if a connection has already in this Sock->ConnectionList\r
+ //\r
+ NET_LIST_FOR_EACH (ListEntry, &Sock->ConnectionList) {\r
+\r
+ Socket = NET_LIST_USER_STRUCT (ListEntry, SOCKET, ConnectionList);\r
+\r
+ if (SOCK_IS_CONNECTED (Socket)) {\r
+ ListenToken->NewChildHandle = Socket->SockHandle;\r
+ SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);\r
+\r
+ RemoveEntryList (ListEntry);\r
+\r
+ ASSERT (Socket->Parent != NULL);\r
+\r
+ Socket->Parent->ConnCnt--;\r
+\r
+ DEBUG (\r
+ (EFI_D_INFO,\r
+ "SockAccept: Accept a socket, now conncount is %d",\r
+ Socket->Parent->ConnCnt)\r
+ );\r
+ Socket->Parent = NULL;\r
+\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Buffer this token for latter incoming connection request\r
+ //\r
+ if (NULL == SockBufferToken (Sock, &(Sock->ListenTokenList), Token, 0)) {\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+Exit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Issue a token with data to the socket to send out.\r
+\r
+ @param[in] Sock Pointer to the socket to process the token with\r
+ data.\r
+ @param[in] Token The token with data that needs to send out.\r
+\r
+ @retval EFI_SUCCESS The token processed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not in a\r
+ synchronized state , or the token is already in one\r
+ of this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+ @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limits.\r
+\r
+**/\r
+EFI_STATUS\r
+SockSend (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token\r
+ )\r
+{\r
+ SOCK_IO_TOKEN *SndToken;\r
+ EFI_EVENT Event;\r
+ UINT32 FreeSpace;\r
+ EFI_TCP4_TRANSMIT_DATA *TxData;\r
+ EFI_STATUS Status;\r
+ SOCK_TOKEN *SockToken;\r
+ UINT32 DataLen;\r
+\r
+ ASSERT (SockStream == Sock->Type);\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockSend: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ SndToken = (SOCK_IO_TOKEN *) Token;\r
+ TxData = (EFI_TCP4_TRANSMIT_DATA *) SndToken->Packet.TxData;\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!(SOCK_IS_CONNECTING (Sock) || SOCK_IS_CONNECTED (Sock))) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // check if a token is already in the token buffer\r
+ //\r
+ Event = SndToken->Token.Event;\r
+\r
+ if (SockTokenExisted (Sock, Event)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ DataLen = TxData->DataLength;\r
+\r
+ //\r
+ // process this sending token now or buffer it only?\r
+ //\r
+ FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);\r
+\r
+ if ((FreeSpace < Sock->SndBuffer.LowWater) || !SOCK_IS_CONNECTED (Sock)) {\r
+\r
+ SockToken = SockBufferToken (\r
+ Sock,\r
+ &Sock->SndTokenList,\r
+ SndToken,\r
+ DataLen\r
+ );\r
+\r
+ if (NULL == SockToken) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+\r
+ SockToken = SockBufferToken (\r
+ Sock,\r
+ &Sock->ProcessingSndTokenList,\r
+ SndToken,\r
+ DataLen\r
+ );\r
+\r
+ if (NULL == SockToken) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockSend: Failed to buffer IO token into socket processing SndToken List\n",\r
+ Status)\r
+ );\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ Status = SockProcessTcpSndData (Sock, TxData);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockSend: Failed to process Snd Data\n",\r
+ Status)\r
+ );\r
+\r
+ RemoveEntryList (&(SockToken->TokenList));\r
+ FreePool (SockToken);\r
+ }\r
+ }\r
+\r
+Exit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Issue a token to get data from the socket.\r
+\r
+ @param[in] Sock Pointer to the socket to get data from.\r
+ @param[in] Token The token to store the received data from the\r
+ socket.\r
+\r
+ @retval EFI_SUCCESS The token processed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not in a\r
+ synchronized state , or the token is already in one\r
+ of this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+ @retval EFI_CONNECTION_FIN The connection is closed and there is no more data.\r
+ @retval EFI_OUT_OF_RESOURCE Failed to buffer the token due to memory limit.\r
+\r
+**/\r
+EFI_STATUS\r
+SockRcv (\r
+ IN SOCKET *Sock,\r
+ IN VOID *Token\r
+ )\r
+{\r
+ SOCK_IO_TOKEN *RcvToken;\r
+ UINT32 RcvdBytes;\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ ASSERT (SockStream == Sock->Type);\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockRcv: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!(SOCK_IS_CONNECTED (Sock) || SOCK_IS_CONNECTING (Sock))) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ RcvToken = (SOCK_IO_TOKEN *) Token;\r
+\r
+ //\r
+ // check if a token is already in the token buffer of this socket\r
+ //\r
+ Event = RcvToken->Token.Event;\r
+ if (SockTokenExisted (Sock, Event)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ RcvToken = (SOCK_IO_TOKEN *) Token;\r
+ RcvdBytes = GET_RCV_DATASIZE (Sock);\r
+\r
+ //\r
+ // check whether an error has happened before\r
+ //\r
+ if (EFI_ABORTED != Sock->SockError) {\r
+\r
+ SIGNAL_TOKEN (&(RcvToken->Token), Sock->SockError);\r
+ Sock->SockError = EFI_ABORTED;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // check whether can not receive and there is no any\r
+ // data buffered in Sock->RcvBuffer\r
+ //\r
+ if (SOCK_IS_NO_MORE_DATA (Sock) && (0 == RcvdBytes)) {\r
+\r
+ Status = EFI_CONNECTION_FIN;\r
+ goto Exit;\r
+ }\r
+\r
+ if (RcvdBytes != 0) {\r
+ Status = SockProcessRcvToken (Sock, RcvToken);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_CONSUMED, NULL);\r
+ } else {\r
+\r
+ if (NULL == SockBufferToken (Sock, &Sock->RcvTokenList, RcvToken, 0)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+Exit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Reset the socket and its associated protocol control block.\r
+\r
+ @param[in, out] Sock Pointer to the socket to be flushed.\r
+\r
+ @retval EFI_SUCCESS The socket is flushed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
+\r
+**/\r
+EFI_STATUS\r
+SockFlush (\r
+ IN OUT SOCKET *Sock\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (SockStream == Sock->Type);\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockFlush: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (!SOCK_IS_CONFIGURED (Sock)) {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_FLUSH, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockFlush: Protocol failed handling SOCK_FLUSH with %r",\r
+ Status)\r
+ );\r
+\r
+ goto Exit;\r
+ }\r
+\r
+ SOCK_ERROR (Sock, EFI_ABORTED);\r
+ SockConnFlush (Sock);\r
+ SockSetState (Sock, SO_CLOSED);\r
+\r
+ Sock->ConfigureState = SO_UNCONFIGURED;\r
+\r
+Exit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Close or abort the socket associated connection.\r
+\r
+ @param[in, out] Sock Pointer to the socket of the connection to close\r
+ or abort.\r
+ @param[in] Token The token for a close operation.\r
+ @param[in] OnAbort TRUE for aborting the connection; FALSE to close it.\r
+\r
+ @retval EFI_SUCCESS The close or abort operation initialized\r
+ successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket, or the\r
+ socket is closed, or the socket is not in a\r
+ synchronized state , or the token is already in one\r
+ of this socket's lists.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockClose (\r
+ IN OUT SOCKET *Sock,\r
+ IN VOID *Token,\r
+ IN BOOLEAN OnAbort\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ ASSERT (SockStream == Sock->Type);\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockClose: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_DISCONNECTING (Sock)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ Event = ((SOCK_COMPLETION_TOKEN *) Token)->Event;\r
+\r
+ if (SockTokenExisted (Sock, Event)) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Exit;\r
+ }\r
+\r
+ Sock->CloseToken = Token;\r
+ SockSetState (Sock, SO_DISCONNECTING);\r
+\r
+ if (OnAbort) {\r
+ Status = Sock->ProtoHandler (Sock, SOCK_ABORT, NULL);\r
+ } else {\r
+ Status = Sock->ProtoHandler (Sock, SOCK_CLOSE, NULL);\r
+ }\r
+\r
+Exit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get the mode data of the low layer protocol.\r
+\r
+ @param[in] Sock Pointer to the socket to get mode data from.\r
+ @param[in, out] Mode Pointer to the data to store the low layer mode\r
+ information.\r
+\r
+ @retval EFI_SUCCESS The mode data was obtained successfully.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockGetMode (\r
+ IN SOCKET *Sock,\r
+ IN OUT VOID *Mode\r
+ )\r
+{\r
+ return Sock->ProtoHandler (Sock, SOCK_MODE, Mode);\r
+}\r
+\r
+/**\r
+ Configure the low level protocol to join a multicast group for\r
+ this socket's connection.\r
+\r
+ @param[in] Sock Pointer to the socket of the connection to join the\r
+ specific multicast group.\r
+ @param[in] GroupInfo Pointer to the multicast group info.\r
+\r
+ @retval EFI_SUCCESS The configuration completed successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockGroup (\r
+ IN SOCKET *Sock,\r
+ IN VOID *GroupInfo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockGroup: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_GROUP, GroupInfo);\r
+\r
+Exit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Add or remove route information in IP route table associated\r
+ with this socket.\r
+\r
+ @param[in] Sock Pointer to the socket associated with the IP route\r
+ table to operate on.\r
+ @param[in] RouteInfo Pointer to the route information to be processed.\r
+\r
+ @retval EFI_SUCCESS The route table updated successfully.\r
+ @retval EFI_ACCESS_DENIED Failed to get the lock to access the socket.\r
+ @retval EFI_NO_MAPPING The IP address configuration operation is not\r
+ finished.\r
+ @retval EFI_NOT_STARTED The socket is not configured.\r
+\r
+**/\r
+EFI_STATUS\r
+SockRoute (\r
+ IN SOCKET *Sock,\r
+ IN VOID *RouteInfo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EfiAcquireLockOrFail (&(Sock->Lock));\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "SockRoute: Get the access for socket failed with %r",\r
+ Status)\r
+ );\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (SOCK_IS_NO_MAPPING (Sock)) {\r
+ Status = EFI_NO_MAPPING;\r
+ goto Exit;\r
+ }\r
+\r
+ if (SOCK_IS_UNCONFIGURED (Sock)) {\r
+ Status = EFI_NOT_STARTED;\r
+ goto Exit;\r
+ }\r
+\r
+ Status = Sock->ProtoHandler (Sock, SOCK_ROUTE, RouteInfo);\r
+\r
+Exit:\r
+ EfiReleaseLock (&(Sock->Lock));\r
+ return Status;\r
+}\r
+\r