]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/TcpDxe/SockInterface.c
Add NetworkPkg (P.UDK2010.UP3.Network.P1)
[mirror_edk2.git] / NetworkPkg / TcpDxe / SockInterface.c
diff --git a/NetworkPkg/TcpDxe/SockInterface.c b/NetworkPkg/TcpDxe/SockInterface.c
new file mode 100644 (file)
index 0000000..e36c0e9
--- /dev/null
@@ -0,0 +1,999 @@
+/** @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