mirror of https://github.com/acidanthera/audk.git
960 lines
24 KiB
C
960 lines
24 KiB
C
/** @file
|
|
Interface function of the Socket.
|
|
|
|
Copyright (c) 2005 - 2006, Intel Corporation<BR>
|
|
All rights reserved. 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;
|
|
}
|
|
|
|
|
|
/**
|
|
Destory 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;
|
|
|
|
ASSERT ((Sock != NULL) && (Sock->ProtoHandler != NULL));
|
|
|
|
if (Sock->IsDestroyed) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Sock->IsDestroyed = TRUE;
|
|
|
|
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->IsDestroyed = 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;
|
|
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));
|
|
|
|
SockDestroy (Sock);
|
|
return NULL;
|
|
}
|
|
//
|
|
// inform the protocol layer to attach the socket
|
|
// with a new protocol control block
|
|
//
|
|
Status = Sock->ProtoHandler (Sock, SOCK_ATTACH, NULL);
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
DEBUG ((EFI_D_ERROR, "SockCreateChild: Protocol failed to"
|
|
" attach a socket with %r\n", Status));
|
|
|
|
SockDestroy (Sock);
|
|
Sock = NULL;
|
|
}
|
|
|
|
EfiReleaseLock (&(Sock->Lock));
|
|
return Sock;
|
|
}
|
|
|
|
|
|
/**
|
|
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 (SOCK_STREAM == 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_INFO,
|
|
"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 (SOCK_STREAM == 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));
|
|
gBS->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 (SOCK_STREAM == 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) {
|
|
Status = SockProcessRcvToken (Sock, RcvToken);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
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 (SOCK_STREAM == 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 (SOCK_STREAM == 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;
|
|
}
|