REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the NetworkPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
		
			
				
	
	
		
			1212 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1212 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Implementation of the Socket.
 | |
| 
 | |
|   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "SockImpl.h"
 | |
| 
 | |
| /**
 | |
|   Get the first buffer block in the specific socket buffer.
 | |
| 
 | |
|   @param[in]  Sockbuf               Pointer to the socket buffer.
 | |
| 
 | |
|   @return Pointer to the first buffer in the queue. NULL if the queue is empty.
 | |
| 
 | |
| **/
 | |
| NET_BUF *
 | |
| SockBufFirst (
 | |
|   IN SOCK_BUFFER  *Sockbuf
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY  *NetbufList;
 | |
| 
 | |
|   NetbufList = &(Sockbuf->DataQueue->BufList);
 | |
| 
 | |
|   if (IsListEmpty (NetbufList)) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   return NET_LIST_HEAD (NetbufList, NET_BUF, List);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the next buffer block in the specific socket buffer.
 | |
| 
 | |
|   @param[in]  Sockbuf     Pointer to the socket buffer.
 | |
|   @param[in]  SockEntry   Pointer to the buffer block prior to the required one.
 | |
| 
 | |
|   @return Pointer to the buffer block next to SockEntry. NULL if SockEntry is
 | |
|           the tail or head entry.
 | |
| 
 | |
| **/
 | |
| NET_BUF *
 | |
| SockBufNext (
 | |
|   IN SOCK_BUFFER  *Sockbuf,
 | |
|   IN NET_BUF      *SockEntry
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY  *NetbufList;
 | |
| 
 | |
|   NetbufList = &(Sockbuf->DataQueue->BufList);
 | |
| 
 | |
|   if ((SockEntry->List.ForwardLink == NetbufList) ||
 | |
|       (SockEntry->List.BackLink == &SockEntry->List) ||
 | |
|       (SockEntry->List.ForwardLink == &SockEntry->List)
 | |
|       )
 | |
|   {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   return NET_LIST_USER_STRUCT (SockEntry->List.ForwardLink, NET_BUF, List);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   User provided callback function for NetbufFromExt.
 | |
| 
 | |
|   @param[in] Arg      The Arg parameter forwarded by NetbufFromExt(). Ignored.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| SockFreeFoo (
 | |
|   IN VOID  *Arg
 | |
|   )
 | |
| {
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the length of the data that can be retrieved from the socket
 | |
|   receive buffer.
 | |
| 
 | |
|   @param[in]  SockBuffer            Pointer to the socket receive buffer.
 | |
|   @param[out] IsUrg                 Pointer to a BOOLEAN variable.
 | |
|                                     If TRUE the data is OOB.
 | |
|   @param[in]  BufLen                The maximum length of the data buffer to
 | |
|                                     store the received data in the socket layer.
 | |
| 
 | |
|   @return The length of the data can be retrieved.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| SockTcpDataToRcv (
 | |
|   IN  SOCK_BUFFER  *SockBuffer,
 | |
|   OUT BOOLEAN      *IsUrg,
 | |
|   IN  UINT32       BufLen
 | |
|   )
 | |
| {
 | |
|   NET_BUF       *RcvBufEntry;
 | |
|   UINT32        DataLen;
 | |
|   TCP_RSV_DATA  *TcpRsvData;
 | |
|   BOOLEAN       Urg;
 | |
| 
 | |
|   ASSERT ((SockBuffer != NULL) && (IsUrg != NULL) && (BufLen > 0));
 | |
| 
 | |
|   //
 | |
|   // Get the first socket receive buffer
 | |
|   //
 | |
|   RcvBufEntry = SockBufFirst (SockBuffer);
 | |
|   ASSERT (RcvBufEntry != NULL);
 | |
| 
 | |
|   TcpRsvData = (TCP_RSV_DATA *)RcvBufEntry->ProtoData;
 | |
| 
 | |
|   //
 | |
|   // Check whether the receive data is out of bound. If yes, calculate the maximum
 | |
|   // allowed length of the urgent data and output it.
 | |
|   //
 | |
|   *IsUrg = (BOOLEAN)((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);
 | |
| 
 | |
|   if (*IsUrg && (TcpRsvData->UrgLen < RcvBufEntry->TotalSize)) {
 | |
|     DataLen = MIN (TcpRsvData->UrgLen, BufLen);
 | |
| 
 | |
|     if (DataLen < TcpRsvData->UrgLen) {
 | |
|       TcpRsvData->UrgLen = TcpRsvData->UrgLen - DataLen;
 | |
|     } else {
 | |
|       TcpRsvData->UrgLen = 0;
 | |
|     }
 | |
| 
 | |
|     return DataLen;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Process the next socket receive buffer to get the maximum allowed length
 | |
|   // of the received data.
 | |
|   //
 | |
|   DataLen = RcvBufEntry->TotalSize;
 | |
| 
 | |
|   RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);
 | |
| 
 | |
|   while ((BufLen > DataLen) && (RcvBufEntry != NULL)) {
 | |
|     TcpRsvData = (TCP_RSV_DATA *)RcvBufEntry->ProtoData;
 | |
| 
 | |
|     Urg = (BOOLEAN)((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);
 | |
| 
 | |
|     if (*IsUrg != Urg) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (*IsUrg && (TcpRsvData->UrgLen < RcvBufEntry->TotalSize)) {
 | |
|       if (TcpRsvData->UrgLen + DataLen < BufLen) {
 | |
|         TcpRsvData->UrgLen = 0;
 | |
|       } else {
 | |
|         TcpRsvData->UrgLen = TcpRsvData->UrgLen - (BufLen - DataLen);
 | |
|       }
 | |
| 
 | |
|       return MIN (TcpRsvData->UrgLen + DataLen, BufLen);
 | |
|     }
 | |
| 
 | |
|     DataLen += RcvBufEntry->TotalSize;
 | |
| 
 | |
|     RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);
 | |
|   }
 | |
| 
 | |
|   DataLen = MIN (BufLen, DataLen);
 | |
|   return DataLen;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Copy data from socket buffer to an application provided receive buffer.
 | |
| 
 | |
|   @param[in]  Sock        Pointer to the socket.
 | |
|   @param[in]  TcpRxData   Pointer to the application provided receive buffer.
 | |
|   @param[in]  RcvdBytes   The maximum length of the data can be copied.
 | |
|   @param[in]  IsUrg       If TRUE the data is Out of Bound, FALSE the data is normal.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockSetTcpRxData (
 | |
|   IN SOCKET   *Sock,
 | |
|   IN VOID     *TcpRxData,
 | |
|   IN UINT32   RcvdBytes,
 | |
|   IN BOOLEAN  IsUrg
 | |
|   )
 | |
| {
 | |
|   UINT32                  Index;
 | |
|   UINT32                  CopyBytes;
 | |
|   UINT32                  OffSet;
 | |
|   EFI_TCP4_RECEIVE_DATA   *RxData;
 | |
|   EFI_TCP4_FRAGMENT_DATA  *Fragment;
 | |
| 
 | |
|   RxData = (EFI_TCP4_RECEIVE_DATA *)TcpRxData;
 | |
| 
 | |
|   OffSet = 0;
 | |
| 
 | |
|   ASSERT (RxData->DataLength >= RcvdBytes);
 | |
| 
 | |
|   RxData->DataLength = RcvdBytes;
 | |
|   RxData->UrgentFlag = IsUrg;
 | |
| 
 | |
|   //
 | |
|   // Copy the CopyBytes data from socket receive buffer to RxData.
 | |
|   //
 | |
|   for (Index = 0; (Index < RxData->FragmentCount) && (RcvdBytes > 0); Index++) {
 | |
|     Fragment  = &RxData->FragmentTable[Index];
 | |
|     CopyBytes = MIN ((UINT32)(Fragment->FragmentLength), RcvdBytes);
 | |
| 
 | |
|     NetbufQueCopy (
 | |
|       Sock->RcvBuffer.DataQueue,
 | |
|       OffSet,
 | |
|       CopyBytes,
 | |
|       Fragment->FragmentBuffer
 | |
|       );
 | |
| 
 | |
|     Fragment->FragmentLength = CopyBytes;
 | |
|     RcvdBytes               -= CopyBytes;
 | |
|     OffSet                  += CopyBytes;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Process the send token.
 | |
| 
 | |
|   @param[in, out]  Sock                  Pointer to the socket.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockProcessSndToken (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   UINT32                  FreeSpace;
 | |
|   SOCK_TOKEN              *SockToken;
 | |
|   UINT32                  DataLen;
 | |
|   SOCK_IO_TOKEN           *SndToken;
 | |
|   EFI_TCP4_TRANSMIT_DATA  *TxData;
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   ASSERT ((Sock != NULL) && (SockStream == Sock->Type));
 | |
| 
 | |
|   FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);
 | |
| 
 | |
|   //
 | |
|   // to determine if process a send token using
 | |
|   // socket layer flow control policy
 | |
|   //
 | |
|   while ((FreeSpace >= Sock->SndBuffer.LowWater) && !IsListEmpty (&Sock->SndTokenList)) {
 | |
|     SockToken = NET_LIST_HEAD (
 | |
|                   &(Sock->SndTokenList),
 | |
|                   SOCK_TOKEN,
 | |
|                   TokenList
 | |
|                   );
 | |
| 
 | |
|     //
 | |
|     // process this token
 | |
|     //
 | |
|     RemoveEntryList (&(SockToken->TokenList));
 | |
|     InsertTailList (
 | |
|       &(Sock->ProcessingSndTokenList),
 | |
|       &(SockToken->TokenList)
 | |
|       );
 | |
| 
 | |
|     //
 | |
|     // Process it in the light of SockType
 | |
|     //
 | |
|     SndToken = (SOCK_IO_TOKEN *)SockToken->Token;
 | |
|     TxData   = SndToken->Packet.TxData;
 | |
| 
 | |
|     DataLen = TxData->DataLength;
 | |
|     Status  = SockProcessTcpSndData (Sock, TxData);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto OnError;
 | |
|     }
 | |
| 
 | |
|     if (DataLen >= FreeSpace) {
 | |
|       FreeSpace = 0;
 | |
|     } else {
 | |
|       FreeSpace -= DataLen;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return;
 | |
| 
 | |
| OnError:
 | |
| 
 | |
|   RemoveEntryList (&SockToken->TokenList);
 | |
|   SIGNAL_TOKEN (SockToken->Token, Status);
 | |
|   FreePool (SockToken);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get received data from the socket layer to the receive token.
 | |
| 
 | |
|   @param[in, out]  Sock       Pointer to the socket.
 | |
|   @param[in, out]  RcvToken   Pointer to the application provided receive token.
 | |
| 
 | |
|   @return The length of data received in this token.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| SockProcessRcvToken (
 | |
|   IN OUT SOCKET         *Sock,
 | |
|   IN OUT SOCK_IO_TOKEN  *RcvToken
 | |
|   )
 | |
| {
 | |
|   UINT32                 TokenRcvdBytes;
 | |
|   EFI_TCP4_RECEIVE_DATA  *RxData;
 | |
|   BOOLEAN                IsUrg;
 | |
| 
 | |
|   ASSERT (Sock != NULL);
 | |
| 
 | |
|   ASSERT (SockStream == Sock->Type);
 | |
| 
 | |
|   RxData = RcvToken->Packet.RxData;
 | |
| 
 | |
|   TokenRcvdBytes = SockTcpDataToRcv (
 | |
|                      &Sock->RcvBuffer,
 | |
|                      &IsUrg,
 | |
|                      RxData->DataLength
 | |
|                      );
 | |
| 
 | |
|   //
 | |
|   // Copy data from RcvBuffer of socket to user
 | |
|   // provided RxData and set the fields in TCP RxData
 | |
|   //
 | |
|   SockSetTcpRxData (Sock, RxData, TokenRcvdBytes, IsUrg);
 | |
| 
 | |
|   NetbufQueTrim (Sock->RcvBuffer.DataQueue, TokenRcvdBytes);
 | |
|   SIGNAL_TOKEN (&(RcvToken->Token), EFI_SUCCESS);
 | |
| 
 | |
|   return TokenRcvdBytes;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Process the TCP send data, buffer the tcp txdata, and append
 | |
|   the buffer to socket send buffer, then try to send it.
 | |
| 
 | |
|   @param[in]  Sock              Pointer to the socket.
 | |
|   @param[in]  TcpTxData         Pointer to the application provided send buffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The operation completed successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Failed due to resource limits.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockProcessTcpSndData (
 | |
|   IN SOCKET  *Sock,
 | |
|   IN VOID    *TcpTxData
 | |
|   )
 | |
| {
 | |
|   NET_BUF                 *SndData;
 | |
|   EFI_STATUS              Status;
 | |
|   EFI_TCP4_TRANSMIT_DATA  *TxData;
 | |
| 
 | |
|   TxData = (EFI_TCP4_TRANSMIT_DATA *)TcpTxData;
 | |
| 
 | |
|   //
 | |
|   // transform this TxData into a NET_BUFFER
 | |
|   // and insert it into Sock->SndBuffer
 | |
|   //
 | |
|   SndData = NetbufFromExt (
 | |
|               (NET_FRAGMENT *)TxData->FragmentTable,
 | |
|               TxData->FragmentCount,
 | |
|               0,
 | |
|               0,
 | |
|               SockFreeFoo,
 | |
|               NULL
 | |
|               );
 | |
| 
 | |
|   if (NULL == SndData) {
 | |
|     DEBUG (
 | |
|       (DEBUG_ERROR,
 | |
|        "SockKProcessSndData: Failed to call NetBufferFromExt\n")
 | |
|       );
 | |
| 
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   NetbufQueAppend (Sock->SndBuffer.DataQueue, SndData);
 | |
| 
 | |
|   //
 | |
|   // notify the low layer protocol to handle this send token
 | |
|   //
 | |
|   if (TxData->Urgent) {
 | |
|     Status = Sock->ProtoHandler (Sock, SOCK_SNDURG, NULL);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (TxData->Push) {
 | |
|     Status = Sock->ProtoHandler (Sock, SOCK_SNDPUSH, NULL);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // low layer protocol should really handle the sending
 | |
|   // process when catching SOCK_SND request
 | |
|   //
 | |
|   Status = Sock->ProtoHandler (Sock, SOCK_SND, NULL);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Flush the tokens in the specific token list.
 | |
| 
 | |
|   @param[in]       Sock                  Pointer to the socket.
 | |
|   @param[in, out]  PendingTokenList      Pointer to the token list to be flushed.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockFlushPendingToken (
 | |
|   IN     SOCKET      *Sock,
 | |
|   IN OUT LIST_ENTRY  *PendingTokenList
 | |
|   )
 | |
| {
 | |
|   SOCK_TOKEN             *SockToken;
 | |
|   SOCK_COMPLETION_TOKEN  *Token;
 | |
| 
 | |
|   ASSERT ((Sock != NULL) && (PendingTokenList != NULL));
 | |
| 
 | |
|   while (!IsListEmpty (PendingTokenList)) {
 | |
|     SockToken = NET_LIST_HEAD (
 | |
|                   PendingTokenList,
 | |
|                   SOCK_TOKEN,
 | |
|                   TokenList
 | |
|                   );
 | |
| 
 | |
|     Token = SockToken->Token;
 | |
|     SIGNAL_TOKEN (Token, Sock->SockError);
 | |
| 
 | |
|     RemoveEntryList (&(SockToken->TokenList));
 | |
|     FreePool (SockToken);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Wake up the connection token while the connection is successfully established,
 | |
|   then try to process any pending send token.
 | |
| 
 | |
|   @param[in, out]  Sock                  Pointer to the socket.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockWakeConnToken (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   ASSERT (Sock->ConnectionToken != NULL);
 | |
| 
 | |
|   SIGNAL_TOKEN (Sock->ConnectionToken, EFI_SUCCESS);
 | |
|   Sock->ConnectionToken = NULL;
 | |
| 
 | |
|   //
 | |
|   // check to see if some pending send token existed?
 | |
|   //
 | |
|   SockProcessSndToken (Sock);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Wake up the listen token while the connection is established successfully.
 | |
| 
 | |
|   @param[in, out]  Sock                  Pointer to the socket.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockWakeListenToken (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   SOCKET                 *Parent;
 | |
|   SOCK_TOKEN             *SockToken;
 | |
|   EFI_TCP4_LISTEN_TOKEN  *ListenToken;
 | |
| 
 | |
|   Parent = Sock->Parent;
 | |
| 
 | |
|   ASSERT ((Parent != NULL) && SOCK_IS_LISTENING (Parent) && SOCK_IS_CONNECTED (Sock));
 | |
| 
 | |
|   if (!IsListEmpty (&Parent->ListenTokenList)) {
 | |
|     SockToken = NET_LIST_HEAD (
 | |
|                   &Parent->ListenTokenList,
 | |
|                   SOCK_TOKEN,
 | |
|                   TokenList
 | |
|                   );
 | |
| 
 | |
|     ListenToken                 = (EFI_TCP4_LISTEN_TOKEN *)SockToken->Token;
 | |
|     ListenToken->NewChildHandle = Sock->SockHandle;
 | |
| 
 | |
|     SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);
 | |
| 
 | |
|     RemoveEntryList (&SockToken->TokenList);
 | |
|     FreePool (SockToken);
 | |
| 
 | |
|     RemoveEntryList (&Sock->ConnectionList);
 | |
| 
 | |
|     Parent->ConnCnt--;
 | |
|     DEBUG (
 | |
|       (DEBUG_NET,
 | |
|        "SockWakeListenToken: accept a socket, now conncnt is %d",
 | |
|        Parent->ConnCnt)
 | |
|       );
 | |
| 
 | |
|     Sock->Parent = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Wake up the receive token while some data is received.
 | |
| 
 | |
|   @param[in, out]  Sock                  Pointer to the socket.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockWakeRcvToken (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   UINT32         RcvdBytes;
 | |
|   UINT32         TokenRcvdBytes;
 | |
|   SOCK_TOKEN     *SockToken;
 | |
|   SOCK_IO_TOKEN  *RcvToken;
 | |
| 
 | |
|   ASSERT (Sock->RcvBuffer.DataQueue != NULL);
 | |
| 
 | |
|   RcvdBytes = (Sock->RcvBuffer.DataQueue)->BufSize;
 | |
| 
 | |
|   ASSERT (RcvdBytes > 0);
 | |
| 
 | |
|   while (RcvdBytes > 0 && !IsListEmpty (&Sock->RcvTokenList)) {
 | |
|     SockToken = NET_LIST_HEAD (
 | |
|                   &Sock->RcvTokenList,
 | |
|                   SOCK_TOKEN,
 | |
|                   TokenList
 | |
|                   );
 | |
| 
 | |
|     RcvToken       = (SOCK_IO_TOKEN *)SockToken->Token;
 | |
|     TokenRcvdBytes = SockProcessRcvToken (Sock, RcvToken);
 | |
| 
 | |
|     if (0 == TokenRcvdBytes) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     RemoveEntryList (&(SockToken->TokenList));
 | |
|     FreePool (SockToken);
 | |
|     RcvdBytes -= TokenRcvdBytes;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Cancel the tokens in the specific token list.
 | |
| 
 | |
|   @param[in]       Token                 Pointer to the Token. If NULL, all tokens
 | |
|                                          in SpecifiedTokenList will be canceled.
 | |
|   @param[in, out]  SpecifiedTokenList    Pointer to the token list to be checked.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Cancel the tokens in the specific token listsuccessfully.
 | |
|   @retval EFI_NOT_FOUND        The Token is not found in SpecifiedTokenList.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SockCancelToken (
 | |
|   IN     SOCK_COMPLETION_TOKEN  *Token,
 | |
|   IN OUT LIST_ENTRY             *SpecifiedTokenList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   LIST_ENTRY  *Entry;
 | |
|   SOCK_TOKEN  *SockToken;
 | |
| 
 | |
|   Status    = EFI_SUCCESS;
 | |
|   Entry     = NULL;
 | |
|   SockToken = NULL;
 | |
| 
 | |
|   if (IsListEmpty (SpecifiedTokenList) && (Token != NULL)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Iterate through the SpecifiedTokenList.
 | |
|   //
 | |
|   Entry = SpecifiedTokenList->ForwardLink;
 | |
|   while (Entry != SpecifiedTokenList) {
 | |
|     SockToken = NET_LIST_USER_STRUCT (Entry, SOCK_TOKEN, TokenList);
 | |
| 
 | |
|     if (Token == NULL) {
 | |
|       SIGNAL_TOKEN (SockToken->Token, EFI_ABORTED);
 | |
|       RemoveEntryList (&SockToken->TokenList);
 | |
|       FreePool (SockToken);
 | |
| 
 | |
|       Entry  = SpecifiedTokenList->ForwardLink;
 | |
|       Status = EFI_SUCCESS;
 | |
|     } else {
 | |
|       if (Token == (VOID *)SockToken->Token) {
 | |
|         SIGNAL_TOKEN (Token, EFI_ABORTED);
 | |
|         RemoveEntryList (&(SockToken->TokenList));
 | |
|         FreePool (SockToken);
 | |
| 
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
| 
 | |
|       Status = EFI_NOT_FOUND;
 | |
| 
 | |
|       Entry = Entry->ForwardLink;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ASSERT (IsListEmpty (SpecifiedTokenList) || Token != NULL);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create a socket with initial data SockInitData.
 | |
| 
 | |
|   @param[in]  SockInitData          Pointer to the initial data of the socket.
 | |
| 
 | |
|   @return Pointer to the newly created socket, return NULL when an exception occurs.
 | |
| 
 | |
| **/
 | |
| SOCKET *
 | |
| SockCreate (
 | |
|   IN SOCK_INIT_DATA  *SockInitData
 | |
|   )
 | |
| {
 | |
|   SOCKET      *Sock;
 | |
|   SOCKET      *Parent;
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_GUID    *TcpProtocolGuid;
 | |
|   UINTN       ProtocolLength;
 | |
| 
 | |
|   ASSERT ((SockInitData != NULL) && (SockInitData->ProtoHandler != NULL));
 | |
|   ASSERT (SockInitData->Type == SockStream);
 | |
|   ASSERT ((SockInitData->ProtoData != NULL) && (SockInitData->DataSize <= PROTO_RESERVED_LEN));
 | |
| 
 | |
|   if (SockInitData->IpVersion == IP_VERSION_4) {
 | |
|     TcpProtocolGuid = &gEfiTcp4ProtocolGuid;
 | |
|     ProtocolLength  = sizeof (EFI_TCP4_PROTOCOL);
 | |
|   } else {
 | |
|     TcpProtocolGuid = &gEfiTcp6ProtocolGuid;
 | |
|     ProtocolLength  = sizeof (EFI_TCP6_PROTOCOL);
 | |
|   }
 | |
| 
 | |
|   Parent = SockInitData->Parent;
 | |
| 
 | |
|   if ((Parent != NULL) && (Parent->ConnCnt == Parent->BackLog)) {
 | |
|     DEBUG (
 | |
|       (DEBUG_ERROR,
 | |
|        "SockCreate: Socket parent has reached its connection limit with %d ConnCnt and %d BackLog\n",
 | |
|        Parent->ConnCnt,
 | |
|        Parent->BackLog)
 | |
|       );
 | |
| 
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Sock = AllocateZeroPool (sizeof (SOCKET));
 | |
|   if (NULL == Sock) {
 | |
|     DEBUG ((DEBUG_ERROR, "SockCreate: No resource to create a new socket\n"));
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   InitializeListHead (&Sock->Link);
 | |
|   InitializeListHead (&Sock->ConnectionList);
 | |
|   InitializeListHead (&Sock->ListenTokenList);
 | |
|   InitializeListHead (&Sock->RcvTokenList);
 | |
|   InitializeListHead (&Sock->SndTokenList);
 | |
|   InitializeListHead (&Sock->ProcessingSndTokenList);
 | |
| 
 | |
|   EfiInitializeLock (&(Sock->Lock), TPL_CALLBACK);
 | |
| 
 | |
|   Sock->SndBuffer.DataQueue = NetbufQueAlloc ();
 | |
|   if (NULL == Sock->SndBuffer.DataQueue) {
 | |
|     DEBUG (
 | |
|       (DEBUG_ERROR,
 | |
|        "SockCreate: No resource to allocate SndBuffer for new socket\n")
 | |
|       );
 | |
| 
 | |
|     goto OnError;
 | |
|   }
 | |
| 
 | |
|   Sock->RcvBuffer.DataQueue = NetbufQueAlloc ();
 | |
|   if (NULL == Sock->RcvBuffer.DataQueue) {
 | |
|     DEBUG (
 | |
|       (DEBUG_ERROR,
 | |
|        "SockCreate: No resource to allocate RcvBuffer for new socket\n")
 | |
|       );
 | |
| 
 | |
|     goto OnError;
 | |
|   }
 | |
| 
 | |
|   Sock->Signature = SOCK_SIGNATURE;
 | |
| 
 | |
|   Sock->Parent              = Parent;
 | |
|   Sock->BackLog             = SockInitData->BackLog;
 | |
|   Sock->ProtoHandler        = SockInitData->ProtoHandler;
 | |
|   Sock->SndBuffer.HighWater = SockInitData->SndBufferSize;
 | |
|   Sock->RcvBuffer.HighWater = SockInitData->RcvBufferSize;
 | |
|   Sock->Type                = SockInitData->Type;
 | |
|   Sock->DriverBinding       = SockInitData->DriverBinding;
 | |
|   Sock->State               = SockInitData->State;
 | |
|   Sock->CreateCallback      = SockInitData->CreateCallback;
 | |
|   Sock->DestroyCallback     = SockInitData->DestroyCallback;
 | |
|   Sock->Context             = SockInitData->Context;
 | |
| 
 | |
|   Sock->SockError          = EFI_ABORTED;
 | |
|   Sock->SndBuffer.LowWater = SOCK_BUFF_LOW_WATER;
 | |
|   Sock->RcvBuffer.LowWater = SOCK_BUFF_LOW_WATER;
 | |
| 
 | |
|   Sock->IpVersion = SockInitData->IpVersion;
 | |
| 
 | |
|   //
 | |
|   // Install protocol on Sock->SockHandle
 | |
|   //
 | |
|   CopyMem (&Sock->NetProtocol, SockInitData->Protocol, ProtocolLength);
 | |
| 
 | |
|   //
 | |
|   // copy the protodata into socket
 | |
|   //
 | |
|   CopyMem (Sock->ProtoReserved, SockInitData->ProtoData, SockInitData->DataSize);
 | |
| 
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &Sock->SockHandle,
 | |
|                   TcpProtocolGuid,
 | |
|                   &Sock->NetProtocol,
 | |
|                   NULL
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG (
 | |
|       (DEBUG_ERROR,
 | |
|        "SockCreate: Install TCP protocol in socket failed with %r\n",
 | |
|        Status)
 | |
|       );
 | |
| 
 | |
|     goto OnError;
 | |
|   }
 | |
| 
 | |
|   if (Parent != NULL) {
 | |
|     ASSERT (Parent->BackLog > 0);
 | |
|     ASSERT (SOCK_IS_LISTENING (Parent));
 | |
| 
 | |
|     //
 | |
|     // need to add it into Parent->ConnectionList
 | |
|     // if the Parent->ConnCnt < Parent->BackLog
 | |
|     //
 | |
|     Parent->ConnCnt++;
 | |
| 
 | |
|     DEBUG (
 | |
|       (DEBUG_NET,
 | |
|        "SockCreate: Create a new socket and add to parent, now conncnt is %d\n",
 | |
|        Parent->ConnCnt)
 | |
|       );
 | |
| 
 | |
|     InsertTailList (&Parent->ConnectionList, &Sock->ConnectionList);
 | |
|   }
 | |
| 
 | |
|   if (Sock->CreateCallback != NULL) {
 | |
|     Status = Sock->CreateCallback (Sock, Sock->Context);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto OnError;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Sock;
 | |
| 
 | |
| OnError:
 | |
| 
 | |
|   if (Sock->SockHandle != NULL) {
 | |
|     gBS->UninstallMultipleProtocolInterfaces (
 | |
|            Sock->SockHandle,
 | |
|            TcpProtocolGuid,
 | |
|            &Sock->NetProtocol,
 | |
|            NULL
 | |
|            );
 | |
|   }
 | |
| 
 | |
|   if (NULL != Sock->SndBuffer.DataQueue) {
 | |
|     NetbufQueFree (Sock->SndBuffer.DataQueue);
 | |
|   }
 | |
| 
 | |
|   if (NULL != Sock->RcvBuffer.DataQueue) {
 | |
|     NetbufQueFree (Sock->RcvBuffer.DataQueue);
 | |
|   }
 | |
| 
 | |
|   FreePool (Sock);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Destroy a socket.
 | |
| 
 | |
|   @param[in, out]  Sock                  Pointer to the socket.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockDestroy (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   ASSERT (SockStream == Sock->Type);
 | |
| 
 | |
|   //
 | |
|   // Flush the completion token buffered
 | |
|   // by sock and rcv, snd buffer
 | |
|   //
 | |
|   if (!SOCK_IS_UNCONFIGURED (Sock)) {
 | |
|     SockConnFlush (Sock);
 | |
|     SockSetState (Sock, SO_CLOSED);
 | |
|     Sock->ConfigureState = SO_UNCONFIGURED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Destroy the RcvBuffer Queue and SendBuffer Queue
 | |
|   //
 | |
|   NetbufQueFree (Sock->RcvBuffer.DataQueue);
 | |
|   NetbufQueFree (Sock->SndBuffer.DataQueue);
 | |
| 
 | |
|   //
 | |
|   // Remove it from parent connection list if needed
 | |
|   //
 | |
|   if (Sock->Parent != NULL) {
 | |
|     RemoveEntryList (&(Sock->ConnectionList));
 | |
|     (Sock->Parent->ConnCnt)--;
 | |
| 
 | |
|     DEBUG (
 | |
|       (DEBUG_WARN,
 | |
|        "SockDestroy: Delete a unaccepted socket from parent now conncnt is %d\n",
 | |
|        Sock->Parent->ConnCnt)
 | |
|       );
 | |
| 
 | |
|     Sock->Parent = NULL;
 | |
|   }
 | |
| 
 | |
|   FreePool (Sock);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Flush the sndBuffer and rcvBuffer of socket.
 | |
| 
 | |
|   @param[in, out]  Sock                  Pointer to the socket.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockConnFlush (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   SOCKET  *Child;
 | |
| 
 | |
|   ASSERT (Sock != NULL);
 | |
| 
 | |
|   //
 | |
|   // Clear the flag in this socket
 | |
|   //
 | |
|   Sock->Flag = 0;
 | |
| 
 | |
|   //
 | |
|   // Flush the SndBuffer and RcvBuffer of Sock
 | |
|   //
 | |
|   NetbufQueFlush (Sock->SndBuffer.DataQueue);
 | |
|   NetbufQueFlush (Sock->RcvBuffer.DataQueue);
 | |
| 
 | |
|   //
 | |
|   // Signal the pending token
 | |
|   //
 | |
|   if (Sock->ConnectionToken != NULL) {
 | |
|     SIGNAL_TOKEN (Sock->ConnectionToken, Sock->SockError);
 | |
|     Sock->ConnectionToken = NULL;
 | |
|   }
 | |
| 
 | |
|   if (Sock->CloseToken != NULL) {
 | |
|     SIGNAL_TOKEN (Sock->CloseToken, Sock->SockError);
 | |
|     Sock->CloseToken = NULL;
 | |
|   }
 | |
| 
 | |
|   SockFlushPendingToken (Sock, &(Sock->ListenTokenList));
 | |
|   SockFlushPendingToken (Sock, &(Sock->RcvTokenList));
 | |
|   SockFlushPendingToken (Sock, &(Sock->SndTokenList));
 | |
|   SockFlushPendingToken (Sock, &(Sock->ProcessingSndTokenList));
 | |
| 
 | |
|   //
 | |
|   // Destroy the pending connection, if it is a listening socket
 | |
|   //
 | |
|   if (SOCK_IS_LISTENING (Sock)) {
 | |
|     while (!IsListEmpty (&Sock->ConnectionList)) {
 | |
|       Child = NET_LIST_HEAD (
 | |
|                 &Sock->ConnectionList,
 | |
|                 SOCKET,
 | |
|                 ConnectionList
 | |
|                 );
 | |
| 
 | |
|       SockDestroyChild (Child);
 | |
|     }
 | |
| 
 | |
|     Sock->ConnCnt = 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set the state of the socket.
 | |
| 
 | |
|   @param[in, out]  Sock                  Pointer to the socket.
 | |
|   @param[in]       State                 The new socket state to be set.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockSetState (
 | |
|   IN OUT SOCKET  *Sock,
 | |
|   IN     UINT8   State
 | |
|   )
 | |
| {
 | |
|   Sock->State = State;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Clone a new socket, including its associated protocol control block.
 | |
| 
 | |
|   @param[in]  Sock                  Pointer to the socket to be cloned.
 | |
| 
 | |
|   @return Pointer to the newly cloned socket. If NULL, an error condition occurred.
 | |
| 
 | |
| **/
 | |
| SOCKET *
 | |
| SockClone (
 | |
|   IN SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   SOCKET          *ClonedSock;
 | |
|   SOCK_INIT_DATA  InitData;
 | |
| 
 | |
|   InitData.BackLog         = Sock->BackLog;
 | |
|   InitData.Parent          = Sock;
 | |
|   InitData.State           = Sock->State;
 | |
|   InitData.ProtoHandler    = Sock->ProtoHandler;
 | |
|   InitData.Type            = Sock->Type;
 | |
|   InitData.RcvBufferSize   = Sock->RcvBuffer.HighWater;
 | |
|   InitData.SndBufferSize   = Sock->SndBuffer.HighWater;
 | |
|   InitData.DriverBinding   = Sock->DriverBinding;
 | |
|   InitData.IpVersion       = Sock->IpVersion;
 | |
|   InitData.Protocol        = &(Sock->NetProtocol);
 | |
|   InitData.CreateCallback  = Sock->CreateCallback;
 | |
|   InitData.DestroyCallback = Sock->DestroyCallback;
 | |
|   InitData.Context         = Sock->Context;
 | |
|   InitData.ProtoData       = Sock->ProtoReserved;
 | |
|   InitData.DataSize        = sizeof (Sock->ProtoReserved);
 | |
| 
 | |
|   ClonedSock = SockCreate (&InitData);
 | |
| 
 | |
|   if (NULL == ClonedSock) {
 | |
|     DEBUG ((DEBUG_ERROR, "SockClone: no resource to create a cloned sock\n"));
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   SockSetState (ClonedSock, SO_CONNECTING);
 | |
|   ClonedSock->ConfigureState = Sock->ConfigureState;
 | |
| 
 | |
|   return ClonedSock;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Called by the low layer protocol to indicate the socket a connection is
 | |
|   established.
 | |
| 
 | |
|   This function just changes the socket's state to SO_CONNECTED
 | |
|   and signals the token used for connection establishment.
 | |
| 
 | |
|   @param[in, out]  Sock         Pointer to the socket associated with the
 | |
|                                 established connection.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockConnEstablished (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   ASSERT (SO_CONNECTING == Sock->State);
 | |
| 
 | |
|   SockSetState (Sock, SO_CONNECTED);
 | |
| 
 | |
|   if (NULL == Sock->Parent) {
 | |
|     SockWakeConnToken (Sock);
 | |
|   } else {
 | |
|     SockWakeListenToken (Sock);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Called by the low layer protocol to indicate the connection is closed.
 | |
| 
 | |
|   This function flushes the socket, sets the state to SO_CLOSED, and signals
 | |
|   the close token.
 | |
| 
 | |
|   @param[in, out]  Sock         Pointer to the socket associated with the closed
 | |
|                                 connection.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockConnClosed (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   if (Sock->CloseToken != NULL) {
 | |
|     SIGNAL_TOKEN (Sock->CloseToken, EFI_SUCCESS);
 | |
|     Sock->CloseToken = NULL;
 | |
|   }
 | |
| 
 | |
|   SockConnFlush (Sock);
 | |
|   SockSetState (Sock, SO_CLOSED);
 | |
| 
 | |
|   if (Sock->Parent != NULL) {
 | |
|     SockDestroyChild (Sock);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Called by low layer protocol to indicate that some data was sent or processed.
 | |
| 
 | |
|   This function trims the sent data in the socket send buffer, and signals the data
 | |
|   token if proper.
 | |
| 
 | |
|   @param[in, out]  Sock      Pointer to the socket.
 | |
|   @param[in]       Count     The length of the data processed or sent, in bytes.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockDataSent (
 | |
|   IN OUT SOCKET  *Sock,
 | |
|   IN     UINT32  Count
 | |
|   )
 | |
| {
 | |
|   SOCK_TOKEN             *SockToken;
 | |
|   SOCK_COMPLETION_TOKEN  *SndToken;
 | |
| 
 | |
|   ASSERT (!IsListEmpty (&Sock->ProcessingSndTokenList));
 | |
|   ASSERT (Count <= (Sock->SndBuffer.DataQueue)->BufSize);
 | |
| 
 | |
|   NetbufQueTrim (Sock->SndBuffer.DataQueue, Count);
 | |
| 
 | |
|   //
 | |
|   // To check if we can signal some snd token in this socket
 | |
|   //
 | |
|   while (Count > 0) {
 | |
|     SockToken = NET_LIST_HEAD (
 | |
|                   &(Sock->ProcessingSndTokenList),
 | |
|                   SOCK_TOKEN,
 | |
|                   TokenList
 | |
|                   );
 | |
| 
 | |
|     SndToken = SockToken->Token;
 | |
| 
 | |
|     if (SockToken->RemainDataLen <= Count) {
 | |
|       RemoveEntryList (&(SockToken->TokenList));
 | |
|       SIGNAL_TOKEN (SndToken, EFI_SUCCESS);
 | |
|       Count -= SockToken->RemainDataLen;
 | |
|       FreePool (SockToken);
 | |
|     } else {
 | |
|       SockToken->RemainDataLen -= Count;
 | |
|       Count                     = 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // to judge if we can process some send token in
 | |
|   // Sock->SndTokenList, if so process those send token
 | |
|   //
 | |
|   SockProcessSndToken (Sock);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Called by the low layer protocol to copy some data in the socket send
 | |
|   buffer starting from the specific offset to a buffer provided by
 | |
|   the caller.
 | |
| 
 | |
|   @param[in]  Sock                  Pointer to the socket.
 | |
|   @param[in]  Offset                The start point of the data to be copied.
 | |
|   @param[in]  Len                   The length of the data to be copied.
 | |
|   @param[out] Dest                  Pointer to the destination to copy the data.
 | |
| 
 | |
|   @return The data size copied.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| SockGetDataToSend (
 | |
|   IN  SOCKET  *Sock,
 | |
|   IN  UINT32  Offset,
 | |
|   IN  UINT32  Len,
 | |
|   OUT UINT8   *Dest
 | |
|   )
 | |
| {
 | |
|   ASSERT ((Sock != NULL) && SockStream == Sock->Type);
 | |
| 
 | |
|   return NetbufQueCopy (
 | |
|            Sock->SndBuffer.DataQueue,
 | |
|            Offset,
 | |
|            Len,
 | |
|            Dest
 | |
|            );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Called by the low layer protocol to deliver received data to socket layer.
 | |
| 
 | |
|   This function will append the data to the socket receive buffer, set the
 | |
|   urgent data length, and then check if any receive token can be signaled.
 | |
| 
 | |
|   @param[in, out]  Sock       Pointer to the socket.
 | |
|   @param[in, out]  NetBuffer  Pointer to the buffer that contains the received data.
 | |
|   @param[in]       UrgLen     The length of the urgent data in the received data.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockDataRcvd (
 | |
|   IN OUT SOCKET   *Sock,
 | |
|   IN OUT NET_BUF  *NetBuffer,
 | |
|   IN     UINT32   UrgLen
 | |
|   )
 | |
| {
 | |
|   ASSERT (
 | |
|     (Sock != NULL) && (Sock->RcvBuffer.DataQueue != NULL) &&
 | |
|     UrgLen <= NetBuffer->TotalSize
 | |
|     );
 | |
| 
 | |
|   NET_GET_REF (NetBuffer);
 | |
| 
 | |
|   ((TCP_RSV_DATA *)(NetBuffer->ProtoData))->UrgLen = UrgLen;
 | |
| 
 | |
|   NetbufQueAppend (Sock->RcvBuffer.DataQueue, NetBuffer);
 | |
| 
 | |
|   SockWakeRcvToken (Sock);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the length of the free space of the specific socket buffer.
 | |
| 
 | |
|   @param[in]  Sock              Pointer to the socket.
 | |
|   @param[in]  Which             Flag to indicate which socket buffer to check:
 | |
|                                 either send buffer or receive buffer.
 | |
| 
 | |
|   @return The length of the free space, in bytes.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| SockGetFreeSpace (
 | |
|   IN SOCKET  *Sock,
 | |
|   IN UINT32  Which
 | |
|   )
 | |
| {
 | |
|   UINT32       BufferCC;
 | |
|   SOCK_BUFFER  *SockBuffer;
 | |
| 
 | |
|   ASSERT (Sock != NULL && ((SOCK_SND_BUF == Which) || (SOCK_RCV_BUF == Which)));
 | |
| 
 | |
|   if (SOCK_SND_BUF == Which) {
 | |
|     SockBuffer = &(Sock->SndBuffer);
 | |
|   } else {
 | |
|     SockBuffer = &(Sock->RcvBuffer);
 | |
|   }
 | |
| 
 | |
|   BufferCC = (SockBuffer->DataQueue)->BufSize;
 | |
| 
 | |
|   if (BufferCC >= SockBuffer->HighWater) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   return SockBuffer->HighWater - BufferCC;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Called by the low layer protocol to indicate that there will be no more data
 | |
|   from the communication peer.
 | |
| 
 | |
|   This function sets the socket's state to SO_NO_MORE_DATA and signals all queued
 | |
|   IO tokens with the error status EFI_CONNECTION_FIN.
 | |
| 
 | |
|   @param[in, out]  Sock                  Pointer to the socket.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SockNoMoreData (
 | |
|   IN OUT SOCKET  *Sock
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Err;
 | |
| 
 | |
|   SOCK_NO_MORE_DATA (Sock);
 | |
| 
 | |
|   if (!IsListEmpty (&Sock->RcvTokenList)) {
 | |
|     ASSERT (0 == GET_RCV_DATASIZE (Sock));
 | |
| 
 | |
|     Err = Sock->SockError;
 | |
| 
 | |
|     SOCK_ERROR (Sock, EFI_CONNECTION_FIN);
 | |
| 
 | |
|     SockFlushPendingToken (Sock, &Sock->RcvTokenList);
 | |
| 
 | |
|     SOCK_ERROR (Sock, Err);
 | |
|   }
 | |
| }
 |